diff --git a/.cargo/config.toml b/.cargo/config.toml index ebfdcef212..03b2e01cd2 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -40,9 +40,12 @@ xclippy = [ "-Wclippy::mut_mut", "-Wclippy::mutex_integer", "-Wclippy::needless_borrow", + "-Wclippy::needless_collect", "-Wclippy::needless_continue", "-Wclippy::path_buf_push_overwrite", "-Wclippy::rc_mutex", + "-Wclippy::redundant_clone", + "-Wclippy::redundant_closure_for_method_calls", "-Wclippy::ref_option_ref", "-Wclippy::rest_pat_in_fully_bound_structs", "-Wclippy::same_functions_in_if_condition", @@ -50,6 +53,8 @@ xclippy = [ "-Wclippy::string_add_assign", "-Wclippy::todo", "-Wclippy::trait_duplication_in_bounds", + "-Wclippy::trivially_copy_pass_by_ref", + "-Wclippy::uninlined_format_args", "-Wclippy::unnested_or_patterns", "-Wclippy::useless_transmute", "-Wclippy::verbose_file_reads", @@ -59,6 +64,7 @@ xclippy = [ "-Wtrivial_numeric_casts", "-Wunexpected_cfgs", "-Wunused_lifetimes", + "-Wunused_qualifications", # The following lints are disabled because they trigger warnings: # -Wclippy::checked_conversions (12 warnings) # -Wclippy::debug_assert_with_mut_call (3 warnings) @@ -125,9 +131,12 @@ xclippy-fix = [ "-Wclippy::mut_mut", "-Wclippy::mutex_integer", "-Wclippy::needless_borrow", + "-Wclippy::needless_collect", "-Wclippy::needless_continue", "-Wclippy::path_buf_push_overwrite", "-Wclippy::rc_mutex", + "-Wclippy::redundant_clone", + "-Wclippy::redundant_closure_for_method_calls", "-Wclippy::ref_option_ref", "-Wclippy::rest_pat_in_fully_bound_structs", "-Wclippy::same_functions_in_if_condition", @@ -135,6 +144,8 @@ xclippy-fix = [ "-Wclippy::string_add_assign", "-Wclippy::todo", "-Wclippy::trait_duplication_in_bounds", + "-Wclippy::trivially_copy_pass_by_ref", + "-Wclippy::uninlined_format_args", "-Wclippy::unnested_or_patterns", "-Wclippy::useless_transmute", "-Wclippy::verbose_file_reads", @@ -144,6 +155,7 @@ xclippy-fix = [ "-Wtrivial_numeric_casts", "-Wunexpected_cfgs", "-Wunused_lifetimes", + "-Wunused_qualifications", ] [target.wasm32-unknown-unknown] diff --git a/.github/actionlint.yaml b/.github/actionlint.yaml new file mode 100644 index 0000000000..66816b6446 --- /dev/null +++ b/.github/actionlint.yaml @@ -0,0 +1,5 @@ +# Allow actionlint to recognize the org's custom Warp runner label used by the +# non-regression benchmark workflows. +self-hosted-runner: + labels: + - warp-ubuntu-latest-x64-8x diff --git a/.github/actions/workspace-release/action.yml b/.github/actions/workspace-release/action.yml index cbb705ef59..bc9099d9b5 100644 --- a/.github/actions/workspace-release/action.yml +++ b/.github/actions/workspace-release/action.yml @@ -32,17 +32,13 @@ runs: fi - name: Install Rust toolchain - uses: dtolnay/rust-toolchain@stable + shell: bash + run: | + rustup update --no-self-update stable + rustup default stable - - name: Cache cargo registry and git index - uses: actions/cache@v4 - with: - path: | - ~/.cargo/registry - ~/.cargo/git - key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} - restore-keys: | - ${{ runner.os }}-cargo- + - name: Cache Rust build artifacts + uses: WarpBuilds/rust-cache@9d0cc3090d9c87de74ea67617b246e978735b1a1 # v2.9.1 - name: Cleanup large tools for build space uses: ./.github/actions/cleanup-runner @@ -50,19 +46,11 @@ runs: # Install cargo-msrv for MSRV checks - name: Install cargo-msrv shell: bash - env: - RUSTUP_TOOLCHAIN: "1.91" - run: cargo install cargo-msrv - - - name: Install Rust 1.91 for MSRV check - shell: bash - run: rustup toolchain install 1.91 + run: cargo install cargo-msrv --version 0.19.3 --locked # Keep your existing MSRV check - name: Check MSRV shell: bash - env: - RUSTUP_TOOLCHAIN: "1.91" run: | chmod +x scripts/check-msrv.sh ./scripts/check-msrv.sh diff --git a/.github/workflows/bench.yml b/.github/workflows/bench.yml index 264237103c..730255a650 100644 --- a/.github/workflows/bench.yml +++ b/.github/workflows/bench.yml @@ -16,7 +16,9 @@ jobs: name: Bench on ubuntu-latest runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + with: + persist-credentials: false - name: Bench for all features run: | rustup +stable update --no-self-update diff --git a/.github/workflows/blake3-nonregression.yml b/.github/workflows/blake3-nonregression.yml new file mode 100644 index 0000000000..c443859663 --- /dev/null +++ b/.github/workflows/blake3-nonregression.yml @@ -0,0 +1,373 @@ +name: blake3 1-to-1 non-regression + +on: + push: + branches: + - main + - next + workflow_dispatch: + inputs: + baseline_ref: + description: Commit or ref to use as the baseline. Defaults to the current ref's first parent. + required: false + type: string + current_ref: + description: Commit or ref to benchmark. Defaults to the workflow ref. + required: false + type: string + regression_threshold_pct: + description: Allowed slowdown before the workflow fails. + required: false + default: "5" + type: string + rayon_num_threads: + description: RAYON_NUM_THREADS value used for the prove command. + required: false + default: "8" + type: string + +concurrency: + group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + benchmark: + name: Benchmark baseline vs current + runs-on: warp-ubuntu-latest-x64-8x + timeout-minutes: 180 + permissions: + contents: read + outputs: + summary: ${{ steps.summary.outputs.summary }} + regression: ${{ steps.compare.outputs.regression }} + status: ${{ steps.compare.outputs.status }} + baseline_sha: ${{ steps.compare.outputs.baseline_sha }} + current_sha: ${{ steps.compare.outputs.current_sha }} + program_delta_ms: ${{ steps.compare.outputs.program_delta_ms }} + program_delta_pct: ${{ steps.compare.outputs.program_delta_pct }} + steps: + - name: Check out repository + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 + with: + fetch-depth: 0 + persist-credentials: false + + - name: Install Rust toolchain + shell: bash + run: | + set -euo pipefail + toolchain="$(sed -n 's/^channel = "\(.*\)"$/\1/p' rust-toolchain.toml)" + rustup toolchain install "${toolchain}" --profile minimal --target wasm32-unknown-unknown + + - name: Cache Rust dependencies + uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 + + - name: Prepare benchmark directories + id: dirs + shell: bash + run: | + set -euo pipefail + run_root="${RUNNER_TEMP}/blake3-nonregression-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}" + artifact_dir="${run_root}/artifacts" + worktree_dir="${run_root}/worktrees" + mkdir -p "${artifact_dir}" "${worktree_dir}" + { + echo "run_root=${run_root}" + echo "artifact_dir=${artifact_dir}" + echo "worktree_dir=${worktree_dir}" + } >> "${GITHUB_OUTPUT}" + + - name: Resolve benchmark refs + id: refs + env: + EVENT_NAME: ${{ github.event_name }} + BEFORE_SHA: ${{ github.event.before }} + INPUT_BASELINE_REF: ${{ inputs.baseline_ref }} + INPUT_CURRENT_REF: ${{ inputs.current_ref }} + INPUT_THRESHOLD_PCT: ${{ inputs.regression_threshold_pct }} + INPUT_RAYON_THREADS: ${{ inputs.rayon_num_threads }} + shell: bash + run: | + set -euo pipefail + + resolve_commit() { + local ref="$1" + git rev-parse --verify --end-of-options "${ref}^{commit}" + } + + fetch_commit_if_needed() { + local ref="$1" + local fetch_log + if resolve_commit "${ref}" >/dev/null 2>&1; then + return 0 + fi + fetch_log="$(mktemp)" + if git fetch --no-tags --depth=1 origin "${ref}" >"${fetch_log}" 2>&1; then + rm -f "${fetch_log}" + resolve_commit "${ref}" >/dev/null 2>&1 + return $? + fi + if grep -Eqi "couldn't find remote ref|not our ref|unadvertised object|reference is not a tree|no such remote ref" "${fetch_log}"; then + rm -f "${fetch_log}" + return 2 + fi + cat "${fetch_log}" >&2 + rm -f "${fetch_log}" + return 1 + } + + if [[ "${EVENT_NAME}" == "push" ]]; then + current_ref="${GITHUB_SHA}" + baseline_ref="${BEFORE_SHA}" + threshold_pct="5" + rayon_threads="8" + else + baseline_ref="${INPUT_BASELINE_REF}" + current_ref="${INPUT_CURRENT_REF}" + threshold_pct="${INPUT_THRESHOLD_PCT}" + rayon_threads="${INPUT_RAYON_THREADS}" + fi + + if [[ -z "${current_ref}" ]]; then + current_ref="${GITHUB_SHA}" + fi + + if [[ -z "${threshold_pct}" ]]; then + threshold_pct="5" + fi + + if [[ -z "${rayon_threads}" ]]; then + rayon_threads="8" + fi + + if [[ ! "${threshold_pct}" =~ ^[0-9]+([.][0-9]+)?$ ]]; then + echo "regression_threshold_pct must be numeric" >&2 + exit 1 + fi + + if [[ ! "${rayon_threads}" =~ ^[0-9]+$ ]]; then + echo "rayon_num_threads must be an integer" >&2 + exit 1 + fi + + if [[ -z "${baseline_ref}" || "${baseline_ref}" == "0000000000000000000000000000000000000000" ]]; then + baseline_ref="${current_ref}^" + fi + + current_sha="$(resolve_commit "${current_ref}")" + fetch_status=0 + + if [[ "${EVENT_NAME}" == "push" && "${BEFORE_SHA}" != "0000000000000000000000000000000000000000" ]]; then + if fetch_commit_if_needed "${baseline_ref}"; then + fetch_status=0 + else + fetch_status=$? + fi + fi + + if [[ "${EVENT_NAME}" == "push" && "${BEFORE_SHA}" != "0000000000000000000000000000000000000000" && ${fetch_status} -eq 0 ]]; then + baseline_sha="$(resolve_commit "${baseline_ref}")" + elif [[ "${EVENT_NAME}" == "push" && "${BEFORE_SHA}" != "0000000000000000000000000000000000000000" && ${fetch_status} -eq 2 ]]; then + echo "push baseline ${baseline_ref} is no longer available; refusing to compare against current_sha^" >&2 + exit 1 + elif resolve_commit "${baseline_ref}" >/dev/null 2>&1; then + baseline_sha="$(resolve_commit "${baseline_ref}")" + elif [[ "${EVENT_NAME}" == "push" && "${BEFORE_SHA}" == "0000000000000000000000000000000000000000" ]]; then + baseline_ref="${current_sha}^" + baseline_sha="$(resolve_commit "${current_sha}^")" + elif [[ "${EVENT_NAME}" == "workflow_dispatch" && -z "${INPUT_BASELINE_REF}" ]]; then + baseline_ref="${current_sha}^" + baseline_sha="$(resolve_commit "${current_sha}^")" + else + echo "baseline_ref must resolve to a commit: ${baseline_ref}" >&2 + exit 1 + fi + + baseline_ref="${baseline_sha}" + + { + echo "baseline_ref=${baseline_ref}" + echo "current_ref=${current_ref}" + echo "baseline_sha=${baseline_sha}" + echo "current_sha=${current_sha}" + echo "threshold_pct=${threshold_pct}" + echo "rayon_threads=${rayon_threads}" + } >> "${GITHUB_OUTPUT}" + + - name: Create worktrees + env: + WORKTREE_DIR: ${{ steps.dirs.outputs.worktree_dir }} + BASELINE_SHA: ${{ steps.refs.outputs.baseline_sha }} + CURRENT_SHA: ${{ steps.refs.outputs.current_sha }} + shell: bash + run: | + set -euo pipefail + git worktree add --detach "${WORKTREE_DIR}/baseline" "${BASELINE_SHA}" + git worktree add --detach "${WORKTREE_DIR}/current" "${CURRENT_SHA}" + + - name: Run baseline benchmark + env: + GITHUB_WORKSPACE_PATH: ${{ github.workspace }} + WORKTREE_DIR: ${{ steps.dirs.outputs.worktree_dir }} + ARTIFACT_DIR: ${{ steps.dirs.outputs.artifact_dir }} + RAYON_THREADS: ${{ steps.refs.outputs.rayon_threads }} + BASELINE_SHA: ${{ steps.refs.outputs.baseline_sha }} + shell: bash + run: | + set -euo pipefail + python3 "${GITHUB_WORKSPACE_PATH}/scripts/blake3_nonregression.py" run \ + --repo-root "${WORKTREE_DIR}/baseline" \ + --output-dir "${ARTIFACT_DIR}/baseline" \ + --rayon-num-threads "${RAYON_THREADS}" \ + --git-ref "${BASELINE_SHA}" + + - name: Run current benchmark + env: + GITHUB_WORKSPACE_PATH: ${{ github.workspace }} + WORKTREE_DIR: ${{ steps.dirs.outputs.worktree_dir }} + ARTIFACT_DIR: ${{ steps.dirs.outputs.artifact_dir }} + RAYON_THREADS: ${{ steps.refs.outputs.rayon_threads }} + CURRENT_SHA: ${{ steps.refs.outputs.current_sha }} + shell: bash + run: | + set -euo pipefail + python3 "${GITHUB_WORKSPACE_PATH}/scripts/blake3_nonregression.py" run \ + --repo-root "${WORKTREE_DIR}/current" \ + --output-dir "${ARTIFACT_DIR}/current" \ + --rayon-num-threads "${RAYON_THREADS}" \ + --git-ref "${CURRENT_SHA}" + + - name: Compare baseline and current results + id: compare + env: + GITHUB_WORKSPACE_PATH: ${{ github.workspace }} + ARTIFACT_DIR: ${{ steps.dirs.outputs.artifact_dir }} + THRESHOLD_PCT: ${{ steps.refs.outputs.threshold_pct }} + shell: bash + run: | + set -euo pipefail + python3 "${GITHUB_WORKSPACE_PATH}/scripts/blake3_nonregression.py" compare \ + --baseline "${ARTIFACT_DIR}/baseline/result.json" \ + --current "${ARTIFACT_DIR}/current/result.json" \ + --summary-out "${ARTIFACT_DIR}/summary.md" \ + --json-out "${ARTIFACT_DIR}/comparison.json" \ + --threshold-pct "${THRESHOLD_PCT}" \ + --github-output "${GITHUB_OUTPUT}" + + - name: Publish job summary + if: always() + env: + ARTIFACT_DIR: ${{ steps.dirs.outputs.artifact_dir }} + shell: bash + run: | + set -euo pipefail + if [[ -f "${ARTIFACT_DIR}/summary.md" ]]; then + cat "${ARTIFACT_DIR}/summary.md" >> "${GITHUB_STEP_SUMMARY}" + fi + + - name: Expose summary for downstream jobs + if: always() + id: summary + env: + ARTIFACT_DIR: ${{ steps.dirs.outputs.artifact_dir }} + shell: bash + run: | + set -euo pipefail + if [[ ! -f "${ARTIFACT_DIR}/summary.md" ]]; then + exit 0 + fi + { + echo "summary<> "${GITHUB_OUTPUT}" + + - name: Upload benchmark artifacts + if: always() + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 + with: + name: blake3-1to1-nonregression + path: ${{ steps.dirs.outputs.artifact_dir }} + if-no-files-found: warn + + - name: Remove worktrees + if: always() + env: + RUN_ROOT: ${{ steps.dirs.outputs.run_root }} + WORKTREE_DIR: ${{ steps.dirs.outputs.worktree_dir }} + shell: bash + run: | + set -euo pipefail + git worktree remove --force "${WORKTREE_DIR}/baseline" || true + git worktree remove --force "${WORKTREE_DIR}/current" || true + rm -rf "${RUN_ROOT}" + + - name: Fail on regression + if: steps.compare.outputs.regression == 'true' + env: + PROGRAM_DELTA_PCT: ${{ steps.compare.outputs.program_delta_pct }} + shell: bash + run: | + set -euo pipefail + echo "blake3 1-to-1 benchmark regressed by ${PROGRAM_DELTA_PCT}%" + exit 1 + + comment: + name: Comment on pushed commit + runs-on: ubuntu-latest + needs: + - benchmark + if: always() && github.event_name == 'push' && needs.benchmark.outputs.current_sha != '' && needs.benchmark.outputs.summary != '' + permissions: + contents: write + steps: + - name: Create or update commit comment + uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b + env: + CURRENT_SHA: ${{ needs.benchmark.outputs.current_sha }} + MARKER: "" + BODY: ${{ needs.benchmark.outputs.summary }} + with: + script: | + const body = [ + process.env.MARKER, + process.env.BODY, + '', + `Workflow run: ${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`, + ].join('\n'); + + const owner = context.repo.owner; + const repo = context.repo.repo; + const commitSha = process.env.CURRENT_SHA; + const marker = process.env.MARKER; + + const comments = await github.paginate( + github.rest.repos.listCommentsForCommit, + { + owner, + repo, + commit_sha: commitSha, + per_page: 100, + }, + ); + + const existing = comments.find(comment => + comment.user?.type === 'Bot' && comment.body?.includes(marker) + ); + + if (existing) { + await github.rest.repos.updateCommitComment({ + owner, + repo, + comment_id: existing.id, + body, + }); + return; + } + + await github.rest.repos.createCommitComment({ + owner, + repo, + commit_sha: commitSha, + body, + }); diff --git a/.github/workflows/build-docs.yml b/.github/workflows/build-docs.yml index 8400212bc1..8c82d89609 100644 --- a/.github/workflows/build-docs.yml +++ b/.github/workflows/build-docs.yml @@ -28,10 +28,12 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + with: + persist-credentials: false - name: Setup Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: "20" cache: "npm" diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 69cea52ee9..4d73094af4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -20,7 +20,9 @@ jobs: matrix: toolchain: [stable, nightly] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + with: + persist-credentials: false - name: Cleanup large tools for build space uses: ./.github/actions/cleanup-runner - name: Build for no-std @@ -29,3 +31,21 @@ jobs: rustup +${{ matrix.toolchain }} target add wasm32-unknown-unknown rustup default ${{ matrix.toolchain }} make build-no-std + fuzz-check: + name: Check for miden-core-fuzz crate + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + with: + persist-credentials: false + - name: Install Rust toolchain + run: rustup toolchain install --no-self-update + - uses: WarpBuilds/rust-cache@9d0cc3090d9c87de74ea67617b246e978735b1a1 # v2.9.1 + with: + # We need to explicitly cache the miden-core-fuzz workspace, as only the root workspace is + # cached by default. + workspaces: | + . + miden-core-fuzz + - name: Check miden-core-fuzz crate + run: cd miden-core-fuzz && cargo check --locked diff --git a/.github/workflows/changelog.yml b/.github/workflows/changelog.yml index f159d08757..f234c7c3b6 100644 --- a/.github/workflows/changelog.yml +++ b/.github/workflows/changelog.yml @@ -14,16 +14,5 @@ on: types: [opened, reopened, synchronize, labeled, unlabeled] jobs: - changelog: - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - name: Check for changes in changelog - env: - BASE_REF: ${{ github.event.pull_request.base.ref }} - NO_CHANGELOG_LABEL: ${{ contains(github.event.pull_request.labels.*.name, 'no changelog') }} - run: ./scripts/check-changelog.sh "${{ inputs.changelog }}" - shell: bash + changelog-reusable: + uses: 0xMiden/.github/.github/workflows/changelog.yml@d34ae3cd29234c5aa4d3ab57635b30563471c3c3 diff --git a/.github/workflows/contribution-quality.yml b/.github/workflows/contribution-quality.yml index f9790808a6..a91900a769 100644 --- a/.github/workflows/contribution-quality.yml +++ b/.github/workflows/contribution-quality.yml @@ -1,8 +1,6 @@ name: Contribution Quality -# Use pull_request_target to get write permissions for fork PRs. -# IMPORTANT: This workflow runs in the context of the BASE branch, not the PR branch. -# Do NOT checkout or run code from the PR itself, only inspect PR metadata via the API. +# Use pull_request_target so the workflow can safely comment/label on PRs. on: pull_request_target: types: [opened, reopened, edited, synchronize, ready_for_review] @@ -19,208 +17,31 @@ on: type: choice options: ["false", "true"] -permissions: - contents: read - pull-requests: write - issues: write +permissions: {} jobs: + contribution-quality-reusable: + permissions: + contents: read + pull-requests: write + issues: write + uses: 0xMiden/.github/.github/workflows/contribution-quality.yml@38552ca595c5773dd361cdc479f349ef75831386 + with: + pr_number: ${{ github.event.inputs.pr_number || '' }} + force_all: ${{ github.event.inputs.force_all || 'false' }} + gate: - if: > - github.event_name == 'workflow_dispatch' || - (github.event_name == 'pull_request' && - github.event.pull_request.head.repo.fork == true) runs-on: ubuntu-latest - env: - DISPATCH_PR_NUMBER: ${{ inputs.pr_number }} - DISPATCH_FORCE_ALL: ${{ inputs.force_all }} + needs: contribution-quality-reusable + if: always() steps: - - name: Resolve PR number and event mode - id: ctx - uses: actions/github-script@v7 - with: - script: | - // pull_request_target has the same payload shape as pull_request - const isPREvent = !!context.payload.pull_request; - const fromDispatch = context.payload?.inputs?.pr_number || process.env.DISPATCH_PR_NUMBER || ''; - const prNumber = isPREvent ? String(context.payload.pull_request.number) : String(fromDispatch || ''); - if (!prNumber) { - core.setFailed('pr_number is required for manual (workflow_dispatch) runs.'); - return; - } - const forceAll = (context.payload?.inputs?.force_all || process.env.DISPATCH_FORCE_ALL || 'false').toLowerCase(); - core.setOutput('is_pr_event', String(isPREvent)); - core.setOutput('pr_number', prNumber); - core.setOutput('force_all', forceAll); - - - name: Load PR details - id: pr - uses: actions/github-script@v7 - with: - script: | - const prNumber = parseInt("${{ steps.ctx.outputs.pr_number }}", 10); - const { data: pr } = await github.rest.pulls.get({ - owner: context.repo.owner, - repo: context.repo.repo, - pull_number: prNumber - }); - core.setOutput('author_association', pr.author_association || 'NONE'); - core.setOutput('draft', pr.draft ? 'true' : 'false'); - core.setOutput('body', (pr.body || '').replace(/\r/g,'')); - core.setOutput('number', String(pr.number)); - - - name: Skip trusted or drafts (unless forced) - id: gate + - name: Mirror reusable workflow result + env: + RESULT: ${{ needs.contribution-quality-reusable.result }} run: | - assoc="${{ steps.pr.outputs.author_association }}" - draft="${{ steps.pr.outputs.draft }}" - force="${{ steps.ctx.outputs.force_all }}" - if [ "$force" = "true" ]; then - echo "skip=false" >> "$GITHUB_OUTPUT" - else - case "$assoc" in - OWNER|COLLABORATOR|MEMBER) echo "skip=true" >> "$GITHUB_OUTPUT" ;; - *) echo "skip=false" >> "$GITHUB_OUTPUT" ;; - esac - [ "$draft" = "true" ] && echo "skip=true" >> "$GITHUB_OUTPUT" || true + if [ "$RESULT" = "success" ] || [ "$RESULT" = "skipped" ]; then + exit 0 fi - - name: Evaluate - if: steps.gate.outputs.skip != 'true' - id: eval - uses: actions/github-script@v7 - env: - PRNUM: ${{ steps.pr.outputs.number }} - BODY: ${{ steps.pr.outputs.body }} - with: - script: | - const prNumber = parseInt(process.env.PRNUM, 10); - const body = process.env.BODY || ''; - - const DOC_ONLY_MAX_LINES = 20; - const CODE_ONLY_MAX_LINES = 8; - const MAX_ISSUES_TO_CHECK = 5; - - const files = await github.rest.pulls.listFiles({ - owner: context.repo.owner, - repo: context.repo.repo, - pull_number: prNumber, - per_page: 100 - }).then(r => r.data); - - const ext = (p) => { const i=p.lastIndexOf('.'); return i>=0?p.slice(i).toLowerCase():''; }; - const DOCS = new Set(['.md','.rst','.txt']); - const CODE = new Set(['.rs','.go','.py','.ts','.tsx','.js','.jsx','.java','.kt','.cpp','.c','.hpp','.hh','.h','.rb','.swift','.scala','.php','.sh','.bash','.zsh','.ps1','.yaml','.yml','.toml','.json']); - const TEST_HINTS = [/^tests?\//i, /\/tests?\//i, /_test\./i, /\.spec\./i, /\.test\./i]; - - const changedFiles = files.length; - const adds = files.reduce((a,f)=>a+(f.additions||0),0); - const dels = files.reduce((a,f)=>a+(f.deletions||0),0); - const onlyDocs = changedFiles>0 && files.every(f => DOCS.has(ext(f.filename))); - const onlyCode = changedFiles>0 && files.every(f => CODE.has(ext(f.filename))); - const touchesTests = files.some(f => TEST_HINTS.some(rx => rx.test(f.filename))); - - const issueNums = new Set(); - for (const m of (body.match(/(?:fixe?s?|close?s?|resolve?s?)\s*#(\d+)/ig) || [])) { - const mm = m.match(/#(\d+)/); if (mm) issueNums.add(mm[1]); - } - for (const m of (body.match(/#(\d+)/g) || [])) { - issueNums.add(m.replace('#','')); - } - - let hasLinkedIssue=false, linkedAssigned=false, linkedNumber=null; - if (issueNums.size) { - const author = (await github.rest.pulls.get({ - owner: context.repo.owner, repo: context.repo.repo, pull_number: prNumber - })).data.user.login.toLowerCase(); - for (const n of [...issueNums].slice(0,MAX_ISSUES_TO_CHECK).map(x=>parseInt(x,10)).filter(Number.isInteger)) { - try { - const { data: iss } = await github.rest.issues.get({ - owner: context.repo.owner, repo: context.repo.repo, issue_number: n - }); - if (!iss.pull_request) { - hasLinkedIssue = true; linkedNumber = n; - const assignees = (iss.assignees||[]).map(a=>a.login.toLowerCase()); - if (assignees.includes(author)) linkedAssigned = true; - break; - } - } catch (err) { core.warning(`Failed to fetch issue #${n}: ${err}`); } - } - } - - const hasRationale = /(^|\n)#{0,3}\s*(rationale|why)\b/i.test(body) || /\bbecause\b/i.test(body); - const hasTestPlan = /(^|\n)#{0,3}\s*(test\s*plan|how\s*i\s*tested)\b/i.test(body); - - const trivialDoc = onlyDocs && (adds+dels)<=DOC_ONLY_MAX_LINES && changedFiles<=2; - const trivialCode = onlyCode && !touchesTests && (adds+dels)<=CODE_ONLY_MAX_LINES && changedFiles<=1; - - const findings = []; - const recommendations = []; - if (!hasLinkedIssue) findings.push('Link an issue in the PR body (e.g., "Fixes #123").'); - else if (!linkedAssigned) findings.push(`Ensure issue #${linkedNumber} is assigned to the PR author.`); - if (!hasRationale) findings.push('Add a short Rationale explaining why the change is needed.'); - if (!hasTestPlan) recommendations.push('Consider adding a Test plan or clear review steps.'); - if (trivialDoc) findings.push('Change appears to be a trivial doc-only edit; may be batched internally.'); - if (trivialCode) findings.push('Change appears to be a trivial code-only edit without tests; may be batched internally.'); - - core.setOutput('hasFindings', String(findings.length > 0)); - core.setOutput('findings', JSON.stringify(findings)); - core.setOutput('recommendations', JSON.stringify(recommendations)); - core.setOutput('linked', linkedNumber ? String(linkedNumber) : ''); - core.setOutput('pr_number', String(prNumber)); - - - name: Apply label and comment - if: steps.gate.outputs.skip != 'true' && (steps.eval.outputs.hasFindings == 'true' || steps.eval.outputs.recommendations != '[]') - uses: actions/github-script@v7 - env: - FINDINGS: ${{ steps.eval.outputs.findings }} - RECOMMENDATIONS: ${{ steps.eval.outputs.recommendations }} - LINK: ${{ steps.eval.outputs.linked }} - PRNUM: ${{ steps.eval.outputs.pr_number }} - HAS_FINDINGS: ${{ steps.eval.outputs.hasFindings }} - with: - script: | - const issue_number = parseInt(process.env.PRNUM, 10); - const findings = JSON.parse(process.env.FINDINGS || "[]"); - const recommendations = JSON.parse(process.env.RECOMMENDATIONS || "[]"); - const linked = process.env.LINK; - const hasFindings = process.env.HAS_FINDINGS === 'true'; - - // Only apply label if there are actual findings (not just recommendations) - if (hasFindings) { - await github.rest.issues.addLabels({ - owner: context.repo.owner, repo: context.repo.repo, issue_number, - labels: ['quality-concern'] - }); - } - - const guidance = [ - linked ? `- Ensure issue #${linked} is assigned to you.` : `- Link a relevant issue (e.g., "Fixes #123") and ensure it is assigned to you.`, - '- See CONTRIBUTING.md for expectations.', - '- If this is a false positive, comment: `/quality-review`.' - ]; - - const commentBody = [ - 'Automated check (CONTRIBUTING.md)', - '' - ]; - - if (findings.length > 0) { - commentBody.push('Findings:'); - commentBody.push(...findings.map(f => `- ${f}`)); - commentBody.push(''); - } - - if (recommendations.length > 0) { - commentBody.push('Recommendations:'); - commentBody.push(...recommendations.map(f => `- ${f}`)); - commentBody.push(''); - } - - commentBody.push('Next steps:'); - commentBody.push(...guidance); - - await github.rest.issues.createComment({ - owner: context.repo.owner, repo: context.repo.repo, issue_number, - body: commentBody.join('\n') - }); + echo "Reusable contribution quality workflow concluded with $RESULT" >&2 + exit 1 diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 0537b1b480..0f6a4ceb57 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -28,35 +28,59 @@ jobs: docs: name: Generate and deploy crate documentation runs-on: ubuntu-latest + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + with: + persist-credentials: false - name: Cleanup large tools for build space uses: ./.github/actions/cleanup-runner + - name: Configure GitHub Pages + uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b # v5.0.0 + - name: Generate documentation run: | rustup update --no-self-update rustup default stable make doc - - name: Prepare publish tree + - name: Prepare GitHub Pages artifact run: | set -euo pipefail - mkdir -p .gh-pages-publish/docs - if git ls-remote --heads origin gh-pages | grep -q gh-pages; then - git fetch --depth=1 origin gh-pages - git worktree add --detach .gh-pages-worktree FETCH_HEAD - rsync -a --delete --exclude ".git" .gh-pages-worktree/ .gh-pages-publish/ - git worktree remove .gh-pages-worktree --force - fi - rm -rf .gh-pages-publish/docs - mkdir -p .gh-pages-publish/docs - rsync -a --delete target/doc/ .gh-pages-publish/docs/ - touch .gh-pages-publish/.nojekyll + mkdir -p _site/docs - - name: Deploy documentation - uses: peaceiris/actions-gh-pages@373f7f263a76c20808c831209c920827a82a2847 # pin@v3 + # Publish a single Pages artifact so the live site does not depend on + # whichever Pages source GitHub happens to be configured to read. + cat > _site/index.html << 'EOF' + + + + + Redirecting to docs.miden.xyz + + + + +

Miden VM Documentation Has Moved

+

This site has moved to + docs.miden.xyz/miden-vm. + You will be redirected automatically.

+ + + EOF + + rsync -a --delete target/doc/ _site/docs/ + touch _site/.nojekyll + + - name: Upload GitHub Pages artifact + uses: actions/upload-pages-artifact@56afc609e74202658d3ffba0e8f6dda462b719fa # v3.0.1 with: - github_token: ${{ secrets.GITHUB_TOKEN }} - publish_dir: ./.gh-pages-publish + path: ./_site + + - name: Deploy documentation + id: deployment + uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4.0.5 diff --git a/.github/workflows/fuzz.yml b/.github/workflows/fuzz.yml index 094c5e4845..c562a03722 100644 --- a/.github/workflows/fuzz.yml +++ b/.github/workflows/fuzz.yml @@ -39,18 +39,58 @@ jobs: - precompile_request_deserialize - library_deserialize - package_deserialize + - package_semantic_deserialize + - project_toml_parse + - project_load + - project_assemble timeout-minutes: 15 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + with: + persist-credentials: false - name: Cleanup large tools for build space uses: ./.github/actions/cleanup-runner - - uses: dtolnay/rust-toolchain@nightly - - uses: Swatinem/rust-cache@v2 + - name: Install Rust toolchain + run: rustup update --no-self-update nightly + - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 - name: Install cargo-fuzz run: cargo install cargo-fuzz --locked + - name: Generate fuzz seed corpus + env: + TARGET: ${{ matrix.target }} + GENERATED_CORPUS_TARGETS: >- + mast_forest_deserialize program_deserialize kernel_deserialize + stack_io_deserialize advice_inputs_deserialize operation_deserialize + execution_proof_deserialize precompile_request_deserialize + library_deserialize package_deserialize package_semantic_deserialize + run: | + if [[ " $GENERATED_CORPUS_TARGETS " == *" $TARGET "* ]]; then + make fuzz-seeds + else + echo "No generated seed corpus for $TARGET" + fi - name: Run fuzz target (smoke test) + env: + TARGET: ${{ matrix.target }} run: | + FUZZ_TARGET="$(cargo +nightly fuzz build --help | awk ' + $0 ~ /^ --target / { in_target = 1; next } + in_target && /\[default:/ { + sub(/^.*\[default: /, "") + sub(/\].*$/, "") + print + exit + } + ')" + test -n "$FUZZ_TARGET" # Build the fuzz target first - cargo +nightly fuzz build --fuzz-dir miden-core-fuzz ${{ matrix.target }} + cargo +nightly fuzz build --target "$FUZZ_TARGET" --fuzz-dir miden-core-fuzz "$TARGET" # Run directly to avoid cargo-fuzz wrapper SIGPIPE issue - miden-core-fuzz/target/x86_64-unknown-linux-gnu/release/${{ matrix.target }} -max_total_time=60 -runs=10000 + FUZZ_BIN="miden-core-fuzz/target/$FUZZ_TARGET/release/$TARGET" + test -x "$FUZZ_BIN" + CORPUS_DIR="miden-core-fuzz/corpus/$TARGET" + if [ -d "$CORPUS_DIR" ]; then + "$FUZZ_BIN" "$CORPUS_DIR" -max_total_time=60 -runs=10000 + else + "$FUZZ_BIN" -max_total_time=60 -runs=10000 + fi diff --git a/.github/workflows/link-checker.yml b/.github/workflows/link-checker.yml index 0155799d8d..918069b0f2 100644 --- a/.github/workflows/link-checker.yml +++ b/.github/workflows/link-checker.yml @@ -20,25 +20,26 @@ jobs: linkChecker: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + with: + persist-credentials: false - name: Set fail-fast flag depending on trigger id: flags run: | if [ "${{ github.event_name }}" = "schedule" ]; then - echo "fail_fast=false" >> $GITHUB_OUTPUT + echo "fail_fast=false" >> "$GITHUB_OUTPUT" else - echo "fail_fast=${{ inputs.fail-fast }}" >> $GITHUB_OUTPUT + echo "fail_fast=${{ inputs.fail-fast }}" >> "$GITHUB_OUTPUT" fi - name: Link Checker id: lychee - uses: lycheeverse/lychee-action@v2.0.2 + uses: lycheeverse/lychee-action@8646ba30535128ac92d33dfc9133794bfdd9b411 # v2.8.0 with: fail: ${{ steps.flags.outputs.fail_fast }} args: | --verbose - --exclude-mail --exclude "localhost" --exclude "127.0.0.1" --exclude "^file://" @@ -49,9 +50,17 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Fail if lychee did not produce a link report + if: steps.lychee.outputs.exit_code != '0' + run: | + if [ ! -s ./lychee/out.md ] || ! grep -q '^# Summary' ./lychee/out.md; then + echo "::error::lychee exited before producing a link-check summary. Check the Link Checker step for a workflow or tool configuration error." + exit 1 + fi + - name: Open issue on failure (only if fail-fast is false) - if: steps.lychee.outputs.exit_code != 0 && steps.flags.outputs.fail_fast != 'true' - uses: peter-evans/create-issue-from-file@v5 + if: steps.lychee.outputs.exit_code != '0' && steps.flags.outputs.fail_fast != 'true' + uses: peter-evans/create-issue-from-file@e8ef132d6df98ed982188e460ebb3b5d4ef3a9cd # v5.0.1 with: title: Link Checker Report content-filepath: ./lychee/out.md diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 91ddda132a..66e435ae6b 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -16,18 +16,52 @@ jobs: name: cargo-deny on ubuntu-latest runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: taiki-e/install-action@v2 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: - tool: cargo-deny + persist-credentials: false + - name: Install cargo-deny + run: cargo install cargo-deny --version 0.19.1 --locked - name: Check dependencies with cargo-deny run: cargo deny check + cargo-shear: + name: cargo-shear on ubuntu-latest + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + with: + persist-credentials: false + - name: Install cargo-shear + run: cargo install cargo-shear --version 1.11.2 --locked + - name: Check for unused dependencies + run: make shear + + workspace-inheritance: + name: workspace inheritance on ubuntu-latest + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + with: + persist-credentials: false + # Do not pin taiki-e's moving tool shortcut tags by hash. Pin a released + # install-action commit and set tool explicitly, or zizmor's + # impostor-commit audit can flag stale shortcut-tag hashes. + - name: Install cargo-binstall + uses: taiki-e/install-action@055f5df8c3f65ea01cd41e9dc855becd88953486 # v2.75.18 + with: + tool: cargo-binstall + - name: Install workspace inheritance checker + run: cargo binstall --no-confirm cargo-workspace-inheritance-check@1.2.0 + - name: Check workspace inheritance + run: cargo workspace-inheritance-check --promotion-threshold 2 --promotion-failure + clippy: name: clippy nightly on ubuntu-latest runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + with: + persist-credentials: false - name: Cleanup large tools for build space uses: ./.github/actions/cleanup-runner - name: Clippy @@ -40,7 +74,9 @@ jobs: name: rustfmt check nightly on ubuntu-latest runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + with: + persist-credentials: false - name: Cleanup large tools for build space uses: ./.github/actions/cleanup-runner - name: Rustfmt @@ -53,7 +89,9 @@ jobs: name: doc stable on ubuntu-latest runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + with: + persist-credentials: false - name: Cleanup large tools for build space uses: ./.github/actions/cleanup-runner - name: Build docs diff --git a/.github/workflows/redirect-pages.yml b/.github/workflows/redirect-pages.yml deleted file mode 100644 index 6a2fbef28c..0000000000 --- a/.github/workflows/redirect-pages.yml +++ /dev/null @@ -1,63 +0,0 @@ -name: Deploy GitHub Pages redirect - -on: - workflow_dispatch: - -permissions: - pages: write - id-token: write - contents: read - -jobs: - deploy: - runs-on: ubuntu-latest - environment: - name: github-pages - url: ${{ steps.deployment.outputs.page_url }} - steps: - - name: Generate redirect site - run: | - mkdir _site - - cat > _site/index.html << 'EOF' - - - - - Redirecting to docs.miden.xyz - - - - -

Miden VM Documentation Has Moved

-

This site has moved to - docs.miden.xyz/miden-vm. - You will be redirected automatically.

- - - EOF - - mkdir -p _site/docs - - cat > _site/docs/index.html << 'EOF' - - - - - Miden VM - Docs Subdirectory - - -

Miden VM Docs

-

Placeholder for future rustdoc and other documentation.

- - - EOF - - touch _site/.nojekyll - - - name: Upload artifact - uses: actions/upload-pages-artifact@v3 - - - name: Deploy to GitHub Pages - id: deployment - uses: actions/deploy-pages@v4 diff --git a/.github/workflows/signed-commits.yml b/.github/workflows/signed-commits.yml new file mode 100644 index 0000000000..7d96e5f785 --- /dev/null +++ b/.github/workflows/signed-commits.yml @@ -0,0 +1,110 @@ +# Verifies that all commits in a PR are signed (GPG or SSH). +# Posts a comment with remediation steps if unsigned commits are found. + +name: signed commits + +permissions: {} + +on: + pull_request_target: + branches: + - main + - next + types: [opened, reopened, synchronize] + +jobs: + check-signed-commits: + runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: write + steps: + - name: Resolve author permission + id: perm + uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0 + with: + script: | + const login = (context.payload.pull_request.user?.login || '').toLowerCase(); + let permission = 'none'; + try { + // Signed-commit checks only apply to maintainers. + // GitHub repo roles are too broad here because most access + // comes from org team permissions, so this probe reads the + // PR author's effective repo write access and decides who + // should be asked to sign commits. + const { data } = await github.rest.repos.getCollaboratorPermissionLevel({ + owner: context.repo.owner, + repo: context.repo.repo, + username: login, + }); + permission = (data.permission || 'none').toLowerCase(); + } catch (error) { + if (error.status !== 404) { + core.warning(`Failed to resolve collaborator permission for ${login}: ${error.message}`); + } + } + + const enforce = ['admin', 'maintain', 'write'].includes(permission); + core.info(`author=${login} permission=${permission} enforce=${enforce}`); + core.setOutput('enforce', enforce ? 'true' : 'false'); + + - name: Check for unsigned commits + if: steps.perm.outputs.enforce == 'true' + id: check + uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0 + with: + script: | + const prNumber = context.payload.pull_request.number; + const commits = await github.rest.pulls.listCommits({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: prNumber, + per_page: 250 + }); + + const unsigned = commits.data.filter(c => !c.commit.verification.verified); + + if (unsigned.length === 0) { + core.setOutput('unsigned', ''); + core.info('All commits are signed.'); + return; + } + + const lines = unsigned.map(c => + `- \`${c.sha.slice(0, 8)}\` ${c.commit.message.split('\n')[0]}` + ); + + core.setOutput('unsigned', lines.join('\n')); + core.setOutput('pr_number', String(prNumber)); + core.setFailed( + `Found ${unsigned.length} unsigned commit(s) in this PR. ` + + 'All commits must be signed (GPG or SSH).' + ); + + - name: Comment with remediation steps + if: failure() && steps.perm.outputs.enforce == 'true' && steps.check.outputs.unsigned != '' + uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0 + env: + UNSIGNED: ${{ steps.check.outputs.unsigned }} + PRNUM: ${{ steps.check.outputs.pr_number }} + with: + script: | + const issue_number = parseInt(process.env.PRNUM, 10); + const unsignedList = process.env.UNSIGNED; + + const body = [ + 'This PR contains unsigned commits. All commits must be cryptographically signed (GPG or SSH).', + '', + 'Unsigned commits:', + unsignedList, + '', + 'For instructions on setting up commit signing and re-signing existing commits, see:', + 'https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits' + ].join('\n'); + + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number, + body + }); diff --git a/.github/workflows/synthetic-tx-nonregression.yml b/.github/workflows/synthetic-tx-nonregression.yml new file mode 100644 index 0000000000..536abc5211 --- /dev/null +++ b/.github/workflows/synthetic-tx-nonregression.yml @@ -0,0 +1,387 @@ +name: synthetic tx kernel non-regression + +on: + push: + branches: + - main + - next + workflow_dispatch: + inputs: + baseline_ref: + description: Commit or ref to use as the baseline. Defaults to the current ref's first parent. + required: false + type: string + current_ref: + description: Commit or ref to benchmark. Defaults to the workflow ref. + required: false + type: string + regression_threshold_pct: + description: Allowed slowdown before the workflow fails. + required: false + default: "5" + type: string + rayon_num_threads: + description: RAYON_NUM_THREADS value used for the benchmark. + required: false + default: "8" + type: string + scenario_filter: + description: Optional SYNTH_SCENARIO filter for the synthetic benchmark. + required: false + default: "" + type: string + +concurrency: + group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + benchmark: + name: Benchmark baseline vs current + runs-on: warp-ubuntu-latest-x64-8x + timeout-minutes: 240 + permissions: + contents: read + outputs: + summary: ${{ steps.summary.outputs.summary }} + regression: ${{ steps.compare.outputs.regression }} + status: ${{ steps.compare.outputs.status }} + baseline_sha: ${{ steps.compare.outputs.baseline_sha }} + current_sha: ${{ steps.compare.outputs.current_sha }} + max_delta_metric: ${{ steps.compare.outputs.max_delta_metric }} + max_delta_pct: ${{ steps.compare.outputs.max_delta_pct }} + steps: + - name: Check out repository + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 + with: + fetch-depth: 0 + persist-credentials: false + + - name: Install Rust toolchain + shell: bash + run: | + set -euo pipefail + toolchain="$(sed -n 's/^channel = "\(.*\)"$/\1/p' rust-toolchain.toml)" + rustup toolchain install "${toolchain}" --profile minimal --target wasm32-unknown-unknown + + - name: Cache Rust dependencies + uses: WarpBuilds/rust-cache@9d0cc3090d9c87de74ea67617b246e978735b1a1 # v2.9.1 + + - name: Prepare benchmark directories + id: dirs + shell: bash + run: | + set -euo pipefail + run_root="${RUNNER_TEMP}/synthetic-tx-nonregression-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}" + artifact_dir="${run_root}/artifacts" + worktree_dir="${run_root}/worktrees" + mkdir -p "${artifact_dir}" "${worktree_dir}" + { + echo "run_root=${run_root}" + echo "artifact_dir=${artifact_dir}" + echo "worktree_dir=${worktree_dir}" + } >> "${GITHUB_OUTPUT}" + + - name: Resolve benchmark refs + id: refs + env: + EVENT_NAME: ${{ github.event_name }} + BEFORE_SHA: ${{ github.event.before }} + INPUT_BASELINE_REF: ${{ inputs.baseline_ref }} + INPUT_CURRENT_REF: ${{ inputs.current_ref }} + INPUT_THRESHOLD_PCT: ${{ inputs.regression_threshold_pct }} + INPUT_RAYON_THREADS: ${{ inputs.rayon_num_threads }} + INPUT_SCENARIO_FILTER: ${{ inputs.scenario_filter }} + shell: bash + run: | + set -euo pipefail + + resolve_commit() { + local ref="$1" + git rev-parse --verify --end-of-options "${ref}^{commit}" + } + + fetch_commit_if_needed() { + local ref="$1" + local fetch_log + if resolve_commit "${ref}" >/dev/null 2>&1; then + return 0 + fi + fetch_log="$(mktemp)" + if git fetch --no-tags --depth=1 origin "${ref}" >"${fetch_log}" 2>&1; then + rm -f "${fetch_log}" + resolve_commit "${ref}" >/dev/null 2>&1 + return $? + fi + if grep -Eqi "couldn't find remote ref|not our ref|unadvertised object|reference is not a tree|no such remote ref" "${fetch_log}"; then + rm -f "${fetch_log}" + return 2 + fi + cat "${fetch_log}" >&2 + rm -f "${fetch_log}" + return 1 + } + + if [[ "${EVENT_NAME}" == "push" ]]; then + current_ref="${GITHUB_SHA}" + baseline_ref="${BEFORE_SHA}" + threshold_pct="5" + rayon_threads="8" + scenario_filter="" + else + baseline_ref="${INPUT_BASELINE_REF}" + current_ref="${INPUT_CURRENT_REF}" + threshold_pct="${INPUT_THRESHOLD_PCT}" + rayon_threads="${INPUT_RAYON_THREADS}" + scenario_filter="${INPUT_SCENARIO_FILTER}" + fi + + if [[ -z "${current_ref}" ]]; then + current_ref="${GITHUB_SHA}" + fi + + if [[ -z "${threshold_pct}" ]]; then + threshold_pct="5" + fi + + if [[ -z "${rayon_threads}" ]]; then + rayon_threads="8" + fi + + if [[ ! "${threshold_pct}" =~ ^[0-9]+([.][0-9]+)?$ ]]; then + echo "regression_threshold_pct must be numeric" >&2 + exit 1 + fi + + if [[ ! "${rayon_threads}" =~ ^[0-9]+$ ]]; then + echo "rayon_num_threads must be an integer" >&2 + exit 1 + fi + + if [[ -z "${baseline_ref}" || "${baseline_ref}" == "0000000000000000000000000000000000000000" ]]; then + baseline_ref="${current_ref}^" + fi + + current_sha="$(resolve_commit "${current_ref}")" + fetch_status=0 + + if [[ "${EVENT_NAME}" == "push" && "${BEFORE_SHA}" != "0000000000000000000000000000000000000000" ]]; then + if fetch_commit_if_needed "${baseline_ref}"; then + fetch_status=0 + else + fetch_status=$? + fi + fi + + if [[ "${EVENT_NAME}" == "push" && "${BEFORE_SHA}" != "0000000000000000000000000000000000000000" && ${fetch_status} -eq 0 ]]; then + baseline_sha="$(resolve_commit "${baseline_ref}")" + elif [[ "${EVENT_NAME}" == "push" && "${BEFORE_SHA}" != "0000000000000000000000000000000000000000" && ${fetch_status} -eq 2 ]]; then + echo "push baseline ${baseline_ref} is no longer available; refusing to compare against current_sha^" >&2 + exit 1 + elif resolve_commit "${baseline_ref}" >/dev/null 2>&1; then + baseline_sha="$(resolve_commit "${baseline_ref}")" + elif [[ "${EVENT_NAME}" == "push" && "${BEFORE_SHA}" == "0000000000000000000000000000000000000000" ]]; then + baseline_ref="${current_sha}^" + baseline_sha="$(resolve_commit "${current_sha}^")" + elif [[ "${EVENT_NAME}" == "workflow_dispatch" && -z "${INPUT_BASELINE_REF}" ]]; then + baseline_ref="${current_sha}^" + baseline_sha="$(resolve_commit "${current_sha}^")" + else + echo "baseline_ref must resolve to a commit: ${baseline_ref}" >&2 + exit 1 + fi + + baseline_ref="${baseline_sha}" + + { + echo "baseline_ref=${baseline_ref}" + echo "current_ref=${current_ref}" + echo "baseline_sha=${baseline_sha}" + echo "current_sha=${current_sha}" + echo "threshold_pct=${threshold_pct}" + echo "rayon_threads=${rayon_threads}" + echo "scenario_filter=${scenario_filter}" + } >> "${GITHUB_OUTPUT}" + + - name: Create worktrees + env: + WORKTREE_DIR: ${{ steps.dirs.outputs.worktree_dir }} + BASELINE_SHA: ${{ steps.refs.outputs.baseline_sha }} + CURRENT_SHA: ${{ steps.refs.outputs.current_sha }} + shell: bash + run: | + set -euo pipefail + git worktree add --detach "${WORKTREE_DIR}/baseline" "${BASELINE_SHA}" + git worktree add --detach "${WORKTREE_DIR}/current" "${CURRENT_SHA}" + + - name: Run baseline benchmark + env: + GITHUB_WORKSPACE_PATH: ${{ github.workspace }} + WORKTREE_DIR: ${{ steps.dirs.outputs.worktree_dir }} + ARTIFACT_DIR: ${{ steps.dirs.outputs.artifact_dir }} + RAYON_THREADS: ${{ steps.refs.outputs.rayon_threads }} + SCENARIO_FILTER: ${{ steps.refs.outputs.scenario_filter }} + BASELINE_SHA: ${{ steps.refs.outputs.baseline_sha }} + shell: bash + run: | + set -euo pipefail + python3 "${GITHUB_WORKSPACE_PATH}/scripts/synthetic_tx_nonregression.py" run \ + --repo-root "${WORKTREE_DIR}/baseline" \ + --output-dir "${ARTIFACT_DIR}/baseline" \ + --rayon-num-threads "${RAYON_THREADS}" \ + --scenario-filter "${SCENARIO_FILTER}" \ + --git-ref "${BASELINE_SHA}" + + - name: Run current benchmark + env: + GITHUB_WORKSPACE_PATH: ${{ github.workspace }} + WORKTREE_DIR: ${{ steps.dirs.outputs.worktree_dir }} + ARTIFACT_DIR: ${{ steps.dirs.outputs.artifact_dir }} + RAYON_THREADS: ${{ steps.refs.outputs.rayon_threads }} + SCENARIO_FILTER: ${{ steps.refs.outputs.scenario_filter }} + CURRENT_SHA: ${{ steps.refs.outputs.current_sha }} + shell: bash + run: | + set -euo pipefail + python3 "${GITHUB_WORKSPACE_PATH}/scripts/synthetic_tx_nonregression.py" run \ + --repo-root "${WORKTREE_DIR}/current" \ + --output-dir "${ARTIFACT_DIR}/current" \ + --rayon-num-threads "${RAYON_THREADS}" \ + --scenario-filter "${SCENARIO_FILTER}" \ + --git-ref "${CURRENT_SHA}" + + - name: Compare baseline and current results + id: compare + env: + GITHUB_WORKSPACE_PATH: ${{ github.workspace }} + ARTIFACT_DIR: ${{ steps.dirs.outputs.artifact_dir }} + THRESHOLD_PCT: ${{ steps.refs.outputs.threshold_pct }} + shell: bash + run: | + set -euo pipefail + python3 "${GITHUB_WORKSPACE_PATH}/scripts/synthetic_tx_nonregression.py" compare \ + --baseline "${ARTIFACT_DIR}/baseline/result.json" \ + --current "${ARTIFACT_DIR}/current/result.json" \ + --summary-out "${ARTIFACT_DIR}/summary.md" \ + --json-out "${ARTIFACT_DIR}/comparison.json" \ + --threshold-pct "${THRESHOLD_PCT}" \ + --github-output "${GITHUB_OUTPUT}" + + - name: Publish job summary + if: always() + env: + ARTIFACT_DIR: ${{ steps.dirs.outputs.artifact_dir }} + shell: bash + run: | + set -euo pipefail + if [[ -f "${ARTIFACT_DIR}/summary.md" ]]; then + cat "${ARTIFACT_DIR}/summary.md" >> "${GITHUB_STEP_SUMMARY}" + fi + + - name: Expose summary for downstream jobs + if: always() + id: summary + env: + ARTIFACT_DIR: ${{ steps.dirs.outputs.artifact_dir }} + shell: bash + run: | + set -euo pipefail + if [[ ! -f "${ARTIFACT_DIR}/summary.md" ]]; then + exit 0 + fi + { + echo "summary<> "${GITHUB_OUTPUT}" + + - name: Upload benchmark artifacts + if: always() + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 + with: + name: synthetic-tx-kernel-nonregression + path: ${{ steps.dirs.outputs.artifact_dir }} + if-no-files-found: warn + + - name: Remove worktrees + if: always() + env: + RUN_ROOT: ${{ steps.dirs.outputs.run_root }} + WORKTREE_DIR: ${{ steps.dirs.outputs.worktree_dir }} + shell: bash + run: | + set -euo pipefail + git worktree remove --force "${WORKTREE_DIR}/baseline" || true + git worktree remove --force "${WORKTREE_DIR}/current" || true + rm -rf "${RUN_ROOT}" + + - name: Fail on regression + if: steps.compare.outputs.regression == 'true' + env: + MAX_DELTA_METRIC: ${{ steps.compare.outputs.max_delta_metric }} + MAX_DELTA_PCT: ${{ steps.compare.outputs.max_delta_pct }} + shell: bash + run: | + set -euo pipefail + echo "synthetic transaction kernel benchmark ${MAX_DELTA_METRIC} regressed by ${MAX_DELTA_PCT}%" + exit 1 + + comment: + name: Comment on pushed commit + runs-on: ubuntu-latest + needs: + - benchmark + if: always() && github.event_name == 'push' && needs.benchmark.outputs.current_sha != '' && needs.benchmark.outputs.summary != '' + permissions: + contents: write + steps: + - name: Create or update commit comment + uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b + env: + CURRENT_SHA: ${{ needs.benchmark.outputs.current_sha }} + MARKER: "" + BODY: ${{ needs.benchmark.outputs.summary }} + with: + script: | + const body = [ + process.env.MARKER, + process.env.BODY, + '', + `Workflow run: ${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`, + ].join('\n'); + + const owner = context.repo.owner; + const repo = context.repo.repo; + const commitSha = process.env.CURRENT_SHA; + const marker = process.env.MARKER; + + const comments = await github.paginate( + github.rest.repos.listCommentsForCommit, + { + owner, + repo, + commit_sha: commitSha, + per_page: 100, + }, + ); + + const existing = comments.find(comment => + comment.user?.type === 'Bot' && comment.body?.includes(marker) + ); + + if (existing) { + await github.rest.repos.updateCommitComment({ + owner, + repo, + comment_id: existing.id, + body, + }); + return; + } + + await github.rest.repos.createCommitComment({ + owner, + repo, + commit_sha: commitSha, + body, + }); diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b91bed1764..223e6f69de 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -11,14 +11,22 @@ permissions: jobs: test: - name: test on ubuntu-latest - runs-on: ubuntu-latest + name: test on warpbuild + runs-on: warp-ubuntu-latest-x64-8x steps: - - uses: actions/checkout@main + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + with: + persist-credentials: false - name: Cleanup large tools for build space uses: ./.github/actions/cleanup-runner - - uses: taiki-e/install-action@nextest - - uses: Swatinem/rust-cache@v2 + # Do not pin taiki-e's moving tool shortcut tags by hash. Pin a released + # install-action commit and set tool explicitly, or zizmor's + # impostor-commit audit can flag stale shortcut-tag hashes. + - name: Install nextest + uses: taiki-e/install-action@055f5df8c3f65ea01cd41e9dc855becd88953486 # v2.75.18 + with: + tool: cargo-nextest + - uses: WarpBuilds/rust-cache@9d0cc3090d9c87de74ea67617b246e978735b1a1 # v2.9.1 with: save-if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/next' }} - name: Install rust @@ -30,12 +38,14 @@ jobs: doc-tests: name: doc-tests - runs-on: ubuntu-latest + runs-on: warp-ubuntu-latest-x64-8x steps: - - uses: actions/checkout@main + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + with: + persist-credentials: false - name: Cleanup large tools for build space uses: ./.github/actions/cleanup-runner - - uses: Swatinem/rust-cache@v2 + - uses: WarpBuilds/rust-cache@9d0cc3090d9c87de74ea67617b246e978735b1a1 # v2.9.1 with: save-if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/next' }} - name: Install rust @@ -45,13 +55,15 @@ jobs: check-core-lib-docs: name: check core library docs - runs-on: ubuntu-latest + runs-on: warp-ubuntu-latest-x64-8x needs: [test, doc-tests] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + with: + persist-credentials: false - name: Cleanup large tools for build space uses: ./.github/actions/cleanup-runner - - uses: Swatinem/rust-cache@v2 + - uses: WarpBuilds/rust-cache@9d0cc3090d9c87de74ea67617b246e978735b1a1 # v2.9.1 with: save-if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/next' }} - name: Install rust @@ -81,14 +93,33 @@ jobs: echo "No documentation changes in crates/lib/core/docs/ - OK" fi + check-constraints: + name: check recursive constraint artifacts + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + with: + persist-credentials: false + - name: Cleanup large tools for build space + uses: ./.github/actions/cleanup-runner + - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 + with: + save-if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/next' }} + - name: Install rust + run: rustup update --no-self-update + - name: Check recursive constraint artifacts for drift + run: make check-constraints + run-examples: name: run masm examples - runs-on: ubuntu-latest + runs-on: warp-ubuntu-latest-x64-8x steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + with: + persist-credentials: false - name: Cleanup large tools for build space uses: ./.github/actions/cleanup-runner - - uses: Swatinem/rust-cache@v2 + - uses: WarpBuilds/rust-cache@9d0cc3090d9c87de74ea67617b246e978735b1a1 # v2.9.1 with: save-if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/next' }} - name: Install rust @@ -98,17 +129,23 @@ jobs: check-features: name: check all feature combinations - runs-on: ubuntu-latest + runs-on: warp-ubuntu-latest-x64-8x steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + with: + persist-credentials: false - name: Cleanup large tools for build space uses: ./.github/actions/cleanup-runner - - uses: Swatinem/rust-cache@v2 + - uses: WarpBuilds/rust-cache@9d0cc3090d9c87de74ea67617b246e978735b1a1 # v2.9.1 with: save-if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/next' }} - name: Install rust run: rustup update --no-self-update + # Keep this on a released install-action commit with an explicit tool; see + # the nextest install above for the zizmor/tool-shortcut rationale. - name: Install cargo-hack - uses: taiki-e/install-action@cargo-hack + uses: taiki-e/install-action@055f5df8c3f65ea01cd41e9dc855becd88953486 # v2.75.18 + with: + tool: cargo-hack - name: Check all feature combinations run: make check-features diff --git a/.github/workflows/workspace-dry-run.yml b/.github/workflows/workspace-dry-run.yml index ed3d90f3f9..eb10b2f0b2 100644 --- a/.github/workflows/workspace-dry-run.yml +++ b/.github/workflows/workspace-dry-run.yml @@ -17,17 +17,18 @@ concurrency: jobs: release-dry-run: if: ${{ github.repository_owner == '0xMiden' }} - runs-on: ubuntu-latest + runs-on: warp-ubuntu-latest-x64-8x steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: fetch-depth: 0 + persist-credentials: false - name: Dry-run workspace release uses: ./.github/actions/workspace-release with: mode: "dry-run" verify-main-head: "false" - # ref left blank: uses the pushed ref \ No newline at end of file + # ref left blank: uses the pushed ref diff --git a/.github/workflows/workspace-publish.yml b/.github/workflows/workspace-publish.yml index 7f6a5378b6..09848d751c 100644 --- a/.github/workflows/workspace-publish.yml +++ b/.github/workflows/workspace-publish.yml @@ -11,18 +11,19 @@ permissions: jobs: publish: if: ${{ github.repository_owner == '0xMiden' }} - runs-on: ubuntu-latest + runs-on: warp-ubuntu-latest-x64-8x environment: release # Optional: for enhanced security steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: fetch-depth: 0 ref: main + persist-credentials: false - name: Authenticate with crates.io - uses: rust-lang/crates-io-auth-action@v1 + uses: rust-lang/crates-io-auth-action@bbd81622f20ce9e2dd9622e3218b975523e45bbe # v1.0.4 id: auth - name: Publish workspace crates @@ -31,4 +32,4 @@ jobs: mode: "publish" verify-main-head: "true" env: - CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }} \ No newline at end of file + CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }} diff --git a/.github/workflows/zizmor.yml b/.github/workflows/zizmor.yml new file mode 100644 index 0000000000..f8a0571b4d --- /dev/null +++ b/.github/workflows/zizmor.yml @@ -0,0 +1,38 @@ +name: GitHub Actions Security Analysis with zizmor + +on: + push: + branches: [main, next] + paths: + - ".github/workflows/**" + - ".github/actions/**" + - "zizmor.yml" + pull_request: + types: [opened, reopened, synchronize] + paths: + - ".github/workflows/**" + - ".github/actions/**" + - "zizmor.yml" + workflow_dispatch: + +permissions: {} + +jobs: + zizmor: + name: Run zizmor + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + steps: + - name: Checkout repository + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + with: + persist-credentials: false + + - name: Run zizmor + uses: zizmorcore/zizmor-action@71321a20a9ded102f6e9ce5718a2fcec2c4f70d8 # v0.5.2 + with: + advanced-security: false + config: zizmor.yml + version: 1.23.1 diff --git a/.gitignore b/.gitignore index 88a02e29d4..5728cdb9d6 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,7 @@ crates/lib/core/assets/core.masl # mdBook book/ + +# Constraint analysis tooling +.constraint-tooling/ +scripts/__pycache__/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 37c2fa52d9..bbc4c9acfd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,91 @@ # Changelog +## v0.23.0 (TBD) + +#### Features + +- Added the `miden-vm-synthetic-bench` crate for VM-level proving regression detection driven by row-count snapshots from an external producer ([#3024](https://github.com/0xMiden/miden-vm/pull/3024)). +- Implemented the `miden-registry` tool for managing a local filesystem-based package registry. This is intended to help us explore what package management in Miden projects might look like with a central registry for sharing packages, without needing to go all-in on implementing one. [#2881](https://github.com/0xMiden/miden-vm/pull/2881). + +#### Fixes + +- Rejected non-syscall references to exported kernel procedures in the linker ([#2902](https://github.com/0xMiden/miden-vm/issues/2902)). +- Reverted the `MainTrace` typed row storage change that caused a large `blake3_1to1` trace-building regression ([#2949](https://github.com/0xMiden/miden-vm/pull/2949)). +- Fixed Falcon `mod_12289` remainder validation and `u64::rotr` overflow handling for rotations by `0` and `32` ([#2968](https://github.com/0xMiden/miden-vm/pull/2968)). +- Hardened SHA256 message word range checks and U32ADD/U32ADD3 carry constraints, updating recursive verifier relation digest artifacts ([#3021](https://github.com/0xMiden/miden-vm/pull/3021)). +- Added bounds checks for non-deterministic `maybe_value_ptr`/`maybe_key_ptr` hints in `sorted_array::find_word` and `find_partial_key_value` ([#3051](https://github.com/0xMiden/miden-vm/pull/3051)). +- [BREAKING] Removed internal `_impl` precompile helpers from the core-lib API, hardened proof deserialization and debug storage errors, and added u256 regression vectors ([#3026](https://github.com/0xMiden/miden-vm/pull/3026)). +- Fixed `u256::wrapping_mul` so it preserves caller stack values below its operands ([#3071](https://github.com/0xMiden/miden-vm/pull/3071)). +- Fixed `FastProcessor` stack growth so operand stack depth is bounded by `ExecutionOptions::max_stack_depth` instead of the internal buffer size ([#3086](https://github.com/0xMiden/miden-vm/pull/3086)). +- Fixed host event and advice-mutation diagnostics to point to the triggering `emit.event(...)` instruction ([#3042](https://github.com/0xMiden/miden-vm/pull/3042)). +- Fixed debug-only underflow in memory range-check trace generation when the first memory access is at `clk = 0` ([#2976](https://github.com/0xMiden/miden-vm/pull/2976)). +- Replaced unsound `ptr::read` with safe unbox in panic recovery, removing UB from potential double-drop ([#2934](https://github.com/0xMiden/miden-vm/pull/2934)). +- Library deserialization now rejects exports whose `MastNodeId` is not a procedure root, closing a silent-failure path ([#2933](https://github.com/0xMiden/miden-vm/pull/2933)). +- Reverted `InvokeKind::ProcRef` back to `InvokeKind::Exec` in `visit_mut_procref` and added an explanatory comment (#2893). +- Fixed `FastProcessor` so `after_exit` trace decorators execute when tracing is enabled without debug mode, and added a tracing-only regression test. +- Fixed the release dry-run publish cycle between `miden-air` and `miden-ace-codegen`, and preserved leaf-only DAG imports with explicit snapshots ([#2931](https://github.com/0xMiden/miden-vm/pull/2931)). +- Added regression coverage for the exact `max_num_continuations` continuation-stack boundary ([#2995](https://github.com/0xMiden/miden-vm/pull/2995)). +- Fixed AEAD padding handling so encrypt does not overwrite memory next to the plaintext buffer and decrypt leaves the plaintext output tail untouched ([#3008](https://github.com/0xMiden/miden-vm/pull/3008)). +- Fixed MAST compaction after debug info is cleared so compiler-generated packages do not grow ([#3044](https://github.com/0xMiden/miden-vm/pull/3044)). +- Fixed same-digest procedure selection so static linking and library-to-executable package conversion preserve the selected procedure's debug metadata ([#3054](https://github.com/0xMiden/miden-vm/pull/3054)). +- Canonicalized `PathBuf::try_from(String)` to match `TryFrom<&str>`/`FromStr`, so semantically equivalent quoted path components compare and hash consistently. +- Fixed missing smt::set validations in corelib ([#3049](https://github.com/0xMiden/miden-vm/pull/3049)). +- Memoized semantic constant evaluation in `AnalysisContext` to prevent exponential work from shared constant-dependency graphs during parsing and semantic analysis ([#2858](https://github.com/0xMiden/miden-vm/pull/2858)). +- Fixed quote-equivalent path ambiguity in library deserialization and linker symbol resolution ([#2836](https://github.com/0xMiden/miden-vm/pull/2836)). +- Treat serialized libraries and kernel libraries as untrusted MAST forests during deserialization, rejecting spoofed node digests ([#2863](https://github.com/0xMiden/miden-vm/pull/2863)). +- Return typed cycle errors for self-recursive and rootless procedure call graphs, and roll back linker state on failure ([#2899](https://github.com/0xMiden/miden-vm/pull/2899)). +- [BREAKING] Reject oversized modules at resolver construction instead of building partial resolver state or panicking ([#2899](https://github.com/0xMiden/miden-vm/pull/2899)). +- Return a normal assembly error when `pub use -> ` does not resolve to an exported procedure ([#2899](https://github.com/0xMiden/miden-vm/pull/2899)). +- [BREAKING] Reject non-procedure invoke targets during semantic analysis, and return an assembly error instead of panicking if one still reaches assembly ([#2899](https://github.com/0xMiden/miden-vm/pull/2899)). +- Added `Package::content_digest()` to identify package contents without changing the MAST digest, including manifest data and semantic package metadata ([#2909](https://github.com/0xMiden/miden-vm/pull/2909)). +- Hardened MAST forest and package byte-slice deserialization against fuzzed length fields ([#3088](https://github.com/0xMiden/miden-vm/pull/3088)). +- [BREAKING] Bounded the live advice map by total field elements during execution; advice-provider setup now returns an error when initial advice exceeds this limit ([#3085](https://github.com/0xMiden/miden-vm/pull/3085)). +- Rejected empty kernel packages before linking so malformed dependency metadata returns a structured package error instead of reaching the linker's non-empty-kernel assertion ([#3082](https://github.com/0xMiden/miden-vm/pull/3082)). +- [BREAKING] Fixed project artifact reuse to ignore unrelated manifest fields, rejected private cross-module imports, and kept signature-only type imports live ([#3091](https://github.com/0xMiden/miden-vm/pull/3091)). +- Fixed stale `ReplayProcessor` doc comment links to `ExecutionTracer` after module-structure refactors. + +#### Changes + +- [BREAKING] Refactored MAST forest serialization around fixed-layout full, stripped, and hashless sections, and bumped the MAST wire format to `0.0.3` ([#2765](https://github.com/0xMiden/miden-vm/pull/2765)). +- Documented sortedness precondition more prominently for sorted array operations ([#2832](https://github.com/0xMiden/miden-vm/pull/2832)). +- Corrected memory trace delta encoding comments to match first-row and same-word clock delta behavior ([#3062](https://github.com/0xMiden/miden-vm/pull/3062)). +- [BREAKING] Updated the Miden crypto stack to `miden-crypto` and `miden-lifted-stark` v0.24, and switched digest-ordering code to `Word`'s native lexicographic ordering ([#3039](https://github.com/0xMiden/miden-vm/pull/3039)). +- Borrowed operation slices in basic-block batching helpers to avoid cloning in the fingerprinting path ([#2994](https://github.com/0xMiden/miden-vm/pull/2994)). +- [BREAKING] Sync execution and proving APIs now require `SyncHost`; async `Host`, `execute`, and `prove` remain available ([#2865](https://github.com/0xMiden/miden-vm/pull/2865)). +- [BREAKING] `miden_processor::execute()` and `execute_sync()` now return `ExecutionOutput`; trace building remains explicit via `execute_trace_inputs*()` and `trace::build_trace()` ([#2865](https://github.com/0xMiden/miden-vm/pull/2865)). +- [BREAKING] Removed the deprecated `FastProcessor::execute_sync_mut()` alias; `execute_mut_sync()` is now the only sync mutable-execution entrypoint ([#2865](https://github.com/0xMiden/miden-vm/pull/2865)). +- [BREAKING] Removed the deprecated `FastProcessor::execute_for_trace_sync()` and `execute_for_trace()` wrappers; use `execute_trace_inputs_sync()` or `execute_trace_inputs()` instead ([#2865](https://github.com/0xMiden/miden-vm/pull/2865)). +- [BREAKING] Removed the deprecated unbound `TraceBuildInputs::new()` and `TraceBuildInputs::from_program()` constructors; use `execute_trace_inputs_sync()` or `execute_trace_inputs()` instead ([#2865](https://github.com/0xMiden/miden-vm/pull/2865)). +- Added `prove_from_trace_sync(...)` for proving from pre-executed trace inputs ([#2865](https://github.com/0xMiden/miden-vm/pull/2865)). +- [BREAKING] Removed the immediate form of `adv_push` (`adv_push.N`); use N consecutive `adv_push` instructions (or `repeat.N adv_push end` for large N) instead ([#2900](https://github.com/0xMiden/miden-vm/pull/2900)). +- [BREAKING] Reduced the prove-from-trace API to post-execution trace inputs: `TraceBuildInputs` no longer carries full execution output, `prove_from_trace_sync()` takes `TraceProvingInputs`, and `ProvingOptions` no longer include `ExecutionOptions` ([#2948](https://github.com/0xMiden/miden-vm/pull/2948)). +- Redesigned the hasher chiplet to use a controller/permutation split architecture with permutation calls deduplication ([#2927](https://github.com/0xMiden/miden-vm/pull/2927)). +- Cached repeated test compilations to speed up assembler tests without changing coverage, and fixed the core library build watch path ([#3047](https://github.com/0xMiden/miden-vm/pull/3047)). +- Documented that enum variants are module-level constants and must be unique within a module ([#2932]((https://github.com/0xMiden/miden-vm/pull/2932)). +- Refactor trace generation to row-major format ([#2937](https://github.com/0xMiden/miden-vm/pull/2937)). +- Documented non-overlap requirement for `memcopy_words`, `memcopy_elements`, and AEAD encrypt/decrypt procedures ([#2941](https://github.com/0xMiden/miden-vm/pull/2941)). +- Clarified that `mmr::get` fails for positions outside the current MMR rather than returning a sentinel value ([#3001](https://github.com/0xMiden/miden-vm/issues/3001)). +- Aligned AEAD key/nonce stack-order documentation and handler comments with the runtime contract ([#3036](https://github.com/0xMiden/miden-vm/pull/3036)). +- Aligned `core_lib::math::u256` user docs with unified LE stack limb ordering (`a0/b0` on top), removing conflicting `[b7..b0, a7..a0]` notation ([#3066](https://github.com/0xMiden/miden-vm/pull/3066)). +- Added chainable `Test` builders for common test setup in `miden-utils-testing` ([#2957](https://github.com/0xMiden/miden-vm/pull/2957)). +- Added fuzz coverage for package semantic deserialization and project parsing, loading, and assembly ([#3015](https://github.com/0xMiden/miden-vm/pull/3015)). +- Made serde opt-in for package crates, and added macro-based binary and serde roundtrip tests for Arbitrary serialization types ([#3058](https://github.com/0xMiden/miden-vm/pull/3058)). +- Speed-up AUX range check trace generation by changing divisors to a flat Vec layout ([#2966](https://github.com/0xMiden/miden-vm/pull/2966)). +- Optimized call graph topological sort from O(V\*E) to O(V + E) by pre-computing in-degrees ([#2830](https://github.com/0xMiden/miden-vm/pull/2830)). +- Removed AIR constraint tagging instrumentation, applied a uniform constraint description style across components, and optimized constraint evaluation ([#2856](https://github.com/0xMiden/miden-vm/pull/2856)). +- [BREAKING] Unified all auxiliary-trace buses under a single declarative LogUp `LookupAir` shared by the verifier, prover aux-trace generator, and recursive ACE circuit; reduced committed boundary values to one per trace ([#2962](https://github.com/0xMiden/miden-vm/pull/2962)). +- Collapsed the kernel ROM chiplet to one row per digest with a LogUp multiplicity, eliminating duplicate-callsite rows ([#2962](https://github.com/0xMiden/miden-vm/pull/2962)). +- Made all internal `core::math` procedures natively little-endian ([#3084](https://github.com/0xMiden/miden-vm/pull/3084)). +- [BREAKING] Updated the Miden crypto stack to `miden-crypto` 0.25, and switched SMT leaf hashing to use Poseidon2 domain separation so masm-side leaf digests match `SmtLeaf::hash()` ([#3095](https://github.com/0xMiden/miden-vm/pull/3095)). +- Follow-up refactoring + couple perf improvements on trace generation ([#2953](https://github.com/0xMiden/miden-vm/pull/2953)). +- Added `FastProcessor::into_parts()` to extract advice provider, memory, and precompile transcript after step-based execution ([#2901](https://github.com/0xMiden/miden-vm/pull/2901)). +- Added deterministic regression vectors for `math::u256` core-lib tests and replaced `BigUint`-based expectations with an in-test `U256` model ([#2974](https://github.com/0xMiden/miden-vm/pull/2974)). + ## 0.22.3 (2026-05-01) - Change value of `Path::MAX_COMPONENT_LENGTH` to `u16::MAX - 2` [#3087](https://github.com/0xMiden/miden-vm/pull/3087) -## 0.22.2 (2026-04-028) +## 0.22.2 (2026-04-28) - Improve debug var loc tracking ([#2955](https://github.com/0xMiden/miden-vm/pull/2955)). @@ -24,7 +105,6 @@ - Added `math::u128` division operations ([#2776](https://github.com/0xMiden/miden-vm/pull/2776)). - [BREAKING] Migrated to lifted-STARK backend and `miden-crypto` to v0.23 ([#2783](https://github.com/0xMiden/miden-vm/pull/2783)). - #### Changes - Consolidated error variants: simplified `AceError` and FRI errors to string-based types, merged `DynamicNodeNotFound`/`NoMastForestWithProcedure` into `ProcedureNotFound`, introduced `HostError` for handler-related variants ([#2675](https://github.com/0xMiden/miden-vm/pull/2675)). @@ -46,10 +126,17 @@ - [BREAKING] `StructType::new` now expects an optional name to be specified ([#2848](https://github.com/0xMiden/miden-vm/pull/2848)) - [BREAKING] `Variant::new` now expects an optional payload type to be specified ([#2848](https://github.com/0xMiden/miden-vm/pull/2848)) - [BREAKING] Enum types are now exported from libraries as a `midenc_hir_type::EnumType`, rather than the type of the discriminant. ([#2848](https://github.com/0xMiden/miden-vm/pull/2848)) +- In `ExecutionTracer`, we no longer record node flags in `CoreTraceFragmentContext` when entering a node (they are redundant) ([#2866](https://github.com/0xMiden/miden-vm/pull/2866)) +- Updated the recursive STARK verifier to work with the lifted-STARK / `p3-miden` backend ([#2869](https://github.com/0xMiden/miden-vm/pull/2869)). +- Switched Keccak STARK config to use stateful binary sponge with `[Felt; VECTOR_LEN]` packing, and reorganized `config.rs` into per-hash-family sections ([#2874](https://github.com/0xMiden/miden-vm/pull/2874)). - Add support to the `Assembler` for assembling Miden projects to Miden packages ([#2877](https://github.com/0xMiden/miden-vm/pull/2877)) #### Fixes +- Fixed `ExecutionTracer` DYNCALL stack-depth off-by-one at `MIN_STACK_DEPTH` ([#2813](https://github.com/0xMiden/miden-vm/issues/2813)). +- Fixed C-like enum validation and constant materialization in `define_enum` ([#2887](https://github.com/0xMiden/miden-vm/pull/2887)). +- **toposort_caller**: Fixed cycle detection in assembly call graph ([#2871](https://github.com/0xMiden/miden-vm/pull/2871)). + - Fixed `Constant::PartialEq` to include `visibility` field in equality comparison, making it consistent with other exportable items (`Procedure`, `TypeAlias`, `EnumType`). - Cryptostream operation now correctly sends chiplets bus memory requests ([#2686](https://github.com/0xMiden/miden-vm/pull/2686)). - Fixed a possible panic in decorator serialization ([#2742](https://github.com/0xMiden/miden-vm/pull/2742)). @@ -67,7 +154,7 @@ - Added bounds to attacker-controlled allocation sizes in advice map and keccak256/sha512 precompiles ([#2805](https://github.com/0xMiden/miden-vm/pull/2805)). - Hardened boundary and overflow checks for `u64::shr`, `ilog2`, `u32clz`, and Falcon `mod_12289` ([#2808](https://github.com/0xMiden/miden-vm/pull/2808)). - `build_trace()` no longer panics when no core trace contexts are provided ([#2809](https://github.com/0xMiden/miden-vm/pull/2809)). -- Set a bound on `ContinuationStack` size, checked during execution ([#2824](https://github.com/0xMiden/miden-vm/pull/2824)). +- Set a bound on `ContinuationStack` size, checked during execution ([#2825](https://github.com/0xMiden/miden-vm/pull/2825)). - Hardened basic-block batch validation and decode-time padding checks to reject inconsistent padded groups and prevent raw-helper underflow/panic paths on malformed forests ([#2839](https://github.com/0xMiden/miden-vm/pull/2839)). - Fixed undefined behavior in parallel trace generation by limiting H0 batch inversion to initialized rows ([#2842](https://github.com/0xMiden/miden-vm/pull/2842)). - `Visit` and `VisitMut` traits now properly visit enum type discriminant values, as well as the new payload `TypeExpr` when present ([#2848](https://github.com/0xMiden/miden-vm/pull/2848)). diff --git a/Cargo.lock b/Cargo.lock index 1ef9e46deb..0d5c53277e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -115,9 +115,9 @@ dependencies = [ [[package]] name = "assert_cmd" -version = "2.2.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a686bbee5efb88a82df0621b236e74d925f470e5445d3220a5648b892ec99c9" +checksum = "39bae1d3fa576f7c6519514180a72559268dd7d1fe104070956cb687bc6673bd" dependencies = [ "anstyle", "bstr", @@ -172,15 +172,15 @@ checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" [[package]] name = "bitflags" -version = "2.11.0" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" +checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" [[package]] name = "blake3" -version = "1.8.4" +version = "1.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d2d5991425dfd0785aed03aedcf0b321d61975c9b5b3689c774a2610ae0b51e" +checksum = "0aa83c34e62843d924f905e0f5c866eb1dd6545fc4d719e803d9ba6030371fce" dependencies = [ "arrayref", "arrayvec", @@ -224,9 +224,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.2.59" +version = "1.2.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7a4d3ec6524d28a329fc53654bbadc9bdd7b0431f5d65f1a56ffb28a1ee5283" +checksum = "d16d90359e986641506914ba71350897565610e87ce0ad9e6f28569db3dd5c6d" dependencies = [ "find-msvc-tools", "jobserver", @@ -304,9 +304,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.6.0" +version = "4.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b193af5b67834b676abd72466a96c1024e6a6ad978a1f484bd90b85c94041351" +checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51" dependencies = [ "clap_builder", "clap_derive", @@ -326,9 +326,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.6.0" +version = "4.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1110bd8a634a1ab8cb04345d8d878267d57c3cf1b38d91b71af6686408bbca6a" +checksum = "f2ce8604710f6733aa641a2b3731eaa1e8b3d9973d5e3565da11800813f997a9" dependencies = [ "heck", "proc-macro2", @@ -423,6 +423,12 @@ dependencies = [ "itertools 0.13.0", ] +[[package]] +name = "critical-section" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" + [[package]] name = "crossbeam-deque" version = "0.8.6" @@ -707,9 +713,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.3.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" [[package]] name = "ff" @@ -957,9 +963,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.16.1" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51" [[package]] name = "heck" @@ -1005,12 +1011,12 @@ checksum = "964de6e86d545b246d84badc0fef527924ace5134f30641c203ef52ba83f58d5" [[package]] name = "indexmap" -version = "2.13.1" +version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45a8a2b9cb3e0b0c1803dbb0758ffac5de2f425b23c28f518faabd9d805342ff" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" dependencies = [ "equivalent", - "hashbrown 0.16.1", + "hashbrown 0.17.0", "serde", "serde_core", ] @@ -1068,9 +1074,9 @@ checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" [[package]] name = "jiff" -version = "0.2.23" +version = "0.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a3546dc96b6d42c5f24902af9e2538e82e39ad350b0c766eb3fbf2d8f3d8359" +checksum = "f00b5dbd620d61dfdcb6007c9c1f6054ebd75319f163d886a9055cec1155073d" dependencies = [ "jiff-static", "log", @@ -1081,9 +1087,9 @@ dependencies = [ [[package]] name = "jiff-static" -version = "0.2.23" +version = "0.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a8c8b344124222efd714b73bb41f8b5120b27a7cc1c75593a6ff768d9d05aa4" +checksum = "e000de030ff8022ea1da3f466fbb0f3a809f5e51ed31f6dd931c35181ad8e6d7" dependencies = [ "proc-macro2", "quote", @@ -1102,10 +1108,12 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.94" +version = "0.3.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e04e2ef80ce82e13552136fabeef8a5ed1f985a96805761cbb9a2c34e7664d9" +checksum = "67df7112613f8bfd9150013a0314e196f4800d3201ae742489d999db2f979f08" dependencies = [ + "cfg-if", + "futures-util", "once_cell", "wasm-bindgen", ] @@ -1177,9 +1185,9 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" [[package]] name = "libc" -version = "0.2.184" +version = "0.2.186" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48f5d2a454e16a5ea0f4ced81bd44e4cfc7bd3a507b61887c99fd3538b28e4af" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" [[package]] name = "libm" @@ -1238,9 +1246,8 @@ checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" [[package]] name = "miden-ace-codegen" -version = "0.22.3" +version = "0.23.0" dependencies = [ - "miden-air", "miden-core", "miden-crypto", "thiserror", @@ -1248,10 +1255,14 @@ dependencies = [ [[package]] name = "miden-air" -version = "0.22.3" +version = "0.23.0" dependencies = [ + "insta", + "miden-ace-codegen", "miden-core", "miden-crypto", + "miden-lifted-stark", + "miden-test-serde-macros", "miden-utils-indexing", "proptest", "thiserror", @@ -1260,7 +1271,7 @@ dependencies = [ [[package]] name = "miden-assembly" -version = "0.22.3" +version = "0.23.0" dependencies = [ "env_logger", "insta", @@ -1271,6 +1282,7 @@ dependencies = [ "miden-mast-package", "miden-package-registry", "miden-project", + "miden-test-serde-macros", "proptest", "smallvec", "tempfile", @@ -1279,7 +1291,7 @@ dependencies = [ [[package]] name = "miden-assembly-syntax" -version = "0.22.3" +version = "0.23.0" dependencies = [ "aho-corasick", "env_logger", @@ -1305,12 +1317,12 @@ dependencies = [ [[package]] name = "miden-core" -version = "0.22.3" +version = "0.23.0" dependencies = [ "criterion", "derive_more", "insta", - "itertools 0.14.0", + "log", "miden-crypto", "miden-debug-types", "miden-formatting", @@ -1331,8 +1343,9 @@ dependencies = [ [[package]] name = "miden-core-lib" -version = "0.22.3" +version = "0.23.0" dependencies = [ + "bincode", "criterion", "env_logger", "fs-err", @@ -1341,6 +1354,7 @@ dependencies = [ "miden-assembly", "miden-core", "miden-crypto", + "miden-lifted-stark", "miden-package-registry", "miden-processor", "miden-prover", @@ -1348,35 +1362,34 @@ dependencies = [ "miden-utils-sync", "miden-verifier", "num", - "num-bigint", - "pretty_assertions", "rand 0.9.4", "rand_chacha", "rstest", - "serde_json", "thiserror", ] [[package]] name = "miden-crypto" -version = "0.23.0" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ed0a034a460e27723dcfdf25effffab84331c3b46b13e7a1bd674197cc71bfe" +checksum = "72ae084a6d15d5d862760bcbdbb5caad41415ed455cd7ab2b53a012d21a431ed" dependencies = [ "blake3", "cc", "chacha20poly1305", "curve25519-dalek", + "der", "ed25519-dalek", "flume", - "glob", "hkdf", "k256", "miden-crypto-derive", "miden-field", + "miden-lifted-stark", "miden-serde-utils", "num", "num-complex", + "once_cell", "p3-blake3", "p3-challenger", "p3-dft", @@ -1384,7 +1397,6 @@ dependencies = [ "p3-keccak", "p3-matrix", "p3-maybe-rayon", - "p3-miden-lifted-stark", "p3-symmetric", "p3-util", "rand 0.9.4", @@ -1402,9 +1414,9 @@ dependencies = [ [[package]] name = "miden-crypto-derive" -version = "0.23.0" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8bf6ebde028e79bcc61a3632d2f375a5cc64caa17d014459f75015238cb1e08" +checksum = "e8523f6ac9b28782ca759920e536164e7eab7dbfaf9132721ca3e325c060df73" dependencies = [ "quote", "syn 2.0.117", @@ -1412,31 +1424,35 @@ dependencies = [ [[package]] name = "miden-debug-types" -version = "0.22.3" +version = "0.23.0" dependencies = [ "memchr", "miden-crypto", "miden-formatting", "miden-miette", + "miden-test-serde-macros", "miden-utils-indexing", "miden-utils-sync", "paste", + "proptest", "serde", + "serde_json", "serde_spanned", "thiserror", ] [[package]] name = "miden-field" -version = "0.23.0" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38011348f4fb4c9e5ce1f471203d024721c00e3b60a91aa91aaefe6738d8b5ea" +checksum = "7b8a48ba526c353bf583bba18ddf62ad4846945e85fcaf44614633276416b5d9" dependencies = [ "miden-serde-utils", "num-bigint", "p3-challenger", "p3-field", "p3-goldilocks", + "p3-util", "paste", "rand 0.10.1", "serde", @@ -1453,11 +1469,46 @@ dependencies = [ "unicode-width 0.1.14", ] +[[package]] +name = "miden-lifted-air" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a00d97ada3bfd70d6cc4f1a13ced8cb509f72fb16b1b28c292366aee846d3220" +dependencies = [ + "p3-air", + "p3-field", + "p3-matrix", + "p3-util", + "thiserror", +] + +[[package]] +name = "miden-lifted-stark" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab3601a30d39e08a31ecc5b5215c87b11623942d9610aebccda89a4a5bf757c4" +dependencies = [ + "miden-lifted-air", + "miden-stark-transcript", + "miden-stateful-hasher", + "p3-challenger", + "p3-dft", + "p3-field", + "p3-goldilocks", + "p3-matrix", + "p3-maybe-rayon", + "p3-symmetric", + "p3-util", + "rand 0.10.1", + "serde", + "thiserror", + "tracing", +] + [[package]] name = "miden-mast-package" -version = "0.22.3" +version = "0.23.0" dependencies = [ - "derive_more", "miden-assembly-syntax", "miden-core", "miden-debug-types", @@ -1507,11 +1558,13 @@ dependencies = [ [[package]] name = "miden-package-registry" -version = "0.22.3" +version = "0.23.0" dependencies = [ "miden-assembly-syntax", "miden-core", "miden-mast-package", + "miden-test-serde-macros", + "proptest", "pubgrub", "serde", "serde_json", @@ -1519,9 +1572,25 @@ dependencies = [ "thiserror", ] +[[package]] +name = "miden-package-registry-local" +version = "0.23.0" +dependencies = [ + "clap", + "miden-assembly-syntax", + "miden-core", + "miden-mast-package", + "miden-package-registry", + "serde", + "serde_json", + "tempfile", + "thiserror", + "toml", +] + [[package]] name = "miden-processor" -version = "0.22.3" +version = "0.23.0" dependencies = [ "insta", "itertools 0.14.0", @@ -1544,7 +1613,7 @@ dependencies = [ [[package]] name = "miden-project" -version = "0.22.3" +version = "0.23.0" dependencies = [ "miden-assembly-syntax", "miden-core", @@ -1563,30 +1632,52 @@ dependencies = [ [[package]] name = "miden-prover" -version = "0.22.3" +version = "0.23.0" dependencies = [ "bincode", "miden-air", + "miden-assembly", "miden-core", "miden-crypto", "miden-debug-types", "miden-processor", "serde", - "thiserror", "tokio", "tracing", ] [[package]] name = "miden-serde-utils" -version = "0.23.0" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff78082e9b4ca89863e68da01b35f8a4029ee6fd912e39fa41fde4273a7debab" +checksum = "d899afcfbf85c851522f2dff73db1064116486fb8e0ebce0ade44ce72dadc075" dependencies = [ "p3-field", "p3-goldilocks", ] +[[package]] +name = "miden-stark-transcript" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c0e1f55bdff89f12ec6fc3881660a0d51d4e77f66026ab0e6ddcbd098a16f2f" +dependencies = [ + "p3-challenger", + "p3-field", + "serde", + "thiserror", +] + +[[package]] +name = "miden-stateful-hasher" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0069bab01139a5660c7189589c95dfedf8449514d03641fd3f9d049e1b031f9" +dependencies = [ + "p3-field", + "p3-symmetric", +] + [[package]] name = "miden-test-serde-macros" version = "0.1.0" @@ -1618,7 +1709,7 @@ dependencies = [ [[package]] name = "miden-utils-core-derive" -version = "0.22.3" +version = "0.23.0" dependencies = [ "proc-macro2", "quote", @@ -1627,38 +1718,39 @@ dependencies = [ [[package]] name = "miden-utils-diagnostics" -version = "0.22.3" +version = "0.23.0" dependencies = [ "miden-crypto", "miden-debug-types", "miden-miette", - "paste", "tracing", ] [[package]] name = "miden-utils-indexing" -version = "0.22.3" +version = "0.23.0" dependencies = [ "miden-crypto", + "miden-test-serde-macros", + "proptest", "serde", + "serde_json", "thiserror", ] [[package]] name = "miden-utils-sync" -version = "0.22.3" +version = "0.23.0" dependencies = [ "lock_api", "loom", "once_cell", "parking_lot", - "proptest", ] [[package]] name = "miden-verifier" -version = "0.22.3" +version = "0.23.0" dependencies = [ "bincode", "miden-air", @@ -1671,7 +1763,7 @@ dependencies = [ [[package]] name = "miden-vm" -version = "0.22.3" +version = "0.23.0" dependencies = [ "assert_cmd", "bincode", @@ -1684,15 +1776,15 @@ dependencies = [ "miden-core-lib", "miden-crypto", "miden-debug-types", + "miden-lifted-stark", "miden-mast-package", "miden-processor", "miden-prover", + "miden-test-serde-macros", "miden-test-utils", "miden-verifier", - "num-bigint", "predicates", - "pretty_assertions", - "rand_chacha", + "proptest", "serde", "serde_json", "tokio", @@ -1702,11 +1794,23 @@ dependencies = [ "walkdir", ] +[[package]] +name = "miden-vm-synthetic-bench" +version = "0.23.0" +dependencies = [ + "criterion", + "miden-processor", + "miden-vm", + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "midenc-hir-type" -version = "0.5.3" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eb29d7c049fb69373c7e775e3d4411e63e4ee608bc43826282ba62c6ec9f891" +checksum = "1ff0511aa2201f7098995e38a3c97a319d379c3b2d26fb83677b21b71f61a7b4" dependencies = [ "miden-formatting", "miden-serde-utils", @@ -1836,6 +1940,10 @@ name = "once_cell" version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" +dependencies = [ + "critical-section", + "portable-atomic", +] [[package]] name = "once_cell_polyfill" @@ -1897,19 +2005,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "p3-commit" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "916ae7989d5c3b49f887f5c55b2f9826bdbb81aaebf834503c4145d8b267c829" -dependencies = [ - "itertools 0.14.0", - "p3-field", - "p3-matrix", - "p3-util", - "serde", -] - [[package]] name = "p3-dft" version = "0.5.2" @@ -2009,102 +2104,6 @@ dependencies = [ "rand 0.10.1", ] -[[package]] -name = "p3-miden-lifted-air" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5c31c65fdc88952d7b301546add9670676e5b878aa0066dd929f107c203b006" -dependencies = [ - "p3-air", - "p3-field", - "p3-matrix", - "p3-util", - "thiserror", -] - -[[package]] -name = "p3-miden-lifted-fri" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab9932f1b0a16609a45cd4ee10a4d35412728bc4b38837c7979d7c85d8dcc9fc" -dependencies = [ - "p3-challenger", - "p3-commit", - "p3-dft", - "p3-field", - "p3-matrix", - "p3-maybe-rayon", - "p3-miden-lmcs", - "p3-miden-transcript", - "p3-util", - "rand 0.10.1", - "thiserror", - "tracing", -] - -[[package]] -name = "p3-miden-lifted-stark" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c3956ab7270c3cdd53ca9796d39ae1821984eb977415b0672110f9666bff5d8" -dependencies = [ - "p3-challenger", - "p3-dft", - "p3-field", - "p3-matrix", - "p3-maybe-rayon", - "p3-miden-lifted-air", - "p3-miden-lifted-fri", - "p3-miden-lmcs", - "p3-miden-stateful-hasher", - "p3-miden-transcript", - "p3-util", - "thiserror", - "tracing", -] - -[[package]] -name = "p3-miden-lmcs" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c46791c983e772136db3d48f102431457451447abb9087deb6c8ce3c1efc86" -dependencies = [ - "p3-commit", - "p3-field", - "p3-matrix", - "p3-maybe-rayon", - "p3-miden-stateful-hasher", - "p3-miden-transcript", - "p3-symmetric", - "p3-util", - "rand 0.10.1", - "serde", - "thiserror", - "tracing", -] - -[[package]] -name = "p3-miden-stateful-hasher" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec47a9d9615eb3d9d2a59b00d19751d9ad85384b55886827913d680d912eac6a" -dependencies = [ - "p3-field", - "p3-symmetric", -] - -[[package]] -name = "p3-miden-transcript" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40c565647487e4a949f67e6f115b0391d6cb82ac8e561165789939bab23d0ae7" -dependencies = [ - "p3-challenger", - "p3-field", - "serde", - "thiserror", -] - [[package]] name = "p3-monty-31" version = "0.5.2" @@ -2287,9 +2286,9 @@ checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" [[package]] name = "portable-atomic-util" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "091397be61a01d4be58e7841595bd4bfedb15f1cd54977d79b8271e94ed799a3" +checksum = "c2a106d1259c23fac8e543272398ae0e3c0b8d33c88ed73d0cc71b0f1d902618" dependencies = [ "portable-atomic", ] @@ -2465,7 +2464,7 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207" dependencies = [ - "rand_core 0.10.0", + "rand_core 0.10.1", ] [[package]] @@ -2498,9 +2497,9 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c8d0fd677905edcbeedbf2edb6494d676f0e98d54d5cf9bda0b061cb8fb8aba" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" [[package]] name = "rand_hc" @@ -2522,9 +2521,9 @@ dependencies = [ [[package]] name = "rayon" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" +checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d" dependencies = [ "either", "rayon-core", @@ -2814,9 +2813,9 @@ dependencies = [ [[package]] name = "sha3" -version = "0.10.8" +version = "0.10.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +checksum = "77fd7028345d415a4034cf8777cd4f8ab1851274233b45f84e3d955502d93874" dependencies = [ "digest", "keccak", @@ -2855,9 +2854,9 @@ checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa" [[package]] name = "siphasher" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e" +checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649" [[package]] name = "slab" @@ -3106,9 +3105,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.51.0" +version = "1.52.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bd1c4c0fc4a7ab90fc15ef6daaa3ec3b893f004f915f2392557ed23237820cd" +checksum = "110a78583f19d5cdb2c5ccf321d1290344e71313c6c37d43520d386027d18386" dependencies = [ "pin-project-lite", "tokio-macros", @@ -3151,9 +3150,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.25.10+spec-1.1.0" +version = "0.25.11+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a82418ca169e235e6c399a84e395ab6debeb3bc90edc959bf0f48647c6a32d1b" +checksum = "0b59c4d22ed448339746c59b905d24568fcbb3ab65a500494f7b8c3e97739f2b" dependencies = [ "indexmap", "toml_datetime", @@ -3284,9 +3283,9 @@ checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" [[package]] name = "typenum" -version = "1.19.0" +version = "1.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" +checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de" [[package]] name = "unarray" @@ -3348,9 +3347,9 @@ checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" [[package]] name = "version-ranges" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3595ffe225639f1e0fd8d7269dcc05d2fbfea93cfac2fea367daf1adb60aae91" +checksum = "31e9bd4e9c9ff6a2a9b5969462ba26216af3e010df0377dad8320ab515262ef8" dependencies = [ "smallvec", ] @@ -3397,11 +3396,11 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasip2" -version = "1.0.2+wasi-0.2.9" +version = "1.0.3+wasi-0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6" dependencies = [ - "wit-bindgen", + "wit-bindgen 0.57.1", ] [[package]] @@ -3410,14 +3409,14 @@ version = "0.4.0+wasi-0.3.0-rc-2026-01-06" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" dependencies = [ - "wit-bindgen", + "wit-bindgen 0.51.0", ] [[package]] name = "wasm-bindgen" -version = "0.2.117" +version = "0.2.121" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0551fc1bb415591e3372d0bc4780db7e587d84e2a7e79da121051c5c4b89d0b0" +checksum = "49ace1d07c165b0864824eee619580c4689389afa9dc9ed3a4c75040d82e6790" dependencies = [ "cfg-if", "once_cell", @@ -3428,9 +3427,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.117" +version = "0.2.121" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fbdf9a35adf44786aecd5ff89b4563a90325f9da0923236f6104e603c7e86be" +checksum = "8e68e6f4afd367a562002c05637acb8578ff2dea1943df76afb9e83d177c8578" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3438,9 +3437,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.117" +version = "0.2.121" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dca9693ef2bab6d4e6707234500350d8dad079eb508dca05530c85dc3a529ff2" +checksum = "d95a9ec35c64b2a7cb35d3fead40c4238d0940c86d107136999567a4703259f2" dependencies = [ "bumpalo", "proc-macro2", @@ -3451,9 +3450,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.117" +version = "0.2.121" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39129a682a6d2d841b6c429d0c51e5cb0ed1a03829d8b3d1e69a011e62cb3d3b" +checksum = "c4e0100b01e9f0d03189a92b96772a1fb998639d981193d7dbab487302513441" dependencies = [ "unicode-ident", ] @@ -3494,9 +3493,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.94" +version = "0.3.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd70027e39b12f0849461e08ffc50b9cd7688d942c1c8e3c7b22273236b4dd0a" +checksum = "4b572dff8bcf38bad0fa19729c89bb5748b2b9b1d8be70cf90df697e3a8f32aa" dependencies = [ "js-sys", "wasm-bindgen", @@ -3559,9 +3558,9 @@ dependencies = [ [[package]] name = "winnow" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09dac053f1cd375980747450bfc7250c264eaae0583872e845c0c7cd578872b5" +checksum = "2ee1708bef14716a11bae175f579062d4554d95be2c6829f518df847b7b3fdd0" dependencies = [ "memchr", ] @@ -3575,6 +3574,12 @@ dependencies = [ "wit-bindgen-rust-macro", ] +[[package]] +name = "wit-bindgen" +version = "0.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + [[package]] name = "wit-bindgen-core" version = "0.51.0" diff --git a/Cargo.toml b/Cargo.toml index 6a7babc9de..10a263a310 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,7 @@ [workspace] members = [ "air", + "benches/synthetic-bench", "core", "crates/ace-codegen", "crates/assembly", @@ -9,6 +10,7 @@ members = [ "crates/lib/core", "crates/mast-package", "crates/package-registry", + "crates/package-registry-local", "crates/project", "crates/test-serde-macros", "crates/test-utils", @@ -32,7 +34,7 @@ homepage = "https://miden.xyz" repository = "https://github.com/0xMiden/miden-vm" exclude = [".github/"] rust-version = "1.90" -version = "0.22.3" +version = "0.23.0" [profile.optimized] inherits = "release" @@ -48,34 +50,37 @@ overflow-checks = true [workspace.dependencies] # Workspace crates -miden-air = { path = "./air", version = "0.22.0", default-features = false } -miden-assembly = { path = "./crates/assembly", version = "0.22.0", default-features = false } -miden-assembly-syntax = { path = "./crates/assembly-syntax", version = "0.22.0", default-features = false } -miden-core = { path = "./core", version = "0.22.0", default-features = false } -miden-debug-types = { path = "./crates/debug-types", version = "0.22.0", default-features = false } -miden-mast-package = { path = "./crates/mast-package", version = "0.22.0", default-features = false } -miden-package-registry = { path = "./crates/package-registry", version = "0.22.0", default-features = false } -miden-processor = { path = "./processor", version = "0.22.0", default-features = false } +miden-ace-codegen = { path = "./crates/ace-codegen", version = "0.23.0", default-features = false } +miden-air = { path = "./air", version = "0.23.0", default-features = false } +miden-assembly = { path = "./crates/assembly", version = "0.23.0", default-features = false } +miden-assembly-syntax = { path = "./crates/assembly-syntax", version = "0.23.0", default-features = false } +miden-core = { path = "./core", version = "0.23.0", default-features = false } +miden-debug-types = { path = "./crates/debug-types", version = "0.23.0", default-features = false } +miden-mast-package = { path = "./crates/mast-package", version = "0.23.0", default-features = false } +miden-package-registry = { path = "./crates/package-registry", version = "0.23.0", default-features = false } +miden-processor = { path = "./processor", version = "0.23.0", default-features = false } miden-test-serde-macros = { path = "./crates/test-serde-macros", default-features = false } -miden-project = { path = "./crates/project", version = "0.22.0", default-features = false } -miden-prover = { path = "./prover", version = "0.22.0", default-features = false } -miden-core-lib = { path = "./crates/lib/core", version = "0.22.0", default-features = false } -miden-utils-core-derive = { path = "./crates/utils-core-derive", version = "0.22.0", default-features = false } -miden-utils-diagnostics = { path = "./crates/utils-diagnostics", version = "0.22.0", default-features = false } -miden-utils-indexing = { path = "./crates/utils-indexing", version = "0.22.0", default-features = false } -miden-utils-sync = { path = "./crates/utils-sync", version = "0.22.0", default-features = false } +miden-project = { path = "./crates/project", version = "0.23.0", default-features = false } +miden-prover = { path = "./prover", version = "0.23.0", default-features = false } +miden-core-lib = { path = "./crates/lib/core", version = "0.23.0", default-features = false } +miden-utils-core-derive = { path = "./crates/utils-core-derive", version = "0.23.0", default-features = false } +miden-utils-diagnostics = { path = "./crates/utils-diagnostics", version = "0.23.0", default-features = false } +miden-utils-indexing = { path = "./crates/utils-indexing", version = "0.23.0", default-features = false } +miden-utils-sync = { path = "./crates/utils-sync", version = "0.23.0", default-features = false } miden-utils-testing = { path = "./crates/test-utils", package = "miden-test-utils" } -miden-verifier = { path = "./verifier", version = "0.22.0", default-features = false } +miden-verifier = { path = "./verifier", version = "0.23.0", default-features = false } # Miden crates -miden-crypto = { version = "0.23", default-features = false } +miden-crypto = { version = "0.25", default-features = false } miden-formatting = { version = "0.1", default-features = false } -midenc-hir-type = { version = "0.5", default-features = false } +miden-lifted-stark = { version = "0.25", default-features = false } +midenc-hir-type = { version = "0.6.1", default-features = false } # Serialization bincode = "1.3" # Third-party crates +clap = { version = "4.5", features = ["derive"] } criterion = { version = "0.7" } derive_more = { version = "2.0", features = ["from"] } env_logger = { version = "0.11" } @@ -85,11 +90,9 @@ log = { version = "0.4", default-features = false } paste = { version = "1.0", default-features = false } proptest = { version = "1.8", default-features = false, features = ["no_std", "alloc"] } proptest-derive = { version = "0.7", default-features = false } -rand = { version = "0.9", default-features = false } serde = { version = "1.0", default-features = false, features = ["alloc", "derive", "rc"] } serde_json = { version = "1.0", default-features = false, features = ["alloc"] } serde-untagged = {version = "0.1" } -semver = { version = "1.0", default-features = false } smallvec = { version = "1.15", default-features = false, features = ["union", "const_generics", "const_new"] } syn = "1.0" tempfile = { version = "3.18", default-features = false } @@ -97,8 +100,14 @@ thiserror = { version = "2.0", default-features = false } tokio = { version = "1.48", default-features = false } tracing = { version = "0.1", default-features = false, features = ["attributes"] } -# WASM support -getrandom = { version = "0.2", default-features = false, features = ["js"] } +loom = "0.7" +miette = { package = "miden-miette", version = "8.0", default-features = false } +pretty_assertions = { version = "1.4", default-features = false } +proc-macro2 = "1.0" +quote = "1.0" +rand_chacha = { version = "0.9", default-features = false } +rstest = "0.26" +toml = { version = "1.0", default-features = false } [workspace.lints.rust] unexpected_cfgs = { check-cfg = ['cfg(fuzzing)'], level = "warn" } diff --git a/Makefile b/Makefile index 8fac4f9457..2a1795d165 100644 --- a/Makefile +++ b/Makefile @@ -19,6 +19,8 @@ help: @printf " make test-prover # Test prover crate\n" @printf " make test-core-lib # Test core-lib crate\n" @printf " make test-verifier # Test verifier crate\n" + @printf " make check-constraints # Check core-lib constraint artifacts\n" + @printf " make regenerate-constraints # Regenerate core-lib constraint artifacts\n" @printf "\nExamples:\n" @printf " make test-air test=\"some_test\" # Test specific function\n" @printf " make test-fast # Fast tests (no proptests/CLI)\n" @@ -86,6 +88,9 @@ format: ## Runs Format using nightly toolchain format-check: ## Runs Format using nightly toolchain but only in check mode cargo +nightly fmt --all --check +.PHONY: shear +shear: ## Runs cargo-shear to find unused or misplaced dependencies + cargo shear .PHONY: lint lint: xclippy xclippy-fix format ## Runs all linting tasks: check with xclippy, fix issues, then format @@ -220,6 +225,14 @@ exec-avx2: ## Builds an executable with AVX2 acceleration enabled exec-sve: ## Builds an executable with SVE acceleration enabled RUSTFLAGS="-C target-feature=+sve" cargo build --profile optimized $(FEATURES_CONCURRENT_EXEC) +.PHONY: regenerate-constraints +regenerate-constraints: ## Regenerate core-lib constraint artifacts + cargo run --package miden-core-lib --features constraints-tools --bin regenerate-constraints -- --write + +.PHONY: check-constraints +check-constraints: ## Check core-lib constraint artifacts for drift + cargo run --package miden-core-lib --features constraints-tools --bin regenerate-constraints -- --check + .PHONY: exec-info exec-info: ## Builds an executable with log tree enabled cargo build --profile optimized $(FEATURES_LOG_TREE) @@ -266,11 +279,23 @@ fuzz-mast-forest: fuzz-seeds ## Run fuzzing for MastForest deserialization fuzz-mast-validate: fuzz-seeds ## Run fuzzing for UntrustedMastForest validation -@cargo +nightly fuzz run mast_forest_validate --release --fuzz-dir miden-core-fuzz +.PHONY: fuzz-mast-node-info +fuzz-mast-node-info: fuzz-seeds ## Run fuzzing for SerializedMastForest node metadata access + -@cargo +nightly fuzz run mast_node_info --release --fuzz-dir miden-core-fuzz + +.PHONY: fuzz-serialized-mast-forest +fuzz-serialized-mast-forest: fuzz-seeds ## Run fuzzing for SerializedMastForest structural inspection + -@cargo +nightly fuzz run serialized_mast_forest_new --release --fuzz-dir miden-core-fuzz + .PHONY: fuzz-all fuzz-all: fuzz-seeds ## Run all fuzz targets (in sequence) -@cargo +nightly fuzz run mast_forest_deserialize --release --fuzz-dir miden-core-fuzz -- -max_total_time=300 -@cargo +nightly fuzz run mast_forest_serde_deserialize --release --fuzz-dir miden-core-fuzz -- -max_total_time=300 -@cargo +nightly fuzz run mast_forest_validate --release --fuzz-dir miden-core-fuzz -- -max_total_time=300 + -@cargo +nightly fuzz run mast_node_info --release --fuzz-dir miden-core-fuzz -- -max_total_time=300 + -@cargo +nightly fuzz run serialized_mast_forest_new --release --fuzz-dir miden-core-fuzz -- -max_total_time=300 + -@cargo +nightly fuzz run basic_block_data --release --fuzz-dir miden-core-fuzz -- -max_total_time=300 + -@cargo +nightly fuzz run debug_info --release --fuzz-dir miden-core-fuzz -- -max_total_time=300 -@cargo +nightly fuzz run program_deserialize --release --fuzz-dir miden-core-fuzz -- -max_total_time=300 -@cargo +nightly fuzz run program_serde_deserialize --release --fuzz-dir miden-core-fuzz -- -max_total_time=300 -@cargo +nightly fuzz run kernel_deserialize --release --fuzz-dir miden-core-fuzz -- -max_total_time=300 @@ -287,7 +312,11 @@ fuzz-all: fuzz-seeds ## Run all fuzz targets (in sequence) -@cargo +nightly fuzz run library_deserialize --release --fuzz-dir miden-core-fuzz -- -max_total_time=300 -@cargo +nightly fuzz run library_serde_deserialize --release --fuzz-dir miden-core-fuzz -- -max_total_time=300 -@cargo +nightly fuzz run package_deserialize --release --fuzz-dir miden-core-fuzz -- -max_total_time=300 + -@cargo +nightly fuzz run package_semantic_deserialize --release --fuzz-dir miden-core-fuzz -- -max_total_time=300 -@cargo +nightly fuzz run package_serde_deserialize --release --fuzz-dir miden-core-fuzz -- -max_total_time=300 + -@cargo +nightly fuzz run project_toml_parse --release --fuzz-dir miden-core-fuzz -- -max_total_time=300 + -@cargo +nightly fuzz run project_load --release --fuzz-dir miden-core-fuzz -- -max_total_time=300 + -@cargo +nightly fuzz run project_assemble --release --fuzz-dir miden-core-fuzz -- -max_total_time=300 .PHONY: fuzz-list fuzz-list: ## List available fuzz targets diff --git a/README.md b/README.md index 1c67142450..48620078ba 100644 --- a/README.md +++ b/README.md @@ -101,7 +101,7 @@ When executed on a single CPU core, the current version of Miden VM operates at | 214 | 0.3 ms | 885 ms | 200 MB | 80 KB | | 216 | 0.7 ms | 3.6 sec | 750 MB | 100 KB | | 218 | 1.2 ms | 14.7 sec | 2.9 GB | 116 KB | -| 220 | 11.1 ms | 59 sec | 11 GB | 136 KB | +| 220 | 6 ms | 59 sec | 11 GB | 136 KB | As can be seen from the above, proving time roughly doubles with every doubling in the number of cycles, but proof size grows much slower. @@ -113,14 +113,14 @@ In the benchmarks below, the VM executes the same Blake3 example program for 220< | Machine | Execution time | Proving time | Slowdown vs BLAKE3 | | ------------------------------ | :------------: | :----------: | :----------------: | -| Apple M1 Pro (16 threads) | 14.5 ms | 31.9 sec | 2.2x | -| Apple M4 Max (16 threads) | 11.1 ms | 12.9 sec | 2.2x | -| Amazon Graviton 4 (64 threads) | 10.7 ms | 9.5 sec | 1.7x | -| AMD EPYC 9R45 (64 threads) | 7.5 ms | 8.6 sec | 1.9x | -| AMD Ryzen 9 9950X (16 threads) | 7.4 ms | 18.9 sec | 2.5x | -| AMD Ryzen 9 9950X (32 threads) | 7.3 ms | 14.8 sec | 2.2x | +| Apple M1 Pro (16 threads) | 9 ms | 25.5 sec | 1.8x | +| Apple M4 Max (16 threads) | 6 ms | 10.1 sec | 1.7x | +| Amazon Graviton 4 (64 threads) | 11 ms | 7.7 sec | 1.6x | +| AMD EPYC 9R45 (64 threads) | 7.5 ms | 6.9 sec | 1.9x | +| AMD Ryzen 9 9950X (16 threads) | 7.2 ms | 16.0 sec | 2.2x | +| AMD Ryzen 9 9950X (32 threads) | 6.5 ms | 12.9 sec | 2.0x | ## References diff --git a/air/Cargo.toml b/air/Cargo.toml index 8b8d1d3a3a..c26690406b 100644 --- a/air/Cargo.toml +++ b/air/Cargo.toml @@ -19,19 +19,26 @@ doctest = false [features] default = ["std"] -std = ["miden-core/std", "thiserror/std"] +arbitrary = ["std", "dep:proptest"] +std = ["miden-core/std", "proptest?/std", "thiserror/std"] concurrent = ["std"] testing = [] [dependencies] # Miden dependencies +miden-ace-codegen.workspace = true miden-core.workspace = true miden-crypto.workspace = true +miden-lifted-stark.workspace = true miden-utils-indexing.workspace = true # External dependencies +proptest = { workspace = true, optional = true } thiserror.workspace = true tracing.workspace = true [dev-dependencies] +insta.workspace = true +miden-ace-codegen = { workspace = true, features = ["testing"] } +miden-test-serde-macros.workspace = true proptest.workspace = true diff --git a/air/src/ace.rs b/air/src/ace.rs new file mode 100644 index 0000000000..6c69d6f8fa --- /dev/null +++ b/air/src/ace.rs @@ -0,0 +1,329 @@ +//! ACE circuit integration for ProcessorAir. +//! +//! This module extends the constraint-evaluation DAG produced by +//! `build_ace_dag_for_air` with the LogUp auxiliary-trace boundary check: +//! +//! ```text +//! 0 = Σ aux_bound[0..NUM_LOGUP_COMMITTED_FINALS] +//! + c_block_hash +//! + c_log_precompile +//! + c_kernel_rom +//! ``` +//! +//! Two of the three corrections depend only on fixed-length public inputs +//! (`c_bh`, `c_lp`), so they are rebuilt directly inside the DAG as rational +//! fractions `(n, d)` and folded into a running rational `(N, D)` without any +//! in-circuit inversion. The kernel-ROM correction depends on the variable- +//! length kernel digest list which the circuit can't walk, so MASM computes +//! it (one final `ext2inv`) and hands it in as a single scalar via the +//! existing `VlpiReduction(0)` input. The final boundary check is the +//! quadratic identity `(Σ aux_bound + c_kr) · D + N = 0`. + +use alloc::{vec, vec::Vec}; + +use miden_ace_codegen::{ + AceCircuit, AceConfig, AceDag, AceError, DagBuilder, InputKey, NodeId, build_ace_dag_for_air, +}; +use miden_core::{Felt, field::ExtensionField}; +use miden_crypto::{ + field::Algebra, + stark::air::{LiftedAir, symbolic::SymbolicExpressionExt}, +}; + +use crate::{PV_PROGRAM_HASH, PV_TRANSCRIPT_STATE}; + +// BATCHING TYPES +// ================================================================================================ + +/// An element in a bus message encoding. +/// +/// Bus messages are encoded as `bus_prefix + sum(beta^i * elements[i])` using the +/// aux randomness challenges. Each element is either a constant base-field value +/// or a reference to a fixed-length public input. +#[derive(Debug, Clone)] +pub enum MessageElement { + /// A constant base-field value. + Constant(Felt), + /// A fixed-length public input value, indexed into the public values array. + PublicInput(usize), +} + +/// Sign applied to a `BusFraction` numerator. +#[derive(Debug, Clone, Copy)] +pub enum Sign { + Plus, + Minus, +} + +/// A rational `±1 / bus_message` contribution to the LogUp boundary sum. +/// +/// The bus message denominator is rebuilt inside the ACE DAG from public inputs +/// and aux randomness, so no external input is needed for this term. +#[derive(Debug, Clone)] +pub struct BusFraction { + pub sign: Sign, + pub bus: usize, + pub message: Vec, +} + +/// Configuration for the LogUp auxiliary-trace boundary batching. +/// +/// Consumed by [`batch_logup_boundary`] to extend the constraint-check DAG with +/// the boundary identity checked by `ProcessorAir::reduced_aux_values`. +#[derive(Debug, Clone)] +pub struct LogUpBoundaryConfig { + /// Aux-bus-boundary column indices summed as `Σ aux_bound[col]`. + pub sum_columns: Vec, + /// Aux-bus-boundary columns that must individually equal zero. Absorbed at + /// an independent γ power from the accumulator sum so a malicious prover + /// cannot cancel them against `sum_columns` or the rational corrections. + /// Mirrors the native runtime check in `ProcessorAir::reduced_aux_values`. + pub zero_columns: Vec, + /// Rational `(±1, d_i)` fractions folded into the running rational `(N, D)`. + pub fractions: Vec, + /// Scalar EF inputs added directly to the aux-boundary sum. Trusted from + /// MASM (the VM's own constraint system covers the procedure that produced + /// them). Typically one entry pointing at `VlpiReduction(0)` for `c_kr`. + pub scalar_corrections: Vec, +} + +// BATCHING FUNCTIONS +// ================================================================================================ + +/// Extend a constraint DAG with the LogUp auxiliary-trace boundary check. +/// +/// Builds: +/// +/// `sum_aux = Σ AuxBusBoundary(col) + Σ scalar_corrections` +/// `(N, D) = fold((0, 1), fractions)` via `(N', D') = (N·d_i + D·n_i, D·d_i)` +/// `boundary = sum_aux · D + N` +/// `zero_sum = Σ AuxBusBoundary(col)` for `col` in `zero_columns` +/// `root = constraint_check + γ · boundary + γ² · zero_sum` +/// +/// Returns the new DAG with the batched root. The zero-columns identity lives at +/// γ² so a nonzero padding slot cannot cancel against the γ¹-batched boundary +/// accumulator. +pub fn batch_logup_boundary( + constraint_dag: AceDag, + config: &LogUpBoundaryConfig, +) -> AceDag +where + EF: ExtensionField, +{ + let constraint_root = constraint_dag.root; + let mut builder = DagBuilder::from_dag(constraint_dag); + + // sum_aux = Σ aux_bound[col] + Σ scalar_corrections + let mut sum_aux = builder.constant(EF::ZERO); + for &col in &config.sum_columns { + let node = builder.input(InputKey::AuxBusBoundary(col)); + sum_aux = builder.add(sum_aux, node); + } + for &scalar in &config.scalar_corrections { + let node = builder.input(scalar); + sum_aux = builder.add(sum_aux, node); + } + + // Fold all rational fractions into a single (N, D) running rational. + let mut num = builder.constant(EF::ZERO); + let mut den = builder.constant(EF::ONE); + for fraction in &config.fractions { + let d_i = encode_bus_message(&mut builder, fraction.bus, &fraction.message); + let sign_value = match fraction.sign { + Sign::Plus => EF::ONE, + Sign::Minus => -EF::ONE, + }; + let n_i = builder.constant(sign_value); + + // (num', den') = (num * d_i + den * n_i, den * d_i) + let num_d = builder.mul(num, d_i); + let den_n = builder.mul(den, n_i); + num = builder.add(num_d, den_n); + den = builder.mul(den, d_i); + } + + // boundary = sum_aux · D + N + let sum_times_den = builder.mul(sum_aux, den); + let boundary = builder.add(sum_times_den, num); + + // zero_sum = Σ aux_bound[col] for col in zero_columns. Each column's identity + // `aux_bound[col] = 0` is batched at γ² so it cannot cancel against boundary + // terms at γ¹ or against other zero columns in the same sum (the whole sum is + // the coefficient of a single γ power, which forces the sum to zero — and since + // the boundary check is linear in each slot, each slot is independently zero with + // high probability over γ). + let mut zero_sum = builder.constant(EF::ZERO); + for &col in &config.zero_columns { + let node = builder.input(InputKey::AuxBusBoundary(col)); + zero_sum = builder.add(zero_sum, node); + } + + // Batch with the constraint root using gamma. + let gamma = builder.input(InputKey::Gamma); + let gamma_boundary = builder.mul(gamma, boundary); + let constraint_plus_boundary = builder.add(constraint_root, gamma_boundary); + let gamma_sq = builder.mul(gamma, gamma); + let gamma_sq_zero = builder.mul(gamma_sq, zero_sum); + let root = builder.add(constraint_plus_boundary, gamma_sq_zero); + + builder.build(root) +} + +/// Encode a bus message as `bus_prefix[bus] + sum(beta^i * elements[i])`. +/// +/// The bus prefix provides domain separation: `bus_prefix[bus] = alpha + (bus+1) * gamma_bus` +/// where `gamma_bus = beta^MIDEN_MAX_MESSAGE_WIDTH`. This matches [`lookup::Challenges::encode`]. +fn encode_bus_message( + builder: &mut DagBuilder, + bus: usize, + elements: &[MessageElement], +) -> NodeId +where + EF: ExtensionField, +{ + use crate::constraints::lookup::messages::MIDEN_MAX_MESSAGE_WIDTH; + + let alpha = builder.input(InputKey::AuxRandAlpha); + let beta = builder.input(InputKey::AuxRandBeta); + + // gamma_bus = beta^MIDEN_MAX_MESSAGE_WIDTH. + let mut gamma_bus = builder.constant(EF::ONE); + for _ in 0..MIDEN_MAX_MESSAGE_WIDTH { + gamma_bus = builder.mul(gamma_bus, beta); + } + + // bus_prefix = alpha + (bus + 1) * gamma_bus + let scale = builder.constant(EF::from(Felt::from_u32((bus as u32) + 1))); + let offset = builder.mul(gamma_bus, scale); + let bus_prefix = builder.add(alpha, offset); + + // acc = bus_prefix + sum(beta^i * elem_i) + // + // Beta powers are built incrementally; the DagBuilder is hash-consed, so + // identical beta^i nodes across multiple message encodings are shared + // automatically. + let mut acc = bus_prefix; + let mut beta_power = builder.constant(EF::ONE); + for elem in elements { + let node = match elem { + MessageElement::Constant(f) => builder.constant(EF::from(*f)), + MessageElement::PublicInput(idx) => builder.input(InputKey::Public(*idx)), + }; + let term = builder.mul(beta_power, node); + acc = builder.add(acc, term); + beta_power = builder.mul(beta_power, beta); + } + acc +} + +// AIR-SPECIFIC CONFIG +// ================================================================================================ + +/// Build the [`LogUpBoundaryConfig`] for the Miden VM ProcessorAir. +/// +/// This mirrors `ProcessorAir::reduced_aux_values` in `air/src/lib.rs`: it sums +/// the sole accumulator column's committed final value, adds the scalar kernel-ROM +/// correction supplied by MASM via `VlpiReduction(0)`, and folds the two open- +/// bus corrections `c_block_hash` and `c_log_precompile` as rational fractions +/// whose denominators are rebuilt from public inputs inside the DAG. +/// +/// The three fractions are: +/// 1. `c_bh = +1 / encode(BLOCK_HASH_TABLE, [ph[0..4], 0, 0, 0])` +/// 2. `c_lp_init = +1 / encode(LOG_PRECOMPILE, [0, 0, 0, 0])` +/// 3. `c_lp_final = −1 / encode(LOG_PRECOMPILE, ts[0..4])` +/// +/// `c_lp_init − c_lp_final` matches `transcript_messages` in `lib.rs` (initial +/// minus final contribution). Splitting it into two rationals keeps the code +/// uniform at the cost of two extra mul gates. +pub fn logup_boundary_config() -> LogUpBoundaryConfig { + use MessageElement::{Constant, PublicInput}; + + use crate::constraints::lookup::messages::BusId; + + // ph_msg = encode([ph[0], ph[1], ph[2], ph[3], 0, 0, 0]) + // Matches `program_hash_message` in lib.rs. + let ph_msg = vec![ + PublicInput(PV_PROGRAM_HASH), + PublicInput(PV_PROGRAM_HASH + 1), + PublicInput(PV_PROGRAM_HASH + 2), + PublicInput(PV_PROGRAM_HASH + 3), + Constant(Felt::ZERO), // parent_id = 0 (root block) + Constant(Felt::ZERO), // is_first_child = false + Constant(Felt::ZERO), // is_loop_body = false + ]; + + // default_lp_msg = encode([0, 0, 0, 0]) + // Matches `transcript_messages(..).0` (initial default state). + let default_lp_msg = vec![ + Constant(Felt::ZERO), + Constant(Felt::ZERO), + Constant(Felt::ZERO), + Constant(Felt::ZERO), + ]; + + // final_lp_msg = encode(ts[0..4]) + // Matches `transcript_messages(..).1` (final public-input state). + let final_lp_msg = vec![ + PublicInput(PV_TRANSCRIPT_STATE), + PublicInput(PV_TRANSCRIPT_STATE + 1), + PublicInput(PV_TRANSCRIPT_STATE + 2), + PublicInput(PV_TRANSCRIPT_STATE + 3), + ]; + + // TODO(#3032): only col 0 carries a real final accumulator; slot 1 is the + // placeholder — see `NUM_LOGUP_COMMITTED_FINALS`. Once trace splitting lands, + // move slot 1 from `zero_columns` to `sum_columns`. + // + // Slot 1 is in `zero_columns` so the recursive verifier independently rejects + // any nonzero padding value. The native verifier applies the matching runtime + // check in `ProcessorAir::reduced_aux_values` (see `lib.rs`). + LogUpBoundaryConfig { + sum_columns: vec![0], + zero_columns: vec![1], + fractions: vec![ + BusFraction { + sign: Sign::Plus, + bus: BusId::BlockHashTable as usize, + message: ph_msg, + }, + BusFraction { + sign: Sign::Plus, + bus: BusId::LogPrecompileTranscript as usize, + message: default_lp_msg, + }, + BusFraction { + sign: Sign::Minus, + bus: BusId::LogPrecompileTranscript as usize, + message: final_lp_msg, + }, + ], + scalar_corrections: vec![InputKey::VlpiReduction(0)], + } +} + +// CONVENIENCE FUNCTION +// ================================================================================================ + +/// Build a batched ACE circuit for the provided AIR. +/// +/// Builds the constraint-evaluation DAG, extends it with the LogUp auxiliary +/// trace boundary check via [`batch_logup_boundary`], and emits the off-VM +/// circuit representation. +/// +/// The output circuit checks `constraint_check + γ · boundary = 0`, where +/// `boundary = (Σ aux_bound + c_kr) · D + N` and `(N, D)` is the rational sum +/// of the in-DAG open-bus corrections. +pub fn build_batched_ace_circuit( + air: &A, + config: AceConfig, + boundary_config: &LogUpBoundaryConfig, +) -> Result, AceError> +where + A: LiftedAir, + EF: ExtensionField, + SymbolicExpressionExt: Algebra, +{ + let artifacts = build_ace_dag_for_air::(air, config)?; + let batched_dag = batch_logup_boundary(artifacts.dag, boundary_config); + miden_ace_codegen::emit_circuit(&batched_dag, artifacts.layout) +} diff --git a/air/src/config.rs b/air/src/config.rs index 58cd2d1a66..c9bef657bd 100644 --- a/air/src/config.rs +++ b/air/src/config.rs @@ -9,37 +9,59 @@ use miden_core::{Felt, field::QuadFelt}; use miden_crypto::{ field::Field, hash::{ - blake::Blake3Hasher, keccak::Keccak256Hash, poseidon2::Poseidon2Permutation256, - rpo::RpoPermutation256, rpx::RpxPermutation256, + blake::Blake3Hasher, + keccak::{Keccak256Hash, KeccakF, VECTOR_LEN}, + poseidon2::Poseidon2Permutation256, + rpo::RpoPermutation256, + rpx::RpxPermutation256, }, stark::{ GenericStarkConfig, - challenger::{DuplexChallenger, HashChallenger, SerializingChallenger64}, + challenger::{CanObserve, DuplexChallenger, HashChallenger, SerializingChallenger64}, dft::Radix2DitParallel, fri::PcsParams, - hasher::{ChainingHasher, StatefulSponge}, - lmcs::LmcsConfig, - symmetric::{CompressionFunctionFromHasher, TruncatedPermutation}, + hasher::{ChainingHasher, SerializingStatefulSponge, StatefulSponge}, + lmcs::config::LmcsConfig, + symmetric::{ + CompressionFunctionFromHasher, CryptographicPermutation, PaddingFreeSponge, + TruncatedPermutation, + }, }, }; +// SHARED TYPES +// ================================================================================================ + +/// Miden VM STARK configuration with pre-filled common type parameters. +/// +/// All Miden configurations use `Felt` as the base field, `QuadFelt` as the extension field, +/// and `Radix2DitParallel` as the DFT. Only the LMCS commitment scheme (`L`) and +/// Fiat-Shamir challenger (`Ch`) vary by hash function. +pub type MidenStarkConfig = + GenericStarkConfig, Ch>; + +type PackedFelt = ::Packing; + +/// Number of inputs to the Merkle compression function. +const COMPRESSION_INPUTS: usize = 2; + // PCS PARAMETERS // ================================================================================================ /// Log2 of the FRI blowup factor (blowup = 8). const LOG_BLOWUP: u8 = 3; /// Log2 of the FRI folding arity (arity = 4). -const LOG_FOLDING_ARITY: u8 = 2; +pub const LOG_FOLDING_ARITY: u8 = 2; /// Log2 of the final polynomial degree (degree = 128). const LOG_FINAL_DEGREE: u8 = 7; /// Proof-of-work bits for FRI folding challenges. -const FOLDING_POW_BITS: usize = 16; +pub const FOLDING_POW_BITS: usize = 4; /// Proof-of-work bits for DEEP composition polynomial. -const DEEP_POW_BITS: usize = 0; +pub const DEEP_POW_BITS: usize = 12; /// Number of FRI query repetitions. const NUM_QUERIES: usize = 27; /// Proof-of-work bits for query phase. -const QUERY_POW_BITS: usize = 0; +const QUERY_POW_BITS: usize = 16; /// Default PCS parameters shared by all hash function configurations. pub fn pcs_params() -> PcsParams { @@ -55,17 +77,74 @@ pub fn pcs_params() -> PcsParams { .expect("invalid PCS parameters") } -// HASH FUNCTION PARAMETERS +// DOMAIN-SEPARATED FIAT-SHAMIR TRANSCRIPT // ================================================================================================ -// Byte-oriented hashes (Blake3, Keccak). +/// RELATION_DIGEST = Poseidon2::hash_elements([PROTOCOL_ID, CIRCUIT_COMMITMENT]). +/// +/// Compile-time constant binding the Fiat-Shamir transcript to the Miden VM AIR. +/// Must match the constants in `crates/lib/core/asm/sys/vm/mod.masm`. +pub const RELATION_DIGEST: [Felt; 4] = [ + Felt::new_unchecked(2564365500194292689), + Felt::new_unchecked(7963649451118915546), + Felt::new_unchecked(13003513905888733288), + Felt::new_unchecked(3704785727996306162), +]; -/// Digest size in bytes for byte-oriented hashes. -const BYTE_DIGEST_SIZE: usize = 32; -/// Number of inputs to the Merkle compression function. -const COMPRESSION_INPUTS: usize = 2; +/// Observes PCS protocol parameters into the challenger. +/// +/// Call on a challenger obtained from `config.challenger()` to complete the +/// domain-separated transcript initialization. The config factories already bind +/// RELATION_DIGEST into the prototype challenger; this function adds the remaining +/// protocol parameters. +pub fn observe_protocol_params(challenger: &mut impl CanObserve) { + // Batch 1: PCS parameters, zero-padded to SPONGE_RATE. + challenger.observe(Felt::new_unchecked(NUM_QUERIES as u64)); + challenger.observe(Felt::new_unchecked(QUERY_POW_BITS as u64)); + challenger.observe(Felt::new_unchecked(DEEP_POW_BITS as u64)); + challenger.observe(Felt::new_unchecked(FOLDING_POW_BITS as u64)); + challenger.observe(Felt::new_unchecked(LOG_BLOWUP as u64)); + challenger.observe(Felt::new_unchecked(LOG_FINAL_DEGREE as u64)); + challenger.observe(Felt::new_unchecked(1_u64 << LOG_FOLDING_ARITY)); + challenger.observe(Felt::ZERO); +} -// Algebraic hashes (RPO, Poseidon2, RPX). +/// Absorbs variable-length public inputs into the challenger. +/// +/// Each VLPI group is a flat slice of fixed-width messages. `message_widths[i]` gives the +/// width of each message in group `i`. Every message is zero-padded to the next multiple +/// of `SPONGE_RATE` and reversed before observation, matching the layout the MASM recursive +/// verifier's `mem_stream` + `horner_eval_base` expects. +pub fn observe_var_len_public_inputs>( + challenger: &mut C, + var_len_public_inputs: &[&[Felt]], + message_widths: &[usize], +) { + assert_eq!( + var_len_public_inputs.len(), + message_widths.len(), + "must provide one message width per VLPI group" + ); + for (group, &msg_width) in var_len_public_inputs.iter().zip(message_widths) { + assert!(msg_width > 0, "VLPI message width must be positive"); + let padded_width = msg_width.next_multiple_of(SPONGE_RATE); + for message in group.chunks(msg_width) { + assert_eq!( + message.len(), + msg_width, + "VLPI group has trailing elements that don't form a complete message" + ); + let mut padded = vec![Felt::ZERO; padded_width]; + for (i, &elem) in message.iter().enumerate() { + padded[padded_width - 1 - i] = elem; + } + challenger.observe_slice(&padded); + } + } +} + +// ALGEBRAIC HASHES (RPO, Poseidon2, RPX) +// ================================================================================================ /// Sponge state width in field elements. const SPONGE_WIDTH: usize = 12; @@ -73,32 +152,8 @@ const SPONGE_WIDTH: usize = 12; const SPONGE_RATE: usize = 8; /// Sponge digest width in field elements. const DIGEST_WIDTH: usize = 4; - -// SHARED TYPE ALIASES -// ================================================================================================ - -type PackedFelt = ::Packing; - -/// Miden VM STARK configuration with pre-filled common type parameters. -/// -/// All Miden configurations use `Felt` as the base field, `QuadFelt` as the extension field, -/// and `Radix2DitParallel` as the DFT. Only the LMCS commitment scheme (`L`) and -/// Fiat-Shamir challenger (`Ch`) vary by hash function. -pub type MidenStarkConfig = - GenericStarkConfig, Ch>; - -/// Byte-oriented LMCS (for Blake3, Keccak). -type ByteLmcs = LmcsConfig< - Felt, - u8, - ChainingHasher, - CompressionFunctionFromHasher, - BYTE_DIGEST_SIZE, - BYTE_DIGEST_SIZE, ->; - -/// Byte-oriented challenger (for Blake3, Keccak). -type ByteChallenger = SerializingChallenger64>; +/// Range of capacity slots within the sponge state array. +const CAPACITY_RANGE: core::ops::Range = SPONGE_RATE..SPONGE_WIDTH; /// Algebraic LMCS (for RPO, Poseidon2, RPX). type AlgLmcs

= LmcsConfig< @@ -113,57 +168,176 @@ type AlgLmcs

= LmcsConfig< /// Algebraic duplex challenger (for RPO, Poseidon2, RPX). type AlgChallenger

= DuplexChallenger; -// CONFIGURATION FACTORIES -// ================================================================================================ - -/// Creates a Blake3_256-based STARK configuration. -pub fn blake3_256_config( - params: PcsParams, -) -> MidenStarkConfig, ByteChallenger> { - let lmcs = LmcsConfig::new( - ChainingHasher::new(Blake3Hasher), - CompressionFunctionFromHasher::new(Blake3Hasher), - ); - let challenger = SerializingChallenger64::from_hasher(vec![], Blake3Hasher); - GenericStarkConfig::new(params, lmcs, Radix2DitParallel::default(), challenger) -} - -/// Creates a Keccak-based STARK configuration. -pub fn keccak_config( - params: PcsParams, -) -> MidenStarkConfig, ByteChallenger> { - let hash = Keccak256Hash {}; - let lmcs = LmcsConfig::new(ChainingHasher::new(hash), CompressionFunctionFromHasher::new(hash)); - let challenger = SerializingChallenger64::from_hasher(vec![], hash); - GenericStarkConfig::new(params, lmcs, Radix2DitParallel::default(), challenger) -} +/// Concrete STARK configuration type for Poseidon2. +pub type Poseidon2Config = + MidenStarkConfig, AlgChallenger>; /// Creates an RPO-based STARK configuration. pub fn rpo_config( params: PcsParams, ) -> MidenStarkConfig, AlgChallenger> { - let perm = RpoPermutation256; - let lmcs = LmcsConfig::new(StatefulSponge::new(perm), TruncatedPermutation::new(perm)); - let challenger = DuplexChallenger::new(perm); - GenericStarkConfig::new(params, lmcs, Radix2DitParallel::default(), challenger) + alg_config(params, RpoPermutation256) } /// Creates a Poseidon2-based STARK configuration. pub fn poseidon2_config( params: PcsParams, ) -> MidenStarkConfig, AlgChallenger> { - let perm = Poseidon2Permutation256; - let lmcs = LmcsConfig::new(StatefulSponge::new(perm), TruncatedPermutation::new(perm)); - let challenger = DuplexChallenger::new(perm); - GenericStarkConfig::new(params, lmcs, Radix2DitParallel::default(), challenger) + alg_config(params, Poseidon2Permutation256) } /// Creates an RPX-based STARK configuration. pub fn rpx_config( params: PcsParams, ) -> MidenStarkConfig, AlgChallenger> { - let perm = RpxPermutation256; + alg_config(params, RpxPermutation256) +} + +/// Internal helper: builds an algebraic STARK configuration from a permutation. +/// +/// The prototype challenger has RELATION_DIGEST pre-loaded in the sponge capacity. +/// When `observe_protocol_params` is called, the first duplexing permutes this +/// capacity together with the PCS parameters written into the rate. +fn alg_config

(params: PcsParams, perm: P) -> MidenStarkConfig, AlgChallenger

> +where + P: CryptographicPermutation<[Felt; SPONGE_WIDTH]> + Copy, +{ let lmcs = LmcsConfig::new(StatefulSponge::new(perm), TruncatedPermutation::new(perm)); - let challenger = DuplexChallenger::new(perm); + let mut state = [Felt::ZERO; SPONGE_WIDTH]; + state[CAPACITY_RANGE].copy_from_slice(&RELATION_DIGEST); + let challenger = DuplexChallenger { + sponge_state: state, + input_buffer: vec![], + output_buffer: vec![], + permutation: perm, + }; + GenericStarkConfig::new(params, lmcs, Radix2DitParallel::default(), challenger) +} + +// BLAKE3 +// ================================================================================================ + +/// Digest size in bytes for Blake3. +const BLAKE_DIGEST_SIZE: usize = 32; + +/// Blake3 LMCS. +type BlakeLmcs = LmcsConfig< + Felt, + u8, + ChainingHasher, + CompressionFunctionFromHasher, + BLAKE_DIGEST_SIZE, + BLAKE_DIGEST_SIZE, +>; + +/// Blake3 challenger. +type BlakeChallenger = + SerializingChallenger64>; + +/// Creates a Blake3_256-based STARK configuration. +pub fn blake3_256_config(params: PcsParams) -> MidenStarkConfig { + let lmcs = LmcsConfig::new( + ChainingHasher::new(Blake3Hasher), + CompressionFunctionFromHasher::new(Blake3Hasher), + ); + let mut challenger = SerializingChallenger64::from_hasher(vec![], Blake3Hasher); + challenger.observe_slice(&RELATION_DIGEST); GenericStarkConfig::new(params, lmcs, Radix2DitParallel::default(), challenger) } + +// KECCAK +// ================================================================================================ + +/// Keccak permutation state width (in u64 elements). +const KECCAK_WIDTH: usize = 25; +/// Keccak sponge rate (absorbable u64 elements per permutation). +const KECCAK_RATE: usize = 17; +/// Keccak digest width (in u64 elements). +const KECCAK_DIGEST: usize = 4; +/// Keccak-256 digest size in bytes (for the Fiat-Shamir challenger). +const KECCAK_CHALLENGER_DIGEST_SIZE: usize = 32; + +/// Keccak MMCS sponge (padding-free, used for compression). +type KeccakMmcsSponge = PaddingFreeSponge; + +/// Keccak LMCS using the stateful binary sponge with `[Felt; VECTOR_LEN]` packing. +type KeccakLmcs = LmcsConfig< + [Felt; VECTOR_LEN], + [u64; VECTOR_LEN], + SerializingStatefulSponge>, + CompressionFunctionFromHasher, + KECCAK_WIDTH, + KECCAK_DIGEST, +>; + +/// Keccak challenger. +type KeccakChallenger = + SerializingChallenger64>; + +/// Creates a Keccak-based STARK configuration. +/// +/// Uses the stateful binary sponge with the Keccak permutation and `[Felt; VECTOR_LEN]` packing +/// for SIMD parallelization. +pub fn keccak_config(params: PcsParams) -> MidenStarkConfig { + let mmcs_sponge = KeccakMmcsSponge::new(KeccakF {}); + let compress = CompressionFunctionFromHasher::new(mmcs_sponge); + let sponge = SerializingStatefulSponge::new(StatefulSponge::new(KeccakF {})); + let lmcs = LmcsConfig::new(sponge, compress); + let mut challenger = SerializingChallenger64::from_hasher(vec![], Keccak256Hash {}); + challenger.observe_slice(&RELATION_DIGEST); + GenericStarkConfig::new(params, lmcs, Radix2DitParallel::default(), challenger) +} + +#[cfg(test)] +mod tests { + extern crate alloc; + use alloc::vec::Vec; + + use miden_ace_codegen::{AceConfig, LayoutKind}; + use miden_core::{Felt, crypto::hash::Poseidon2, field::QuadFelt}; + + use crate::{ProcessorAir, ace}; + + const PROTOCOL_ID: u64 = 0; + const REGEN_HINT: &str = "cargo run -p miden-core-lib --features constraints-tools --bin regenerate-constraints -- --write"; + + /// Snapshot test: catches any AIR change that alters the constraint circuit. + /// + /// If this test fails, regenerate with: + /// cargo run -p miden-core-lib --features constraints-tools --bin regenerate-constraints -- + /// --write + #[test] + fn relation_digest_matches_current_air() { + let config = AceConfig { + num_quotient_chunks: 8, + num_vlpi_groups: 1, + layout: LayoutKind::Masm, + }; + let air = ProcessorAir; + let boundary_config = ace::logup_boundary_config(); + let circuit = + ace::build_batched_ace_circuit::<_, QuadFelt>(&air, config, &boundary_config).unwrap(); + let encoded = circuit.to_ace().unwrap(); + let circuit_commitment: [Felt; 4] = encoded.circuit_hash().into(); + + let input: Vec = core::iter::once(Felt::new_unchecked(PROTOCOL_ID)) + .chain(circuit_commitment.iter().copied()) + .collect(); + let digest = Poseidon2::hash_elements(&input); + let expected: Vec = digest.as_elements().iter().map(Felt::as_canonical_u64).collect(); + + let snapshot = format!( + "num_inputs: {}\nnum_eval_gates: {}\nrelation_digest: {:?}", + encoded.num_vars(), + encoded.num_eval_rows(), + expected, + ); + insta::assert_snapshot!(snapshot); + + let actual: Vec = super::RELATION_DIGEST.iter().map(Felt::as_canonical_u64).collect(); + assert_eq!( + actual, expected, + "RELATION_DIGEST in config.rs is stale. Regenerate with: {REGEN_HINT}" + ); + } +} diff --git a/air/src/constraints/bus.rs b/air/src/constraints/bus.rs deleted file mode 100644 index 12dfd65b10..0000000000 --- a/air/src/constraints/bus.rs +++ /dev/null @@ -1,31 +0,0 @@ -//! Bus shared definitions. -//! -//! This module provides shared indices for auxiliary (bus) constraints. -//! The bus columns live in the auxiliary trace and are ordered as follows: -//! - p1/p2/p3 (decoder) -//! - p1 (stack overflow, stack aux segment) -//! - b_range (range checker LogUp) -//! - b_hash_kernel (chiplets virtual table) -//! - b_chiplets (chiplets bus) -//! - v_wiring (ACE wiring LogUp) - -/// Auxiliary trace column indices. -#[allow(dead_code)] -pub mod indices { - /// Block stack table (decoder control flow) - pub const P1_BLOCK_STACK: usize = 0; - /// Block hash table (decoder digest tracking) - pub const P2_BLOCK_HASH: usize = 1; - /// Op group table (decoder operation batching) - pub const P3_OP_GROUP: usize = 2; - /// Stack overflow table (stack p1) - pub const P1_STACK: usize = 3; - /// Range checker bus - pub const B_RANGE: usize = 4; - /// Hash kernel bus: sibling table + ACE memory + log_precompile - pub const B_HASH_KERNEL: usize = 5; - /// Main chiplets bus - pub const B_CHIPLETS: usize = 6; - /// Wiring bus for ACE circuit connections - pub const V_WIRING: usize = 7; -} diff --git a/air/src/constraints/chiplets/ace.rs b/air/src/constraints/chiplets/ace.rs index 35279ed6f2..eb0686b066 100644 --- a/air/src/constraints/chiplets/ace.rs +++ b/air/src/constraints/chiplets/ace.rs @@ -28,465 +28,183 @@ //! | m0 | Wire bus multiplicity for node 0 | use miden_core::field::PrimeCharacteristicRing; +use miden_crypto::stark::air::AirBuilder; -use super::selectors::{ace_chiplet_flag, memory_chiplet_flag}; +use super::selectors::ChipletFlags; use crate::{ - Felt, MainTraceRow, - constraints::tagging::{TagGroup, TaggingAirBuilderExt, tagged_assert_zero_integrity}, - trace::chiplets::ace::{ - CLK_IDX, CTX_IDX, EVAL_OP_IDX, ID_0_IDX, ID_1_IDX, PTR_IDX, READ_NUM_EVAL_IDX, - SELECTOR_BLOCK_IDX, SELECTOR_START_IDX, V_0_0_IDX, V_0_1_IDX, V_1_0_IDX, V_1_1_IDX, - V_2_0_IDX, V_2_1_IDX, + MainCols, MidenAirBuilder, + constraints::{ + constants::{F_1, F_4}, + ext_field::{QuadFeltAirBuilder, QuadFeltExpr}, + utils::BoolNot, }, }; -// CONSTANTS -// ================================================================================================ - -// ACE chiplet offset from CHIPLETS_OFFSET (after s0, s1, s2, s3). -const ACE_OFFSET: usize = 4; - -// TAGGING IDS -// ================================================================================================ - -const ACE_BASE_ID: usize = super::memory::MEMORY_BASE_ID + super::memory::MEMORY_COUNT; -pub(super) const ACE_COUNT: usize = 20; - -const ACE_BINARY_BASE_ID: usize = ACE_BASE_ID; -const ACE_SECTION_BASE_ID: usize = ACE_BASE_ID + 2; -const ACE_WITHIN_SECTION_BASE_ID: usize = ACE_BASE_ID + 7; -const ACE_READ_ID_ID: usize = ACE_BASE_ID + 11; -const ACE_READ_TO_EVAL_ID: usize = ACE_BASE_ID + 12; -const ACE_EVAL_OP_ID: usize = ACE_BASE_ID + 13; -const ACE_EVAL_RESULT_BASE_ID: usize = ACE_BASE_ID + 14; -const ACE_FINAL_BASE_ID: usize = ACE_BASE_ID + 16; -const ACE_FIRST_ROW_ID: usize = ACE_BASE_ID + 19; - -const ACE_BINARY_NAMESPACE: &str = "chiplets.ace.selector.binary"; -const ACE_SECTION_NAMESPACE: &str = "chiplets.ace.section.flags"; -const ACE_WITHIN_SECTION_NAMESPACE: &str = "chiplets.ace.section.transition"; -const ACE_READ_ID_NAMESPACE: &str = "chiplets.ace.read.ids"; -const ACE_READ_TO_EVAL_NAMESPACE: &str = "chiplets.ace.read.to_eval"; -const ACE_EVAL_OP_NAMESPACE: &str = "chiplets.ace.eval.op"; -const ACE_EVAL_RESULT_NAMESPACE: &str = "chiplets.ace.eval.result"; -const ACE_FINAL_NAMESPACE: &str = "chiplets.ace.final.zero"; -const ACE_FIRST_ROW_NAMESPACE: &str = "chiplets.ace.first_row.start"; - -const ACE_BINARY_NAMES: [&str; 2] = [ACE_BINARY_NAMESPACE; 2]; -const ACE_SECTION_NAMES: [&str; 5] = [ACE_SECTION_NAMESPACE; 5]; -const ACE_WITHIN_SECTION_NAMES: [&str; 4] = [ACE_WITHIN_SECTION_NAMESPACE; 4]; -const ACE_READ_ID_NAMES: [&str; 1] = [ACE_READ_ID_NAMESPACE; 1]; -const ACE_READ_TO_EVAL_NAMES: [&str; 1] = [ACE_READ_TO_EVAL_NAMESPACE; 1]; -const ACE_EVAL_OP_NAMES: [&str; 1] = [ACE_EVAL_OP_NAMESPACE; 1]; -const ACE_EVAL_RESULT_NAMES: [&str; 2] = [ACE_EVAL_RESULT_NAMESPACE; 2]; -const ACE_FINAL_NAMES: [&str; 3] = [ACE_FINAL_NAMESPACE; 3]; -const ACE_FIRST_ROW_NAMES: [&str; 1] = [ACE_FIRST_ROW_NAMESPACE; 1]; - -const ACE_BINARY_TAGS: TagGroup = TagGroup { - base: ACE_BINARY_BASE_ID, - names: &ACE_BINARY_NAMES, -}; -const ACE_SECTION_TAGS: TagGroup = TagGroup { - base: ACE_SECTION_BASE_ID, - names: &ACE_SECTION_NAMES, -}; -const ACE_WITHIN_SECTION_TAGS: TagGroup = TagGroup { - base: ACE_WITHIN_SECTION_BASE_ID, - names: &ACE_WITHIN_SECTION_NAMES, -}; -const ACE_READ_ID_TAGS: TagGroup = TagGroup { - base: ACE_READ_ID_ID, - names: &ACE_READ_ID_NAMES, -}; -const ACE_READ_TO_EVAL_TAGS: TagGroup = TagGroup { - base: ACE_READ_TO_EVAL_ID, - names: &ACE_READ_TO_EVAL_NAMES, -}; -const ACE_EVAL_OP_TAGS: TagGroup = TagGroup { - base: ACE_EVAL_OP_ID, - names: &ACE_EVAL_OP_NAMES, -}; -const ACE_EVAL_RESULT_TAGS: TagGroup = TagGroup { - base: ACE_EVAL_RESULT_BASE_ID, - names: &ACE_EVAL_RESULT_NAMES, -}; -const ACE_FINAL_TAGS: TagGroup = TagGroup { - base: ACE_FINAL_BASE_ID, - names: &ACE_FINAL_NAMES, -}; -const ACE_FIRST_ROW_TAGS: TagGroup = TagGroup { - base: ACE_FIRST_ROW_ID, - names: &ACE_FIRST_ROW_NAMES, -}; - // ENTRY POINTS // ================================================================================================ -/// Enforce ACE chiplet constraints with transition handling. -pub fn enforce_ace_constraints( - builder: &mut AB, - local: &MainTraceRow, - next: &MainTraceRow, -) where - AB: TaggingAirBuilderExt, -{ - // Load selectors - let s0: AB::Expr = local.chiplets[0].clone().into(); - let s1: AB::Expr = local.chiplets[1].clone().into(); - let s2: AB::Expr = local.chiplets[2].clone().into(); - let s2_next: AB::Expr = next.chiplets[2].clone().into(); - let s3_next: AB::Expr = next.chiplets[3].clone().into(); - - // Gate transition constraints by is_transition() to avoid last-row issues - let is_transition: AB::Expr = builder.is_transition(); - - // ACE constraints on all rows (already internally gated) - enforce_ace_constraints_all_rows(builder, local, next); - - // ACE first row constraints (transitioning from memory to ACE) - // Flag: current row is memory (s0*s1*!s2), next row is ACE (s2'=1 AND s3'=0) - // The s3'=0 check is critical because: - // 1. A trace may skip ACE entirely (going memory -> kernel ROM) - // 2. When not in ACE, chiplets[4] is s4 (selector), not sstart - // 3. Without the s3'=0 check, we'd read the wrong column - // Must be gated by is_transition since it accesses next-row values - let memory_flag = memory_chiplet_flag(s0, s1, s2); - // ace_next = s2' * !s3' - let ace_next = s2_next * (AB::Expr::ONE - s3_next); - let flag_next_row_first_ace = is_transition * memory_flag * ace_next; - enforce_ace_constraints_first_row(builder, local, next, flag_next_row_first_ace); -} - /// Enforce ACE chiplet constraints that apply to all rows. pub fn enforce_ace_constraints_all_rows( builder: &mut AB, - local: &MainTraceRow, - next: &MainTraceRow, + local: &MainCols, + next: &MainCols, + flags: &ChipletFlags, ) where - AB: TaggingAirBuilderExt, + AB: MidenAirBuilder, { - // Compute ACE active flag from top-level selectors - let s0: AB::Expr = local.chiplets[0].clone().into(); - let s1: AB::Expr = local.chiplets[1].clone().into(); - let s2: AB::Expr = local.chiplets[2].clone().into(); - let s3: AB::Expr = local.chiplets[3].clone().into(); - let s3_next: AB::Expr = next.chiplets[3].clone().into(); - - let ace_flag = ace_chiplet_flag(s0.clone(), s1.clone(), s2.clone(), s3.clone()); - - // Load ACE columns - let sstart: AB::Expr = load_ace_col::(local, SELECTOR_START_IDX); - let sstart_next: AB::Expr = load_ace_col::(next, SELECTOR_START_IDX); - let sblock: AB::Expr = load_ace_col::(local, SELECTOR_BLOCK_IDX); - let sblock_next: AB::Expr = load_ace_col::(next, SELECTOR_BLOCK_IDX); - let ctx: AB::Expr = load_ace_col::(local, CTX_IDX); - let ctx_next: AB::Expr = load_ace_col::(next, CTX_IDX); - let ptr: AB::Expr = load_ace_col::(local, PTR_IDX); - let ptr_next: AB::Expr = load_ace_col::(next, PTR_IDX); - let clk: AB::Expr = load_ace_col::(local, CLK_IDX); - let clk_next: AB::Expr = load_ace_col::(next, CLK_IDX); - let op: AB::Expr = load_ace_col::(local, EVAL_OP_IDX); - let id0: AB::Expr = load_ace_col::(local, ID_0_IDX); - let id0_next: AB::Expr = load_ace_col::(next, ID_0_IDX); - let id1: AB::Expr = load_ace_col::(local, ID_1_IDX); - // n_eval stores (num_eval_rows - 1) so READ→EVAL switches when id0' == n_eval. - let n_eval: AB::Expr = load_ace_col::(local, READ_NUM_EVAL_IDX); - let n_eval_next: AB::Expr = load_ace_col::(next, READ_NUM_EVAL_IDX); - - let v0_0: AB::Expr = load_ace_col::(local, V_0_0_IDX); - let v0_1: AB::Expr = load_ace_col::(local, V_0_1_IDX); - let v1_0: AB::Expr = load_ace_col::(local, V_1_0_IDX); - let v1_1: AB::Expr = load_ace_col::(local, V_1_1_IDX); - let v2_0: AB::Expr = load_ace_col::(local, V_2_0_IDX); - let v2_1: AB::Expr = load_ace_col::(local, V_2_1_IDX); - - let one: AB::Expr = AB::Expr::ONE; - let four: AB::Expr = AB::Expr::from_u32(4); - - // Gate all transition constraints by is_transition() to avoid last-row issues - let is_transition: AB::Expr = builder.is_transition(); - - // ACE continuing to the next row (not transitioning out). - // Includes is_transition because it reads next-row values. - let flag_ace_next = is_transition.clone() * (one.clone() - s3_next.clone()); - // Last ACE row (next row transitions out of ACE). - // Includes is_transition because it reads next-row values. - let flag_ace_last = is_transition.clone() * s3_next.clone(); + let local = local.ace(); + let next = next.ace(); + + let ace_flag = flags.is_active.clone(); + let ace_transition = flags.is_transition.clone(); + let ace_last = flags.is_last.clone(); + + // Derived section flags + let s_start = local.s_start; + let s_start_next = next.s_start; + let s_transition = s_start_next.into().not(); + + // ========================================================================== + // FIRST ROW CONSTRAINTS + // ========================================================================== + + // First row of ACE must have sstart' = 1 + builder.when(flags.next_is_first.clone()).assert_one(s_start_next); // ========================================================================== // BINARY CONSTRAINTS // ========================================================================== - let mut idx = 0; - tagged_assert_zero_integrity( - builder, - &ACE_BINARY_TAGS, - &mut idx, - ace_flag.clone() * sstart.clone() * (sstart.clone() - one.clone()), - ); - tagged_assert_zero_integrity( - builder, - &ACE_BINARY_TAGS, - &mut idx, - ace_flag.clone() * sblock.clone() * (sblock.clone() - one.clone()), - ); + // When ACE is active, section flags must be boolean. + { + let builder = &mut builder.when(ace_flag.clone()); + builder.assert_bool(local.s_start); + builder.assert_bool(local.s_block); + } + + let f_eval = local.s_block; + let f_eval_next = next.s_block; + let f_read = f_eval.into().not(); + let f_read_next = f_eval_next.into().not(); // ========================================================================== // SECTION/BLOCK FLAGS CONSTRAINTS // ========================================================================== + { + // Last row of ACE chiplet cannot be section start + builder.when(ace_last).assert_zero(s_start); + + // Prevent consecutive section starts within ACE chiplet + builder.when(ace_transition.clone()).when(s_start).assert_zero(s_start_next); + + // Sections must start with READ blocks (not EVAL) + builder.when(ace_flag.clone()).when(s_start).assert_zero(f_eval); - let f_next = one.clone() - sstart_next.clone(); - - // Sections must end with EVAL blocks (not READ). - // OR(t*a, t*b) = t*OR(a, b) when t is binary. - let f_end = binary_or((one.clone() - s3_next.clone()) * sstart_next.clone(), s3_next.clone()); - - let mut idx = 0; - // Last row of ACE chiplet cannot be section start - tagged_assert_zero_integrity( - builder, - &ACE_SECTION_TAGS, - &mut idx, - ace_flag.clone() * flag_ace_last.clone() * sstart.clone(), - ); - // Prevent consecutive section starts within ACE chiplet - tagged_assert_zero_integrity( - builder, - &ACE_SECTION_TAGS, - &mut idx, - ace_flag.clone() * flag_ace_next.clone() * sstart.clone() * sstart_next.clone(), - ); - // Sections must start with READ blocks (not EVAL): f_eval = 0 when f_start - tagged_assert_zero_integrity( - builder, - &ACE_SECTION_TAGS, - &mut idx, - ace_flag.clone() * sstart.clone() * sblock.clone(), - ); - // EVAL blocks cannot be followed by READ blocks within same section - tagged_assert_zero_integrity( - builder, - &ACE_SECTION_TAGS, - &mut idx, - ace_flag.clone() - * flag_ace_next.clone() - * f_next.clone() - * sblock.clone() - * (one.clone() - sblock_next.clone()), - ); - // Sections must end with EVAL blocks (not READ) - tagged_assert_zero_integrity( - builder, - &ACE_SECTION_TAGS, - &mut idx, - ace_flag.clone() * is_transition.clone() * f_end.clone() * (one.clone() - sblock.clone()), - ); + // EVAL blocks cannot be followed by READ blocks within same section + builder + .when(ace_transition.clone()) + .when(s_transition.clone()) + .when(f_eval) + .assert_zero(f_read_next.clone()); + } // ========================================================================== // SECTION CONSTRAINTS (within section) // ========================================================================== - let flag_within_section = one.clone() - sstart_next.clone(); - let f_read = one.clone() - sblock.clone(); - let f_eval = sblock.clone(); - - // Context consistency within a section - // Use a combined gate to share `ace_flag * flag_ace_next * flag_within_section` - // across all within-section transition constraints. - let within_section_gate = - ace_flag.clone() * flag_ace_next.clone() * flag_within_section.clone(); - - // Memory pointer increments: +4 in READ, +1 in EVAL - // ptr' = ptr + 4 * f_read + f_eval - let expected_ptr_next = ptr.clone() + four.clone() * f_read.clone() + f_eval.clone(); - - // Node ID decrements: -2 in READ, -1 in EVAL - // id0 = id0' + 2 * f_read + f_eval - let expected_id0 = id0_next.clone() + f_read.clone().double() + f_eval.clone(); - let mut idx = 0; - tagged_assert_zero_integrity( - builder, - &ACE_WITHIN_SECTION_TAGS, - &mut idx, - within_section_gate.clone() * (ctx_next.clone() - ctx.clone()), - ); - tagged_assert_zero_integrity( - builder, - &ACE_WITHIN_SECTION_TAGS, - &mut idx, - within_section_gate.clone() * (clk_next.clone() - clk.clone()), - ); - tagged_assert_zero_integrity( - builder, - &ACE_WITHIN_SECTION_TAGS, - &mut idx, - within_section_gate.clone() * (ptr_next.clone() - expected_ptr_next), - ); - tagged_assert_zero_integrity( - builder, - &ACE_WITHIN_SECTION_TAGS, - &mut idx, - within_section_gate * (id0.clone() - expected_id0), - ); + // Within-section transitions: context, clock, pointer, and node ID consistency. + { + let builder = &mut builder.when(ace_transition.clone() * s_transition); + + // clk and ctx are stable + builder.assert_eq(next.ctx, local.ctx); + builder.assert_eq(next.clk, local.clk); + + // Memory pointer increments: +4 in READ, +1 in EVAL + // ptr' = ptr + 4 * f_read + f_eval + let expected_ptr: AB::Expr = local.ptr + f_read.clone() * F_4 + f_eval; + builder.assert_eq(next.ptr, expected_ptr); + + // Node ID decrements: -2 in READ, -1 in EVAL + // id0 = id0' + 2 * f_read + f_eval + let expected_id0: AB::Expr = next.id_0 + f_read.double() + f_eval; + builder.assert_eq(local.id_0, expected_id0); + } // ========================================================================== // READ BLOCK CONSTRAINTS // ========================================================================== // In READ block, the two node IDs should be consecutive (id1 = id0 - 1) - let mut idx = 0; - tagged_assert_zero_integrity( - builder, - &ACE_READ_ID_TAGS, - &mut idx, - ace_flag.clone() * f_read.clone() * (id1.clone() - id0.clone() + one.clone()), - ); + builder + .when(ace_flag.clone()) + .when(f_read.clone()) + .assert_eq(local.id_1, local.id_0 - F_1); // READ→EVAL transition occurs when n_eval matches the first EVAL id0. // n_eval is constant across READ rows and encodes (num_eval_rows - 1). // Enforce: f_read * (f_read' * n_eval' + f_eval' * id0' - n_eval) = 0 - let f_read_next = one.clone() - sblock_next.clone(); - let f_eval_next = sblock_next.clone(); - let selected = f_read_next * n_eval_next.clone() + f_eval_next * id0_next.clone(); - let mut idx = 0; - tagged_assert_zero_integrity( - builder, - &ACE_READ_TO_EVAL_TAGS, - &mut idx, - is_transition.clone() * ace_flag.clone() * f_read.clone() * (selected - n_eval), - ); + let selected: AB::Expr = f_read_next * next.read().num_eval + f_eval_next * next.id_0; + builder + .when(ace_transition) + .when(f_read.clone()) + .assert_eq(selected, local.read().num_eval); // ========================================================================== // EVAL BLOCK CONSTRAINTS // ========================================================================== - // op must be -1, 0, or 1: op * (op - 1) * (op + 1) = 0 - let mut idx = 0; - tagged_assert_zero_integrity( - builder, - &ACE_EVAL_OP_TAGS, - &mut idx, - ace_flag.clone() - * f_eval.clone() - * op.clone() - * (op.clone() - one.clone()) - * (op.clone() + one.clone()), - ); - - // Arithmetic operation constraints - let eval_gate = ace_flag.clone() * f_eval.clone(); - let (expected_0, expected_1) = compute_arithmetic_expected::(op, v1_0, v1_1, v2_0, v2_1); - let mut idx = 0; - tagged_assert_zero_integrity( - builder, - &ACE_EVAL_RESULT_TAGS, - &mut idx, - eval_gate.clone() * (expected_0 - v0_0.clone()), - ); - tagged_assert_zero_integrity( - builder, - &ACE_EVAL_RESULT_TAGS, - &mut idx, - eval_gate.clone() * (expected_1 - v0_1.clone()), - ); + // EVAL block: op ternary validity and arithmetic operation result. + { + let builder = &mut builder.when(ace_flag * f_eval); + let op: AB::Expr = local.eval_op.into(); + + let op_square = op.square(); + // op must be -1, 0, or 1: ternary validity + // op * (op² - 1) = op ( op - 1) ( op + 1 ) + builder.assert_zero(op.clone() * (op_square.clone() - F_1)); + + // Compute expected EVAL block output (v0) from op and operands. + // + // Operations in extension field 𝔽ₚ[x]/(x² - 7): + // - op = -1: Subtraction (v0 = v1 - v2) + // - op = 0: Multiplication (v0 = v1 × v2) + // - op = 1: Addition (v0 = v1 + v2) + let v0: QuadFeltExpr = local.v_0.into_expr(); + let v1: QuadFeltExpr = local.v_1.into_expr(); + let v2: QuadFeltExpr = local.eval().v_2.into_expr(); + + let expected = { + // Linear operation: v1 + op * v2 (works for ADD when op=1, SUB when op=-1) + let linear = v1.clone() + v2.clone() * op; + + // Non-linear operation: multiplication in extension field (α² = 7) + let nonlinear = v1 * v2; + + // Select based on op²: if op² = 1, use linear; if op² = 0, use nonlinear + // result = op² * (linear - nonlinear) + nonlinear + (linear - nonlinear.clone()) * op_square + nonlinear + }; + builder.assert_eq_quad(v0, expected); + } // ========================================================================== // FINALIZATION CONSTRAINTS // ========================================================================== - // At section end: v0 = 0, id0 = 0 - // Use a combined gate to share `ace_flag * is_transition * f_end` across all finalization - // constraints. - let gate = ace_flag * is_transition * f_end; - let mut idx = 0; - tagged_assert_zero_integrity(builder, &ACE_FINAL_TAGS, &mut idx, gate.clone() * v0_0); - tagged_assert_zero_integrity(builder, &ACE_FINAL_TAGS, &mut idx, gate.clone() * v0_1); - tagged_assert_zero_integrity(builder, &ACE_FINAL_TAGS, &mut idx, gate * id0); -} - -/// Enforce ACE first row constraints. -/// -/// On the first row of ACE chiplet, sstart' must be 1. -pub fn enforce_ace_constraints_first_row( - builder: &mut AB, - _local: &MainTraceRow, - next: &MainTraceRow, - flag_next_row_first_ace: AB::Expr, -) where - AB: TaggingAirBuilderExt, -{ - let sstart_next: AB::Expr = load_ace_col::(next, SELECTOR_START_IDX); - let one: AB::Expr = AB::Expr::ONE; - - // First row of ACE must have sstart' = 1 - let mut idx = 0; - tagged_assert_zero_integrity( - builder, - &ACE_FIRST_ROW_TAGS, - &mut idx, - flag_next_row_first_ace * (sstart_next - one), - ); -} + // At section end: result value and node ID must be zero. + { + // f_end fires on the last ACE row or on section boundaries. + let f_end = flags.is_last.clone() + flags.is_transition.clone() * s_start_next; + let builder = &mut builder.when(f_end); -// INTERNAL HELPERS -// ================================================================================================ + // Sections must end with EVAL blocks (not READ). + builder.assert_zero(f_read); -/// Load a column from the ACE section of chiplets. -fn load_ace_col(row: &MainTraceRow, ace_col_idx: usize) -> AB::Expr -where - AB: TaggingAirBuilderExt, -{ - // ACE columns start after s0, s1, s2, s3 (4 selectors) - let local_idx = ACE_OFFSET + ace_col_idx; - row.chiplets[local_idx].clone().into() -} - -/// Compute expected EVAL block outputs (v0) from op and operands. -/// -/// Operations in extension field 𝔽ₚ[x]/(x² - 7): -/// - op = -1: Subtraction (v0 = v1 - v2) -/// - op = 0: Multiplication (v0 = v1 × v2) -/// - op = 1: Addition (v0 = v1 + v2) -fn compute_arithmetic_expected( - op: AB::Expr, - v1_0: AB::Expr, - v1_1: AB::Expr, - v2_0: AB::Expr, - v2_1: AB::Expr, -) -> (AB::Expr, AB::Expr) -where - AB: TaggingAirBuilderExt, -{ - use crate::constraints::ext_field::QuadFeltExpr; + let v0: QuadFeltExpr = local.v_0.into_expr(); - let v1 = QuadFeltExpr(v1_0, v1_1); - let v2 = QuadFeltExpr(v2_0, v2_1); + builder.assert_eq_quad(v0, QuadFeltExpr::new(AB::Expr::ZERO, AB::Expr::ZERO)); - // Linear operation: v1 + op * v2 (works for ADD when op=1, SUB when op=-1) - let linear = v1.clone() + v2.clone() * op.clone(); - - // Non-linear operation: multiplication in extension field (α² = 7) - let nonlinear = v1 * v2; - - // Select based on op²: if op² = 1, use linear; if op² = 0, use nonlinear - // op_square * (linear - nonlinear) + nonlinear = v0 - let op_square = op.clone() * op; - let expected = QuadFeltExpr( - op_square.clone() * (linear.0.clone() - nonlinear.0.clone()) + nonlinear.0, - op_square * (linear.1.clone() - nonlinear.1.clone()) + nonlinear.1, - ); - - expected.into_parts().into() -} - -/// Computes binary OR: `a + b - a * b` -/// -/// Assumes both a and b are binary (0 or 1). -/// Returns 1 if either a=1 or b=1. -#[inline] -pub fn binary_or(a: E, b: E) -> E -where - E: Clone + core::ops::Add + core::ops::Sub + core::ops::Mul, -{ - a.clone() + b.clone() - a * b + builder.assert_zero(local.id_0); + } } diff --git a/air/src/constraints/chiplets/bitwise.rs b/air/src/constraints/chiplets/bitwise.rs index dcc8c58395..afe74e1bbd 100644 --- a/air/src/constraints/chiplets/bitwise.rs +++ b/air/src/constraints/chiplets/bitwise.rs @@ -21,102 +21,20 @@ //! | zp | Previous aggregated output | //! | z | Current aggregated output | -use alloc::vec::Vec; +use core::{array, borrow::Borrow}; use miden_core::field::PrimeCharacteristicRing; -use super::{ - hasher::periodic::NUM_PERIODIC_COLUMNS as HASHER_NUM_PERIODIC_COLUMNS, - selectors::bitwise_chiplet_flag, -}; +use super::selectors::ChipletFlags; use crate::{ - Felt, MainTraceRow, - constraints::tagging::{TagGroup, TaggingAirBuilderExt, tagged_assert_zero_integrity}, - trace::{ - CHIPLETS_OFFSET, - chiplets::{ - BITWISE_A_COL_IDX, BITWISE_A_COL_RANGE, BITWISE_B_COL_IDX, BITWISE_B_COL_RANGE, - BITWISE_OUTPUT_COL_IDX, BITWISE_PREV_OUTPUT_COL_IDX, BITWISE_SELECTOR_COL_IDX, - }, + AirBuilder, MainCols, MidenAirBuilder, + constraints::{ + chiplets::columns::{BitwiseCols, PeriodicCols}, + constants::F_16, + utils::horner_eval_bits, }, }; -// CONSTANTS -// ================================================================================================ - -/// Index of k_first periodic column (marks first row of 8-row cycle). -/// Placed after hasher periodic columns. -pub const P_BITWISE_K_FIRST: usize = HASHER_NUM_PERIODIC_COLUMNS; - -/// Index of k_transition periodic column (marks non-last rows of 8-row cycle). -pub const P_BITWISE_K_TRANSITION: usize = HASHER_NUM_PERIODIC_COLUMNS + 1; - -/// Total number of periodic columns (hasher + bitwise periodic columns). -#[cfg(all(test, feature = "std"))] -pub const NUM_PERIODIC_COLUMNS: usize = HASHER_NUM_PERIODIC_COLUMNS + 2; - -/// Number of bits processed per row. -const NUM_BITS_PER_ROW: usize = 4; - -// TAGGING IDS -// ================================================================================================ - -pub(super) const BITWISE_BASE_ID: usize = super::hasher::HASHER_MERKLE_ABSORB_BASE_ID + 12; -pub(super) const BITWISE_COUNT: usize = 17; -const BITWISE_OP_BINARY_ID: usize = BITWISE_BASE_ID; -const BITWISE_A_BITS_BINARY_BASE_ID: usize = BITWISE_BASE_ID + 2; -const BITWISE_B_BITS_BINARY_BASE_ID: usize = BITWISE_A_BITS_BINARY_BASE_ID + NUM_BITS_PER_ROW; -const BITWISE_FIRST_ROW_BASE_ID: usize = BITWISE_B_BITS_BINARY_BASE_ID + NUM_BITS_PER_ROW; -const BITWISE_INPUT_TRANSITION_BASE_ID: usize = BITWISE_FIRST_ROW_BASE_ID + 3; -const BITWISE_OUTPUT_PREV_ID: usize = BITWISE_INPUT_TRANSITION_BASE_ID + 2; -const BITWISE_OUTPUT_AGG_ID: usize = BITWISE_OUTPUT_PREV_ID + 1; - -const OP_BINARY_NAMESPACE: &str = "chiplets.bitwise.op.binary"; -const OP_STABILITY_NAMESPACE: &str = "chiplets.bitwise.op.stability"; -const A_BITS_BINARY_NAMESPACE: &str = "chiplets.bitwise.a_bits.binary"; -const B_BITS_BINARY_NAMESPACE: &str = "chiplets.bitwise.b_bits.binary"; -const FIRST_ROW_NAMESPACE: &str = "chiplets.bitwise.first_row"; -const INPUT_TRANSITION_NAMESPACE: &str = "chiplets.bitwise.input.transition"; -const OUTPUT_PREV_NAMESPACE: &str = "chiplets.bitwise.output.prev"; -const OUTPUT_AGG_NAMESPACE: &str = "chiplets.bitwise.output.aggregate"; - -const OP_NAMES: [&str; 2] = [OP_BINARY_NAMESPACE, OP_STABILITY_NAMESPACE]; -const A_BITS_NAMES: [&str; NUM_BITS_PER_ROW] = [A_BITS_BINARY_NAMESPACE; NUM_BITS_PER_ROW]; -const B_BITS_NAMES: [&str; NUM_BITS_PER_ROW] = [B_BITS_BINARY_NAMESPACE; NUM_BITS_PER_ROW]; -const FIRST_ROW_NAMES: [&str; 3] = [FIRST_ROW_NAMESPACE; 3]; -const INPUT_TRANSITION_NAMES: [&str; 2] = [INPUT_TRANSITION_NAMESPACE; 2]; -const OUTPUT_PREV_NAMES: [&str; 1] = [OUTPUT_PREV_NAMESPACE; 1]; -const OUTPUT_AGG_NAMES: [&str; 1] = [OUTPUT_AGG_NAMESPACE; 1]; - -const OP_TAGS: TagGroup = TagGroup { - base: BITWISE_OP_BINARY_ID, - names: &OP_NAMES, -}; -const A_BITS_TAGS: TagGroup = TagGroup { - base: BITWISE_A_BITS_BINARY_BASE_ID, - names: &A_BITS_NAMES, -}; -const B_BITS_TAGS: TagGroup = TagGroup { - base: BITWISE_B_BITS_BINARY_BASE_ID, - names: &B_BITS_NAMES, -}; -const FIRST_ROW_TAGS: TagGroup = TagGroup { - base: BITWISE_FIRST_ROW_BASE_ID, - names: &FIRST_ROW_NAMES, -}; -const INPUT_TRANSITION_TAGS: TagGroup = TagGroup { - base: BITWISE_INPUT_TRANSITION_BASE_ID, - names: &INPUT_TRANSITION_NAMES, -}; -const OUTPUT_PREV_TAGS: TagGroup = TagGroup { - base: BITWISE_OUTPUT_PREV_ID, - names: &OUTPUT_PREV_NAMES, -}; -const OUTPUT_AGG_TAGS: TagGroup = TagGroup { - base: BITWISE_OUTPUT_AGG_ID, - names: &OUTPUT_AGG_NAMES, -}; - // ENTRY POINTS // ================================================================================================ @@ -128,102 +46,73 @@ const OUTPUT_AGG_TAGS: TagGroup = TagGroup { /// 3. Output aggregation constraints pub fn enforce_bitwise_constraints( builder: &mut AB, - local: &MainTraceRow, - next: &MainTraceRow, + local: &MainCols, + next: &MainCols, + flags: &ChipletFlags, ) where - AB: TaggingAirBuilderExt, + AB: MidenAirBuilder, { - let (k_first, k_transition) = { - // Clone out what we need to avoid holding a borrow of `builder` while asserting - // constraints. - let periodic = builder.periodic_values(); - debug_assert!(periodic.len() > P_BITWISE_K_TRANSITION); - (periodic[P_BITWISE_K_FIRST].into(), periodic[P_BITWISE_K_TRANSITION].into()) - }; + let periodic: &PeriodicCols<_> = builder.periodic_values().borrow(); + let k_first = periodic.bitwise.k_first; + let k_transition = periodic.bitwise.k_transition; - // Compute bitwise active flag from top-level selectors - let s0: AB::Expr = local.chiplets[0].clone().into(); - let s1: AB::Expr = local.chiplets[1].clone().into(); - let bitwise_flag = bitwise_chiplet_flag(s0, s1); + let bitwise_flag = flags.is_active.clone(); - // Load bitwise columns using typed struct - let cols: BitwiseColumns = BitwiseColumns::from_row(local); - let cols_next: BitwiseColumns = BitwiseColumns::from_row(next); + let cols: &BitwiseCols = local.bitwise(); + let cols_next: &BitwiseCols = next.bitwise(); - let one: AB::Expr = AB::Expr::ONE; - let sixteen: AB::Expr = AB::Expr::from_u32(16); + // All bitwise constraints are gated on the bitwise chiplet being active. + let bitwise_builder = &mut builder.when(bitwise_flag); // ========================================================================== // OPERATION FLAG CONSTRAINTS // ========================================================================== // op_flag must be binary (0 for AND, 1 for XOR) - let mut idx = 0; - tagged_assert_zero_integrity( - builder, - &OP_TAGS, - &mut idx, - bitwise_flag.clone() * cols.op_flag.clone() * (cols.op_flag.clone() - one.clone()), - ); + let op_flag = cols.op_flag; + bitwise_builder.assert_bool(op_flag); // op_flag must remain constant within the 8-row cycle (can only change when k1=0) - let gate_transition = k_transition.clone() * bitwise_flag.clone(); - tagged_assert_zero_integrity( - builder, - &OP_TAGS, - &mut idx, - gate_transition.clone() * (cols.op_flag.clone() - cols_next.op_flag.clone()), - ); + let op_flag_next = cols_next.op_flag; + bitwise_builder.when(k_transition).assert_eq(op_flag, op_flag_next); // ========================================================================== // INPUT DECOMPOSITION CONSTRAINTS // ========================================================================== + let (a, a_bits) = (cols.a, cols.a_bits); + let (b, b_bits) = (cols.b, cols.b_bits); // Bit decomposition columns must be binary - let gate = bitwise_flag.clone(); - let mut idx = 0; - for i in 0..NUM_BITS_PER_ROW { - tagged_assert_zero_integrity( - builder, - &A_BITS_TAGS, - &mut idx, - gate.clone() * cols.a_bits[i].clone() * (cols.a_bits[i].clone() - one.clone()), - ); - } - - let mut idx = 0; - for i in 0..NUM_BITS_PER_ROW { - tagged_assert_zero_integrity( - builder, - &B_BITS_TAGS, - &mut idx, - gate.clone() * cols.b_bits[i].clone() * (cols.b_bits[i].clone() - one.clone()), - ); - } + bitwise_builder.assert_bools(a_bits); + bitwise_builder.assert_bools(b_bits); // First row of cycle (k0=1): a = aggregated bits, b = aggregated bits - let a_agg = aggregate_limbs(&cols.a_bits); - let b_agg = aggregate_limbs(&cols.b_bits); - let gate_first = k_first.clone() * bitwise_flag.clone(); - let mut idx = 0; - for expr in [cols.a.clone() - a_agg, cols.b.clone() - b_agg, cols.prev_output.clone()] { - tagged_assert_zero_integrity(builder, &FIRST_ROW_TAGS, &mut idx, gate_first.clone() * expr); + // First row: input aggregation must match, and previous output must be zero. + { + let builder = &mut bitwise_builder.when(k_first); + + let a_expected = horner_eval_bits(&a_bits); + builder.assert_eq(a, a_expected); + + let b_expected = horner_eval_bits(&b_bits); + builder.assert_eq(b, b_expected); + + builder.assert_zero(cols.prev_output); } + let (a_next, a_next_bits) = (cols_next.a, cols_next.a_bits); + let (b_next, b_next_bits) = (cols_next.b, cols_next.b_bits); + // Transition rows (k1=1): a' = 16*a + agg(a'_bits), b' = 16*b + agg(b'_bits) - let a_agg_next = aggregate_limbs(&cols_next.a_bits); - let b_agg_next = aggregate_limbs(&cols_next.b_bits); - let mut idx = 0; - for expr in [ - cols_next.a.clone() - (cols.a.clone() * sixteen.clone() + a_agg_next), - cols_next.b.clone() - (cols.b.clone() * sixteen.clone() + b_agg_next), - ] { - tagged_assert_zero_integrity( - builder, - &INPUT_TRANSITION_TAGS, - &mut idx, - gate_transition.clone() * expr, - ); + // Transition rows: inputs aggregate with 16x shift. + { + let builder = &mut bitwise_builder.when(k_transition); + + let a_next_expected = a * F_16 + horner_eval_bits(&a_next_bits); + builder.assert_eq(a_next, a_next_expected); + + let b_next_expected = b * F_16 + horner_eval_bits(&b_next_bits); + builder.assert_eq(b_next, b_next_expected); } // ========================================================================== @@ -231,148 +120,27 @@ pub fn enforce_bitwise_constraints( // ========================================================================== // Transition rows (k1=1): output_prev' = output - let mut idx = 0; - tagged_assert_zero_integrity( - builder, - &OUTPUT_PREV_TAGS, - &mut idx, - gate_transition * (cols_next.prev_output.clone() - cols.output.clone()), - ); + let output = cols.output; + let prev_output_next = cols_next.prev_output; + bitwise_builder.when(k_transition).assert_eq(output, prev_output_next); // Every row: output = 16*output_prev + bitwise_result - let a_and_b = compute_limb_and(&cols.a_bits, &cols.b_bits); - let a_xor_b = compute_limb_xor(&cols.a_bits, &cols.b_bits); - - // z = zp * 16 + (op_flag ? a_xor_b : a_and_b) - // Equivalent: z = zp * 16 + a_and_b + op_flag * (a_xor_b - a_and_b) - let expected_z = cols.prev_output.clone() * sixteen - + a_and_b.clone() - + cols.op_flag.clone() * (a_xor_b.clone() - a_and_b); - - let mut idx = 0; - tagged_assert_zero_integrity( - builder, - &OUTPUT_AGG_TAGS, - &mut idx, - bitwise_flag * (cols.output.clone() - expected_z), - ); -} -// INTERNAL HELPERS -// ================================================================================================ + // Compute AND of 4-bit limbs: sum(2^i * (a[i] * b[i])) + let a_and_b_bits: [AB::Expr; 4] = array::from_fn(|i| a_bits[i] * b_bits[i]); + let a_and_b: AB::Expr = horner_eval_bits(&a_and_b_bits); -/// Typed access to bitwise chiplet columns. -/// -/// This struct provides named access to bitwise columns, eliminating error-prone -/// index arithmetic. Created from a `MainTraceRow` reference. -pub struct BitwiseColumns { - /// Operation flag: 0=AND, 1=XOR - pub op_flag: E, - /// Aggregated value of input a - pub a: E, - /// Aggregated value of input b - pub b: E, - /// 4-bit decomposition of a (little-endian) - pub a_bits: [E; NUM_BITS_PER_ROW], - /// 4-bit decomposition of b (little-endian) - pub b_bits: [E; NUM_BITS_PER_ROW], - /// Previous aggregated output - pub prev_output: E, - /// Current aggregated output - pub output: E, -} + // Compute XOR of 4-bit limbs: sum(2^i * (a[i] + b[i] - 2*a[i]*b[i])) + // Reuses a_and_b_bits: xor_bit = a + b - 2*and_bit + let a_xor_b_bits: [AB::Expr; 4] = + array::from_fn(|i| a_bits[i] + b_bits[i] - a_and_b_bits[i].clone().double()); + let a_xor_b: AB::Expr = horner_eval_bits(&a_xor_b_bits); -impl BitwiseColumns { - /// Extract bitwise columns from a main trace row. - pub fn from_row(row: &MainTraceRow) -> Self - where - V: Into + Clone, - { - let op_idx = BITWISE_SELECTOR_COL_IDX - CHIPLETS_OFFSET; - let a_idx = BITWISE_A_COL_IDX - CHIPLETS_OFFSET; - let b_idx = BITWISE_B_COL_IDX - CHIPLETS_OFFSET; - let a_bits_start = BITWISE_A_COL_RANGE.start - CHIPLETS_OFFSET; - let b_bits_start = BITWISE_B_COL_RANGE.start - CHIPLETS_OFFSET; - let zp_idx = BITWISE_PREV_OUTPUT_COL_IDX - CHIPLETS_OFFSET; - let z_idx = BITWISE_OUTPUT_COL_IDX - CHIPLETS_OFFSET; - - BitwiseColumns { - op_flag: row.chiplets[op_idx].clone().into(), - a: row.chiplets[a_idx].clone().into(), - b: row.chiplets[b_idx].clone().into(), - a_bits: core::array::from_fn(|i| row.chiplets[a_bits_start + i].clone().into()), - b_bits: core::array::from_fn(|i| row.chiplets[b_bits_start + i].clone().into()), - prev_output: row.chiplets[zp_idx].clone().into(), - output: row.chiplets[z_idx].clone().into(), - } - } -} - -/// Aggregate 4 bits into a value (little-endian): sum(2^i * limb[i]) -/// Uses Horner's method: ((b3*2 + b2)*2 + b1)*2 + b0 -fn aggregate_limbs(limbs: &[E; 4]) -> E { - limbs - .iter() - .rev() - .cloned() - .reduce(|acc, bit| acc.double() + bit) - .expect("non-empty array") -} - -/// Compute AND of 4-bit limbs: sum(2^i * (a[i] * b[i])) -/// Uses Horner's method for aggregation -fn compute_limb_and(a: &[E; 4], b: &[E; 4]) -> E { - (0..4) - .rev() - .map(|i| a[i].clone() * b[i].clone()) - .reduce(|acc, bit| acc.double() + bit) - .expect("non-empty range") -} - -/// Compute XOR of 4-bit limbs: sum(2^i * (a[i] + b[i] - 2*a[i]*b[i])) -/// Uses Horner's method for aggregation -fn compute_limb_xor(a: &[E; 4], b: &[E; 4]) -> E { - (0..4) - .rev() - .map(|i| { - let and_bit = a[i].clone() * b[i].clone(); - a[i].clone() + b[i].clone() - and_bit.double() - }) - .reduce(|acc, bit| acc.double() + bit) - .expect("non-empty range") -} - -// ============================================================================= -// PERIODIC COLUMNS -// ============================================================================= - -/// Generate periodic columns for the bitwise chiplet. -/// -/// Returns [k_first, k_transition] where: -/// - k_first: [1, 0, 0, 0, 0, 0, 0, 0] (period 8) -/// - k_transition: [1, 1, 1, 1, 1, 1, 1, 0] (period 8) -pub fn periodic_columns() -> [Vec; 2] { - let k_first = vec![ - Felt::ONE, - Felt::ZERO, - Felt::ZERO, - Felt::ZERO, - Felt::ZERO, - Felt::ZERO, - Felt::ZERO, - Felt::ZERO, - ]; - - let k_transition = vec![ - Felt::ONE, - Felt::ONE, - Felt::ONE, - Felt::ONE, - Felt::ONE, - Felt::ONE, - Felt::ONE, - Felt::ZERO, - ]; + // z = zp * 16 + (op_flag ? a_xor_b : a_and_b) + // Equivalent: z = zp * 16 + a_and_b + op_flag * (a_xor_b - a_and_b) + let zp = cols.prev_output; + let expected_z = zp * F_16 + a_and_b.clone() + op_flag * (a_xor_b - a_and_b); - [k_first, k_transition] + let z = cols.output; + bitwise_builder.assert_eq(z, expected_z); } diff --git a/air/src/constraints/chiplets/bus/chiplets.rs b/air/src/constraints/chiplets/bus/chiplets.rs deleted file mode 100644 index b03d71133a..0000000000 --- a/air/src/constraints/chiplets/bus/chiplets.rs +++ /dev/null @@ -1,1806 +0,0 @@ -//! Chiplets bus constraint (b_chiplets). -//! -//! This module enforces the running product constraint for the main chiplets bus -//! (bus_6_chiplets_bus). The chiplets bus handles communication between the VM components (stack, -//! decoder) and the specialized chiplets (hasher, bitwise, memory, ACE, kernel ROM). -//! -//! ## Running Product Protocol -//! -//! The bus accumulator b_chiplets uses a multiset running product: -//! - Boundary: b_chiplets[0] = 1, b_chiplets[last] = reduced_kernel_digests (via aux_finals) -//! - Transition: b_chiplets' * requests = b_chiplets * responses -//! -//! The bus starts at 1. Kernel ROM INIT_LABEL responses multiply in the kernel procedure hashes, -//! so aux_final[b_chiplets] = reduced_kernel_digests. The verifier checks this against the -//! expected value computed from kernel hashes provided as variable-length public inputs. -//! -//! ## Message Types -//! -//! ### Hasher Chiplet Messages (15 elements) -//! Format: header + state where: -//! - header = alpha + beta^0 * transition_label + beta^1 * addr + beta^2 * node_index -//! - state = sum(beta^(3+i) * hasher_state[i]) for i in 0..12 -//! -//! ### Bitwise Chiplet Messages (5 elements) -//! Format: alpha + beta^0*label + beta^1*a + beta^2*b + beta^3*z -//! -//! ### Memory Chiplet Messages (6-9 elements) -//! Element format: alpha + beta^0*label + ... + beta^4*element -//! Word format: alpha + beta^0*label + ... + beta^7*word[3] -//! -//! ## References -//! - Air-script: ~/air-script/constraints/chiplets.air -//! - Processor: processor/src/chiplets/aux_trace/bus/ - -use miden_core::{FMP_ADDR, FMP_INIT_VALUE, field::PrimeCharacteristicRing, operations::opcodes}; -use miden_crypto::stark::air::{ExtensionBuilder, LiftedAirBuilder, WindowAccess}; - -use crate::{ - Felt, MainTraceRow, - constraints::{ - bus::indices::B_CHIPLETS, - chiplets::{bitwise::P_BITWISE_K_TRANSITION, hasher}, - op_flags::OpFlags, - tagging::{TaggingAirBuilderExt, ids::TAG_CHIPLETS_BUS_BASE}, - }, - trace::{ - Challenges, - chiplets::{ - NUM_ACE_SELECTORS, NUM_KERNEL_ROM_SELECTORS, - ace::{ - ACE_INIT_LABEL, CLK_IDX, CTX_IDX, ID_0_IDX, PTR_IDX, READ_NUM_EVAL_IDX, - SELECTOR_START_IDX, - }, - bitwise::{self, BITWISE_AND_LABEL, BITWISE_XOR_LABEL}, - hasher::{ - HASH_CYCLE_LEN, LINEAR_HASH_LABEL, MP_VERIFY_LABEL, MR_UPDATE_NEW_LABEL, - MR_UPDATE_OLD_LABEL, RETURN_HASH_LABEL, RETURN_STATE_LABEL, - }, - kernel_rom::{KERNEL_PROC_CALL_LABEL, KERNEL_PROC_INIT_LABEL}, - memory::{ - MEMORY_READ_ELEMENT_LABEL, MEMORY_READ_WORD_LABEL, MEMORY_WRITE_ELEMENT_LABEL, - MEMORY_WRITE_WORD_LABEL, - }, - }, - decoder::{ADDR_COL_IDX, HASHER_STATE_RANGE, USER_OP_HELPERS_OFFSET}, - log_precompile::{ - HELPER_ADDR_IDX, HELPER_CAP_PREV_RANGE, STACK_CAP_NEXT_RANGE, STACK_COMM_RANGE, - STACK_R0_RANGE, STACK_R1_RANGE, STACK_TAG_RANGE, - }, - }, -}; - -/// Tag ID and namespace for the main chiplets bus transition constraint. -const CHIPLET_BUS_ID: usize = TAG_CHIPLETS_BUS_BASE; -const CHIPLET_BUS_NAMESPACE: &str = "chiplets.bus.chiplets.transition"; - -// ENTRY POINTS -// ================================================================================================ - -/// Enforces the chiplets bus constraint. -/// -/// This is the main constraint for bus_6_chiplets_bus, which handles all communication -/// between VM components and specialized chiplets. -/// -/// The constraint follows the running product protocol: -/// - `b_chiplets' * requests = b_chiplets * responses` -/// -/// Where `requests` are messages inserted by VM operations (stack/decoder) and -/// `responses` are messages removed by chiplet operations. -pub fn enforce_chiplets_bus_constraint( - builder: &mut AB, - local: &MainTraceRow, - next: &MainTraceRow, - op_flags: &OpFlags, - challenges: &Challenges, -) where - AB: LiftedAirBuilder, -{ - // Auxiliary trace must be present. - - // Extract auxiliary trace values. - let (b_local_val, b_next_val) = { - let aux = builder.permutation(); - let aux_local = aux.current_slice(); - let aux_next = aux.next_slice(); - (aux_local[B_CHIPLETS], aux_next[B_CHIPLETS]) - }; - - // ========================================================================= - // COMPUTE REQUEST MULTIPLIER - // ========================================================================= - - // --- Hasher request flags --- - let f_hperm: AB::Expr = op_flags.hperm(); - let f_mpverify: AB::Expr = op_flags.mpverify(); - let f_mrupdate: AB::Expr = op_flags.mrupdate(); - - // --- Control block flags --- - let f_join: AB::Expr = op_flags.join(); - let f_split: AB::Expr = op_flags.split(); - let f_loop: AB::Expr = op_flags.loop_op(); - let f_call: AB::Expr = op_flags.call(); - let f_dyn: AB::Expr = op_flags.dyn_op(); - let f_dyncall: AB::Expr = op_flags.dyncall(); - let f_syscall: AB::Expr = op_flags.syscall(); - let f_span: AB::Expr = op_flags.span(); - let f_respan: AB::Expr = op_flags.respan(); - let f_end: AB::Expr = op_flags.end(); - - // --- Memory request flags --- - let f_mload: AB::Expr = op_flags.mload(); - let f_mstore: AB::Expr = op_flags.mstore(); - let f_mloadw: AB::Expr = op_flags.mloadw(); - let f_mstorew: AB::Expr = op_flags.mstorew(); - let f_hornerbase: AB::Expr = op_flags.hornerbase(); - let f_hornerext: AB::Expr = op_flags.hornerext(); - let f_mstream: AB::Expr = op_flags.mstream(); - let f_pipe: AB::Expr = op_flags.pipe(); - let f_cryptostream: AB::Expr = op_flags.cryptostream(); - - // --- Bitwise request flags --- - let f_u32and: AB::Expr = op_flags.u32and(); - let f_u32xor: AB::Expr = op_flags.u32xor(); - - // --- ACE and log_precompile request flags --- - let f_evalcircuit: AB::Expr = op_flags.evalcircuit(); - let f_logprecompile: AB::Expr = op_flags.log_precompile(); - - // --- Hasher request values --- - let v_hperm = compute_hperm_request::(local, next, challenges); - let v_mpverify = compute_mpverify_request::(local, challenges); - let v_mrupdate = compute_mrupdate_request::(local, next, challenges); - - // --- Control block request values --- - let v_join = compute_control_block_request::(local, next, challenges, ControlBlockOp::Join); - let v_split = - compute_control_block_request::(local, next, challenges, ControlBlockOp::Split); - let v_loop = compute_control_block_request::(local, next, challenges, ControlBlockOp::Loop); - let v_call = compute_call_request::(local, next, challenges); - let v_dyn = compute_dyn_request::(local, next, challenges); - let v_dyncall = compute_dyncall_request::(local, next, challenges); - let v_syscall = compute_syscall_request::(local, next, challenges); - let v_span = compute_span_request::(local, next, challenges); - let v_respan = compute_respan_request::(local, next, challenges); - let v_end = compute_end_request::(local, challenges); - - // --- Memory request values --- - let v_mload = compute_memory_element_request::(local, next, challenges, true); // is_read = true - let v_mstore = compute_memory_element_request::(local, next, challenges, false); // is_read = false - let v_mloadw = compute_memory_word_request::(local, next, challenges, true); // is_read = true - let v_mstorew = compute_memory_word_request::(local, next, challenges, false); // is_read = false - let v_hornerbase = compute_hornerbase_request::(local, challenges); - let v_hornerext = compute_hornerext_request::(local, challenges); - let v_mstream = compute_mstream_request::(local, next, challenges); - let v_pipe = compute_pipe_request::(local, next, challenges); - let v_cryptostream = compute_cryptostream_request::(local, next, challenges); - - // --- Bitwise request values --- - let v_u32and = compute_bitwise_request::(local, next, challenges, false); // is_xor = false - let v_u32xor = compute_bitwise_request::(local, next, challenges, true); // is_xor = true - - // --- ACE and log_precompile request values --- - let v_evalcircuit = compute_ace_request::(local, challenges); - let v_logprecompile = compute_log_precompile_request::(local, next, challenges); - - // Sum of request flags (hasher + control blocks + memory + bitwise + ACE + log_precompile) - let request_flag_sum: AB::Expr = f_hperm.clone() - + f_mpverify.clone() - + f_mrupdate.clone() - + f_join.clone() - + f_split.clone() - + f_loop.clone() - + f_call.clone() - + f_dyn.clone() - + f_dyncall.clone() - + f_syscall.clone() - + f_span.clone() - + f_respan.clone() - + f_end.clone() - + f_mload.clone() - + f_mstore.clone() - + f_mloadw.clone() - + f_mstorew.clone() - + f_hornerbase.clone() - + f_hornerext.clone() - + f_mstream.clone() - + f_pipe.clone() - + f_cryptostream.clone() - + f_u32and.clone() - + f_u32xor.clone() - + f_evalcircuit.clone() - + f_logprecompile.clone(); - - let one_ef = AB::ExprEF::ONE; - - // Request multiplier = sum(flag * value) + (1 - sum(flags)) - let requests: AB::ExprEF = v_hperm * f_hperm.clone() - + v_mpverify * f_mpverify.clone() - + v_mrupdate * f_mrupdate.clone() - + v_join * f_join.clone() - + v_split * f_split.clone() - + v_loop * f_loop.clone() - + v_call * f_call.clone() - + v_dyn * f_dyn.clone() - + v_dyncall * f_dyncall.clone() - + v_syscall * f_syscall.clone() - + v_span * f_span.clone() - + v_respan * f_respan.clone() - + v_end * f_end.clone() - + v_mload * f_mload.clone() - + v_mstore * f_mstore.clone() - + v_mloadw * f_mloadw.clone() - + v_mstorew * f_mstorew.clone() - + v_hornerbase * f_hornerbase.clone() - + v_hornerext * f_hornerext.clone() - + v_mstream * f_mstream.clone() - + v_pipe * f_pipe.clone() - + v_cryptostream * f_cryptostream.clone() - + v_u32and * f_u32and.clone() - + v_u32xor * f_u32xor.clone() - + v_evalcircuit * f_evalcircuit.clone() - + v_logprecompile * f_logprecompile.clone() - + (one_ef.clone() - request_flag_sum); - - // ========================================================================= - // COMPUTE RESPONSE MULTIPLIER - // ========================================================================= - // Responses come from chiplet rows. Chiplet selectors are mutually exclusive. - - // --- Get periodic columns we need for hasher cycle detection and bitwise cycle gating --- - let (cycle_row_0, cycle_row_31, k_transition) = { - let p = builder.periodic_values(); - let cycle_row_0: AB::Expr = p[hasher::periodic::P_CYCLE_ROW_0].into(); - let cycle_row_31: AB::Expr = p[hasher::periodic::P_CYCLE_ROW_31].into(); - let k_transition: AB::Expr = p[P_BITWISE_K_TRANSITION].into(); - (cycle_row_0, cycle_row_31, k_transition) - }; - - // --- Chiplet selector flags (from chiplets columns) --- - let chiplet_s0: AB::Expr = local.chiplets[0].clone().into(); - let chiplet_s1: AB::Expr = local.chiplets[1].clone().into(); - let chiplet_s2: AB::Expr = local.chiplets[2].clone().into(); - let chiplet_s3: AB::Expr = local.chiplets[3].clone().into(); - let chiplet_s4: AB::Expr = local.chiplets[4].clone().into(); - - // Bitwise chiplet active: s0=1, s1=0 - // Bitwise responds only on last row of 8-row cycle (when k_transition=0) - let is_bitwise_row: AB::Expr = chiplet_s0.clone() * (AB::Expr::ONE - chiplet_s1.clone()); - let is_bitwise_responding: AB::Expr = is_bitwise_row * (AB::Expr::ONE - k_transition); - - // Memory chiplet active: s0=1, s1=1, s2=0 - let is_memory: AB::Expr = - chiplet_s0.clone() * chiplet_s1.clone() * (AB::Expr::ONE - chiplet_s2.clone()); - - // ACE chiplet active: s0=1, s1=1, s2=1, s3=0 - // Response only on start rows (ace_start_selector = 1) - let is_ace_row: AB::Expr = chiplet_s0.clone() - * chiplet_s1.clone() - * chiplet_s2.clone() - * (AB::Expr::ONE - chiplet_s3.clone()); - let ace_start_selector: AB::Expr = - local.chiplets[NUM_ACE_SELECTORS + SELECTOR_START_IDX].clone().into(); - let is_ace: AB::Expr = is_ace_row * ace_start_selector; - - // Kernel ROM chiplet active: s0=1, s1=1, s2=1, s3=1, s4=0 - let is_kernel_rom: AB::Expr = chiplet_s0.clone() - * chiplet_s1.clone() - * chiplet_s2.clone() - * chiplet_s3.clone() - * (AB::Expr::ONE - chiplet_s4.clone()); - - // --- Hasher response (complex, depends on cycle position and selectors) --- - let hasher_response = - compute_hasher_response::(local, next, challenges, cycle_row_0, cycle_row_31); - - // --- Bitwise response --- - let v_bitwise = compute_bitwise_response::(local, challenges); - - // --- Memory response --- - let v_memory = compute_memory_response::(local, challenges); - - // --- ACE response --- - let v_ace = compute_ace_response::(local, challenges); - - // --- Kernel ROM response --- - let v_kernel_rom = compute_kernel_rom_response::(local, challenges); - - // Convert flags to ExprEF - // Responses: hasher + bitwise + memory + ACE + kernel ROM contributions, others return 1 - let responses: AB::ExprEF = hasher_response.sum - + v_bitwise * is_bitwise_responding.clone() - + v_memory * is_memory.clone() - + v_ace * is_ace.clone() - + v_kernel_rom * is_kernel_rom.clone() - + (AB::ExprEF::ONE - - hasher_response.flag_sum - - is_bitwise_responding - - is_memory - - is_ace - - is_kernel_rom); - - // ========================================================================= - // RUNNING PRODUCT TRANSITION CONSTRAINT - // ========================================================================= - // b_chiplets' * requests = b_chiplets * responses - - let lhs: AB::ExprEF = Into::::into(b_next_val) * requests; - let rhs: AB::ExprEF = Into::::into(b_local_val) * responses; - builder.tagged(CHIPLET_BUS_ID, CHIPLET_BUS_NAMESPACE, |builder| { - builder.when_transition().assert_zero_ext(lhs - rhs); - }); -} - -// BITWISE MESSAGE HELPERS -// ================================================================================================ - -/// Computes the bitwise request message value. -/// -/// Format: alpha + beta^0*label + beta^1*a + beta^2*b + beta^3*z -/// -/// Stack layout for U32AND/U32XOR: [a, b, ...] -> [z, ...] -fn compute_bitwise_request>( - local: &MainTraceRow, - next: &MainTraceRow, - challenges: &Challenges, - is_xor: bool, -) -> AB::ExprEF { - let label: Felt = if is_xor { BITWISE_XOR_LABEL } else { BITWISE_AND_LABEL }; - let label: AB::Expr = AB::Expr::from(label); - - // Stack values - let a: AB::Expr = local.stack[0].clone().into(); - let b: AB::Expr = local.stack[1].clone().into(); - let z: AB::Expr = next.stack[0].clone().into(); - - challenges.encode([label, a, b, z]) -} - -/// Computes the bitwise chiplet response message value. -/// -/// Format: alpha + beta^0*label + beta^1*a + beta^2*b + beta^3*z -fn compute_bitwise_response>( - local: &MainTraceRow, - challenges: &Challenges, -) -> AB::ExprEF { - use crate::trace::chiplets::NUM_BITWISE_SELECTORS; - - // Bitwise chiplet columns start at NUM_BITWISE_SELECTORS=2 in local.chiplets - let bw_offset = NUM_BITWISE_SELECTORS; - - // Get bitwise operation selector and compute label - // The AND/XOR selector is at bitwise[0] = local.chiplets[bw_offset] - // label = (1 - sel) * AND_LABEL + sel * XOR_LABEL - let sel: AB::Expr = local.chiplets[bw_offset].clone().into(); - let one_minus_sel = AB::Expr::ONE - sel.clone(); - let label = one_minus_sel * AB::Expr::from(BITWISE_AND_LABEL) - + sel.clone() * AB::Expr::from(BITWISE_XOR_LABEL); - - // Bitwise chiplet data columns (offset by bw_offset + bitwise internal indices) - let a: AB::Expr = local.chiplets[bw_offset + bitwise::A_COL_IDX].clone().into(); - let b: AB::Expr = local.chiplets[bw_offset + bitwise::B_COL_IDX].clone().into(); - let z: AB::Expr = local.chiplets[bw_offset + bitwise::OUTPUT_COL_IDX].clone().into(); - - challenges.encode([label, a, b, z]) -} - -// MEMORY MESSAGE HELPERS -// ================================================================================================ - -/// Computes the memory word request message value. -/// -/// Format: alpha + beta^0*label + beta^1*ctx + beta^2*addr + beta^3*clk + -/// beta^4..beta^7 * word -/// -/// Stack layout for MLOADW: [addr, ...] -> [word[0], word[1], word[2], word[3], ...] -/// Stack layout for MSTOREW: [addr, word[0], word[1], word[2], word[3], ...] -fn compute_memory_word_request>( - local: &MainTraceRow, - next: &MainTraceRow, - challenges: &Challenges, - is_read: bool, -) -> AB::ExprEF { - let label = if is_read { - MEMORY_READ_WORD_LABEL - } else { - MEMORY_WRITE_WORD_LABEL - }; - let label: AB::Expr = AB::Expr::from_u16(label as u16); - - // Context and clock from system columns - let ctx: AB::Expr = local.ctx.clone().into(); - let clk: AB::Expr = local.clk.clone().into(); - - // Address is at stack[0] - let addr: AB::Expr = local.stack[0].clone().into(); - - // Word values depend on read vs write - let (w0, w1, w2, w3) = if is_read { - // MLOADW: word comes from next stack state - ( - next.stack[0].clone().into(), - next.stack[1].clone().into(), - next.stack[2].clone().into(), - next.stack[3].clone().into(), - ) - } else { - // MSTOREW: word comes from current stack[1..5] - ( - local.stack[1].clone().into(), - local.stack[2].clone().into(), - local.stack[3].clone().into(), - local.stack[4].clone().into(), - ) - }; - - challenges.encode([label, ctx, addr, clk, w0, w1, w2, w3]) -} - -/// Computes the memory element request message value. -/// -/// Format: alpha + beta^0*label + beta^1*ctx + beta^2*addr + beta^3*clk + beta^4*element -fn compute_memory_element_request>( - local: &MainTraceRow, - next: &MainTraceRow, - challenges: &Challenges, - is_read: bool, -) -> AB::ExprEF { - let label = if is_read { - MEMORY_READ_ELEMENT_LABEL - } else { - MEMORY_WRITE_ELEMENT_LABEL - }; - let label: AB::Expr = AB::Expr::from_u16(label as u16); - - // Context and clock from system columns - let ctx: AB::Expr = local.ctx.clone().into(); - let clk: AB::Expr = local.clk.clone().into(); - - // Address is at stack[0] - let addr: AB::Expr = local.stack[0].clone().into(); - - // Element value - let element = if is_read { - // MLOAD: element comes from next stack[0] - next.stack[0].clone().into() - } else { - // MSTORE: element comes from current stack[1] - local.stack[1].clone().into() - }; - - challenges.encode([label, ctx, addr, clk, element]) -} - -/// Computes the MSTREAM request message value (two word reads). -fn compute_mstream_request>( - local: &MainTraceRow, - next: &MainTraceRow, - challenges: &Challenges, -) -> AB::ExprEF { - let label: AB::Expr = AB::Expr::from_u16(MEMORY_READ_WORD_LABEL as u16); - let ctx: AB::Expr = local.ctx.clone().into(); - let clk: AB::Expr = local.clk.clone().into(); - let addr: AB::Expr = local.stack[12].clone().into(); - let four: AB::Expr = AB::Expr::from_u16(4); - - // First word: next.stack[0..4] at addr - let word1 = [ - next.stack[0].clone().into(), - next.stack[1].clone().into(), - next.stack[2].clone().into(), - next.stack[3].clone().into(), - ]; - - // Second word: next.stack[4..8] at addr + 4 - let word2 = [ - next.stack[4].clone().into(), - next.stack[5].clone().into(), - next.stack[6].clone().into(), - next.stack[7].clone().into(), - ]; - - let msg1 = challenges.encode([ - label.clone(), - ctx.clone(), - addr.clone(), - clk.clone(), - word1[0].clone(), - word1[1].clone(), - word1[2].clone(), - word1[3].clone(), - ]); - - let msg2 = challenges.encode([ - label, - ctx, - addr + four.clone(), - clk, - word2[0].clone(), - word2[1].clone(), - word2[2].clone(), - word2[3].clone(), - ]); - - msg1 * msg2 -} - -/// Computes the PIPE request message value (two word writes). -fn compute_pipe_request>( - local: &MainTraceRow, - next: &MainTraceRow, - challenges: &Challenges, -) -> AB::ExprEF { - let label: AB::Expr = AB::Expr::from_u16(MEMORY_WRITE_WORD_LABEL as u16); - let ctx: AB::Expr = local.ctx.clone().into(); - let clk: AB::Expr = local.clk.clone().into(); - let addr: AB::Expr = local.stack[12].clone().into(); - let four: AB::Expr = AB::Expr::from_u16(4); - - // First word to addr: next.stack[0..4] - let word1 = [ - next.stack[0].clone().into(), - next.stack[1].clone().into(), - next.stack[2].clone().into(), - next.stack[3].clone().into(), - ]; - - // Second word to addr + 4: next.stack[4..8] - let word2 = [ - next.stack[4].clone().into(), - next.stack[5].clone().into(), - next.stack[6].clone().into(), - next.stack[7].clone().into(), - ]; - - let msg1 = challenges.encode([ - label.clone(), - ctx.clone(), - addr.clone(), - clk.clone(), - word1[0].clone(), - word1[1].clone(), - word1[2].clone(), - word1[3].clone(), - ]); - - let msg2 = challenges.encode([ - label, - ctx, - addr + four.clone(), - clk, - word2[0].clone(), - word2[1].clone(), - word2[2].clone(), - word2[3].clone(), - ]); - - msg1 * msg2 -} - -/// Computes the CRYPTOSTREAM request value (two word reads + two word writes). -fn compute_cryptostream_request>( - local: &MainTraceRow, - next: &MainTraceRow, - challenges: &Challenges, -) -> AB::ExprEF { - let read_label: AB::Expr = AB::Expr::from_u16(MEMORY_READ_WORD_LABEL as u16); - let write_label: AB::Expr = AB::Expr::from_u16(MEMORY_WRITE_WORD_LABEL as u16); - let ctx: AB::Expr = local.ctx.clone().into(); - let clk: AB::Expr = local.clk.clone().into(); - let src: AB::Expr = local.stack[12].clone().into(); - let dst: AB::Expr = local.stack[13].clone().into(); - let four: AB::Expr = AB::Expr::from_u16(4); - - let rate: [AB::Expr; 8] = core::array::from_fn(|i| local.stack[i].clone().into()); - let cipher: [AB::Expr; 8] = core::array::from_fn(|i| next.stack[i].clone().into()); - let plain: [AB::Expr; 8] = core::array::from_fn(|i| cipher[i].clone() - rate[i].clone()); - - let read_msg1 = challenges.encode([ - read_label.clone(), - ctx.clone(), - src.clone(), - clk.clone(), - plain[0].clone(), - plain[1].clone(), - plain[2].clone(), - plain[3].clone(), - ]); - - let read_msg2 = challenges.encode([ - read_label, - ctx.clone(), - src + four.clone(), - clk.clone(), - plain[4].clone(), - plain[5].clone(), - plain[6].clone(), - plain[7].clone(), - ]); - - let write_msg1 = challenges.encode([ - write_label.clone(), - ctx.clone(), - dst.clone(), - clk.clone(), - cipher[0].clone(), - cipher[1].clone(), - cipher[2].clone(), - cipher[3].clone(), - ]); - - let write_msg2 = challenges.encode([ - write_label, - ctx, - dst + four, - clk, - cipher[4].clone(), - cipher[5].clone(), - cipher[6].clone(), - cipher[7].clone(), - ]); - - read_msg1 * read_msg2 * write_msg1 * write_msg2 -} - -/// Computes the HORNERBASE request value (two element reads). -fn compute_hornerbase_request>( - local: &MainTraceRow, - challenges: &Challenges, -) -> AB::ExprEF { - let label: AB::Expr = AB::Expr::from_u16(MEMORY_READ_ELEMENT_LABEL as u16); - let ctx: AB::Expr = local.ctx.clone().into(); - let clk: AB::Expr = local.clk.clone().into(); - let addr: AB::Expr = local.stack[13].clone().into(); - let one: AB::Expr = AB::Expr::ONE; - - // Helper registers hold eval_point_0 and eval_point_1 - let helper0_idx = USER_OP_HELPERS_OFFSET; - let helper1_idx = helper0_idx + 1; - let eval0: AB::Expr = local.decoder[helper0_idx].clone().into(); - let eval1: AB::Expr = local.decoder[helper1_idx].clone().into(); - - let msg0 = challenges.encode([label.clone(), ctx.clone(), addr.clone(), clk.clone(), eval0]); - - let msg1 = challenges.encode([label, ctx, addr + one, clk, eval1]); - - msg0 * msg1 -} - -/// Computes the HORNEREXT request value (one word read). -fn compute_hornerext_request>( - local: &MainTraceRow, - challenges: &Challenges, -) -> AB::ExprEF { - let label: AB::Expr = AB::Expr::from_u16(MEMORY_READ_WORD_LABEL as u16); - let ctx: AB::Expr = local.ctx.clone().into(); - let clk: AB::Expr = local.clk.clone().into(); - let addr: AB::Expr = local.stack[13].clone().into(); - - // Helpers 0..3 hold eval_point_0, eval_point_1, mem_junk_0, mem_junk_1 - let base = USER_OP_HELPERS_OFFSET; - let word = [ - local.decoder[base].clone().into(), - local.decoder[base + 1].clone().into(), - local.decoder[base + 2].clone().into(), - local.decoder[base + 3].clone().into(), - ]; - - challenges.encode([ - label, - ctx, - addr, - clk, - word[0].clone(), - word[1].clone(), - word[2].clone(), - word[3].clone(), - ]) -} - -/// Computes the memory chiplet response message value. -/// -/// The memory chiplet uses different labels for read/write and element/word operations. -/// Address is computed as: word + 2*idx1 + idx0 -/// For element access, the correct element is selected based on idx0, idx1. -fn compute_memory_response>( - local: &MainTraceRow, - challenges: &Challenges, -) -> AB::ExprEF { - use crate::trace::chiplets::{NUM_MEMORY_SELECTORS, memory}; - - // Memory chiplet columns (offset by NUM_MEMORY_SELECTORS=3 for s0, s1, s2 selectors) - // local.chiplets is relative to CHIPLETS_OFFSET, memory columns start at index 3 - let mem_offset = NUM_MEMORY_SELECTORS; - let is_read: AB::Expr = local.chiplets[mem_offset + memory::IS_READ_COL_IDX].clone().into(); - let is_word: AB::Expr = - local.chiplets[mem_offset + memory::IS_WORD_ACCESS_COL_IDX].clone().into(); - let ctx: AB::Expr = local.chiplets[mem_offset + memory::CTX_COL_IDX].clone().into(); - let word: AB::Expr = local.chiplets[mem_offset + memory::WORD_COL_IDX].clone().into(); - let idx0: AB::Expr = local.chiplets[mem_offset + memory::IDX0_COL_IDX].clone().into(); - let idx1: AB::Expr = local.chiplets[mem_offset + memory::IDX1_COL_IDX].clone().into(); - let clk: AB::Expr = local.chiplets[mem_offset + memory::CLK_COL_IDX].clone().into(); - - // Compute address: addr = word + 2*idx1 + idx0 - let addr: AB::Expr = word + idx1.clone() * AB::Expr::from_u16(2) + idx0.clone(); - - // Compute label from flags using the canonical constants. - let one = AB::Expr::ONE; - let write_element_label = AB::Expr::from_u16(MEMORY_WRITE_ELEMENT_LABEL as u16); - let write_word_label = AB::Expr::from_u16(MEMORY_WRITE_WORD_LABEL as u16); - let read_element_label = AB::Expr::from_u16(MEMORY_READ_ELEMENT_LABEL as u16); - let read_word_label = AB::Expr::from_u16(MEMORY_READ_WORD_LABEL as u16); - let write_label = - (one.clone() - is_word.clone()) * write_element_label + is_word.clone() * write_word_label; - let read_label = - (one.clone() - is_word.clone()) * read_element_label + is_word.clone() * read_word_label; - let label = (one.clone() - is_read.clone()) * write_label + is_read.clone() * read_label; - - // Get value columns (v0, v1, v2, v3) - let v0: AB::Expr = local.chiplets[mem_offset + memory::V_COL_RANGE.start].clone().into(); - let v1: AB::Expr = local.chiplets[mem_offset + memory::V_COL_RANGE.start + 1].clone().into(); - let v2: AB::Expr = local.chiplets[mem_offset + memory::V_COL_RANGE.start + 2].clone().into(); - let v3: AB::Expr = local.chiplets[mem_offset + memory::V_COL_RANGE.start + 3].clone().into(); - - // For element access, select the correct element based on idx0, idx1: - // - (0,0) -> v0, (1,0) -> v1, (0,1) -> v2, (1,1) -> v3 - // element = v0*(1-idx0)*(1-idx1) + v1*idx0*(1-idx1) + v2*(1-idx0)*idx1 + v3*idx0*idx1 - let element: AB::Expr = - v0.clone() * (one.clone() - idx0.clone()) * (one.clone() - idx1.clone()) - + v1.clone() * idx0.clone() * (one.clone() - idx1.clone()) - + v2.clone() * (one.clone() - idx0.clone()) * idx1.clone() - + v3.clone() * idx0.clone() * idx1.clone(); - - // For word access, all v0..v3 are used - let is_element = one.clone() - is_word.clone(); - - // Element access: include the selected element in the last slot. - let element_msg = - challenges.encode([label.clone(), ctx.clone(), addr.clone(), clk.clone(), element]); - - // Word access: include all 4 values. - let word_msg = challenges.encode([label, ctx, addr, clk, v0, v1, v2, v3]); - - // Select based on is_word - element_msg * is_element + word_msg * is_word -} - -// HASHER RESPONSE HELPERS -// ================================================================================================ - -/// Hasher response contribution to the chiplets bus. -struct HasherResponse { - sum: EF, - flag_sum: E, -} - -/// Computes the hasher chiplet response message value. -/// -/// The hasher responds at two cycle positions: -/// - Row 0: Initialization (f_bp, f_mp, f_mv, f_mu) -/// - Row 31: Output/Absorption (f_hout, f_sout, f_abp) -fn compute_hasher_response>( - local: &MainTraceRow, - next: &MainTraceRow, - challenges: &Challenges, - cycle_row_0: AB::Expr, - cycle_row_31: AB::Expr, -) -> HasherResponse { - use crate::trace::{ - CHIPLETS_OFFSET, - chiplets::{HASHER_NODE_INDEX_COL_IDX, HASHER_STATE_COL_RANGE}, - }; - - let one = AB::Expr::ONE; - // Hasher is active when chiplets[0] == 0 - let hasher_active: AB::Expr = one.clone() - local.chiplets[0].clone().into(); - - // Hasher selectors (when hasher is active, chiplets[0]=0) - // chiplets[1..4] are the hasher's internal selectors s0, s1, s2 - let hs0: AB::Expr = local.chiplets[1].clone().into(); - let hs1: AB::Expr = local.chiplets[2].clone().into(); - let hs2: AB::Expr = local.chiplets[3].clone().into(); - - // Compute operation flags (each flag is active at most once) - // All hasher flags require hasher_active (chiplets[0] == 0) - // Row 0 flags: - // f_bp = hasher_active * cycle_row_0 * s0 * !s1 * !s2 - let f_bp = hasher_active.clone() - * cycle_row_0.clone() - * hs0.clone() - * (one.clone() - hs1.clone()) - * (one.clone() - hs2.clone()); - // f_mp = hasher_active * cycle_row_0 * s0 * !s1 * s2 - let f_mp = hasher_active.clone() - * cycle_row_0.clone() - * hs0.clone() - * (one.clone() - hs1.clone()) - * hs2.clone(); - // f_mv = hasher_active * cycle_row_0 * s0 * s1 * !s2 - let f_mv = hasher_active.clone() - * cycle_row_0.clone() - * hs0.clone() - * hs1.clone() - * (one.clone() - hs2.clone()); - // f_mu = hasher_active * cycle_row_0 * s0 * s1 * s2 - let f_mu = - hasher_active.clone() * cycle_row_0.clone() * hs0.clone() * hs1.clone() * hs2.clone(); - - // Row 31 flags: - // f_hout = hasher_active * cycle_row_31 * !s0 * !s1 * !s2 - let f_hout = hasher_active.clone() - * cycle_row_31.clone() - * (one.clone() - hs0.clone()) - * (one.clone() - hs1.clone()) - * (one.clone() - hs2.clone()); - // f_sout = hasher_active * cycle_row_31 * !s0 * !s1 * s2 - let f_sout = hasher_active.clone() - * cycle_row_31.clone() - * (one.clone() - hs0.clone()) - * (one.clone() - hs1.clone()) - * hs2.clone(); - // f_abp = hasher_active * cycle_row_31 * s0 * !s1 * !s2 - let f_abp = hasher_active.clone() - * cycle_row_31.clone() - * hs0.clone() - * (one.clone() - hs1.clone()) - * (one.clone() - hs2.clone()); - - // Get current hasher state (12 elements) and node index - let state: [AB::Expr; 12] = core::array::from_fn(|i| { - let col_idx = HASHER_STATE_COL_RANGE.start - CHIPLETS_OFFSET + i; - local.chiplets[col_idx].clone().into() - }); - let node_index: AB::Expr = - local.chiplets[HASHER_NODE_INDEX_COL_IDX - CHIPLETS_OFFSET].clone().into(); - - // Get next row's hasher state (for f_abp) - let state_next: [AB::Expr; 12] = core::array::from_fn(|i| { - let col_idx = HASHER_STATE_COL_RANGE.start - CHIPLETS_OFFSET + i; - next.chiplets[col_idx].clone().into() - }); - - // Get next row's node_index for computing the node_index bit - let node_index_next: AB::Expr = - next.chiplets[HASHER_NODE_INDEX_COL_IDX - CHIPLETS_OFFSET].clone().into(); - - // addr_next = row + 1 (using clk as proxy since clk = row in the trace) - let addr_next: AB::Expr = local.clk.clone().into() + one.clone(); - - // Build message values for each operation type using canonical labels. - let label_bp = AB::Expr::from_u16(LINEAR_HASH_LABEL as u16 + 16); - let label_mp = AB::Expr::from_u16(MP_VERIFY_LABEL as u16 + 16); - let label_mv = AB::Expr::from_u16(MR_UPDATE_OLD_LABEL as u16 + 16); - let label_mu = AB::Expr::from_u16(MR_UPDATE_NEW_LABEL as u16 + 16); - let label_hout = AB::Expr::from_u16(RETURN_HASH_LABEL as u16 + 32); - let label_sout = AB::Expr::from_u16(RETURN_STATE_LABEL as u16 + 32); - let label_abp = AB::Expr::from_u16(LINEAR_HASH_LABEL as u16 + 32); - - // v_bp: Full state message for f_bp (linear hash / 2-to-1 hash init) - let v_bp = compute_hasher_message::( - challenges, - label_bp, - addr_next.clone(), - node_index.clone(), - &state, - ); - - // v_sout: Full state message for f_sout (return full state) - let v_sout = compute_hasher_message::( - challenges, - label_sout, - addr_next.clone(), - node_index.clone(), - &state, - ); - - // v_leaf: Leaf node message (for f_mp, f_mv, f_mu) - // The leaf is encoded as a 4-lane word, matching the processor. - // The bit determines which part of the trace state to use: - // - bit=0: use RATE0 (state[0..4]) - // - bit=1: use RATE1 (state[4..8]) - // The bit can be computed as: bit = node_index - 2 * node_index_next - let two = AB::Expr::from_u16(2); - let bit = node_index.clone() - two * node_index_next.clone(); - - // Leaf word uses RATE0 or RATE1 depending on bit: - // bit=0: use state[0..4] (RATE0) - // bit=1: use state[4..8] (RATE1) - let leaf_word: [AB::Expr; 4] = [ - (one.clone() - bit.clone()) * state[0].clone() + bit.clone() * state[4].clone(), - (one.clone() - bit.clone()) * state[1].clone() + bit.clone() * state[5].clone(), - (one.clone() - bit.clone()) * state[2].clone() + bit.clone() * state[6].clone(), - (one.clone() - bit.clone()) * state[3].clone() + bit.clone() * state[7].clone(), - ]; - let v_mp = compute_hasher_word_message::( - challenges, - label_mp, - addr_next.clone(), - node_index.clone(), - &leaf_word, - ); - let v_mv = compute_hasher_word_message::( - challenges, - label_mv, - addr_next.clone(), - node_index.clone(), - &leaf_word, - ); - let v_mu = compute_hasher_word_message::( - challenges, - label_mu, - addr_next.clone(), - node_index.clone(), - &leaf_word, - ); - - // v_hout: Hash output message (for f_hout) - // Digest from RATE0 (state[0..4]) encoded as a 4-lane word. - let result_word: [AB::Expr; 4] = - [state[0].clone(), state[1].clone(), state[2].clone(), state[3].clone()]; - let v_hout = compute_hasher_word_message::( - challenges, - label_hout, - addr_next.clone(), - node_index.clone(), - &result_word, - ); - - // v_abp: Absorption message (for f_abp) - uses NEXT row's rate (8 elements) - // Rate from state_next[0..8] is encoded as an 8-lane rate message. - let rate_next: [AB::Expr; 8] = [ - state_next[0].clone(), - state_next[1].clone(), - state_next[2].clone(), - state_next[3].clone(), - state_next[4].clone(), - state_next[5].clone(), - state_next[6].clone(), - state_next[7].clone(), - ]; - let v_abp = compute_hasher_rate_message::( - challenges, - label_abp, - addr_next.clone(), - node_index.clone(), - &rate_next, - ); - - // Sum of all hasher response flags - let flag_sum = f_bp.clone() - + f_mp.clone() - + f_mv.clone() - + f_mu.clone() - + f_hout.clone() - + f_sout.clone() - + f_abp.clone(); - - // Sum of response values (rest term handled by caller). - let sum = v_bp * f_bp - + v_mp * f_mp - + v_mv * f_mv - + v_mu * f_mu - + v_hout * f_hout - + v_sout * f_sout - + v_abp * f_abp; - - HasherResponse { sum, flag_sum } -} - -// HASHER MESSAGE HELPERS -// ================================================================================================ - -/// Computes the HPERM request message value. -/// -/// HPERM sends two messages to the hasher chiplet: -/// 1. Input message: LINEAR_HASH_LABEL + 16, with input state from stack[0..12] -/// 2. Output message: RETURN_STATE_LABEL + 32, with output state from next stack[0..12] -/// -/// The combined request is the product of these two message values. -/// -/// Stack layout: [s0, s1, ..., s11, ...] -> [s0', s1', ..., s11', ...] -fn compute_hperm_request>( - local: &MainTraceRow, - next: &MainTraceRow, - challenges: &Challenges, -) -> AB::ExprEF { - use crate::trace::decoder::USER_OP_HELPERS_OFFSET; - - // Hasher address from helper register 0 - let addr: AB::Expr = local.decoder[USER_OP_HELPERS_OFFSET].clone().into(); - - // Input state from current stack[0..12] - let input_state: [AB::Expr; 12] = core::array::from_fn(|i| local.stack[i].clone().into()); - - // Output state from next stack[0..12] - let output_state: [AB::Expr; 12] = core::array::from_fn(|i| next.stack[i].clone().into()); - - // Input message: transition_label = LINEAR_HASH_LABEL + 16 = 3 + 16 = 19 - let input_label: AB::Expr = AB::Expr::from_u16(LINEAR_HASH_LABEL as u16 + 16); - let node_index_zero: AB::Expr = AB::Expr::ZERO; - - let input_msg = compute_hasher_message::( - challenges, - input_label, - addr.clone(), - node_index_zero.clone(), - &input_state, - ); - - // Output message: transition_label = RETURN_STATE_LABEL + 32 = 9 + 32 = 41 - // addr_next = addr + (HASH_CYCLE_LEN - 1) = addr + 31 - let output_label: AB::Expr = AB::Expr::from_u16(RETURN_STATE_LABEL as u16 + 32); - let addr_offset: AB::Expr = AB::Expr::from_u16((HASH_CYCLE_LEN - 1) as u16); - let addr_next = addr + addr_offset; - - let output_msg = compute_hasher_message::( - challenges, - output_label, - addr_next, - node_index_zero, - &output_state, - ); - - // Combined request is product of input and output messages - input_msg * output_msg -} - -/// Computes the LOG_PRECOMPILE request message value. -/// -/// LOG_PRECOMPILE absorbs `[COMM, TAG]` with capacity `CAP_PREV` and returns `[R0, R1, CAP_NEXT]`. -/// The request is the product of input (LINEAR_HASH + 16) and output (RETURN_STATE + 32) messages. -fn compute_log_precompile_request>( - local: &MainTraceRow, - next: &MainTraceRow, - challenges: &Challenges, -) -> AB::ExprEF { - // Helper registers - let helper_base = USER_OP_HELPERS_OFFSET; - let addr: AB::Expr = local.decoder[helper_base + HELPER_ADDR_IDX].clone().into(); - - // CAP_PREV from helper registers (4 lanes) - let cap_prev: [AB::Expr; 4] = core::array::from_fn(|i| { - local.decoder[helper_base + HELPER_CAP_PREV_RANGE.start + i].clone().into() - }); - - // COMM and TAG from the current stack - let comm: [AB::Expr; 4] = - core::array::from_fn(|i| local.stack[STACK_COMM_RANGE.start + i].clone().into()); - let tag: [AB::Expr; 4] = - core::array::from_fn(|i| local.stack[STACK_TAG_RANGE.start + i].clone().into()); - - // Input state [COMM, TAG, CAP_PREV] - let state_input: [AB::Expr; 12] = [ - comm[0].clone(), - comm[1].clone(), - comm[2].clone(), - comm[3].clone(), - tag[0].clone(), - tag[1].clone(), - tag[2].clone(), - tag[3].clone(), - cap_prev[0].clone(), - cap_prev[1].clone(), - cap_prev[2].clone(), - cap_prev[3].clone(), - ]; - - // Output state from next stack [R0, R1, CAP_NEXT] - let r0: [AB::Expr; 4] = - core::array::from_fn(|i| next.stack[STACK_R0_RANGE.start + i].clone().into()); - let r1: [AB::Expr; 4] = - core::array::from_fn(|i| next.stack[STACK_R1_RANGE.start + i].clone().into()); - let cap_next: [AB::Expr; 4] = - core::array::from_fn(|i| next.stack[STACK_CAP_NEXT_RANGE.start + i].clone().into()); - let state_output: [AB::Expr; 12] = [ - r0[0].clone(), - r0[1].clone(), - r0[2].clone(), - r0[3].clone(), - r1[0].clone(), - r1[1].clone(), - r1[2].clone(), - r1[3].clone(), - cap_next[0].clone(), - cap_next[1].clone(), - cap_next[2].clone(), - cap_next[3].clone(), - ]; - - // Input message: LINEAR_HASH_LABEL + 16 - let input_label: AB::Expr = AB::Expr::from_u16(LINEAR_HASH_LABEL as u16 + 16); - let input_msg = compute_hasher_message::( - challenges, - input_label, - addr.clone(), - AB::Expr::ZERO, - &state_input, - ); - - // Output message: RETURN_STATE_LABEL + 32 with addr offset by HASH_CYCLE_LEN - 1 - let output_label: AB::Expr = AB::Expr::from_u16(RETURN_STATE_LABEL as u16 + 32); - let addr_offset: AB::Expr = AB::Expr::from_u16((HASH_CYCLE_LEN - 1) as u16); - let output_msg = compute_hasher_message::( - challenges, - output_label, - addr + addr_offset, - AB::Expr::ZERO, - &state_output, - ); - - input_msg * output_msg -} - -/// Computes a hasher message value. -/// -/// Format: header + state where: -/// - header = alpha + beta^0 * transition_label + beta^1 * addr + beta^2 * node_index -/// - state = sum(beta^(3+i) * hasher_state[i]) for i in 0..12 -fn compute_hasher_message>( - challenges: &Challenges, - transition_label: AB::Expr, - addr: AB::Expr, - node_index: AB::Expr, - state: &[AB::Expr; 12], -) -> AB::ExprEF { - challenges.encode([ - transition_label, - addr, - node_index, - state[0].clone(), - state[1].clone(), - state[2].clone(), - state[3].clone(), - state[4].clone(), - state[5].clone(), - state[6].clone(), - state[7].clone(), - state[8].clone(), - state[9].clone(), - state[10].clone(), - state[11].clone(), - ]) -} - -/// Computes a hasher message for a 4-lane word. -fn compute_hasher_word_message>( - challenges: &Challenges, - transition_label: AB::Expr, - addr: AB::Expr, - node_index: AB::Expr, - word: &[AB::Expr; 4], -) -> AB::ExprEF { - challenges.encode([ - transition_label, - addr, - node_index, - word[0].clone(), - word[1].clone(), - word[2].clone(), - word[3].clone(), - ]) -} - -/// Computes a hasher message for an 8-lane rate. -fn compute_hasher_rate_message>( - challenges: &Challenges, - transition_label: AB::Expr, - addr: AB::Expr, - node_index: AB::Expr, - rate: &[AB::Expr; 8], -) -> AB::ExprEF { - challenges.encode([ - transition_label, - addr, - node_index, - rate[0].clone(), - rate[1].clone(), - rate[2].clone(), - rate[3].clone(), - rate[4].clone(), - rate[5].clone(), - rate[6].clone(), - rate[7].clone(), - ]) -} - -// ACE MESSAGE HELPERS -// ================================================================================================ - -/// Computes the ACE request message value. -/// -/// Format: alpha + beta^0*label + beta^1*clk + beta^2*ctx + beta^3*ptr -/// + beta^4*num_read_rows + beta^5*num_eval_rows -/// -/// Stack layout for EVALCIRCUIT: [ptr, num_read_rows, num_eval_rows, ...] -fn compute_ace_request>( - local: &MainTraceRow, - challenges: &Challenges, -) -> AB::ExprEF { - // Label is ACE_INIT_LABEL - let label: AB::Expr = AB::Expr::from(ACE_INIT_LABEL); - - // Context and clock from system columns - let ctx: AB::Expr = local.ctx.clone().into(); - let clk: AB::Expr = local.clk.clone().into(); - - // Stack values - let ptr: AB::Expr = local.stack[0].clone().into(); - let num_read_rows: AB::Expr = local.stack[1].clone().into(); - let num_eval_rows: AB::Expr = local.stack[2].clone().into(); - - challenges.encode([label, clk, ctx, ptr, num_read_rows, num_eval_rows]) -} - -/// Computes the ACE chiplet response message value. -/// -/// Format: alpha + beta^0*label + beta^1*clk + beta^2*ctx + beta^3*ptr -/// + beta^4*num_read_rows + beta^5*num_eval_rows -/// -/// The chiplet reads from its internal columns: -/// - clk from CLK_IDX -/// - ctx from CTX_IDX -/// - ptr from PTR_IDX -/// - num_eval_rows computed from READ_NUM_EVAL_IDX + 1 -/// - num_read_rows = id_0 + 1 - num_eval_rows -fn compute_ace_response>( - local: &MainTraceRow, - challenges: &Challenges, -) -> AB::ExprEF { - // Label is ACE_INIT_LABEL - let label: AB::Expr = AB::Expr::from(ACE_INIT_LABEL); - - // Read values from ACE chiplet columns (offset by NUM_ACE_SELECTORS) - let clk: AB::Expr = local.chiplets[NUM_ACE_SELECTORS + CLK_IDX].clone().into(); - let ctx: AB::Expr = local.chiplets[NUM_ACE_SELECTORS + CTX_IDX].clone().into(); - let ptr: AB::Expr = local.chiplets[NUM_ACE_SELECTORS + PTR_IDX].clone().into(); - - // num_eval_rows = READ_NUM_EVAL_IDX value + 1 - let read_num_eval: AB::Expr = - local.chiplets[NUM_ACE_SELECTORS + READ_NUM_EVAL_IDX].clone().into(); - let num_eval_rows: AB::Expr = read_num_eval + AB::Expr::ONE; - - // id_0 from ID_0_IDX - let id_0: AB::Expr = local.chiplets[NUM_ACE_SELECTORS + ID_0_IDX].clone().into(); - - // num_read_rows = id_0 + 1 - num_eval_rows - let num_read_rows: AB::Expr = id_0 + AB::Expr::ONE - num_eval_rows.clone(); - - challenges.encode([label, clk, ctx, ptr, num_read_rows, num_eval_rows]) -} - -// KERNEL ROM MESSAGE HELPERS -// ================================================================================================ - -/// Computes the kernel ROM chiplet response message value. -/// -/// Format: alpha + beta^0*label + beta^1*digest[0] + beta^2*digest[1] -/// + beta^3*digest[2] + beta^4*digest[3] -/// -/// The label depends on s_first flag: -/// - s_first=1: KERNEL_PROC_INIT_LABEL (responding to verifier/public input init request) -/// - s_first=0: KERNEL_PROC_CALL_LABEL (responding to decoder SYSCALL request) -fn compute_kernel_rom_response>( - local: &MainTraceRow, - challenges: &Challenges, -) -> AB::ExprEF { - // s_first flag is at CHIPLETS_OFFSET + 5 (after 5 selectors), which is chiplets[5] - let s_first: AB::Expr = local.chiplets[NUM_KERNEL_ROM_SELECTORS].clone().into(); - - // Label depends on s_first: - // label = s_first * INIT_LABEL + (1 - s_first) * CALL_LABEL - let init_label: AB::Expr = AB::Expr::from(KERNEL_PROC_INIT_LABEL); - let call_label: AB::Expr = AB::Expr::from(KERNEL_PROC_CALL_LABEL); - let label: AB::Expr = s_first.clone() * init_label + (AB::Expr::ONE - s_first) * call_label; - - // Kernel procedure digest (root0..root3) at columns 6, 7, 8, 9 relative to chiplets - // These are at NUM_KERNEL_ROM_SELECTORS + 1..5 (after s_first which is at +0) - let root0: AB::Expr = local.chiplets[NUM_KERNEL_ROM_SELECTORS + 1].clone().into(); - let root1: AB::Expr = local.chiplets[NUM_KERNEL_ROM_SELECTORS + 2].clone().into(); - let root2: AB::Expr = local.chiplets[NUM_KERNEL_ROM_SELECTORS + 3].clone().into(); - let root3: AB::Expr = local.chiplets[NUM_KERNEL_ROM_SELECTORS + 4].clone().into(); - - challenges.encode([label, root0, root1, root2, root3]) -} - -// CONTROL BLOCK REQUEST HELPERS -// ================================================================================================ - -/// Control block operation types for request message construction. -#[derive(Clone, Copy)] -enum ControlBlockOp { - Join, - Split, - Loop, - Call, - Syscall, -} - -impl ControlBlockOp { - /// Returns the opcode value for this control block operation. - fn opcode(&self) -> u8 { - match self { - ControlBlockOp::Join => opcodes::JOIN, - ControlBlockOp::Split => opcodes::SPLIT, - ControlBlockOp::Loop => opcodes::LOOP, - ControlBlockOp::Call => opcodes::CALL, - ControlBlockOp::Syscall => opcodes::SYSCALL, - } - } -} - -/// Computes the control block request message value for JOIN, SPLIT, LOOP, CALL, and SYSCALL. -/// -/// Format follows ControlBlockRequestMessage from processor: -/// - header = alpha + beta^0 * transition_label + beta^1 * addr_next -/// - state = 12-lane sponge with 8-element decoder hasher state as rate + opcode as domain -/// -/// The message reconstructs: -/// - transition_label = LINEAR_HASH_LABEL + 16 = 3 + 16 = 19 -/// - addr_next = decoder address at next row (from next row's addr column) -/// - hasher_state = rate lanes from decoder hasher columns + opcode in capacity domain position -fn compute_control_block_request>( - local: &MainTraceRow, - next: &MainTraceRow, - challenges: &Challenges, - op: ControlBlockOp, -) -> AB::ExprEF { - // transition_label = LINEAR_HASH_LABEL + 16 = 19 - let transition_label: AB::Expr = AB::Expr::from_u16(LINEAR_HASH_LABEL as u16 + 16); - - // addr_next = next row's decoder address - let addr_next: AB::Expr = next.decoder[ADDR_COL_IDX].clone().into(); - - // Get decoder hasher state (8 elements) - let hasher_state: [AB::Expr; 8] = - core::array::from_fn(|i| local.decoder[HASHER_STATE_RANGE.start + i].clone().into()); - - // op_code as domain in capacity position - let op_code: AB::Expr = AB::Expr::from_u16(op.opcode() as u16); - - // Build 12-lane sponge state: - // [RATE0: h[0..4], RATE1: h[4..8], CAPACITY: [0, domain, 0, 0]] - // LE layout: RATE0 at 0..4, RATE1 at 4..8, CAPACITY at 8..12 - let state: [AB::Expr; 12] = [ - hasher_state[0].clone(), - hasher_state[1].clone(), - hasher_state[2].clone(), - hasher_state[3].clone(), - hasher_state[4].clone(), - hasher_state[5].clone(), - hasher_state[6].clone(), - hasher_state[7].clone(), - AB::Expr::ZERO, - op_code, // domain at CAPACITY_DOMAIN_IDX = 9 - AB::Expr::ZERO, - AB::Expr::ZERO, - ]; - - compute_hasher_message::(challenges, transition_label, addr_next, AB::Expr::ZERO, &state) -} - -/// Computes the CALL request message value. -/// -/// CALL sends: -/// 1. Control block request (with decoder hasher state) -/// 2. FMP initialization write request (to set up new execution context) -fn compute_call_request>( - local: &MainTraceRow, - next: &MainTraceRow, - challenges: &Challenges, -) -> AB::ExprEF { - // Control block request - let control_req = - compute_control_block_request::(local, next, challenges, ControlBlockOp::Call); - - // FMP initialization write request - let fmp_req = compute_fmp_write_request::(local, next, challenges); - - control_req * fmp_req -} - -/// Computes the DYN request message value. -/// -/// DYN sends: -/// 1. Control block request (with zeros for hasher state since callee is dynamic) -/// 2. Memory read request for callee hash from stack[0] -fn compute_dyn_request>( - local: &MainTraceRow, - next: &MainTraceRow, - challenges: &Challenges, -) -> AB::ExprEF { - // Control block request with zeros for hasher state (callee is dynamic) - let control_req = - compute_control_block_request_zeros::(local, next, challenges, opcodes::DYN); - - // Memory read for callee hash (word read from stack[0] address) - let callee_hash_req = compute_dyn_callee_hash_read::(local, challenges); - - control_req * callee_hash_req -} - -/// Computes the DYNCALL request message value. -/// -/// DYNCALL sends: -/// 1. Control block request (with zeros for hasher state since callee is dynamic) -/// 2. Memory read request for callee hash from stack[0] -/// 3. FMP initialization write request -fn compute_dyncall_request>( - local: &MainTraceRow, - next: &MainTraceRow, - challenges: &Challenges, -) -> AB::ExprEF { - // Control block request with zeros for hasher state (callee is dynamic) - let control_req = - compute_control_block_request_zeros::(local, next, challenges, opcodes::DYNCALL); - - // Memory read for callee hash (word read from stack[0] address) - let callee_hash_req = compute_dyn_callee_hash_read::(local, challenges); - - // FMP initialization write request - let fmp_req = compute_fmp_write_request::(local, next, challenges); - - control_req * callee_hash_req * fmp_req -} - -/// Computes the SYSCALL request message value. -/// -/// SYSCALL sends: -/// 1. Control block request (with decoder hasher state) -/// 2. Kernel ROM lookup request (to verify kernel procedure) -fn compute_syscall_request>( - local: &MainTraceRow, - next: &MainTraceRow, - challenges: &Challenges, -) -> AB::ExprEF { - // Control block request - let control_req = - compute_control_block_request::(local, next, challenges, ControlBlockOp::Syscall); - - // Kernel ROM lookup request (digest from first 4 elements of decoder hasher state) - let root0: AB::Expr = local.decoder[HASHER_STATE_RANGE.start].clone().into(); - let root1: AB::Expr = local.decoder[HASHER_STATE_RANGE.start + 1].clone().into(); - let root2: AB::Expr = local.decoder[HASHER_STATE_RANGE.start + 2].clone().into(); - let root3: AB::Expr = local.decoder[HASHER_STATE_RANGE.start + 3].clone().into(); - - let label: AB::Expr = AB::Expr::from(KERNEL_PROC_CALL_LABEL); - let kernel_req = challenges.encode([label, root0, root1, root2, root3]); - - control_req * kernel_req -} - -/// Computes the SPAN block request message value. -/// -/// Format: header + full 12-lane sponge state (8 rate lanes + 4 capacity lanes zeroed) -fn compute_span_request>( - local: &MainTraceRow, - next: &MainTraceRow, - challenges: &Challenges, -) -> AB::ExprEF { - // transition_label = LINEAR_HASH_LABEL + 16 = 19 - let transition_label: AB::Expr = AB::Expr::from_u16(LINEAR_HASH_LABEL as u16 + 16); - - // addr_next = next row's decoder address - let addr_next: AB::Expr = next.decoder[ADDR_COL_IDX].clone().into(); - - // Get decoder hasher state (8 elements) - let hasher_state: [AB::Expr; 8] = - core::array::from_fn(|i| local.decoder[HASHER_STATE_RANGE.start + i].clone().into()); - - // Build full 12-lane state with capacity zeroed - let state: [AB::Expr; 12] = [ - hasher_state[0].clone(), - hasher_state[1].clone(), - hasher_state[2].clone(), - hasher_state[3].clone(), - hasher_state[4].clone(), - hasher_state[5].clone(), - hasher_state[6].clone(), - hasher_state[7].clone(), - AB::Expr::ZERO, - AB::Expr::ZERO, - AB::Expr::ZERO, - AB::Expr::ZERO, - ]; - - compute_hasher_message::(challenges, transition_label, addr_next, AB::Expr::ZERO, &state) -} - -/// Computes the RESPAN block request message value. -/// -/// Rate occupies message positions 3..10 (after label/addr/node_index). -fn compute_respan_request>( - local: &MainTraceRow, - next: &MainTraceRow, - challenges: &Challenges, -) -> AB::ExprEF { - // transition_label = LINEAR_HASH_LABEL + 32 = 35 - let transition_label: AB::Expr = AB::Expr::from_u16(LINEAR_HASH_LABEL as u16 + 32); - - // RESPAN message uses addr_next - 1, where addr_next is the next row's decoder address - let addr_next: AB::Expr = next.decoder[ADDR_COL_IDX].clone().into(); - let addr_for_msg = addr_next - AB::Expr::ONE; - - // Get decoder hasher state (8 elements) - let hasher_state: [AB::Expr; 8] = - core::array::from_fn(|i| local.decoder[HASHER_STATE_RANGE.start + i].clone().into()); - - compute_hasher_rate_message::( - challenges, - transition_label, - addr_for_msg, - AB::Expr::ZERO, - &hasher_state, - ) -} - -/// Computes the END block request message value. -/// -/// Digest occupies message positions 3..6 (after label/addr/node_index). -fn compute_end_request>( - local: &MainTraceRow, - challenges: &Challenges, -) -> AB::ExprEF { - // transition_label = RETURN_HASH_LABEL + 32 = 1 + 32 = 33 - let transition_label: AB::Expr = AB::Expr::from_u16(RETURN_HASH_LABEL as u16 + 32); - - // addr = decoder.addr + (HASH_CYCLE_LEN - 1) = addr + 31 - let addr: AB::Expr = local.decoder[ADDR_COL_IDX].clone().into() - + AB::Expr::from_u16((HASH_CYCLE_LEN - 1) as u16); - - // Get digest from decoder hasher state (first 4 elements) - let digest: [AB::Expr; 4] = - core::array::from_fn(|i| local.decoder[HASHER_STATE_RANGE.start + i].clone().into()); - - compute_hasher_word_message::(challenges, transition_label, addr, AB::Expr::ZERO, &digest) -} - -/// Computes control block request with zeros for hasher state (for DYN/DYNCALL). -fn compute_control_block_request_zeros>( - _local: &MainTraceRow, - next: &MainTraceRow, - challenges: &Challenges, - opcode: u8, -) -> AB::ExprEF { - // transition_label = LINEAR_HASH_LABEL + 16 = 19 - let transition_label: AB::Expr = AB::Expr::from_u16(LINEAR_HASH_LABEL as u16 + 16); - - // addr_next = next row's decoder address - let addr_next: AB::Expr = next.decoder[ADDR_COL_IDX].clone().into(); - - // op_code as domain - let op_code: AB::Expr = AB::Expr::from_u16(opcode as u16); - - // State with zeros for rate lanes, opcode in capacity domain - let state: [AB::Expr; 12] = [ - AB::Expr::ZERO, - AB::Expr::ZERO, - AB::Expr::ZERO, - AB::Expr::ZERO, - AB::Expr::ZERO, - AB::Expr::ZERO, - AB::Expr::ZERO, - AB::Expr::ZERO, - AB::Expr::ZERO, - op_code, // domain at CAPACITY_DOMAIN_IDX = 9 - AB::Expr::ZERO, - AB::Expr::ZERO, - ]; - - compute_hasher_message::(challenges, transition_label, addr_next, AB::Expr::ZERO, &state) -} - -/// Computes the FMP initialization write request. -/// -/// This writes FMP_INIT_VALUE to FMP_ADDR in the new context. -fn compute_fmp_write_request>( - local: &MainTraceRow, - next: &MainTraceRow, - challenges: &Challenges, -) -> AB::ExprEF { - let label: AB::Expr = AB::Expr::from_u16(MEMORY_WRITE_ELEMENT_LABEL as u16); - - // ctx from next row (new execution context) - let ctx: AB::Expr = next.ctx.clone().into(); - let clk: AB::Expr = local.clk.clone().into(); - let addr: AB::Expr = AB::Expr::from(FMP_ADDR); - let element: AB::Expr = AB::Expr::from(FMP_INIT_VALUE); - - challenges.encode([label, ctx, addr, clk, element]) -} - -/// Computes the callee hash read request for DYN/DYNCALL. -/// -/// Reads a word from the address at stack[0] containing the callee hash. -fn compute_dyn_callee_hash_read>( - local: &MainTraceRow, - challenges: &Challenges, -) -> AB::ExprEF { - let label: AB::Expr = AB::Expr::from_u16(MEMORY_READ_WORD_LABEL as u16); - - let ctx: AB::Expr = local.ctx.clone().into(); - let clk: AB::Expr = local.clk.clone().into(); - let addr: AB::Expr = local.stack[0].clone().into(); - - // The callee hash is read into decoder hasher state first half - let w0: AB::Expr = local.decoder[HASHER_STATE_RANGE.start].clone().into(); - let w1: AB::Expr = local.decoder[HASHER_STATE_RANGE.start + 1].clone().into(); - let w2: AB::Expr = local.decoder[HASHER_STATE_RANGE.start + 2].clone().into(); - let w3: AB::Expr = local.decoder[HASHER_STATE_RANGE.start + 3].clone().into(); - - challenges.encode([label, ctx, addr, clk, w0, w1, w2, w3]) -} - -// MPVERIFY/MRUPDATE REQUEST HELPERS -// ================================================================================================ - -/// Computes the MPVERIFY request message value. -/// -/// MPVERIFY sends two messages: -/// 1. Input: node value at RATE1 (indices 4..8) -/// 2. Output: root value at RATE1 (indices 4..8) -fn compute_mpverify_request>( - local: &MainTraceRow, - challenges: &Challenges, -) -> AB::ExprEF { - use crate::trace::decoder::USER_OP_HELPERS_OFFSET; - - let helper_0: AB::Expr = local.decoder[USER_OP_HELPERS_OFFSET].clone().into(); - let merkle_cycle_len: AB::Expr = AB::Expr::from_u16(HASH_CYCLE_LEN as u16); - - // Stack layout: [node_value0..3, node_depth, node_index, root0..3, ...] - let node_value: [AB::Expr; 4] = core::array::from_fn(|i| local.stack[i].clone().into()); - let node_depth: AB::Expr = local.stack[4].clone().into(); - let node_index: AB::Expr = local.stack[5].clone().into(); - let root: [AB::Expr; 4] = core::array::from_fn(|i| local.stack[6 + i].clone().into()); - - let input_label: AB::Expr = AB::Expr::from_u16(MP_VERIFY_LABEL as u16 + 16); - let input_msg = compute_hasher_word_message::( - challenges, - input_label, - helper_0.clone(), - node_index.clone(), - &node_value, - ); - - // addr_next = helper_0 + node_depth * merkle_cycle_len - 1 - let output_addr = helper_0 + node_depth * merkle_cycle_len - AB::Expr::ONE; - let output_label: AB::Expr = AB::Expr::from_u16(RETURN_HASH_LABEL as u16 + 32); - let output_msg = compute_hasher_word_message::( - challenges, - output_label, - output_addr, - AB::Expr::ZERO, - &root, - ); - - input_msg * output_msg -} - -/// Computes the MRUPDATE request message value. -/// -/// MRUPDATE sends four messages: -/// 1. Input old: old node value at RATE0 (positions 0-3 in LE layout) -/// 2. Output old: old root at RATE0 -/// 3. Input new: new node value at RATE0 -/// 4. Output new: new root at RATE0 -fn compute_mrupdate_request>( - local: &MainTraceRow, - next: &MainTraceRow, - challenges: &Challenges, -) -> AB::ExprEF { - use crate::trace::decoder::USER_OP_HELPERS_OFFSET; - - let helper_0: AB::Expr = local.decoder[USER_OP_HELPERS_OFFSET].clone().into(); - let merkle_cycle_len: AB::Expr = AB::Expr::from_u16(HASH_CYCLE_LEN as u16); - let two_merkle_cycles: AB::Expr = merkle_cycle_len.clone() + merkle_cycle_len.clone(); - - // Stack layout: [old_node0..3, depth, index, old_root0..3, new_node0..3, ...] - let old_node: [AB::Expr; 4] = core::array::from_fn(|i| local.stack[i].clone().into()); - let depth: AB::Expr = local.stack[4].clone().into(); - let index: AB::Expr = local.stack[5].clone().into(); - let old_root: [AB::Expr; 4] = core::array::from_fn(|i| local.stack[6 + i].clone().into()); - let new_node: [AB::Expr; 4] = core::array::from_fn(|i| local.stack[10 + i].clone().into()); - // New root is at next.stack[0..4] - let new_root: [AB::Expr; 4] = core::array::from_fn(|i| next.stack[i].clone().into()); - - let input_old_label: AB::Expr = AB::Expr::from_u16(MR_UPDATE_OLD_LABEL as u16 + 16); - let input_old_msg = compute_hasher_word_message::( - challenges, - input_old_label, - helper_0.clone(), - index.clone(), - &old_node, - ); - - let output_old_addr = - helper_0.clone() + depth.clone() * merkle_cycle_len.clone() - AB::Expr::ONE; - let output_old_label: AB::Expr = AB::Expr::from_u16(RETURN_HASH_LABEL as u16 + 32); - let output_old_msg = compute_hasher_word_message::( - challenges, - output_old_label.clone(), - output_old_addr, - AB::Expr::ZERO, - &old_root, - ); - - let input_new_addr = helper_0.clone() + depth.clone() * merkle_cycle_len.clone(); - let input_new_label: AB::Expr = AB::Expr::from_u16(MR_UPDATE_NEW_LABEL as u16 + 16); - let input_new_msg = compute_hasher_word_message::( - challenges, - input_new_label, - input_new_addr, - index, - &new_node, - ); - - let output_new_addr = helper_0 + depth * two_merkle_cycles - AB::Expr::ONE; - let output_new_msg = compute_hasher_word_message::( - challenges, - output_old_label, - output_new_addr, - AB::Expr::ZERO, - &new_root, - ); - - input_old_msg * output_old_msg * input_new_msg * output_new_msg -} - -// TESTS -// ================================================================================================ - -#[cfg(test)] -mod tests { - use crate::{ - Felt, - trace::chiplets::{ - ace::ACE_INIT_LABEL, - bitwise::{BITWISE_AND_LABEL, BITWISE_XOR_LABEL}, - kernel_rom::{KERNEL_PROC_CALL_LABEL, KERNEL_PROC_INIT_LABEL}, - memory::{ - MEMORY_READ_ELEMENT_LABEL, MEMORY_READ_WORD_LABEL, MEMORY_WRITE_ELEMENT_LABEL, - MEMORY_WRITE_WORD_LABEL, - }, - }, - }; - - #[test] - fn test_operation_labels() { - // Verify operation labels match expected values - assert_eq!(BITWISE_AND_LABEL, Felt::new(2)); - assert_eq!(BITWISE_XOR_LABEL, Felt::new(6)); - assert_eq!(MEMORY_WRITE_ELEMENT_LABEL, 4); - assert_eq!(MEMORY_READ_ELEMENT_LABEL, 12); - assert_eq!(MEMORY_WRITE_WORD_LABEL, 20); - assert_eq!(MEMORY_READ_WORD_LABEL, 28); - } - - #[test] - fn test_memory_label_formula() { - // Verify: label = 4 + 8*is_read + 16*is_word - fn label(is_read: u64, is_word: u64) -> u64 { - 4 + 8 * is_read + 16 * is_word - } - - assert_eq!(label(0, 0), MEMORY_WRITE_ELEMENT_LABEL as u64); // 4 - assert_eq!(label(1, 0), MEMORY_READ_ELEMENT_LABEL as u64); // 12 - assert_eq!(label(0, 1), MEMORY_WRITE_WORD_LABEL as u64); // 20 - assert_eq!(label(1, 1), MEMORY_READ_WORD_LABEL as u64); // 28 - } - - #[test] - fn test_ace_label() { - // ACE label: selector = [1, 1, 1, 0], reversed = [0, 1, 1, 1] = 7, +1 = 8 - assert_eq!(ACE_INIT_LABEL, Felt::new(8)); - } - - #[test] - fn test_kernel_rom_labels() { - // Kernel ROM call label: selector = [1, 1, 1, 1, 0 | 0], reversed = [0, 0, 1, 1, 1, 1] = - // 15, +1 = 16 - assert_eq!(KERNEL_PROC_CALL_LABEL, Felt::new(16)); - - // Kernel ROM init label: selector = [1, 1, 1, 1, 0 | 1], reversed = [1, 0, 1, 1, 1, 1] = - // 47, +1 = 48 - assert_eq!(KERNEL_PROC_INIT_LABEL, Felt::new(48)); - } -} diff --git a/air/src/constraints/chiplets/bus/hash_kernel.rs b/air/src/constraints/chiplets/bus/hash_kernel.rs deleted file mode 100644 index 0356fbaa2b..0000000000 --- a/air/src/constraints/chiplets/bus/hash_kernel.rs +++ /dev/null @@ -1,326 +0,0 @@ -//! Hash kernel virtual table bus constraint (`b_hash_kernel`). -//! -//! This module enforces a single running-product column (aux index 5) which aggregates three -//! logically separate tables: -//! -//! 1. **Sibling table** for Merkle root updates (hasher chiplet). -//! 2. **ACE memory reads** (ACE chiplet requests; memory chiplet responses on `b_chiplets`). -//! 3. **Log-precompile transcript** (capacity state transitions for LOGPRECOMPILE). -//! -//! Rows contribute either a request term, a response term, or the identity (when no flag is set). -//! The request/response values use the standard message format: -//! `alpha + sum_i beta^i * element[i]`. - -use miden_core::field::PrimeCharacteristicRing; -use miden_crypto::stark::air::{LiftedAirBuilder, WindowAccess}; - -use crate::{ - Felt, MainTraceRow, - constraints::{ - bus::indices::B_HASH_KERNEL, - chiplets::hasher::{flags, periodic}, - op_flags::OpFlags, - tagging::{ - TagGroup, TaggingAirBuilderExt, ids::TAG_HASH_KERNEL_BUS_BASE, tagged_assert_zero_ext, - }, - }, - trace::{ - CHIPLETS_OFFSET, Challenges, LOG_PRECOMPILE_LABEL, - chiplets::{ - HASHER_NODE_INDEX_COL_IDX, HASHER_SELECTOR_COL_RANGE, HASHER_STATE_COL_RANGE, - NUM_ACE_SELECTORS, - ace::{ - ACE_INSTRUCTION_ID1_OFFSET, ACE_INSTRUCTION_ID2_OFFSET, CLK_IDX, CTX_IDX, - EVAL_OP_IDX, ID_1_IDX, ID_2_IDX, PTR_IDX, SELECTOR_BLOCK_IDX, V_0_0_IDX, V_0_1_IDX, - V_1_0_IDX, V_1_1_IDX, - }, - memory::{MEMORY_READ_ELEMENT_LABEL, MEMORY_READ_WORD_LABEL}, - }, - decoder::USER_OP_HELPERS_OFFSET, - log_precompile::{HELPER_CAP_PREV_RANGE, STACK_CAP_NEXT_RANGE}, - }, -}; - -// CONSTANTS -// ================================================================================================ - -// Column offsets relative to chiplets array. -const S_START: usize = HASHER_SELECTOR_COL_RANGE.start - CHIPLETS_OFFSET; -const H_START: usize = HASHER_STATE_COL_RANGE.start - CHIPLETS_OFFSET; -const IDX_COL: usize = HASHER_NODE_INDEX_COL_IDX - CHIPLETS_OFFSET; - -/// Tag ID and namespace for the hash-kernel (virtual table) bus transition constraint. -const HASH_KERNEL_BUS_ID: usize = TAG_HASH_KERNEL_BUS_BASE; -const HASH_KERNEL_BUS_NAMESPACE: &str = "chiplets.bus.hash_kernel.transition"; -const HASH_KERNEL_BUS_NAMES: [&str; 1] = [HASH_KERNEL_BUS_NAMESPACE; 1]; -const HASH_KERNEL_BUS_TAGS: TagGroup = TagGroup { - base: HASH_KERNEL_BUS_ID, - names: &HASH_KERNEL_BUS_NAMES, -}; - -// ENTRY POINTS -// ================================================================================================ - -/// Enforces the hash kernel virtual table (b_hash_kernel) bus constraint. -/// -/// This constraint combines: -/// 1. Sibling table for Merkle root updates -/// 2. ACE memory read requests -/// 3. Log precompile transcript tracking -pub fn enforce_hash_kernel_constraint( - builder: &mut AB, - local: &MainTraceRow, - next: &MainTraceRow, - op_flags: &OpFlags, - challenges: &Challenges, -) where - AB: TaggingAirBuilderExt, -{ - // ========================================================================= - // AUXILIARY TRACE ACCESS - // ========================================================================= - - let (p_local, p_next) = { - let aux = builder.permutation(); - let aux_local = aux.current_slice(); - let aux_next = aux.next_slice(); - (aux_local[B_HASH_KERNEL], aux_next[B_HASH_KERNEL]) - }; - - let one = AB::Expr::ONE; - let one_ef = AB::ExprEF::ONE; - - // ========================================================================= - // PERIODIC VALUES - // ========================================================================= - - let (cycle_row_0, cycle_row_31) = { - // Clone only the periodic values we need (avoids per-eval `to_vec()` allocation). - let p = builder.periodic_values(); - let cycle_row_0: AB::Expr = p[periodic::P_CYCLE_ROW_0].into(); - let cycle_row_31: AB::Expr = p[periodic::P_CYCLE_ROW_31].into(); - (cycle_row_0, cycle_row_31) - }; - - // ========================================================================= - // COMMON VALUES - // ========================================================================= - - // Hasher chiplet rows have s0 = 0 (chiplet selector). - let chiplet_selector: AB::Expr = local.chiplets[0].clone().into(); - let is_hasher: AB::Expr = one.clone() - chiplet_selector.clone(); - - // Hasher operation selectors (only meaningful within hasher chiplet) - let s0: AB::Expr = local.chiplets[S_START].clone().into(); - let s1: AB::Expr = local.chiplets[S_START + 1].clone().into(); - let s2: AB::Expr = local.chiplets[S_START + 2].clone().into(); - - // Node index for sibling table - let node_index: AB::Expr = local.chiplets[IDX_COL].clone().into(); - let node_index_next: AB::Expr = next.chiplets[IDX_COL].clone().into(); - - // Hasher state for sibling values - let h: [AB::Expr; 12] = core::array::from_fn(|i| local.chiplets[H_START + i].clone().into()); - let h_next: [AB::Expr; 12] = - core::array::from_fn(|i| next.chiplets[H_START + i].clone().into()); - - // ========================================================================= - // SIBLING TABLE FLAGS AND VALUES - // ========================================================================= - - // MU/MUA flags (requests - remove siblings during new path). - let f_mu: AB::Expr = - is_hasher.clone() * flags::f_mu(cycle_row_0.clone(), s0.clone(), s1.clone(), s2.clone()); - let f_mua: AB::Expr = - is_hasher.clone() * flags::f_mua(cycle_row_31.clone(), s0.clone(), s1.clone(), s2.clone()); - - // MV/MVA flags (responses - add siblings during old path). - let f_mv: AB::Expr = - is_hasher.clone() * flags::f_mv(cycle_row_0.clone(), s0.clone(), s1.clone(), s2.clone()); - let f_mva: AB::Expr = is_hasher.clone() * flags::f_mva(cycle_row_31.clone(), s0, s1, s2); - - // Compute sibling values based on bit b (LSB of node index). - // The hasher constraints enforce that b is binary on shift rows. - let b: AB::Expr = node_index.clone() - node_index_next.clone().double(); - let is_b_zero = one.clone() - b.clone(); - let is_b_one = b; - - // Sibling value for current row (uses current hasher state). - // b selects which half of the rate holds the sibling. - let v_sibling_curr = compute_sibling_b0::(challenges, &node_index, &h) * is_b_zero.clone() - + compute_sibling_b1::(challenges, &node_index, &h) * is_b_one.clone(); - - // Sibling value for next row (used by MVA/MUA on the transition row). - let v_sibling_next = compute_sibling_b0::(challenges, &node_index, &h_next) * is_b_zero - + compute_sibling_b1::(challenges, &node_index, &h_next) * is_b_one; - - // ========================================================================= - // ACE MEMORY FLAGS AND VALUES - // ========================================================================= - - // ACE chiplet selector: s0=1, s1=1, s2=1, s3=0 - let s3: AB::Expr = local.chiplets[3].clone().into(); - let chiplet_s1: AB::Expr = local.chiplets[1].clone().into(); - let chiplet_s2: AB::Expr = local.chiplets[2].clone().into(); - - let is_ace_row: AB::Expr = - chiplet_selector.clone() * chiplet_s1.clone() * chiplet_s2.clone() * (one.clone() - s3); - - // Block selector determines read (0) vs eval (1) - let block_selector: AB::Expr = - local.chiplets[NUM_ACE_SELECTORS + SELECTOR_BLOCK_IDX].clone().into(); - - let f_ace_read: AB::Expr = is_ace_row.clone() * (one.clone() - block_selector.clone()); - let f_ace_eval: AB::Expr = is_ace_row * block_selector; - - // ACE columns for memory messages - let ace_clk: AB::Expr = local.chiplets[NUM_ACE_SELECTORS + CLK_IDX].clone().into(); - let ace_ctx: AB::Expr = local.chiplets[NUM_ACE_SELECTORS + CTX_IDX].clone().into(); - let ace_ptr: AB::Expr = local.chiplets[NUM_ACE_SELECTORS + PTR_IDX].clone().into(); - - // Word read value: label + ctx + ptr + clk + 4-lane value. - let v_ace_word = { - let v0_0: AB::Expr = local.chiplets[NUM_ACE_SELECTORS + V_0_0_IDX].clone().into(); - let v0_1: AB::Expr = local.chiplets[NUM_ACE_SELECTORS + V_0_1_IDX].clone().into(); - let v1_0: AB::Expr = local.chiplets[NUM_ACE_SELECTORS + V_1_0_IDX].clone().into(); - let v1_1: AB::Expr = local.chiplets[NUM_ACE_SELECTORS + V_1_1_IDX].clone().into(); - let label: AB::Expr = AB::Expr::from(Felt::from_u8(MEMORY_READ_WORD_LABEL)); - - challenges.encode([ - label, - ace_ctx.clone(), - ace_ptr.clone(), - ace_clk.clone(), - v0_0, - v0_1, - v1_0, - v1_1, - ]) - }; - - // Element read value: label + ctx + ptr + clk + element. - let v_ace_element = { - let id_1: AB::Expr = local.chiplets[NUM_ACE_SELECTORS + ID_1_IDX].clone().into(); - let id_2: AB::Expr = local.chiplets[NUM_ACE_SELECTORS + ID_2_IDX].clone().into(); - let eval_op: AB::Expr = local.chiplets[NUM_ACE_SELECTORS + EVAL_OP_IDX].clone().into(); - - let offset1: AB::Expr = AB::Expr::from(ACE_INSTRUCTION_ID1_OFFSET); - let offset2: AB::Expr = AB::Expr::from(ACE_INSTRUCTION_ID2_OFFSET); - let element = id_1 + id_2 * offset1 + (eval_op + one.clone()) * offset2; - let label: AB::Expr = AB::Expr::from(Felt::from_u8(MEMORY_READ_ELEMENT_LABEL)); - - challenges.encode([label, ace_ctx, ace_ptr, ace_clk, element]) - }; - - // ========================================================================= - // LOG PRECOMPILE FLAGS AND VALUES - // ========================================================================= - - let f_logprecompile: AB::Expr = op_flags.log_precompile(); - - // CAP_PREV from helper registers (provided and constrained by the decoder logic). - let cap_prev: [AB::Expr; 4] = core::array::from_fn(|i| { - local.decoder[USER_OP_HELPERS_OFFSET + HELPER_CAP_PREV_RANGE.start + i] - .clone() - .into() - }); - - // CAP_NEXT from next-row stack. - let cap_next: [AB::Expr; 4] = - core::array::from_fn(|i| next.stack[STACK_CAP_NEXT_RANGE.start + i].clone().into()); - - let log_label: AB::Expr = AB::Expr::from(Felt::from_u8(LOG_PRECOMPILE_LABEL)); - - // CAP_PREV value (request - removed). - let v_cap_prev = challenges.encode([ - log_label.clone(), - cap_prev[0].clone(), - cap_prev[1].clone(), - cap_prev[2].clone(), - cap_prev[3].clone(), - ]); - - // CAP_NEXT value (response - inserted). - let v_cap_next = challenges.encode([ - log_label, - cap_next[0].clone(), - cap_next[1].clone(), - cap_next[2].clone(), - cap_next[3].clone(), - ]); - - // ========================================================================= - // RUNNING PRODUCT CONSTRAINT - // ========================================================================= - - // Include the identity term when no request/response flag is set on a row. - // Flags are mutually exclusive by construction (chiplet selectors + op flags). - let request_flag_sum = f_mu.clone() - + f_mua.clone() - + f_ace_read.clone() - + f_ace_eval.clone() - + f_logprecompile.clone(); - let requests: AB::ExprEF = v_sibling_curr.clone() * f_mu.clone() - + v_sibling_next.clone() * f_mua.clone() - + v_ace_word * f_ace_read - + v_ace_element * f_ace_eval - + v_cap_prev * f_logprecompile.clone() - + (one_ef.clone() - request_flag_sum); - - let response_flag_sum = f_mv.clone() + f_mva.clone() + f_logprecompile.clone(); - let responses: AB::ExprEF = v_sibling_curr * f_mv - + v_sibling_next * f_mva - + v_cap_next * f_logprecompile - + (one_ef - response_flag_sum); - - // Running product constraint: p' * requests = p * responses - let p_local_ef: AB::ExprEF = p_local.into(); - let p_next_ef: AB::ExprEF = p_next.into(); - - let mut idx = 0; - tagged_assert_zero_ext( - builder, - &HASH_KERNEL_BUS_TAGS, - &mut idx, - p_next_ef * requests - p_local_ef * responses, - ); -} - -// INTERNAL HELPERS -// ================================================================================================ - -/// Sibling at h[4..7]: positions [2, 7, 8, 9, 10]. -const SIBLING_B0_LAYOUT: [usize; 5] = [2, 7, 8, 9, 10]; -/// Sibling at h[0..3]: positions [2, 3, 4, 5, 6]. -const SIBLING_B1_LAYOUT: [usize; 5] = [2, 3, 4, 5, 6]; - -fn compute_sibling_b0( - challenges: &Challenges, - node_index: &AB::Expr, - h: &[AB::Expr; 12], -) -> AB::ExprEF -where - AB: LiftedAirBuilder, -{ - challenges.encode_sparse( - SIBLING_B0_LAYOUT, - [node_index.clone(), h[4].clone(), h[5].clone(), h[6].clone(), h[7].clone()], - ) -} - -/// Compute sibling value when b=1 (sibling at h[0..3]). -/// -/// Message layout: alpha[0] (constant) + alpha[3] * node_index + alpha[4..7] * h[0..3]. -fn compute_sibling_b1( - challenges: &Challenges, - node_index: &AB::Expr, - h: &[AB::Expr; 12], -) -> AB::ExprEF -where - AB: LiftedAirBuilder, -{ - challenges.encode_sparse( - SIBLING_B1_LAYOUT, - [node_index.clone(), h[0].clone(), h[1].clone(), h[2].clone(), h[3].clone()], - ) -} diff --git a/air/src/constraints/chiplets/bus/mod.rs b/air/src/constraints/chiplets/bus/mod.rs deleted file mode 100644 index 383362cee1..0000000000 --- a/air/src/constraints/chiplets/bus/mod.rs +++ /dev/null @@ -1,30 +0,0 @@ -//! Chiplets bus constraints. -//! -//! This module groups auxiliary (bus) constraints associated with chiplets. -//! Currently implemented: -//! - b_hash_kernel: hash-kernel virtual table bus -//! - b_chiplets: main chiplets communication bus -//! - b_wiring: ACE wiring bus - -pub mod chiplets; -pub mod hash_kernel; -pub mod wiring; - -use miden_crypto::stark::air::LiftedAirBuilder; - -use crate::{Felt, MainTraceRow, constraints::op_flags::OpFlags, trace::Challenges}; - -/// Enforces chiplets bus constraints. -pub fn enforce_bus( - builder: &mut AB, - local: &MainTraceRow, - next: &MainTraceRow, - op_flags: &OpFlags, - challenges: &Challenges, -) where - AB: LiftedAirBuilder, -{ - hash_kernel::enforce_hash_kernel_constraint(builder, local, next, op_flags, challenges); - chiplets::enforce_chiplets_bus_constraint(builder, local, next, op_flags, challenges); - wiring::enforce_wiring_bus_constraint(builder, local, next, challenges); -} diff --git a/air/src/constraints/chiplets/bus/wiring.rs b/air/src/constraints/chiplets/bus/wiring.rs deleted file mode 100644 index 3ea3ab5564..0000000000 --- a/air/src/constraints/chiplets/bus/wiring.rs +++ /dev/null @@ -1,217 +0,0 @@ -//! ACE wiring bus constraint. -//! -//! This module enforces the running-sum constraint for the ACE wiring bus (v_wiring). -//! The wiring bus verifies the wiring of the arithmetic circuit (which node feeds which gate). -//! It does this by enforcing that every node (id, value) inserted into the ACE DAG is later -//! consumed the claimed number of times, via a LogUp running‑sum relation. -//! -//! ## Wire message format -//! -//! Each wire is encoded as: -//! `alpha + beta^0 * clk + beta^1 * ctx + beta^2 * id + beta^3 * v0 + beta^4 * v1` -//! -//! Where: -//! - clk: memory access clock cycle -//! - ctx: memory access context -//! - id: node identifier -//! - v0, v1: extension field element coefficients -//! -//! ## LogUp protocol -//! -//! **READ blocks (sblock = 0):** -//! - Insert wire_0 with multiplicity m0. -//! - Insert wire_1 with multiplicity m1. -//! -//! **EVAL blocks (sblock = 1):** -//! - Insert wire_0 with multiplicity m0. -//! - Remove wire_1 with multiplicity 1. -//! - Remove wire_2 with multiplicity 1. -//! -//! Boundary constraints for v_wiring are handled by the wrapper AIR (aux_finals). - -use miden_core::field::PrimeCharacteristicRing; -use miden_crypto::stark::air::{LiftedAirBuilder, WindowAccess}; - -use crate::{ - Felt, MainTraceRow, - constraints::{ - bus::indices::V_WIRING, - chiplets::selectors::ace_chiplet_flag, - tagging::{ - TagGroup, TaggingAirBuilderExt, ids::TAG_WIRING_BUS_BASE, tagged_assert_zero_ext, - }, - }, - trace::{ - Challenges, - chiplets::ace::{ - CLK_IDX, CTX_IDX, ID_0_IDX, ID_1_IDX, ID_2_IDX, M_0_IDX, M_1_IDX, SELECTOR_BLOCK_IDX, - V_0_0_IDX, V_0_1_IDX, V_1_0_IDX, V_1_1_IDX, V_2_0_IDX, V_2_1_IDX, - }, - }, -}; - -// CONSTANTS -// ================================================================================================ - -// ACE chiplet offset from CHIPLETS_OFFSET (after s0, s1, s2, s3). -const ACE_OFFSET: usize = 4; - -/// Tag IDs and namespaces for wiring bus constraints. -const WIRING_BUS_BASE_ID: usize = TAG_WIRING_BUS_BASE; -const WIRING_BUS_NAME: &str = "chiplets.bus.wiring.transition"; -const WIRING_BUS_NAMES: [&str; 1] = [WIRING_BUS_NAME; 1]; -const WIRING_BUS_TAGS: TagGroup = TagGroup { - base: WIRING_BUS_BASE_ID, - names: &WIRING_BUS_NAMES, -}; - -// ENTRY POINTS -// ================================================================================================ - -/// Enforces the ACE wiring bus constraint. -pub fn enforce_wiring_bus_constraint( - builder: &mut AB, - local: &MainTraceRow, - _next: &MainTraceRow, - challenges: &Challenges, -) where - AB: TaggingAirBuilderExt, -{ - // --------------------------------------------------------------------- - // Auxiliary trace access. - // --------------------------------------------------------------------- - - let (v_local, v_next) = { - let aux = builder.permutation(); - let aux_local = aux.current_slice(); - let aux_next = aux.next_slice(); - (aux_local[V_WIRING], aux_next[V_WIRING]) - }; - - // --------------------------------------------------------------------- - // Chiplet selectors. - // --------------------------------------------------------------------- - - let s0: AB::Expr = local.chiplets[0].clone().into(); - let s1: AB::Expr = local.chiplets[1].clone().into(); - let s2: AB::Expr = local.chiplets[2].clone().into(); - let s3: AB::Expr = local.chiplets[3].clone().into(); - let ace_flag = ace_chiplet_flag(s0, s1, s2, s3); - - // Block selector: sblock = 0 for READ, sblock = 1 for EVAL. - let sblock: AB::Expr = load_ace_col::(local, SELECTOR_BLOCK_IDX); - let is_eval = sblock.clone(); - let is_read = AB::Expr::ONE - sblock; - - // --------------------------------------------------------------------- - // Load ACE columns. - // --------------------------------------------------------------------- - - let clk: AB::Expr = load_ace_col::(local, CLK_IDX); - let ctx: AB::Expr = load_ace_col::(local, CTX_IDX); - - let wire_0 = load_ace_wire::(local, ID_0_IDX, V_0_0_IDX, V_0_1_IDX); - let wire_1 = load_ace_wire::(local, ID_1_IDX, V_1_0_IDX, V_1_1_IDX); - let wire_2 = load_ace_wire::(local, ID_2_IDX, V_2_0_IDX, V_2_1_IDX); - let m0: AB::Expr = load_ace_col::(local, M_0_IDX); - // On READ rows this column stores m1 (fan-out for wire_1). On EVAL rows it is v2_1, - // but we only use it under the READ gate below. - let m1: AB::Expr = load_ace_col::(local, M_1_IDX); - - // --------------------------------------------------------------------- - // Wire value computation. - // --------------------------------------------------------------------- - - let wire_0: AB::ExprEF = encode_wire::(challenges, &clk, &ctx, &wire_0); - let wire_1: AB::ExprEF = encode_wire::(challenges, &clk, &ctx, &wire_1); - let wire_2: AB::ExprEF = encode_wire::(challenges, &clk, &ctx, &wire_2); - - // --------------------------------------------------------------------- - // Transition constraint. - // --------------------------------------------------------------------- - // - // LogUp definition: - // v' - v = Σ (num_i / den_i) - // - // READ rows: - // v' - v = m0 / wire_0 + m1 / wire_1 - // - // EVAL rows: - // v' - v = m0 / wire_0 - 1 / wire_1 - 1 / wire_2 - // - // Multiply by the common denominator wire_0 * wire_1 * wire_2 to stay in a - // single polynomial form; the READ/EVAL gates select the appropriate RHS. - - let v_local_ef: AB::ExprEF = v_local.into(); - let v_next_ef: AB::ExprEF = v_next.into(); - let delta = v_next_ef.clone() - v_local_ef.clone(); - - // RHS under the common denominator: - // - READ: m0 * w1 * w2 + m1 * w0 * w2 - // - EVAL: m0 * w1 * w2 - w0 * w2 - w0 * w1 - let read_terms = - wire_1.clone() * wire_2.clone() * m0.clone() + wire_0.clone() * wire_2.clone() * m1; - let eval_terms = wire_1.clone() * wire_2.clone() * m0 - - wire_0.clone() * wire_2.clone() - - wire_0.clone() * wire_1.clone(); - - // Gates: non-ACE rows must contribute zero; READ/EVAL are mutually exclusive. - let read_gate = ace_flag.clone() * is_read; - let eval_gate = ace_flag * is_eval; - - let common_den = wire_0.clone() * wire_1.clone() * wire_2.clone(); - let rhs = read_terms * read_gate + eval_terms * eval_gate; - let wiring_constraint = delta * common_den - rhs; - - let mut idx = 0; - tagged_assert_zero_ext(builder, &WIRING_BUS_TAGS, &mut idx, wiring_constraint); -} - -// INTERNAL HELPERS -// ================================================================================================ - -/// ACE wire triplet (id, v0, v1). -struct AceWire { - id: Expr, - v0: Expr, - v1: Expr, -} - -/// Load an ACE wire (id, v0, v1) from the chiplet slice. -fn load_ace_wire( - row: &MainTraceRow, - id_idx: usize, - v0_idx: usize, - v1_idx: usize, -) -> AceWire -where - AB: LiftedAirBuilder, -{ - AceWire { - id: load_ace_col::(row, id_idx), - v0: load_ace_col::(row, v0_idx), - v1: load_ace_col::(row, v1_idx), - } -} - -/// Encode an ACE wire using the wiring-bus challenge vector. -fn encode_wire( - challenges: &Challenges, - clk: &AB::Expr, - ctx: &AB::Expr, - wire: &AceWire, -) -> AB::ExprEF -where - AB: LiftedAirBuilder, -{ - challenges.encode([clk.clone(), ctx.clone(), wire.id.clone(), wire.v0.clone(), wire.v1.clone()]) -} - -/// Load a column from the ACE section of chiplets. -fn load_ace_col(row: &MainTraceRow, ace_col_idx: usize) -> AB::Expr -where - AB: LiftedAirBuilder, -{ - let local_idx = ACE_OFFSET + ace_col_idx; - row.chiplets[local_idx].clone().into() -} diff --git a/air/src/constraints/chiplets/columns.rs b/air/src/constraints/chiplets/columns.rs new file mode 100644 index 0000000000..c0e687f73d --- /dev/null +++ b/air/src/constraints/chiplets/columns.rs @@ -0,0 +1,774 @@ +//! Column structs for all chiplet sub-components and periodic columns. + +use alloc::{vec, vec::Vec}; +use core::{borrow::Borrow, mem::size_of}; + +use miden_core::{Felt, WORD_SIZE, chiplets::hasher::Hasher, field::PrimeCharacteristicRing}; + +use super::super::{columns::indices_arr, ext_field::QuadFeltExpr}; +use crate::trace::chiplets::{ + bitwise::NUM_DECOMP_BITS, + hasher::{CAPACITY_LEN, DIGEST_LEN, HASH_CYCLE_LEN, NUM_SELECTORS, RATE_LEN, STATE_WIDTH}, +}; + +// HELPERS +// ================================================================================================ + +/// Zero-copy cast from a slice to a `#[repr(C)]` chiplet column struct. +pub fn borrow_chiplet(slice: &[T]) -> &S { + let (prefix, cols, suffix) = unsafe { slice.align_to::() }; + debug_assert!(prefix.is_empty() && suffix.is_empty() && cols.len() == 1); + &cols[0] +} + +// PERMUTATION COLUMNS +// ================================================================================================ + +/// Permutation chiplet columns (19 columns), viewed from `chiplets[1..20]`. +/// +/// Logical overlay for permutation segment rows (`s_perm = 1`). The 3 witness columns +/// `w0..w2` share the same physical columns as the controller's `s0/s1/s2` selectors, +/// and `multiplicity` shares the same physical column as the controller's `node_index`. +/// +/// `s_ctrl` (= `chiplets[0]`) and `s_perm` (= `MainCols::s_perm`) are consumed by the chiplet +/// selector system and are NOT part of this overlay. +/// +/// The state holds a Poseidon2 sponge in `[RATE0, RATE1, CAPACITY]` layout. +/// Helper methods `rate0()`, `rate1()`, `capacity()`, and `digest()` provide +/// sub-views into the state array. +/// +/// ## Layout +/// +/// ```text +/// | witnesses[3] | state[12] | extra cols | +/// | | rate0[4] (= digest) | rate1[4] | capacity[4] | | +/// | w0, w1, w2 | h0..h3 | h4..h7 | h8..h11 | m -- -- -- | +/// ``` +#[repr(C)] +pub struct PermutationCols { + /// S-box witness columns (same physical columns as hasher selectors). + pub witnesses: [T; NUM_SELECTORS], + /// Poseidon2 state (12 field elements: 8 rate + 4 capacity). + pub state: [T; STATE_WIDTH], + /// Request multiplicity (same physical column as node_index). + pub multiplicity: T, + /// Physical slots for controller columns mrupdate_id, is_boundary, and direction_bit. + /// These must be zero on permutation rows; access via [`Self::unused_padding()`] only. + _unused: [T; 3], +} + +impl PermutationCols { + /// Returns the rate portion of the state (state[0..8]). + pub fn rate(&self) -> [T; RATE_LEN] { + [ + self.state[0], + self.state[1], + self.state[2], + self.state[3], + self.state[4], + self.state[5], + self.state[6], + self.state[7], + ] + } + + /// Returns the capacity portion of the state (state[8..12]). + pub fn capacity(&self) -> [T; CAPACITY_LEN] { + [self.state[8], self.state[9], self.state[10], self.state[11]] + } + + /// Returns the digest portion of the state (state[0..4]). + pub fn digest(&self) -> [T; DIGEST_LEN] { + [self.state[0], self.state[1], self.state[2], self.state[3]] + } + + /// Returns rate0 (state[0..4]). + pub fn rate0(&self) -> [T; DIGEST_LEN] { + [self.state[0], self.state[1], self.state[2], self.state[3]] + } + + /// Returns rate1 (state[4..8]). + pub fn rate1(&self) -> [T; DIGEST_LEN] { + [self.state[4], self.state[5], self.state[6], self.state[7]] + } + + /// Returns the 3 padding columns (mrupdate_id, is_boundary, direction_bit) that must + /// be zero on permutation rows. + pub fn unused_padding(&self) -> [T; 3] { + self._unused + } +} + +// CONTROLLER COLUMNS +// ================================================================================================ + +/// Controller chiplet columns (19 columns), viewed from `chiplets[1..20]`. +/// +/// Logical overlay for controller rows (`s_ctrl = 1`). `s0` distinguishes input rows +/// (`s0 = 1`) from output/padding rows (`s0 = 0`). The physical layout mirrors +/// [`PermutationCols`], but column names reflect the controller/permutation split. +/// +/// `s_ctrl` (= `chiplets[0]`) and `s_perm` (= `MainCols::s_perm`) are consumed by the chiplet +/// selector system and are NOT part of this overlay. Because the chiplet-level +/// non-hasher selector is only ever a virtual expression (`1 - s_ctrl - s_perm`) and is +/// never a named column or struct field, there is no name collision with the +/// controller-internal `s0` defined here. +/// +/// The state holds a Poseidon2 sponge in `[RATE0, RATE1, CAPACITY]` layout. +/// Helper methods `rate0()`, `rate1()`, `capacity()`, and `digest()` provide +/// sub-views into the state array. +/// +/// ## Layout +/// +/// ```text +/// | s0 s1 s2 | state[12] | extra cols | +/// | | rate0[4] (= digest) | rate1[4] | capacity[4] | | +/// | | h0..h3 | h4..h7 | h8..h11 | i mr bnd dir | +/// ``` +#[repr(C)] +pub struct ControllerCols { + /// Hasher-internal sub-selector: `s0 = 1` on controller input rows, 0 on output/padding. + pub s0: T, + /// Operation sub-selector s1. + pub s1: T, + /// Operation sub-selector s2. + pub s2: T, + /// Poseidon2 state (12 field elements: 8 rate + 4 capacity). + pub state: [T; STATE_WIDTH], + /// Merkle tree node index. + pub node_index: T, + /// Domain separator for sibling table across MRUPDATE ops. + pub mrupdate_id: T, + /// 1 on boundary rows (first input or last output of each permutation). + pub is_boundary: T, + /// Direction bit for Merkle path verification. + pub direction_bit: T, +} + +impl ControllerCols { + /// Returns the rate portion of the state (state[0..8]). + pub fn rate(&self) -> [T; RATE_LEN] { + [ + self.state[0], + self.state[1], + self.state[2], + self.state[3], + self.state[4], + self.state[5], + self.state[6], + self.state[7], + ] + } + + /// Returns the capacity portion of the state (state[8..12]). + pub fn capacity(&self) -> [T; CAPACITY_LEN] { + [self.state[8], self.state[9], self.state[10], self.state[11]] + } + + /// Returns the digest portion of the state (state[0..4]). + pub fn digest(&self) -> [T; DIGEST_LEN] { + [self.state[0], self.state[1], self.state[2], self.state[3]] + } + + /// Returns rate0 (state[0..4]). + pub fn rate0(&self) -> [T; DIGEST_LEN] { + [self.state[0], self.state[1], self.state[2], self.state[3]] + } + + /// Returns rate1 (state[4..8]). + pub fn rate1(&self) -> [T; DIGEST_LEN] { + [self.state[4], self.state[5], self.state[6], self.state[7]] + } + + /// Merkle-update new-path flag: `s0 * s1 * s2`. + /// + /// Active on controller input rows that insert the new Merkle path into the sibling + /// table (request/remove side of the sibling bus). + pub fn f_mu(&self) -> E + where + T: Into, + { + self.s0.into() * self.s1.into() * self.s2.into() + } + + /// Merkle-verify / old-path flag: `s0 * s1 * (1 - s2)`. + /// + /// Active on controller input rows that extract the old Merkle path from the sibling + /// table (response/add side of the sibling bus). + pub fn f_mv(&self) -> E + where + T: Into, + { + self.s0.into() * self.s1.into() * (E::ONE - self.s2.into()) + } +} + +// BITWISE COLUMNS +// ================================================================================================ + +/// Bitwise chiplet columns (13 columns), viewed from `chiplets[2..15]`. +/// +/// Bit decomposition columns (`a_bits`, `b_bits`) are in **little-endian** order: +/// `value = bits[0] + 2*bits[1] + 4*bits[2] + 8*bits[3]`. +#[repr(C)] +pub struct BitwiseCols { + /// Operation flag: 0 = AND, 1 = XOR. + pub op_flag: T, + /// Aggregated input a. + pub a: T, + /// Aggregated input b. + pub b: T, + /// 4-bit decomposition of a. + pub a_bits: [T; NUM_DECOMP_BITS], + /// 4-bit decomposition of b. + pub b_bits: [T; NUM_DECOMP_BITS], + /// Previous aggregated output. + pub prev_output: T, + /// Current aggregated output. + pub output: T, +} + +// MEMORY COLUMNS +// ================================================================================================ + +/// Memory chiplet columns (15 columns), viewed from `chiplets[3..18]`. +/// +/// When reading from a new word address (first access to a context/addr pair), the +/// `values` are initialized to zero. +#[repr(C)] +pub struct MemoryCols { + /// Read/write flag (0 = write, 1 = read). + pub is_read: T, + /// Element/word flag (0 = element, 1 = word). + pub is_word: T, + /// Memory context ID. + pub ctx: T, + /// Word address. + pub word_addr: T, + /// First bit of the address index within the word. + pub idx0: T, + /// Second bit of the address index within the word. + pub idx1: T, + /// Clock cycle of the memory access. + pub clk: T, + /// Values stored at this context/word/clock after the operation. + pub values: [T; WORD_SIZE], + /// Lower 16 bits of delta. + pub d0: T, + /// Upper 16 bits of delta. + pub d1: T, + /// Inverse of delta. + pub d_inv: T, + /// Flag: same context and same word address as previous operation (docs: `f_sca`). + pub is_same_ctx_and_addr: T, +} + +// ACE COLUMNS +// ================================================================================================ + +/// ACE chiplet columns (16 columns), viewed from `chiplets[4..20]`. +/// +/// The ACE (Arithmetic Circuit Evaluator) chiplet evaluates arithmetic circuits over +/// quadratic extension field elements. Each circuit evaluation consists of two phases: +/// +/// 1. **READ** (`s_block=0`): loads wire values from memory into the chiplet. +/// 2. **EVAL** (`s_block=1`): evaluates arithmetic gates on loaded wire values. +/// +/// The first 12 columns are common to both modes. The last 4 (`mode`) are overlaid +/// and reinterpreted depending on `s_block`: +/// +/// ```text +/// mode idx | READ (s_block=0) | EVAL (s_block=1) +/// ---------+------------------------+------------------- +/// 0 | num_eval | id_2 +/// 1 | (unused) | v_2.0 +/// 2 | m_1 (wire-1 mult) | v_2.1 +/// 3 | m_0 (wire-0 mult) | m_0 (wire-0 mult) +/// ``` +/// +/// Use `ace.read()` / `ace.eval()` for typed overlays of the mode columns. +#[repr(C)] +pub struct AceCols { + /// Start-of-circuit flag (1 on the first row of a new circuit evaluation). + pub s_start: T, + /// Block selector: 0 = READ (memory loads), 1 = EVAL (gate evaluation). + pub s_block: T, + /// Memory context for the current circuit evaluation. + pub ctx: T, + /// Memory pointer from which to read the next two wire values or instruction. + pub ptr: T, + /// Clock cycle at which the memory read is performed. + pub clk: T, + /// Arithmetic operation selector (determines which gate to evaluate in EVAL mode). + pub eval_op: T, + /// ID of the first wire (output wire / left operand). + pub id_0: T, + /// Value of the first wire (quadratic extension field element). + pub v_0: QuadFeltExpr, + /// ID of the second wire (first input / left operand). + pub id_1: T, + /// Value of the second wire (quadratic extension field element). + pub v_1: QuadFeltExpr, + /// Mode-dependent columns (interpretation depends on `s_block`; see table above). + mode: [T; 4], +} + +impl AceCols { + /// Returns a READ-mode overlay of the mode-dependent columns. + pub fn read(&self) -> &AceReadCols { + borrow_chiplet(&self.mode) + } + + /// Returns an EVAL-mode overlay of the mode-dependent columns. + pub fn eval(&self) -> &AceEvalCols { + borrow_chiplet(&self.mode) + } +} + +impl AceCols { + /// ACE read flag: `1 - s_block`. + /// + /// Active on ACE rows in READ mode (memory word reads for circuit inputs). + pub fn f_read(&self) -> E + where + T: Into, + { + E::ONE - self.s_block.into() + } + + /// ACE eval flag: `s_block`. + /// + /// Active on ACE rows in EVAL mode (circuit gate evaluation). + pub fn f_eval(&self) -> E + where + T: Into, + { + self.s_block.into() + } +} + +/// READ mode overlay for ACE mode-dependent columns (4 columns). +/// +/// In READ mode, the chiplet loads wire values from memory. The multiplicity columns +/// (`m_0`, `m_1`) track how many times each wire participates in circuit gates, used +/// by the wiring bus to verify correct wire connections. +#[repr(C)] +pub struct AceReadCols { + /// Number of EVAL rows that follow this READ block. + pub num_eval: T, + /// Unused column (padding for layout alignment with EVAL overlay). + pub unused: T, + /// Multiplicity of the second wire (wire 1). + pub m_1: T, + /// Multiplicity of the first wire (wire 0). + pub m_0: T, +} + +/// EVAL mode overlay for ACE mode-dependent columns (4 columns). +/// +/// In EVAL mode, the chiplet evaluates an arithmetic gate on three wires: two inputs +/// (`id_1`, `id_2`) and one output (`id_0`). The third wire's ID and value occupy the +/// same physical columns as `num_eval`/`unused`/`m_1` in READ mode. +#[repr(C)] +pub struct AceEvalCols { + /// ID of the third wire (second input / right operand). + pub id_2: T, + /// Value of the third wire. + pub v_2: QuadFeltExpr, + /// Multiplicity of the first wire (wire 0). + pub m_0: T, +} + +// ACE COLUMN INDEX MAPS +// ================================================================================================ + +/// Compile-time index map for the top-level ACE chiplet columns (16 columns). +#[allow(dead_code)] +pub const ACE_COL_MAP: AceCols = { + assert!(size_of::>() == 16); + unsafe { core::mem::transmute(indices_arr::<{ size_of::>() }>()) } +}; + +/// Compile-time index map for the READ overlay (relative to `mode`). +pub const ACE_READ_COL_MAP: AceReadCols = { + assert!(size_of::>() == 4); + unsafe { core::mem::transmute(indices_arr::<{ size_of::>() }>()) } +}; + +/// Compile-time index map for the EVAL overlay (relative to `mode`). +pub const ACE_EVAL_COL_MAP: AceEvalCols = { + assert!(size_of::>() == 4); + unsafe { core::mem::transmute(indices_arr::<{ size_of::>() }>()) } +}; + +/// Offset of the `mode` array within the ACE chiplet columns. +#[allow(dead_code)] +pub const MODE_OFFSET: usize = ACE_COL_MAP.mode[0]; + +const _: () = { + assert!(size_of::>() == 16); + assert!(size_of::>() == 4); + assert!(size_of::>() == 4); + + // m_0 is at the same position in both overlays. + assert!(ACE_READ_COL_MAP.m_0 == ACE_EVAL_COL_MAP.m_0); + + // READ-only and EVAL-only columns overlap at the expected positions. + assert!(ACE_READ_COL_MAP.num_eval == ACE_EVAL_COL_MAP.id_2); + assert!(ACE_READ_COL_MAP.m_1 == ACE_EVAL_COL_MAP.v_2.1); +}; + +// KERNEL ROM COLUMNS +// ================================================================================================ + +/// Kernel ROM chiplet columns (5 columns), viewed from `chiplets[5..10]`. +#[repr(C)] +pub struct KernelRomCols { + /// Number of SYSCALLs to this procedure (CALL-label multiplicity). + pub multiplicity: T, + /// Kernel procedure root digest. + pub root: [T; WORD_SIZE], +} + +// PERIODIC COLUMNS +// ================================================================================================ + +/// All chiplet periodic columns (20 columns). +/// +/// Aggregates hasher (18 columns) and bitwise (2 columns) periodic values into a single +/// typed view. Use `builder.periodic_values().borrow()` to obtain a `&PeriodicCols<_>`. +#[derive(Clone, Copy)] +#[repr(C)] +pub struct PeriodicCols { + /// Hasher periodic columns (cycle markers, step selectors, round constants). + pub hasher: HasherPeriodicCols, + /// Bitwise periodic columns. + pub bitwise: BitwisePeriodicCols, +} + +/// Hasher chiplet periodic columns (16 columns, period = 16 rows). +/// +/// Provides step-type selectors and Poseidon2 round constants for the hasher chiplet. +/// The hasher operates on a 16-row cycle (15 transitions + 1 boundary row). +/// +/// ## Layout +/// +/// | Index | Name | Description | +/// |-------|----------------|-------------| +/// | 0 | is_init_ext | 1 on row 0 (init linear + first external round) | +/// | 1 | is_ext | 1 on rows 1-3, 12-14 (single external round) | +/// | 2 | is_packed_int | 1 on rows 4-10 (3 packed internal rounds) | +/// | 3 | is_int_ext | 1 on row 11 (int22 + ext5 merged) | +/// | 4-15 | ark[0..12] | Shared round constants | +#[derive(Clone, Copy)] +#[repr(C)] +pub struct HasherPeriodicCols { + /// 1 on row 0 (init linear + first external round). + pub is_init_ext: T, + /// 1 on rows 1-3, 12-14 (single external round). + pub is_ext: T, + /// 1 on rows 4-10 (3 packed internal rounds). + pub is_packed_int: T, + /// 1 on row 11 (int22 + ext5 merged). + pub is_int_ext: T, + /// Shared round constants (12 lanes). Carry external round constants on external + /// rows, and internal round constants in ark[0..2] on packed-internal rows. + pub ark: [T; STATE_WIDTH], +} + +/// Bitwise chiplet periodic columns (2 columns, period = 8 rows). +#[derive(Clone, Copy)] +#[repr(C)] +pub struct BitwisePeriodicCols { + /// Marks first row of 8-row cycle: `[1, 0, 0, 0, 0, 0, 0, 0]`. + pub k_first: T, + /// Marks non-last rows of 8-row cycle: `[1, 1, 1, 1, 1, 1, 1, 0]`. + pub k_transition: T, +} + +// PERIODIC COLUMN GENERATION +// ================================================================================================ + +#[allow(clippy::new_without_default)] +impl HasherPeriodicCols> { + /// Generate periodic columns for the Poseidon2 hasher chiplet. + /// + /// All columns repeat every 16 rows, matching one permutation cycle. + /// + /// The 4 selector columns identify the row type. The 12 ark columns carry either + /// external round constants (on external rows) or internal round constants in + /// `ark[0..2]` (on packed-internal rows). + /// + /// ## 16-Row Schedule + /// + /// ```text + /// Row Transition Selector + /// 0 init + ext1 is_init_ext + /// 1-3 ext2-ext4 is_ext + /// 4-10 3x packed internal is_packed_int + /// 11 int22 + ext5 is_int_ext + /// 12-14 ext6-ext8 is_ext + /// 15 boundary (none) + /// ``` + #[allow(clippy::needless_range_loop)] + pub fn new() -> Self { + // ------------------------------------------------------------------------- + // Selectors + // ------------------------------------------------------------------------- + let mut is_init_ext = vec![Felt::ZERO; HASH_CYCLE_LEN]; + let mut is_ext = vec![Felt::ZERO; HASH_CYCLE_LEN]; + let mut is_packed_int = vec![Felt::ZERO; HASH_CYCLE_LEN]; + let mut is_int_ext = vec![Felt::ZERO; HASH_CYCLE_LEN]; + + is_init_ext[0] = Felt::ONE; + + for r in [1, 2, 3, 12, 13, 14] { + is_ext[r] = Felt::ONE; + } + + for r in 4..=10 { + is_packed_int[r] = Felt::ONE; + } + + is_int_ext[11] = Felt::ONE; + + // ------------------------------------------------------------------------- + // Shared round constants (12 columns) + // ------------------------------------------------------------------------- + // On external rows (0-3, 11-14): hold per-lane external round constants. + // On packed-internal rows (4-10): ark[0..2] hold 3 internal round constants, + // ark[3..12] are zero. + // On boundary (row 15): all zero. + let ark = core::array::from_fn(|lane| { + let mut col = vec![Felt::ZERO; HASH_CYCLE_LEN]; + + // Row 0 (init+ext1): first initial external round constants + col[0] = Hasher::ARK_EXT_INITIAL[0][lane]; + + // Rows 1-3 (ext2, ext3, ext4): remaining initial external round constants + for r in 1..=3 { + col[r] = Hasher::ARK_EXT_INITIAL[r][lane]; + } + + // Rows 4-10 (packed internal): internal constants in lanes 0-2 only + if lane < 3 { + for triple in 0..7_usize { + let row = 4 + triple; + let ark_idx = triple * 3 + lane; + col[row] = Hasher::ARK_INT[ark_idx]; + } + } + + // Row 11 (int22+ext5): terminal external round 0 constants + // (internal constant ARK_INT[21] is hardcoded in the constraint) + col[11] = Hasher::ARK_EXT_TERMINAL[0][lane]; + + // Rows 12-14 (ext6, ext7, ext8): remaining terminal external round constants + for r in 12..=14 { + col[r] = Hasher::ARK_EXT_TERMINAL[r - 11][lane]; + } + + col + }); + + Self { + is_init_ext, + is_ext, + is_packed_int, + is_int_ext, + ark, + } + } +} + +#[allow(clippy::new_without_default)] +impl BitwisePeriodicCols> { + /// Generate periodic columns for the bitwise chiplet. + pub fn new() -> Self { + let k_first = vec![ + Felt::ONE, + Felt::ZERO, + Felt::ZERO, + Felt::ZERO, + Felt::ZERO, + Felt::ZERO, + Felt::ZERO, + Felt::ZERO, + ]; + + let k_transition = vec![ + Felt::ONE, + Felt::ONE, + Felt::ONE, + Felt::ONE, + Felt::ONE, + Felt::ONE, + Felt::ONE, + Felt::ZERO, + ]; + + Self { k_first, k_transition } + } +} + +impl PeriodicCols> { + /// Generate all chiplet periodic columns as a flat `Vec>`. + pub fn periodic_columns() -> Vec> { + let HasherPeriodicCols { + is_init_ext, + is_ext, + is_packed_int, + is_int_ext, + ark: [a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11], + } = HasherPeriodicCols::new(); + + let BitwisePeriodicCols { k_first, k_transition } = BitwisePeriodicCols::new(); + + vec![ + is_init_ext, + is_ext, + is_packed_int, + is_int_ext, + a0, + a1, + a2, + a3, + a4, + a5, + a6, + a7, + a8, + a9, + a10, + a11, + k_first, + k_transition, + ] + } +} + +/// Total number of periodic columns across all chiplets. +pub const NUM_PERIODIC_COLUMNS: usize = size_of::>(); + +impl Borrow> for [T] { + fn borrow(&self) -> &PeriodicCols { + debug_assert_eq!(self.len(), NUM_PERIODIC_COLUMNS); + let (prefix, cols, suffix) = unsafe { self.align_to::>() }; + debug_assert!(prefix.is_empty() && suffix.is_empty() && cols.len() == 1); + &cols[0] + } +} + +const _: () = { + assert!(size_of::>() == 18); + assert!(size_of::>() == 16); + assert!(size_of::>() == 2); + + // PermutationCols and ControllerCols overlay chiplets[1..20] (19 columns, + // excluding s_perm which is consumed by the chiplet selector system). + assert!(size_of::>() == 19); + assert!(size_of::>() == 19); +}; + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn periodic_columns_dimensions() { + let cols = PeriodicCols::periodic_columns(); + assert_eq!(cols.len(), NUM_PERIODIC_COLUMNS); + + let (hasher_cols, bitwise_cols) = cols.split_at(size_of::>()); + for col in hasher_cols { + assert_eq!(col.len(), HASH_CYCLE_LEN); + } + for col in bitwise_cols { + assert_eq!(col.len(), 8); + } + } + + #[test] + fn hasher_step_selectors_are_exclusive() { + let h = HasherPeriodicCols::new(); + for row in 0..HASH_CYCLE_LEN { + let init_ext = h.is_init_ext[row]; + let ext = h.is_ext[row]; + let packed_int = h.is_packed_int[row]; + let int_ext = h.is_int_ext[row]; + + // Each selector is binary. + assert_eq!(init_ext * (init_ext - Felt::ONE), Felt::ZERO); + assert_eq!(ext * (ext - Felt::ONE), Felt::ZERO); + assert_eq!(packed_int * (packed_int - Felt::ONE), Felt::ZERO); + assert_eq!(int_ext * (int_ext - Felt::ONE), Felt::ZERO); + + // At most one selector is active per row. + let sum = init_ext + ext + packed_int + int_ext; + assert!(sum == Felt::ZERO || sum == Felt::ONE, "row {row}: sum = {sum}"); + } + } + + #[test] + fn external_round_constants_correct() { + let h = HasherPeriodicCols::new(); + + // Row 0: ARK_EXT_INITIAL[0] + for lane in 0..STATE_WIDTH { + assert_eq!(h.ark[lane][0], Hasher::ARK_EXT_INITIAL[0][lane]); + } + + // Rows 1-3: ARK_EXT_INITIAL[1..3] + for r in 1..=3 { + for lane in 0..STATE_WIDTH { + assert_eq!(h.ark[lane][r], Hasher::ARK_EXT_INITIAL[r][lane]); + } + } + + // Row 11: ARK_EXT_TERMINAL[0] + for lane in 0..STATE_WIDTH { + assert_eq!(h.ark[lane][11], Hasher::ARK_EXT_TERMINAL[0][lane]); + } + + // Rows 12-14: ARK_EXT_TERMINAL[1..3] + for r in 12..=14 { + for lane in 0..STATE_WIDTH { + assert_eq!(h.ark[lane][r], Hasher::ARK_EXT_TERMINAL[r - 11][lane]); + } + } + } + + #[test] + fn internal_round_constants_correct() { + let h = HasherPeriodicCols::new(); + + // Rows 4-10: packed internal round constants in ark[0..2] + for triple in 0..7_usize { + let row = 4 + triple; + for k in 0..3 { + let ark_idx = triple * 3 + k; + assert_eq!( + h.ark[k][row], + Hasher::ARK_INT[ark_idx], + "mismatch at row {row}, int constant {k} (ARK_INT[{ark_idx}])" + ); + } + // ark[3..12] must be zero on packed-internal rows + for lane in 3..STATE_WIDTH { + assert_eq!( + h.ark[lane][row], + Felt::ZERO, + "ark[{lane}] nonzero at packed-int row {row}" + ); + } + } + } + + #[test] + fn boundary_row_all_zero() { + let h = HasherPeriodicCols::new(); + for (lane, col) in h.ark.iter().enumerate() { + assert_eq!(col[15], Felt::ZERO, "ark column {lane} nonzero at row 15"); + } + } +} diff --git a/air/src/constraints/chiplets/hasher/flags.rs b/air/src/constraints/chiplets/hasher/flags.rs deleted file mode 100644 index 9378912b91..0000000000 --- a/air/src/constraints/chiplets/hasher/flags.rs +++ /dev/null @@ -1,289 +0,0 @@ -//! Hasher chiplet flag computation functions. -//! -//! This module provides functions to compute operation flags for the hasher chiplet. -//! Each flag identifies when a specific operation is active based on selector values -//! and cycle position. -//! -//! ## Unused Flags -//! -//! Some flags are defined but unused (`#[allow(dead_code)]`): -//! -//! - **`f_bp`**: BP (Begin Permutation) needs no special constraints - the round function -//! constraints apply identically regardless of which operation started it. -//! - **`f_hout`, `f_sout`**: The combined `f_out` flag suffices for hasher constraints. -//! -//! ## Selector Encoding -//! -//! The hasher uses 3 selector columns `s[0..2]` to encode operations: -//! -//! | Operation | s0 | s1 | s2 | Cycle Position | Description | -//! |-----------|----|----|----|--------------------|-------------| -//! | BP | 1 | 0 | 0 | row 0 | Begin permutation | -//! | MP | 1 | 0 | 1 | row 0 | Merkle path verify | -//! | MV | 1 | 1 | 0 | row 0 | Merkle verify (old root) | -//! | MU | 1 | 1 | 1 | row 0 | Merkle update (new root) | -//! | ABP | 1 | 0 | 0 | row 31 | Absorb for linear hash | -//! | MPA | 1 | 0 | 1 | row 31 | Merkle path absorb | -//! | MVA | 1 | 1 | 0 | row 31 | Merkle verify absorb | -//! | MUA | 1 | 1 | 1 | row 31 | Merkle update absorb | -//! | HOUT | 0 | 0 | 0 | row 31 | Hash output (digest) | -//! | SOUT | 0 | 0 | 1 | row 31 | State output (full) | -use miden_core::field::PrimeCharacteristicRing; - -// INTERNAL HELPERS -// ================================================================================================ - -// INITIALIZATION FLAGS (row 0 of 32-row cycle) -// ================================================================================================ - -/// BP: Begin Permutation flag `(1,0,0)` on cycle row 0. -/// -/// Initiates single permutation, 2-to-1 hash, or linear hash computation. -/// -/// # Degree -/// - Periodic: 1 (cycle_row_0) -/// - Selectors: 3 (s0 * !s1 * !s2) -/// - Total: 4 -#[inline] -#[allow(dead_code)] -pub fn f_bp(cycle_row_0: E, s0: E, s1: E, s2: E) -> E -where - E: PrimeCharacteristicRing, -{ - cycle_row_0 * s0 * (E::ONE - s1) * (E::ONE - s2) -} - -/// MP: Merkle Path verification flag `(1,0,1)` on cycle row 0. -/// -/// Initiates standard Merkle path verification computation. -/// -/// # Degree -/// - Periodic: 1 (cycle_row_0) -/// - Selectors: 3 (s0 * !s1 * s2) -/// - Total: 4 -#[inline] -pub fn f_mp(cycle_row_0: E, s0: E, s1: E, s2: E) -> E -where - E: PrimeCharacteristicRing, -{ - cycle_row_0 * s0 * (E::ONE - s1) * s2 -} - -/// MV: Merkle Verify (old root) flag `(1,1,0)` on cycle row 0. -/// -/// Begins verification for old leaf value during Merkle root update. -/// -/// # Degree -/// - Periodic: 1 (cycle_row_0) -/// - Selectors: 3 (s0 * s1 * !s2) -/// - Total: 4 -#[inline] -pub fn f_mv(cycle_row_0: E, s0: E, s1: E, s2: E) -> E -where - E: PrimeCharacteristicRing, -{ - cycle_row_0 * s0 * s1 * (E::ONE - s2) -} - -/// MU: Merkle Update (new root) flag `(1,1,1)` on cycle row 0. -/// -/// Starts verification for new leaf value during Merkle root update. -/// -/// # Degree -/// - Periodic: 1 (cycle_row_0) -/// - Selectors: 3 (s0 * s1 * s2) -/// - Total: 4 -#[inline] -pub fn f_mu(cycle_row_0: E, s0: E, s1: E, s2: E) -> E -where - E: PrimeCharacteristicRing, -{ - cycle_row_0 * s0 * s1 * s2 -} - -// ================================================================================================ -// ABSORPTION FLAGS (row 31 of 32-row cycle) -// ================================================================================================ - -/// ABP: Absorb for linear hash flag `(1,0,0)` on cycle row 31. -/// -/// Absorbs next set of elements into hasher state during linear hash computation. -/// -/// # Degree -/// - Periodic: 1 (cycle_row_31) -/// - Selectors: 3 (s0 * !s1 * !s2) -/// - Total: 4 -#[inline] -pub fn f_abp(cycle_row_31: E, s0: E, s1: E, s2: E) -> E -where - E: PrimeCharacteristicRing, -{ - cycle_row_31 * s0 * (E::ONE - s1) * (E::ONE - s2) -} - -/// MPA: Merkle Path Absorb flag `(1,0,1)` on cycle row 31. -/// -/// Absorbs next Merkle path node during standard verification. -/// -/// # Degree -/// - Periodic: 1 (cycle_row_31) -/// - Selectors: 3 (s0 * !s1 * s2) -/// - Total: 4 -#[inline] -pub fn f_mpa(cycle_row_31: E, s0: E, s1: E, s2: E) -> E -where - E: PrimeCharacteristicRing, -{ - cycle_row_31 * s0 * (E::ONE - s1) * s2 -} - -/// MVA: Merkle Verify Absorb flag `(1,1,0)` on cycle row 31. -/// -/// Absorbs next node during "old" leaf verification (Merkle root update). -/// -/// # Degree -/// - Periodic: 1 (cycle_row_31) -/// - Selectors: 3 (s0 * s1 * !s2) -/// - Total: 4 -#[inline] -pub fn f_mva(cycle_row_31: E, s0: E, s1: E, s2: E) -> E -where - E: PrimeCharacteristicRing, -{ - cycle_row_31 * s0 * s1 * (E::ONE - s2) -} - -/// MUA: Merkle Update Absorb flag `(1,1,1)` on cycle row 31. -/// -/// Absorbs next node during "new" leaf verification (Merkle root update). -/// -/// # Degree -/// - Periodic: 1 (cycle_row_31) -/// - Selectors: 3 (s0 * s1 * s2) -/// - Total: 4 -#[inline] -pub fn f_mua(cycle_row_31: E, s0: E, s1: E, s2: E) -> E -where - E: PrimeCharacteristicRing, -{ - cycle_row_31 * s0 * s1 * s2 -} - -// ================================================================================================ -// OUTPUT FLAGS (row 31 of 32-row cycle) -// ================================================================================================ - -/// HOUT: Hash Output flag `(0,0,0)` on cycle row 31. -/// -/// Returns the 4-element hash result (digest). -/// -/// # Degree -/// - Periodic: 1 (cycle_row_31) -/// - Selectors: 3 (!s0 * !s1 * !s2) -/// - Total: 4 -#[inline] -#[allow(dead_code)] -pub fn f_hout(cycle_row_31: E, s0: E, s1: E, s2: E) -> E -where - E: PrimeCharacteristicRing, -{ - cycle_row_31 * (E::ONE - s0) * (E::ONE - s1) * (E::ONE - s2) -} - -/// SOUT: State Output flag `(0,0,1)` on cycle row 31. -/// -/// Returns the entire 12-element hasher state. -/// -/// # Degree -/// - Periodic: 1 (cycle_row_31) -/// - Selectors: 3 (!s0 * !s1 * s2) -/// - Total: 4 -#[inline] -#[allow(dead_code)] -pub fn f_sout(cycle_row_31: E, s0: E, s1: E, s2: E) -> E -where - E: PrimeCharacteristicRing, -{ - cycle_row_31 * (E::ONE - s0) * (E::ONE - s1) * s2 -} - -/// Combined output flag: `f_hout | f_sout` = `(0,0,*)` on cycle row 31. -/// -/// True when any output operation is active (HOUT or SOUT). -/// -/// # Degree -/// - Periodic: 1 (cycle_row_31) -/// - Selectors: 2 (!s0 * !s1) -/// - Total: 3 -#[inline] -pub fn f_out(cycle_row_31: E, s0: E, s1: E) -> E -where - E: PrimeCharacteristicRing, -{ - cycle_row_31 * (E::ONE - s0) * (E::ONE - s1) -} - -/// Lookahead output flag on cycle row 30. -/// -/// True when the *next* row will be an output operation. -/// Used for selector stability constraints. -/// -/// # Degree -/// - Periodic: 1 (cycle_row_30) -/// - Next selectors: 2 (!s0' * !s1') -/// - Total: 3 -#[inline] -pub fn f_out_next(cycle_row_30: E, s0_next: E, s1_next: E) -> E -where - E: PrimeCharacteristicRing, -{ - cycle_row_30 * (E::ONE - s0_next) * (E::ONE - s1_next) -} - -// ================================================================================================ -// COMPOSITE FLAGS -// ================================================================================================ - -/// Merkle operation active flag. -/// -/// True when any Merkle operation (MP, MV, MU, MPA, MVA, MUA) is active. -/// Used for gating index shift constraints. -/// -/// # Degree -/// - Depends on constituent flags, typically 4 -#[inline] -pub fn f_merkle_active(f_mp: E, f_mv: E, f_mu: E, f_mpa: E, f_mva: E, f_mua: E) -> E -where - E: PrimeCharacteristicRing, -{ - f_mp + f_mv + f_mu + f_mpa + f_mva + f_mua -} - -/// Merkle absorb flag (row 31 only). -/// -/// True when absorbing the next node during Merkle path computation. -/// -/// # Degree -/// - Depends on constituent flags, typically 4 -#[inline] -pub fn f_merkle_absorb(f_mpa: E, f_mva: E, f_mua: E) -> E -where - E: PrimeCharacteristicRing, -{ - f_mpa + f_mva + f_mua -} - -/// Continuation flag for hashing operations. -/// -/// True when operation continues to next cycle (ABP, MPA, MVA, MUA). -/// Constrains s0' = 0 to ensure proper sequencing. -/// -/// # Degree -/// - Depends on constituent flags, typically 4 -#[inline] -pub fn f_continuation(f_abp: E, f_mpa: E, f_mva: E, f_mua: E) -> E -where - E: PrimeCharacteristicRing, -{ - f_abp + f_mpa + f_mva + f_mua -} diff --git a/air/src/constraints/chiplets/hasher/merkle.rs b/air/src/constraints/chiplets/hasher/merkle.rs deleted file mode 100644 index 502746a0cd..0000000000 --- a/air/src/constraints/chiplets/hasher/merkle.rs +++ /dev/null @@ -1,219 +0,0 @@ -//! Hasher chiplet Merkle path constraints. -//! -//! This module enforces constraints specific to Merkle tree operations: -//! -//! - **Index shifting**: Node index shifts right by 1 bit at absorb points -//! - **Index stability**: Index unchanged outside of Merkle operations -//! - **Capacity reset**: Capacity lanes reset to zero on Merkle absorb -//! - **Digest placement**: Current digest placed in rate0 or rate1 based on direction bit -//! -//! ## Merkle Operations -//! -//! | Flag | Operation | Description | -//! |------|-----------|-------------| -//! | MP | Merkle Path | Standard path verification | -//! | MV | Merkle Verify | Old root verification (for updates) | -//! | MU | Merkle Update | New root computation (for updates) | -//! | MPA | Merkle Path Absorb | Absorb next sibling (standard) | -//! | MVA | Merkle Verify Absorb | Absorb next sibling (old path) | -//! | MUA | Merkle Update Absorb | Absorb next sibling (new path) | - -use miden_core::field::PrimeCharacteristicRing; - -use super::{HasherColumns, HasherFlags}; -use crate::{ - Felt, - constraints::tagging::{ - TagGroup, TaggingAirBuilderExt, tagged_assert_zero, tagged_assert_zero_integrity, - tagged_assert_zeros, - }, -}; - -// TAGGING NAMESPACES -// ================================================================================================ - -const MERKLE_INDEX_BINARY_NAMESPACE: &str = "chiplets.hasher.merkle.index.binary"; -const MERKLE_INDEX_STABILITY_NAMESPACE: &str = "chiplets.hasher.merkle.index.stability"; -const MERKLE_CAP_NAMESPACE: &str = "chiplets.hasher.merkle.capacity"; -const MERKLE_RATE0_NAMESPACE: &str = "chiplets.hasher.merkle.digest.rate0"; -const MERKLE_RATE1_NAMESPACE: &str = "chiplets.hasher.merkle.digest.rate1"; - -const OUTPUT_INDEX_NAMES: [&str; 1] = [super::OUTPUT_INDEX_NAMESPACE]; -const MERKLE_INDEX_NAMES: [&str; 2] = - [MERKLE_INDEX_BINARY_NAMESPACE, MERKLE_INDEX_STABILITY_NAMESPACE]; -const MERKLE_ABSORB_NAMES: [&str; 12] = [ - MERKLE_CAP_NAMESPACE, - MERKLE_CAP_NAMESPACE, - MERKLE_CAP_NAMESPACE, - MERKLE_CAP_NAMESPACE, - MERKLE_RATE0_NAMESPACE, - MERKLE_RATE0_NAMESPACE, - MERKLE_RATE0_NAMESPACE, - MERKLE_RATE0_NAMESPACE, - MERKLE_RATE1_NAMESPACE, - MERKLE_RATE1_NAMESPACE, - MERKLE_RATE1_NAMESPACE, - MERKLE_RATE1_NAMESPACE, -]; - -const OUTPUT_INDEX_TAGS: TagGroup = TagGroup { - base: super::HASHER_OUTPUT_IDX_ID, - names: &OUTPUT_INDEX_NAMES, -}; -const MERKLE_INDEX_TAGS: TagGroup = TagGroup { - base: super::HASHER_MERKLE_INDEX_BASE_ID, - names: &MERKLE_INDEX_NAMES, -}; -const MERKLE_ABSORB_TAGS: TagGroup = TagGroup { - base: super::HASHER_MERKLE_ABSORB_BASE_ID, - names: &MERKLE_ABSORB_NAMES, -}; - -// CONSTRAINT HELPERS -// ================================================================================================ - -/// Enforces node index constraints for Merkle operations. -/// -/// ## Index Shift Constraint -/// -/// On Merkle start (row 0) and absorb (row 31) operations, the index shifts right by 1 bit: -/// `i' = floor(i/2)`. The discarded bit `b = i - 2*i'` must be binary. -/// -/// This encodes the tree traversal from leaf to root. -/// -/// ## Index Stability Constraint -/// -/// Outside of shift rows (and output rows), the index must remain unchanged. -pub(super) fn enforce_node_index_constraints( - builder: &mut AB, - hasher_flag: AB::Expr, - cols: &HasherColumns, - cols_next: &HasherColumns, - flags: &HasherFlags, -) where - AB: TaggingAirBuilderExt, -{ - let one: AB::Expr = AB::Expr::ONE; - - // ------------------------------------------------------------------------- - // Output Index Constraint - // ------------------------------------------------------------------------- - - // Constraint 1: Index must be 0 on output rows. - let mut idx = 0; - tagged_assert_zero_integrity( - builder, - &OUTPUT_INDEX_TAGS, - &mut idx, - hasher_flag.clone() * flags.f_out.clone() * cols.node_index.clone(), - ); - - // ------------------------------------------------------------------------- - // Index Shift Constraint - // ------------------------------------------------------------------------- - - let f_shift = flags.f_merkle_active(); - let f_out = flags.f_out.clone(); - - // Direction bit: b = i - 2*i' - // This is the bit discarded when shifting index right by 1. - let b = cols.node_index.clone() - AB::Expr::TWO * cols_next.node_index.clone(); - - // Constraint 2: b must be binary when shifting (b^2 - b = 0) - let gate = hasher_flag.clone() * f_shift.clone(); - let mut idx = 0; - tagged_assert_zero(builder, &MERKLE_INDEX_TAGS, &mut idx, gate * (b.square() - b.clone())); - - // ------------------------------------------------------------------------- - // Index Stability Constraint - // ------------------------------------------------------------------------- - - // Constraint 3: Index unchanged when not shifting or outputting - // keep = 1 - f_out - f_shift - let keep = one.clone() - f_out - f_shift; - let gate = hasher_flag.clone() * keep; - tagged_assert_zero( - builder, - &MERKLE_INDEX_TAGS, - &mut idx, - gate * (cols_next.node_index.clone() - cols.node_index.clone()), - ); -} - -/// Enforces state constraints for Merkle absorb operations (MPA/MVA/MUA on row 31). -/// -/// ## Capacity Reset -/// -/// The capacity lanes `h[8..12]` are reset to zero for the next 2-to-1 compression. -/// -/// ## Digest Placement -/// -/// The current digest `h[0..4]` is copied to either rate0 or rate1 based on direction bit `b`: -/// - If `b=0`: digest goes to rate0 (`h'[0..4] = h[0..4]`), sibling to rate1 (witness) -/// - If `b=1`: digest goes to rate1 (`h'[4..8] = h[0..4]`), sibling to rate0 (witness) -pub(super) fn enforce_merkle_absorb_state( - builder: &mut AB, - hasher_flag: AB::Expr, - cols: &HasherColumns, - cols_next: &HasherColumns, - flags: &HasherFlags, -) where - AB: TaggingAirBuilderExt, -{ - let one: AB::Expr = AB::Expr::ONE; - let f_absorb = flags.f_merkle_absorb(); - - let digest = cols.digest(); - let rate0_next = cols_next.rate0(); - let rate1_next = cols_next.rate1(); - let cap_next = cols_next.capacity(); - - // Direction bit: b = i - 2*i' - let b = cols.node_index.clone() - AB::Expr::TWO * cols_next.node_index.clone(); - - // ------------------------------------------------------------------------- - // Capacity Reset Constraint - // ------------------------------------------------------------------------- - - // Constraint 1: Capacity reset to zero (batched). - // Use a combined gate to share `hasher_flag * f_absorb` across all 4 lanes. - let gate_absorb = hasher_flag.clone() * f_absorb.clone(); - let mut idx = 0; - tagged_assert_zeros( - builder, - &MERKLE_ABSORB_TAGS, - &mut idx, - MERKLE_CAP_NAMESPACE, - core::array::from_fn::<_, 4, _>(|i| gate_absorb.clone() * cap_next[i].clone()), - ); - - // ------------------------------------------------------------------------- - // Digest Placement Constraints - // ------------------------------------------------------------------------- - - // Constraint 2: If b=0, digest goes to rate0 (h'[0..4] = h[0..4]) - let f_b0 = f_absorb.clone() * (one.clone() - b.clone()); - let gate_b0 = hasher_flag.clone() * f_b0; - tagged_assert_zeros( - builder, - &MERKLE_ABSORB_TAGS, - &mut idx, - MERKLE_RATE0_NAMESPACE, - core::array::from_fn::<_, 4, _>(|i| { - gate_b0.clone() * (rate0_next[i].clone() - digest[i].clone()) - }), - ); - - // Constraint 3: If b=1, digest goes to rate1 (h'[4..8] = h[0..4]) - let f_b1 = f_absorb * b; - let gate_b1 = hasher_flag * f_b1; - tagged_assert_zeros( - builder, - &MERKLE_ABSORB_TAGS, - &mut idx, - MERKLE_RATE1_NAMESPACE, - core::array::from_fn::<_, 4, _>(|i| { - gate_b1.clone() * (rate1_next[i].clone() - digest[i].clone()) - }), - ); -} diff --git a/air/src/constraints/chiplets/hasher/mod.rs b/air/src/constraints/chiplets/hasher/mod.rs deleted file mode 100644 index e5603e2c15..0000000000 --- a/air/src/constraints/chiplets/hasher/mod.rs +++ /dev/null @@ -1,376 +0,0 @@ -//! Hasher chiplet constraints. -//! -//! This module implements constraints for the hasher chiplet, organized into sub-modules: -//! -//! - [`flags`]: Operation flag computation functions -//! - [`periodic`]: Periodic column definitions (cycle markers, round constants) -//! - [`selectors`]: Selector logic constraints -//! - [`state`]: Permutation state constraints -//! - [`merkle`]: Merkle tree operation constraints -//! -//! ## Hasher Operations -//! -//! The hasher supports: -//! 1. Single permutation of Poseidon2 -//! 2. 2-to-1 hash (merge) -//! 3. Linear hash of n field elements -//! 4. Merkle path verification -//! 5. Merkle root update -//! -//! ## Column Layout (within chiplet, offset by selectors) -//! -//! | Column | Purpose | -//! |----------|---------| -//! | s[0..2] | Selector flags | -//! | h[0..12) | Hasher state (RATE0, RATE1, CAP) | -//! | i | Node index (for Merkle operations) | -//! -//! ## References -//! -//! - [Hasher chiplet design](https://0xmiden.github.io/miden-vm/design/chiplets/hasher.html) - -pub mod flags; -pub mod merkle; -pub mod periodic; -pub mod selectors; -pub mod state; - -use miden_core::field::PrimeCharacteristicRing; -use miden_crypto::stark::air::LiftedAirBuilder; -// Re-export commonly used items -pub use periodic::{STATE_WIDTH, periodic_columns}; - -use crate::{ - Felt, MainTraceRow, - constraints::tagging::{TaggingAirBuilderExt, ids::TAG_CHIPLETS_BASE}, - trace::{ - CHIPLETS_OFFSET, - chiplets::{HASHER_NODE_INDEX_COL_IDX, HASHER_SELECTOR_COL_RANGE, HASHER_STATE_COL_RANGE}, - }, -}; - -// TAGGING IDS -// ================================================================================================ - -/// Base ID for hasher chiplet constraints (next after chiplet selectors). -pub(super) const HASHER_BASE_ID: usize = TAG_CHIPLETS_BASE + 10; -pub(super) const HASHER_PERM_INIT_BASE_ID: usize = HASHER_BASE_ID; -pub(super) const HASHER_PERM_EXT_BASE_ID: usize = HASHER_PERM_INIT_BASE_ID + STATE_WIDTH; -pub(super) const HASHER_PERM_INT_BASE_ID: usize = HASHER_PERM_EXT_BASE_ID + STATE_WIDTH; -pub(super) const HASHER_SELECTOR_BOOL_BASE_ID: usize = HASHER_PERM_INT_BASE_ID + STATE_WIDTH; -pub(super) const HASHER_SELECTOR_CONSIST_BASE_ID: usize = HASHER_SELECTOR_BOOL_BASE_ID + 3; -pub(super) const HASHER_ABP_BASE_ID: usize = HASHER_SELECTOR_CONSIST_BASE_ID + 4; -pub(super) const HASHER_OUTPUT_IDX_ID: usize = HASHER_ABP_BASE_ID + 4; -pub(super) const HASHER_MERKLE_INDEX_BASE_ID: usize = HASHER_OUTPUT_IDX_ID + 1; -pub(super) const HASHER_MERKLE_ABSORB_BASE_ID: usize = HASHER_MERKLE_INDEX_BASE_ID + 2; - -const OUTPUT_INDEX_NAMESPACE: &str = "chiplets.hasher.output.index"; - -/// Precomputed hasher flags derived from selectors and cycle markers. -struct HasherFlags { - pub cycle_row_31: E, - pub f_abp: E, - pub f_mpa: E, - pub f_mva: E, - pub f_mua: E, - pub f_out: E, - pub f_out_next: E, - pub f_mp: E, - pub f_mv: E, - pub f_mu: E, -} - -impl HasherFlags { - #[inline] - fn f_merkle_active(&self) -> E { - flags::f_merkle_active( - self.f_mp.clone(), - self.f_mv.clone(), - self.f_mu.clone(), - self.f_mpa.clone(), - self.f_mva.clone(), - self.f_mua.clone(), - ) - } - - #[inline] - fn f_merkle_absorb(&self) -> E { - flags::f_merkle_absorb(self.f_mpa.clone(), self.f_mva.clone(), self.f_mua.clone()) - } - - #[inline] - fn f_continuation(&self) -> E { - flags::f_continuation( - self.f_abp.clone(), - self.f_mpa.clone(), - self.f_mva.clone(), - self.f_mua.clone(), - ) - } -} - -/// Typed access to hasher chiplet columns. -/// -/// This struct provides named access to hasher columns, eliminating error-prone -/// index arithmetic. Created from a `MainTraceRow` reference. -/// -/// ## Layout -/// - `s0, s1, s2`: Selector columns determining operation type -/// - `state[0..12]`: Poseidon2 state (RATE0[0..4], RATE1[4..8], CAP[8..12]) -/// - `node_index`: Merkle tree node index -pub struct HasherColumns { - /// Selector 0 - pub s0: E, - /// Selector 1 - pub s1: E, - /// Selector 2 - pub s2: E, - /// Full Poseidon2 state (12 elements) - pub state: [E; STATE_WIDTH], - /// Node index for Merkle operations - pub node_index: E, -} - -impl HasherColumns { - /// Extract hasher columns from a main trace row. - pub fn from_row(row: &MainTraceRow) -> Self - where - V: Into + Clone, - { - let s_start = HASHER_SELECTOR_COL_RANGE.start - CHIPLETS_OFFSET; - let h_start = HASHER_STATE_COL_RANGE.start - CHIPLETS_OFFSET; - let idx_col = HASHER_NODE_INDEX_COL_IDX - CHIPLETS_OFFSET; - - HasherColumns { - s0: row.chiplets[s_start].clone().into(), - s1: row.chiplets[s_start + 1].clone().into(), - s2: row.chiplets[s_start + 2].clone().into(), - state: core::array::from_fn(|i| row.chiplets[h_start + i].clone().into()), - node_index: row.chiplets[idx_col].clone().into(), - } - } - - /// Get the digest (first 4 elements of state, same as rate0). - #[inline] - pub fn digest(&self) -> [E; 4] { - core::array::from_fn(|i| self.state[i].clone()) - } - - /// Get rate0 (state[0..4]). - #[inline] - pub fn rate0(&self) -> [E; 4] { - core::array::from_fn(|i| self.state[i].clone()) - } - - /// Get rate1 (state[4..8]). - #[inline] - pub fn rate1(&self) -> [E; 4] { - core::array::from_fn(|i| self.state[4 + i].clone()) - } - - /// Get capacity (state[8..12]). - #[inline] - pub fn capacity(&self) -> [E; 4] { - core::array::from_fn(|i| self.state[8 + i].clone()) - } -} - -struct HasherContext> { - pub cols: HasherColumns, - pub cols_next: HasherColumns, - pub flags: HasherFlags, - pub hasher_flag: AB::Expr, - pub periodic: [AB::PeriodicVar; periodic::NUM_PERIODIC_COLUMNS], -} - -impl HasherContext -where - AB: TaggingAirBuilderExt, -{ - pub fn new( - builder: &mut AB, - local: &MainTraceRow, - next: &MainTraceRow, - ) -> Self { - let periodic: [AB::PeriodicVar; periodic::NUM_PERIODIC_COLUMNS] = { - let periodic = builder.periodic_values(); - debug_assert!( - periodic.len() >= periodic::NUM_PERIODIC_COLUMNS, - "not enough periodic values for hasher constraints" - ); - core::array::from_fn(|i| periodic[i]) - }; - - let hasher_flag: AB::Expr = AB::Expr::ONE - local.chiplets[0].clone().into(); - let cols: HasherColumns = HasherColumns::from_row(local); - let cols_next: HasherColumns = HasherColumns::from_row(next); - let flags = compute_hasher_flags::(&periodic, &cols, &cols_next); - - HasherContext:: { - cols, - cols_next, - flags, - hasher_flag, - periodic, - } - } -} - -// ENTRY POINTS -// ================================================================================================ - -/// Enforce all hasher chiplet constraints. -/// -/// This is the main entry point for hasher constraints, enforcing: -/// 1. Permutation step constraints -/// 2. Selector constraints -/// 3. Boundary constraints -/// 4. Merkle operation constraints -/// -/// ## Chiplet Activation -/// -/// The hasher chiplet is active when `chiplets[0] = 0` (i.e., `!s0` at the chiplet level). -pub fn enforce_hasher_constraints( - builder: &mut AB, - local: &MainTraceRow, - next: &MainTraceRow, -) where - AB: TaggingAirBuilderExt, -{ - let ctx = HasherContext::::new(builder, local, next); - - enforce_permutation(builder, &ctx); - // Enforce selector booleanity using raw vars. - let cols_var: HasherColumns = HasherColumns::::from_row(local); - selectors::enforce_selector_booleanity( - builder, - ctx.hasher_flag.clone(), - cols_var.s0, - cols_var.s1, - cols_var.s2, - ); - enforce_selector_consistency(builder, &ctx); - enforce_abp_capacity(builder, &ctx); - enforce_merkle_constraints(builder, &ctx); -} - -// INTERNAL HELPERS -// ================================================================================================ - -/// Enforce Poseidon2 permutation step constraints. -/// -/// Delegates to [`state::enforce_permutation_steps`] with proper column extraction. -fn enforce_permutation(builder: &mut AB, ctx: &HasherContext) -where - AB: TaggingAirBuilderExt, -{ - // Enforce permutation steps - state::enforce_permutation_steps( - builder, - ctx.hasher_flag.clone(), - &ctx.cols.state, - &ctx.cols_next.state, - &ctx.periodic, - ); -} - -/// Enforce selector consistency constraints. -/// -/// Delegates to [`selectors::enforce_selector_consistency`] with proper column extraction. -fn enforce_selector_consistency(builder: &mut AB, ctx: &HasherContext) -where - AB: TaggingAirBuilderExt, -{ - selectors::enforce_selector_consistency( - builder, - ctx.hasher_flag.clone(), - &ctx.cols, - &ctx.cols_next, - &ctx.flags, - ); -} - -/// Enforce ABP capacity preservation on row 31 of the cycle. -fn enforce_abp_capacity(builder: &mut AB, ctx: &HasherContext) -where - AB: TaggingAirBuilderExt, -{ - state::enforce_abp_capacity_preservation( - builder, - ctx.hasher_flag.clone(), - ctx.flags.f_abp.clone(), - &ctx.cols.capacity(), - &ctx.cols_next.capacity(), - ); -} - -/// Enforce Merkle path constraints. -/// -/// Delegates to [`merkle`] module functions for index and state constraints. -fn enforce_merkle_constraints(builder: &mut AB, ctx: &HasherContext) -where - AB: TaggingAirBuilderExt, -{ - // Node index constraints - merkle::enforce_node_index_constraints( - builder, - ctx.hasher_flag.clone(), - &ctx.cols, - &ctx.cols_next, - &ctx.flags, - ); - - // Merkle absorb state constraints - merkle::enforce_merkle_absorb_state( - builder, - ctx.hasher_flag.clone(), - &ctx.cols, - &ctx.cols_next, - &ctx.flags, - ); -} - -fn compute_hasher_flags( - periodic: &[AB::PeriodicVar], - cols: &HasherColumns, - cols_next: &HasherColumns, -) -> HasherFlags -where - AB: LiftedAirBuilder, -{ - let cycle_row_31: AB::Expr = periodic[periodic::P_CYCLE_ROW_31].into(); - - let cycle_row_0: AB::Expr = periodic[periodic::P_CYCLE_ROW_0].into(); - let cycle_row_30: AB::Expr = periodic[periodic::P_CYCLE_ROW_30].into(); - - let s0 = cols.s0.clone(); - let s1 = cols.s1.clone(); - let s2 = cols.s2.clone(); - let s0_next = cols_next.s0.clone(); - let s1_next = cols_next.s1.clone(); - - let f_mp = flags::f_mp(cycle_row_0.clone(), s0.clone(), s1.clone(), s2.clone()); - let f_mv = flags::f_mv(cycle_row_0.clone(), s0.clone(), s1.clone(), s2.clone()); - let f_mu = flags::f_mu(cycle_row_0.clone(), s0.clone(), s1.clone(), s2.clone()); - - let f_abp = flags::f_abp(cycle_row_31.clone(), s0.clone(), s1.clone(), s2.clone()); - let f_mpa = flags::f_mpa(cycle_row_31.clone(), s0.clone(), s1.clone(), s2.clone()); - let f_mva = flags::f_mva(cycle_row_31.clone(), s0.clone(), s1.clone(), s2.clone()); - let f_mua = flags::f_mua(cycle_row_31.clone(), s0.clone(), s1.clone(), s2.clone()); - - let f_out = flags::f_out(cycle_row_31.clone(), s0, s1.clone()); - let f_out_next = flags::f_out_next(cycle_row_30, s0_next, s1_next); - - HasherFlags { - cycle_row_31, - f_abp, - f_mpa, - f_mva, - f_mua, - f_out, - f_out_next, - f_mp, - f_mv, - f_mu, - } -} diff --git a/air/src/constraints/chiplets/hasher/periodic.rs b/air/src/constraints/chiplets/hasher/periodic.rs deleted file mode 100644 index 207683024a..0000000000 --- a/air/src/constraints/chiplets/hasher/periodic.rs +++ /dev/null @@ -1,197 +0,0 @@ -//! Hasher chiplet periodic columns. -//! -//! This module defines the periodic columns used by the Poseidon2 hasher chiplet. -//! The hasher operates on a 32-row cycle, and periodic columns provide cycle-position -//! markers and round constants. -//! -//! ## Column Layout -//! -//! | Index | Name | Description | -//! |-------|----------------|-------------| -//! | 0 | cycle_row_0 | 1 on first row of cycle, 0 elsewhere | -//! | 1 | cycle_row_30 | 1 on penultimate row (lookahead for output) | -//! | 2 | cycle_row_31 | 1 on final row (boundary/output row) | -//! | 3 | p2_is_external | 1 on external round rows (1-4, 27-30) | -//! | 4 | p2_is_internal | 1 on internal round rows (5-26) | -//! | 5-16 | ark_ext[0..12] | External round constants per lane | -//! | 17 | ark_int | Internal round constant (lane 0 only) | - -use alloc::vec::Vec; - -use miden_core::chiplets::hasher::Hasher; - -use crate::Felt; - -// CONSTANTS -// ================================================================================================ - -/// Length of one hash cycle. -pub const HASH_CYCLE_LEN: usize = 32; - -/// Width of the hasher state. -pub const STATE_WIDTH: usize = 12; - -// Periodic column indices. -pub const P_CYCLE_ROW_0: usize = 0; -pub const P_CYCLE_ROW_30: usize = 1; -pub const P_CYCLE_ROW_31: usize = 2; -pub const P_IS_EXTERNAL: usize = 3; -pub const P_IS_INTERNAL: usize = 4; -pub const P_ARK_EXT_START: usize = 5; -pub const P_ARK_INT: usize = P_ARK_EXT_START + STATE_WIDTH; - -/// Total number of periodic columns for the hasher chiplet. -pub const NUM_PERIODIC_COLUMNS: usize = P_ARK_INT + 1; - -// INTERNAL HELPERS -// ================================================================================================ - -/// Returns periodic columns for the Poseidon2 hasher chiplet. -/// -/// ## Layout -/// -/// All columns repeat every 32 rows, matching one permutation cycle: -/// -/// - **Cycle markers** (`cycle_row_0`, `cycle_row_30`, `cycle_row_31`): Single-one markers for the -/// first row, penultimate row, and final row of a cycle. Row 31 is the boundary/output row where -/// we do **not** enforce a step transition. -/// -/// - **Step selectors** (`p2_is_external`, `p2_is_internal`): Mutually exclusive step selectors: -/// - Rows 1-4 and 27-30 are external rounds (full S-box on all lanes + M_E). -/// - Rows 5-26 are internal rounds (add RC to lane 0, S-box lane 0 only, then M_I). -/// - Row 0 is the initial "linear" step (M_E only) and row 31 is no-op; both selectors are 0. -/// -/// - **External round constants** (`ark_ext_0..11`): Lane-indexed constants, non-zero only on -/// external-round rows (1-4 = initial; 27-30 = terminal). -/// -/// - **Internal round constant** (`ark_int`): Constant for lane 0 only, non-zero on internal rows -/// 5-26. -#[allow(clippy::needless_range_loop)] -pub fn periodic_columns() -> Vec> { - let mut cols: Vec> = Vec::with_capacity(NUM_PERIODIC_COLUMNS); - - // ------------------------------------------------------------------------- - // Cycle markers - // ------------------------------------------------------------------------- - let mut row0 = vec![Felt::ZERO; HASH_CYCLE_LEN]; - let mut row30 = vec![Felt::ZERO; HASH_CYCLE_LEN]; - let mut row31 = vec![Felt::ZERO; HASH_CYCLE_LEN]; - row0[0] = Felt::ONE; - row30[30] = Felt::ONE; - row31[31] = Felt::ONE; - cols.push(row0); - cols.push(row30); - cols.push(row31); - - // ------------------------------------------------------------------------- - // Step-type selectors - // ------------------------------------------------------------------------- - let mut p2_is_external = vec![Felt::ZERO; HASH_CYCLE_LEN]; - let mut p2_is_internal = vec![Felt::ZERO; HASH_CYCLE_LEN]; - - // External rounds: rows 1-4 (initial) and 27-30 (terminal) - for r in 1..=4 { - p2_is_external[r] = Felt::ONE; - } - for r in 27..=30 { - p2_is_external[r] = Felt::ONE; - } - - // Internal rounds: rows 5-26 - for r in 5..=26 { - p2_is_internal[r] = Felt::ONE; - } - - cols.push(p2_is_external); - cols.push(p2_is_internal); - - // ------------------------------------------------------------------------- - // External round constants (12 lanes) - // ------------------------------------------------------------------------- - for lane in 0..STATE_WIDTH { - let mut col = vec![Felt::ZERO; HASH_CYCLE_LEN]; - // Initial external rounds: rows 1-4 - for r in 1..=4 { - col[r] = Hasher::ARK_EXT_INITIAL[r - 1][lane]; - } - // Terminal external rounds: rows 27-30 - for r in 27..=30 { - col[r] = Hasher::ARK_EXT_TERMINAL[r - 27][lane]; - } - cols.push(col); - } - - // ------------------------------------------------------------------------- - // Internal round constant (lane 0 only) - // ------------------------------------------------------------------------- - let mut ark_int = vec![Felt::ZERO; HASH_CYCLE_LEN]; - ark_int[5..=26].copy_from_slice(&Hasher::ARK_INT); - cols.push(ark_int); - - cols -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn periodic_columns_dimensions() { - let cols = periodic_columns(); - assert_eq!(cols.len(), NUM_PERIODIC_COLUMNS); - for col in &cols { - assert_eq!(col.len(), HASH_CYCLE_LEN); - } - } - - #[test] - fn cycle_markers_are_exclusive() { - let cols = periodic_columns(); - for (row_idx, ((row0, row30), row31)) in cols[P_CYCLE_ROW_0] - .iter() - .zip(&cols[P_CYCLE_ROW_30]) - .zip(&cols[P_CYCLE_ROW_31]) - .enumerate() - { - // Booleanity checks - assert_eq!(*row0 * (*row0 - Felt::ONE), Felt::ZERO); - assert_eq!(*row30 * (*row30 - Felt::ONE), Felt::ZERO); - assert_eq!(*row31 * (*row31 - Felt::ONE), Felt::ZERO); - - // Mutual exclusivity (XOR when boolean) - assert_eq!(*row0 * *row30, Felt::ZERO); - assert_eq!(*row0 * *row31, Felt::ZERO); - assert_eq!(*row30 * *row31, Felt::ZERO); - - // Exactness: only the designated rows are 1. - let expected = match row_idx { - 0 | 30 | 31 => Felt::ONE, - _ => Felt::ZERO, - }; - assert_eq!(*row0 + *row30 + *row31, expected); - } - } - - #[test] - fn step_selectors_are_exclusive() { - let cols = periodic_columns(); - for (row_idx, (is_ext, is_int)) in - cols[P_IS_EXTERNAL].iter().zip(&cols[P_IS_INTERNAL]).enumerate() - { - // Booleanity checks - assert_eq!(*is_ext * (*is_ext - Felt::ONE), Felt::ZERO); - assert_eq!(*is_int * (*is_int - Felt::ONE), Felt::ZERO); - - // Mutual exclusivity (XOR when boolean) - assert_eq!(*is_ext * *is_int, Felt::ZERO); - - // Exactness per row - let expected = match row_idx { - 1..=4 | 27..=30 => (Felt::ONE, Felt::ZERO), - 5..=26 => (Felt::ZERO, Felt::ONE), - _ => (Felt::ZERO, Felt::ZERO), - }; - assert_eq!((*is_ext, *is_int), expected); - } - } -} diff --git a/air/src/constraints/chiplets/hasher/selectors.rs b/air/src/constraints/chiplets/hasher/selectors.rs deleted file mode 100644 index 28007998c0..0000000000 --- a/air/src/constraints/chiplets/hasher/selectors.rs +++ /dev/null @@ -1,156 +0,0 @@ -//! Hasher chiplet selector consistency constraints. -//! -//! This module enforces constraints on the selector columns `s[0..2]` that control -//! hasher operation modes. These constraints ensure: -//! -//! 1. **Booleanity**: Selector values are binary (0 or 1) -//! 2. **Stability**: Selectors remain unchanged except at cycle boundaries -//! 3. **Sequencing**: After absorb operations, computation continues properly -//! 4. **Validity**: Invalid selector combinations are rejected -//! -//! ## Selector Encodings on Row 31 -//! -//! | Operation | s0 | s1 | s2 | Description | -//! |-----------|----|----|----|--------------------| -//! | ABP | 1 | 0 | 0 | Absorb for linear hash | -//! | HOUT | 0 | 0 | 0 | Output digest | -//! | SOUT | 0 | 0 | 1 | Output full state | -//! | MPA | 1 | 0 | 1 | Merkle path absorb | -//! | MVA | 1 | 1 | 0 | Merkle verify absorb | -//! | MUA | 1 | 1 | 1 | Merkle update absorb | - -use miden_core::field::PrimeCharacteristicRing; - -use super::{HasherColumns, HasherFlags}; -use crate::{ - Felt, - constraints::tagging::{ - TagGroup, TaggingAirBuilderExt, tagged_assert_zero, tagged_assert_zero_integrity, - tagged_assert_zeros, tagged_assert_zeros_integrity, - }, -}; - -// TAGGING NAMESPACES -// ================================================================================================ - -const SELECTOR_BOOL_NAMESPACE: &str = "chiplets.hasher.selectors.binary"; -const SELECTOR_STABILITY_NAMESPACE: &str = "chiplets.hasher.selectors.stability"; -const SELECTOR_CONT_NAMESPACE: &str = "chiplets.hasher.selectors.continuation"; -const SELECTOR_INVALID_NAMESPACE: &str = "chiplets.hasher.selectors.invalid"; - -const SELECTOR_BOOL_NAMES: [&str; 3] = [SELECTOR_BOOL_NAMESPACE; 3]; -const SELECTOR_CONSIST_NAMES: [&str; 4] = [ - SELECTOR_STABILITY_NAMESPACE, - SELECTOR_STABILITY_NAMESPACE, - SELECTOR_CONT_NAMESPACE, - SELECTOR_INVALID_NAMESPACE, -]; - -const SELECTOR_BOOL_TAGS: TagGroup = TagGroup { - base: super::HASHER_SELECTOR_BOOL_BASE_ID, - names: &SELECTOR_BOOL_NAMES, -}; -const SELECTOR_CONSIST_TAGS: TagGroup = TagGroup { - base: super::HASHER_SELECTOR_CONSIST_BASE_ID, - names: &SELECTOR_CONSIST_NAMES, -}; - -// CONSTRAINT HELPERS -// ================================================================================================ - -/// Enforces selector consistency constraints for the hasher chiplet. -/// -/// ## Constraints -/// -/// 1. **Selector stability**: `s[1]` and `s[2]` must remain unchanged across rows, except: -/// - On output rows (HOUT/SOUT on row 31), where selectors can change for the next cycle. -/// - On lookahead rows (row 30 when next row is output), to prepare output selectors. -/// -/// 2. **Continuation sequencing**: After ABP/MPA/MVA/MUA (absorb operations on row 31), the next -/// cycle must continue hashing, so `s[0]' = 0`. -/// -/// 3. **Invalid combination rejection**: On row 31, if `s[0]=0` then `s[1]` must also be 0. This -/// prevents invalid selector states like `(0,1,0)` or `(0,1,1)`. -pub(super) fn enforce_selector_consistency( - builder: &mut AB, - hasher_flag: AB::Expr, - cols: &HasherColumns, - cols_next: &HasherColumns, - flags: &HasherFlags, -) where - AB: TaggingAirBuilderExt, -{ - let one: AB::Expr = AB::Expr::ONE; - - // ------------------------------------------------------------------------- - // Constraint 1: Selector stability - // ------------------------------------------------------------------------- - // s[1] and s[2] unchanged unless f_out or f_out_next. - // Constraint: (1 - f_out - f_out_next) * (s[i]' - s[i]) = 0 - // Note: f_out and f_out_next are mutually exclusive (row30 vs row31), so no overlap. - let stability_gate = one.clone() - flags.f_out.clone() - flags.f_out_next.clone(); - - // Use a combined gate to share `hasher_flag * stability_gate` across both stability - // constraints. - let gate = hasher_flag.clone() * stability_gate; - let mut idx = 0; - tagged_assert_zeros( - builder, - &SELECTOR_CONSIST_TAGS, - &mut idx, - SELECTOR_STABILITY_NAMESPACE, - [ - gate.clone() * (cols_next.s1.clone() - cols.s1.clone()), - gate * (cols_next.s2.clone() - cols.s2.clone()), - ], - ); - - // Continuation constraint: hasher_flag * flag_cont * s0' = 0. - // (Single constraint, so no batching benefit beyond using `.when(gate)`.) - let gate = hasher_flag.clone() * flags.f_continuation(); - tagged_assert_zero(builder, &SELECTOR_CONSIST_TAGS, &mut idx, gate * cols_next.s0.clone()); - - // ------------------------------------------------------------------------- - // Constraint 3: Invalid selector combinations rejection - // ------------------------------------------------------------------------- - // On row31, if s0 = 0 then s1 must be 0. This prevents (0,1,*) combinations. - // Constraint: row31 * (1 - s0) * s1 = 0 - tagged_assert_zero_integrity( - builder, - &SELECTOR_CONSIST_TAGS, - &mut idx, - hasher_flag - * flags.cycle_row_31.clone() - * (one.clone() - cols.s0.clone()) - * cols.s1.clone(), - ); -} - -/// Enforces that selector columns are binary. -/// -/// This is called from the main permutation constraint with the step gate. -pub fn enforce_selector_booleanity( - builder: &mut AB, - hasher_flag: AB::Expr, - s0: AB::Var, - s1: AB::Var, - s2: AB::Var, -) where - AB: TaggingAirBuilderExt, -{ - let s0: AB::Expr = s0.into(); - let s1: AB::Expr = s1.into(); - let s2: AB::Expr = s2.into(); - let mut idx = 0; - tagged_assert_zeros_integrity( - builder, - &SELECTOR_BOOL_TAGS, - &mut idx, - SELECTOR_BOOL_NAMESPACE, - [ - hasher_flag.clone() * s0.clone() * (s0 - AB::Expr::ONE), - hasher_flag.clone() * s1.clone() * (s1 - AB::Expr::ONE), - hasher_flag * s2.clone() * (s2 - AB::Expr::ONE), - ], - ); -} diff --git a/air/src/constraints/chiplets/hasher/state.rs b/air/src/constraints/chiplets/hasher/state.rs deleted file mode 100644 index 1c924ba516..0000000000 --- a/air/src/constraints/chiplets/hasher/state.rs +++ /dev/null @@ -1,257 +0,0 @@ -//! Hasher chiplet state transition constraints. -//! -//! This module enforces the Poseidon2 permutation constraints for the hasher chiplet. -//! The permutation operates on a 32-row cycle with three types of steps: -//! -//! - **Row 0 (init linear)**: Apply external linear layer M_E only -//! - **Rows 1-4, 27-30 (external)**: Add lane RCs, full S-box^7, then M_E -//! - **Rows 5-26 (internal)**: Add RC to lane 0, S-box lane 0 only, then M_I -//! - **Row 31 (boundary)**: No step constraint (output/absorb row) -//! -//! ## Poseidon2 Parameters -//! -//! - State width: 12 field elements -//! - External rounds: 8 (4 initial + 4 terminal) -//! - Internal rounds: 22 -//! - S-box: x^7 - -use miden_core::{chiplets::hasher::Hasher, field::PrimeCharacteristicRing}; -use miden_crypto::stark::air::LiftedAirBuilder; - -use super::periodic::{ - P_ARK_EXT_START, P_ARK_INT, P_CYCLE_ROW_0, P_IS_EXTERNAL, P_IS_INTERNAL, STATE_WIDTH, -}; -use crate::{ - Felt, - constraints::tagging::{TagGroup, TaggingAirBuilderExt, tagged_assert_zeros}, -}; - -// TAGGING NAMESPACES -// ================================================================================================ - -const PERM_INIT_NAMESPACE: &str = "chiplets.hasher.permutation.init"; -const PERM_EXT_NAMESPACE: &str = "chiplets.hasher.permutation.external"; -const PERM_INT_NAMESPACE: &str = "chiplets.hasher.permutation.internal"; -const ABP_CAP_NAMESPACE: &str = "chiplets.hasher.abp.capacity"; - -const PERM_INIT_NAMES: [&str; STATE_WIDTH] = [PERM_INIT_NAMESPACE; STATE_WIDTH]; -const PERM_EXT_NAMES: [&str; STATE_WIDTH] = [PERM_EXT_NAMESPACE; STATE_WIDTH]; -const PERM_INT_NAMES: [&str; STATE_WIDTH] = [PERM_INT_NAMESPACE; STATE_WIDTH]; -const ABP_CAP_NAMES: [&str; 4] = [ABP_CAP_NAMESPACE; 4]; - -const PERM_INIT_TAGS: TagGroup = TagGroup { - base: super::HASHER_PERM_INIT_BASE_ID, - names: &PERM_INIT_NAMES, -}; -const PERM_EXT_TAGS: TagGroup = TagGroup { - base: super::HASHER_PERM_EXT_BASE_ID, - names: &PERM_EXT_NAMES, -}; -const PERM_INT_TAGS: TagGroup = TagGroup { - base: super::HASHER_PERM_INT_BASE_ID, - names: &PERM_INT_NAMES, -}; -const ABP_CAP_TAGS: TagGroup = TagGroup { - base: super::HASHER_ABP_BASE_ID, - names: &ABP_CAP_NAMES, -}; - -// CONSTRAINT HELPERS -// ================================================================================================ - -/// Enforces Poseidon2 permutation step constraints. -/// -/// ## Step Types -/// -/// 1. **Init linear (row 0)**: `h' = M_E(h)` -/// 2. **External round (rows 1-4, 27-30)**: `h' = M_E(S-box(h + ark_ext))` -/// 3. **Internal round (rows 5-26)**: `h' = M_I(h with lane0 = (h[0] + ark_int)^7)` -/// 4. **Boundary (row 31)**: No constraint -pub fn enforce_permutation_steps( - builder: &mut AB, - hasher_flag: AB::Expr, - h: &[AB::Expr; STATE_WIDTH], - h_next: &[AB::Expr; STATE_WIDTH], - periodic: &[AB::PeriodicVar], -) where - AB: TaggingAirBuilderExt, -{ - // Cycle markers and step selectors - let cycle_row_0: AB::Expr = periodic[P_CYCLE_ROW_0].into(); - let is_external: AB::Expr = periodic[P_IS_EXTERNAL].into(); - let is_internal: AB::Expr = periodic[P_IS_INTERNAL].into(); - let is_init_linear = cycle_row_0.clone(); - - // External round constants - let mut ark_ext = [AB::Expr::ZERO; STATE_WIDTH]; - for lane in 0..STATE_WIDTH { - ark_ext[lane] = periodic[P_ARK_EXT_START + lane].into(); - } - let ark_int: AB::Expr = periodic[P_ARK_INT].into(); - - // ------------------------------------------------------------------------- - // Compute expected next states for each step type - // ------------------------------------------------------------------------- - - // Init linear: h' = M_E(h) - let expected_init = apply_matmul_external::(h); - - // External round: h' = M_E(S-box(h + ark_ext)) - let ext_with_rc: [AB::Expr; STATE_WIDTH] = - core::array::from_fn(|i| h[i].clone() + ark_ext[i].clone()); - let ext_with_sbox: [AB::Expr; STATE_WIDTH] = - core::array::from_fn(|i| ext_with_rc[i].clone().exp_const_u64::<7>()); - let expected_ext = apply_matmul_external::(&ext_with_sbox); - - // Internal round: h' = M_I(h with h[0] = (h[0] + ark_int)^7) - let mut tmp_int = h.clone(); - tmp_int[0] = (tmp_int[0].clone() + ark_int).exp_const_u64::<7>(); - let expected_int = apply_matmul_internal::(&tmp_int); - - // ------------------------------------------------------------------------- - // Enforce step constraints - // ------------------------------------------------------------------------- - - // Use combined gates to share `hasher_flag * step_type` across all lanes. - let gate_init = hasher_flag.clone() * is_init_linear; - let mut idx = 0; - tagged_assert_zeros( - builder, - &PERM_INIT_TAGS, - &mut idx, - PERM_INIT_NAMESPACE, - core::array::from_fn::<_, STATE_WIDTH, _>(|i| { - gate_init.clone() * (h_next[i].clone() - expected_init[i].clone()) - }), - ); - - let gate_ext = hasher_flag.clone() * is_external; - let mut idx = 0; - tagged_assert_zeros( - builder, - &PERM_EXT_TAGS, - &mut idx, - PERM_EXT_NAMESPACE, - core::array::from_fn::<_, STATE_WIDTH, _>(|i| { - gate_ext.clone() * (h_next[i].clone() - expected_ext[i].clone()) - }), - ); - - let gate_int = hasher_flag * is_internal; - let mut idx = 0; - tagged_assert_zeros( - builder, - &PERM_INT_TAGS, - &mut idx, - PERM_INT_NAMESPACE, - core::array::from_fn::<_, STATE_WIDTH, _>(|i| { - gate_int.clone() * (h_next[i].clone() - expected_int[i].clone()) - }), - ); -} - -/// Enforces ABP capacity preservation constraint. -/// -/// When absorbing the next set of elements during linear hash computation (ABP on row 31), -/// the capacity portion `h[8..12]` is preserved unchanged. -pub fn enforce_abp_capacity_preservation( - builder: &mut AB, - hasher_flag: AB::Expr, - f_abp: AB::Expr, - h_cap: &[AB::Expr; 4], - h_cap_next: &[AB::Expr; 4], -) where - AB: TaggingAirBuilderExt, -{ - // Use a combined gate to share `hasher_flag * f_abp` across all 4 lanes. - let gate = hasher_flag * f_abp; - let mut idx = 0; - tagged_assert_zeros( - builder, - &ABP_CAP_TAGS, - &mut idx, - ABP_CAP_NAMESPACE, - core::array::from_fn::<_, 4, _>(|i| { - gate.clone() * (h_cap_next[i].clone() - h_cap[i].clone()) - }), - ); -} - -// ============================================================================= -// LINEAR ALGEBRA HELPERS -// ============================================================================= - -/// Applies the external linear layer M_E to the state. -/// -/// The external layer consists of: -/// 1. Apply M4 to each 4-element block -/// 2. Add cross-block sums to each element -fn apply_matmul_external>( - state: &[AB::Expr; STATE_WIDTH], -) -> [AB::Expr; STATE_WIDTH] { - // Apply M4 to each block - let b0 = - matmul_m4::(&[state[0].clone(), state[1].clone(), state[2].clone(), state[3].clone()]); - let b1 = - matmul_m4::(&[state[4].clone(), state[5].clone(), state[6].clone(), state[7].clone()]); - let b2 = matmul_m4::(&[ - state[8].clone(), - state[9].clone(), - state[10].clone(), - state[11].clone(), - ]); - - // Compute cross-block sums - let stored0 = b0[0].clone() + b1[0].clone() + b2[0].clone(); - let stored1 = b0[1].clone() + b1[1].clone() + b2[1].clone(); - let stored2 = b0[2].clone() + b1[2].clone() + b2[2].clone(); - let stored3 = b0[3].clone() + b1[3].clone() + b2[3].clone(); - - // Add sums to each element - [ - b0[0].clone() + stored0.clone(), - b0[1].clone() + stored1.clone(), - b0[2].clone() + stored2.clone(), - b0[3].clone() + stored3.clone(), - b1[0].clone() + stored0.clone(), - b1[1].clone() + stored1.clone(), - b1[2].clone() + stored2.clone(), - b1[3].clone() + stored3.clone(), - b2[0].clone() + stored0, - b2[1].clone() + stored1, - b2[2].clone() + stored2, - b2[3].clone() + stored3, - ] -} - -/// Applies the 4x4 MDS matrix M4. -fn matmul_m4>(input: &[AB::Expr; 4]) -> [AB::Expr; 4] { - let [a, b, c, d] = input.clone(); - - let t0 = a.clone() + b.clone(); - let t1 = c.clone() + d.clone(); - let t2 = b.clone() + b.clone() + t1.clone(); // 2b + t1 - let t3 = d.clone() + d.clone() + t0.clone(); // 2d + t0 - let t4 = t1.clone().double() + t1.clone().double() + t3.clone(); // 4*t1 + t3 - let t5 = t0.clone().double() + t0.clone().double() + t2.clone(); // 4*t0 + t2 - - let out0 = t3.clone() + t5.clone(); - let out1 = t5; - let out2 = t2 + t4.clone(); - let out3 = t4; - - [out0, out1, out2, out3] -} - -/// Applies the internal linear layer M_I to the state. -/// -/// M_I = I + diag(MAT_DIAG) where all rows share the same sum. -fn apply_matmul_internal>( - state: &[AB::Expr; STATE_WIDTH], -) -> [AB::Expr; STATE_WIDTH] { - // Sum of all state elements - let sum: AB::Expr = state.iter().cloned().reduce(|a, b| a + b).expect("STATE_WIDTH > 0"); - - // result[i] = state[i] * MAT_DIAG[i] + sum - core::array::from_fn(|i| state[i].clone() * AB::Expr::from(Hasher::MAT_DIAG[i]) + sum.clone()) -} diff --git a/air/src/constraints/chiplets/hasher_control/flags.rs b/air/src/constraints/chiplets/hasher_control/flags.rs new file mode 100644 index 0000000000..37b14cbcbd --- /dev/null +++ b/air/src/constraints/chiplets/hasher_control/flags.rs @@ -0,0 +1,145 @@ +//! Semantic row-kind flags for the controller sub-chiplet. +//! +//! [`ControllerFlags`] is a pure naming layer over compositions of the hasher-internal +//! sub-selectors `(s0, s1, s2)` on the current and next rows. Each field gives a +//! meaningful name to a bit-pattern product so constraint code never references +//! raw `cols.s0 / cols.s1 / cols.s2` as ad-hoc gate factors. +//! +//! This struct contains **no** chiplet-level scope (`is_active`, `is_transition`): +//! those live on [`ChipletFlags`] and are combined with these row flags by +//! multiplication at each call site. +//! +//! ## Selector encoding (current row, within controller rows) +//! +//! | s0 | s1 | s2 | Row type | Flag | +//! |----|----|----|----------|------| +//! | 1 | 0 | 0 | Sponge input (LINEAR_HASH / 2-to-1 / HPERM) | `is_sponge_input` | +//! | 1 | 0 | 1 | MP input (Merkle path verify) | `is_merkle_input` | +//! | 1 | 1 | 0 | MV input (old-path Merkle root update) | `is_merkle_input` / `is_mv_input` | +//! | 1 | 1 | 1 | MU input (new-path Merkle root update) | `is_merkle_input` | +//! | 0 | 0 | 0 | HOUT output (return digest) | `is_hout` / `is_output` | +//! | 0 | 0 | 1 | SOUT output (return full state) | `is_sout` / `is_output` | +//! | 0 | 1 | * | Padding (inactive slot) | `is_padding` | +//! +//! On permutation rows (`s_perm = 1`), `s0/s1/s2` hold S-box witnesses, so these +//! flags are don't-care there — constraint code gates them by `ChipletFlags.is_active` +//! (= `s_ctrl`) at the call site. +//! +//! ## Operation semantics +//! +//! - **Sponge** (`is_sponge_input`): LINEAR_HASH (multi-batch span), single 2-to-1 hash, or HPERM. +//! In sponge mode, capacity is set once on the first input and carried through across +//! continuations; in tree mode (Merkle ops), capacity is zeroed at every level. +//! - **MP**: MPVERIFY — read-only Merkle path check. Does not interact with the sibling table. +//! - **MV**: old-path leg of MRUPDATE. Each MV row inserts a sibling into the virtual sibling table +//! via the hash_kernel bus. +//! - **MU**: new-path leg of MRUPDATE. Each MU row removes a sibling from the virtual sibling +//! table. The table balance ensures the same siblings are used for both the old and new paths. + +use miden_core::field::PrimeCharacteristicRing; + +use crate::constraints::{chiplets::columns::ControllerCols, utils::BoolNot}; + +// CONTROLLER FLAGS +// ================================================================================================ + +/// Named compositions of the controller sub-selectors `(s0, s1, s2)` on the current +/// and next rows. +/// +/// Pure row-kind layer — contains no chiplet-level scope. Combine with [`ChipletFlags`]( +/// super::super::selectors::ChipletFlags) at the call site by multiplication. +pub struct ControllerFlags { + // ======================================================================== + // Current row — compositions of cols.{s0, s1, s2} + // ======================================================================== + /// Input row: `s0` (deg 1). Covers all input operations (sponge + Merkle variants). + pub is_input: E, + + /// Output row: `(1-s0)*(1-s1)` (deg 2). Covers HOUT and SOUT. + pub is_output: E, + + /// Padding row: `(1-s0)*s1` (deg 2). Inactive controller slot. + pub is_padding: E, + + /// Sponge input row (LINEAR_HASH / 2-to-1 / HPERM): `s0*(1-s1)*(1-s2)` (deg 3). + pub is_sponge_input: E, + + /// Any Merkle input row (MP/MV/MU): `s0*(s1+s2-s1*s2)` (deg 3). + /// + /// The expression `s1 + s2 - s1*s2` equals `s1 OR s2` for binary inputs. + pub is_merkle_input: E, + + /// HOUT (return digest) output: `(1-s0)*(1-s1)*(1-s2)` (deg 3). + pub is_hout: E, + + /// SOUT (return full state) output: `(1-s0)*(1-s1)*s2` (deg 3). + pub is_sout: E, + + // ======================================================================== + // Next row — compositions of cols_next.{s0, s1, s2} + // ======================================================================== + /// Next row is an output row: `(1-s0')*(1-s1')` (deg 2). + pub is_output_next: E, + + /// Next row is a padding row: `(1-s0')*s1'` (deg 2). + pub is_padding_next: E, + + /// Next row is a sponge input — LINEAR_HASH continuation: `s0'*(1-s1')*(1-s2')` (deg 3). + pub is_sponge_input_next: E, + + /// Next row is any Merkle input (MP/MV/MU): `s0'*(s1'+s2'-s1'*s2')` (deg 3). + pub is_merkle_input_next: E, + + /// Next row is an MV input — old-path MRUPDATE start: `s0'*s1'*(1-s2')` (deg 3). + pub is_mv_input_next: E, +} + +impl ControllerFlags { + /// Build all row-kind flags from the current and next row's sub-selector columns. + pub fn new>(cols: &ControllerCols, cols_next: &ControllerCols) -> Self { + // --- Current row --- + let s0: E = cols.s0.into(); + let s1: E = cols.s1.into(); + let s2: E = cols.s2.into(); + let not_s0 = s0.not(); + let not_s1 = s1.not(); + let not_s2 = s2.not(); + + let is_input = s0.clone(); + let is_output = not_s0.clone() * not_s1.clone(); + let is_padding = not_s0 * s1.clone(); + let is_sponge_input = s0.clone() * not_s1 * not_s2.clone(); + let is_merkle_input = s0 * (s1.clone() + s2.clone() - s1 * s2.clone()); + let is_hout = is_output.clone() * not_s2; + let is_sout = is_output.clone() * s2; + + // --- Next row --- + let s0n: E = cols_next.s0.into(); + let s1n: E = cols_next.s1.into(); + let s2n: E = cols_next.s2.into(); + let not_s0n = s0n.not(); + let not_s1n = s1n.not(); + let not_s2n = s2n.not(); + + let is_output_next = not_s0n.clone() * not_s1n.clone(); + let is_padding_next = not_s0n * s1n.clone(); + let is_sponge_input_next = s0n.clone() * not_s1n * not_s2n.clone(); + let is_merkle_input_next = s0n.clone() * (s1n.clone() + s2n.clone() - s1n.clone() * s2n); + let is_mv_input_next = s0n * s1n * not_s2n; + + Self { + is_input, + is_output, + is_padding, + is_sponge_input, + is_merkle_input, + is_hout, + is_sout, + is_output_next, + is_padding_next, + is_sponge_input_next, + is_merkle_input_next, + is_mv_input_next, + } + } +} diff --git a/air/src/constraints/chiplets/hasher_control/mod.rs b/air/src/constraints/chiplets/hasher_control/mod.rs new file mode 100644 index 0000000000..88be324cb9 --- /dev/null +++ b/air/src/constraints/chiplets/hasher_control/mod.rs @@ -0,0 +1,367 @@ +//! Controller sub-chiplet constraints (dispatch side). +//! +//! The hasher uses a dispatch/compute split architecture: the **controller** (this module) +//! records permutation requests as compact (input, output) row pairs and responds to the +//! chiplets bus; the **permutation** sub-chiplet executes the actual Poseidon2 cycles. +//! A LogUp perm-link bus on the shared `v_wiring` column binds the two regions. +//! +//! The controller is active when `s_ctrl = chiplets[0] = 1`, which covers ALL controller +//! rows (input, output, and padding). +//! +//! ## Sub-modules +//! +//! - [`flags`]: Pure row-kind [`ControllerFlags`](flags::ControllerFlags) — compositions of `(s0, +//! s1, s2)` on current and next rows. Contains no chiplet-level scope; combined with +//! [`ChipletFlags`] at each call site. +//! +//! ## Constraint layout (narrative by operation lifetime) +//! +//! Constraints are organized in the order an operation walks through them: +//! +//! 1. **Trace skeleton** — first-row boundary, selector booleanity, adjacency/stability rules that +//! don't depend on the operation kind. These are the trace-layout invariants. +//! 2. **Operation start** — input is_boundary booleanity and the input→output adjacency law that +//! every operation hits on its first row. +//! 3. **Sponge operations** (LINEAR_HASH / 2-to-1 / HPERM) — input state pinning plus the respan +//! capacity preservation that glues multi-batch spans. +//! 4. **Merkle operations** (MP / MV / MU) — per-level input state, cross-level transitions (index +//! continuity, direction bit propagation, digest routing), and the MRUPDATE domain-separator +//! progression. +//! 5. **Operation end** — output is_boundary booleanity and the HOUT / SOUT return-value +//! constraints. +//! +//! Every constraint takes both a [`ChipletFlags`] (scope: active / transition) and a +//! [`ControllerFlags`] (row-kind: input/output/...), combined by multiplication at each +//! gate site. With one exception — the sub-selector booleanity assertion below — no raw +//! `cols.s0 / cols.s1 / cols.s2` columns are referenced in constraint gates. + +pub mod flags; + +use flags::ControllerFlags; +use miden_core::field::PrimeCharacteristicRing; +use miden_crypto::stark::air::AirBuilder; + +use crate::{ + MainCols, MidenAirBuilder, + constraints::{ + chiplets::{columns::ControllerCols, selectors::ChipletFlags}, + utils::BoolNot, + }, +}; + +// ENTRY POINT +// ================================================================================================ + +/// Enforce all controller sub-chiplet constraints. +/// +/// Receives pre-computed [`ChipletFlags`] from `build_chiplet_selectors`. The `s_ctrl` +/// column (`chiplets[0]`) is never referenced directly by constraint code. +pub fn enforce_controller_constraints( + builder: &mut AB, + local: &MainCols, + next: &MainCols, + chiplet: &ChipletFlags, +) where + AB: MidenAirBuilder, +{ + let cols: &ControllerCols = local.controller(); + let cols_next: &ControllerCols = next.controller(); + + let rows = ControllerFlags::::new(cols, cols_next); + + // ===================================================================== + // 1. TRACE SKELETON + // + // Invariants on the shape of the controller section: where it starts, + // which selectors are binary, what can follow what. These constraints + // don't depend on which hasher operation is running. + // ===================================================================== + + // --- First-row boundary --- + // The first row of the trace must be a controller input row: asserting + // `is_active * is_input = 1` forces both `s_ctrl = 1` and `s0 = 1` because + // the only solution to a product of booleans equaling 1 is all factors = 1. + // NOTE: this assumes the controller is the first chiplet section in the trace. + // The transition rules (s_ctrl → s_ctrl' + s_perm' = 1) and the trace layout + // guarantee this, but a reordering of chiplet sections would require moving + // this constraint. + builder + .when_first_row() + .assert_one(chiplet.is_active.clone() * rows.is_input.clone()); + + // --- Sub-selector booleanity --- + // s0, s1, s2 are binary on all controller rows. On permutation rows, these + // columns hold S-box witnesses and are unconstrained here. + // + // NOTE: these are the only direct references to the raw `s0/s1/s2` columns + // in the controller constraint body — booleanity is inherent to the columns + // themselves and cannot be expressed through a composed row-kind flag. + builder + .when(chiplet.is_active.clone()) + .assert_bools([cols.s0, cols.s1, cols.s2]); + + // --- is_boundary booleanity on all controller rows --- + // `is_boundary = 1` marks the first row of a new operation (sponge start + // or Merkle path level 0); `is_boundary = 0` elsewhere. Hoisted to + // `when(is_active)` because input ∪ output ∪ padding covers every ctrl row + // — padding forces it to 0 (§1 below) and input/output use it as a bit. + builder.when(chiplet.is_active.clone()).assert_bool(cols.is_boundary); + + // --- Output non-adjacency --- + // An output row cannot be followed by another output row. Combined with the + // input→output adjacency law (§2 below), this guarantees strictly alternating + // (input, output) pairs for every operation. + // + // Gated on `is_transition` so `cols_next.*` columns are read only when the + // next row is also a controller row (on perm/s0 rows, `s0/s1/s2` hold + // unrelated data). + // Degree: is_transition(3) * is_output(2) * is_output_next(2) = 7. + builder + .when(chiplet.is_transition.clone()) + .when(rows.is_output.clone()) + .assert_zero(rows.is_output_next.clone()); + + // --- Padding stability --- + // A padding row may only be followed by another padding row (or the first + // permutation row, which ends the controller section). Gating on + // `chiplet.is_transition` = `is_transition * s_ctrl * s_ctrl'` makes the + // constraint vanish on the last padding row when the next row is a permutation + // row (where `cols_next.s0/s1/s2` hold S-box witnesses). + // + // Asserting `is_padding_next = (1-s0')*s1' = 1` forces `s0' = 0` and `s1' = 1`. + // Degree: is_transition(3) * is_padding(2) * is_padding_next(2) = 7. + builder + .when(chiplet.is_transition.clone()) + .when(rows.is_padding.clone()) + .assert_one(rows.is_padding_next.clone()); + + // --- Padding confinement --- + // is_boundary and direction_bit must be zero on padding rows. + builder + .when(chiplet.is_active.clone()) + .when(rows.is_padding.clone()) + .assert_zeros([cols.is_boundary, cols.direction_bit]); + + // ===================================================================== + // 2. OPERATION START + // + // The first row of every operation is a controller input row (s_ctrl = 1, + // s0 = 1). These constraints apply to ANY input row regardless of + // operation kind. + // ===================================================================== + + // --- No input row at the ctrl→perm boundary --- + // An input row cannot be the last controller row. Without this, the + // adjacency rule below (which relies on `s_ctrl'` so that `s0'/s1'` are + // binary on the next row) would have a hole at the ctrl→perm transition. + // `chiplet.is_last = s_ctrl * (1 - s_ctrl')` fires exactly on that boundary. + builder.when(chiplet.is_last.clone()).assert_zero(rows.is_input.clone()); + + // --- No non-final output at the ctrl→perm boundary --- + // Defensive: an output row at the ctrl→perm boundary must be final + // (is_boundary = 1). Without this, a non-final output (is_boundary = 0) + // would expect a continuation input that never comes, since the next row + // belongs to the permutation segment. + // Degree: is_last(2) * is_output(2) * inner(1) = 5. + builder + .when(chiplet.is_last.clone()) + .when(rows.is_output.clone()) + .assert_one(cols.is_boundary); + + // --- Input→output adjacency on ctrl→ctrl transitions --- + // On a ctrl→ctrl transition from an input row, the next row must be an + // output row. `is_transition` carries the `s_ctrl'` factor, so on this + // gate `cols_next.s0/s1` are boolean and `(1 - s0')(1 - s1') = 1` really + // does force both to 0. Combined with the `is_last` guard above, every + // ctrl_input is followed by a ctrl_output. + builder + .when(chiplet.is_transition.clone()) + .when(rows.is_input.clone()) + .assert_one(rows.is_output_next.clone()); + + // ===================================================================== + // 3. SPONGE OPERATIONS (LINEAR_HASH / 2-to-1 / HPERM) + // + // Sponge operations process rate data in (possibly multi-batch) spans. + // Capacity is set once on the first input (is_boundary = 1) and carried + // through RESPAN continuations via the preservation constraint below. + // Sponge operations have no tree position and don't use direction_bit. + // ===================================================================== + + // --- Sponge input state --- + // Sponge operations don't have a Merkle tree position, so `node_index = 0`, + // and they don't use `direction_bit` at all, so it's confined to 0. + builder + .when(chiplet.is_active.clone()) + .when(rows.is_sponge_input.clone()) + .assert_zeros([cols.node_index, cols.direction_bit]); + + // --- Respan capacity preservation --- + // During multi-batch linear hashing (RESPAN), each new batch overwrites the rate + // (h0..h7) but the capacity (h8..h11) must carry over from the previous permutation + // output. Without this, a prover could inject arbitrary capacity values on + // continuation rows, corrupting the sponge state. + // + // `is_sponge_input_next` restricts this to LINEAR_HASH continuations only (Merkle + // ops zero capacity at each level). The `!is_boundary_next` factor restricts to + // continuations (not new operation starts, which set fresh capacity). + // `is_transition` guarantees both rows are controller rows. + // Degree: is_transition(3) * is_sponge_input_next(3) * !is_boundary_next(1) * diff(1) = 8. + { + let is_boundary_next: AB::Expr = cols_next.is_boundary.into(); + let gate = chiplet.is_transition.clone() + * rows.is_sponge_input_next.clone() + * is_boundary_next.not(); + + let cap = cols.capacity(); + let cap_next = cols_next.capacity(); + + let builder = &mut builder.when(gate); + for i in 0..4 { + builder.assert_eq(cap_next[i], cap[i]); + } + } + + // ===================================================================== + // 4. MERKLE OPERATIONS (MP / MV / MU) + // + // Merkle path operations walk a 2-to-1 compression tree from leaf to root. + // Each level is an (input, output) pair: the input holds the current node + // plus the sibling in the correct rate half (selected by direction_bit), + // and the output holds the compressed digest. Between levels, the digest + // routes into the next input's rate half and the index shifts one bit. + // + // See [`flags::ControllerFlags`] for MP / MV / MU operation semantics. + // MV and MU interact with the sibling table via the hash_kernel bus; the + // shared sibling set is domain-separated by `mrupdate_id`. + // ===================================================================== + + // --- Merkle input state --- + // On each Merkle input row: + // - index decomposition: `idx = 2 * idx_next + direction_bit` threads the path bits down one + // level at a time + // - direction_bit is binary (left/right child selector) + // - capacity lanes h[8..12] are zeroed so each 2-to-1 compression starts with a clean sponge + // capacity + // Degree: is_active(1) * is_merkle_input(3) * diff(1) = 5 (on the decomp assert). + { + let gate = chiplet.is_active.clone() * rows.is_merkle_input.clone(); + let builder = &mut builder.when(gate); + + // idx = 2 * idx_next + direction_bit + let node_index_next: AB::Expr = cols_next.node_index.into(); + let idx_expected = node_index_next.double() + cols.direction_bit; + builder.assert_eq(cols.node_index, idx_expected); + + // direction_bit is binary + builder.assert_bool(cols.direction_bit); + + // Capacity lanes h[8..12] must be zero on Merkle input rows. + builder.assert_zeros(cols.capacity()); + } + + // --- Cross-step Merkle index continuity --- + // On non-final output rows, if the next row is a Merkle input, the node + // index must carry over: `idx_next = idx`. (The decomposition constraint + // above shifts the index on the input row itself.) + // + // NOTE: `is_merkle_input_next` is read without an explicit `is_active_next` + // gate. This is safe because `is_active` already scopes the current row to + // the controller section, and the transition rules enforce that the next + // row after a controller row must be either another controller row or a + // permutation row — never a non-hasher row. + // Gate: is_active(1) * is_output(2) * !is_boundary(1) * is_merkle_input_next(3) = 7 + // Constraint degree: gate(7) * diff(1) = 8 + let not_boundary: AB::Expr = cols.is_boundary.into().not(); + builder + .when(chiplet.is_active.clone()) + .when(rows.is_output.clone()) + .when(not_boundary.clone()) + .when(rows.is_merkle_input_next.clone()) + .assert_eq(cols_next.node_index, cols.node_index); + + // --- Direction bit forward propagation + digest routing --- + // + // **Forward propagation.** On non-final output → next-input Merkle boundaries, + // the `direction_bit` on the output must equal the `direction_bit` on the next + // input row. This makes `b_{i+1}` (the next step's direction bit) available on + // the output row so the digest can be routed to the correct rate half. + // + // **Digest routing.** The digest from output_i (in rate0, `h[0..4]`) must + // appear in the correct rate half of input_{i+1}, selected by direction_bit: + // - `direction_bit = 0`: digest goes to rate0 of input_{i+1} (`h_next[j]`) + // - `direction_bit = 1`: digest goes to rate1 of input_{i+1} (`h_next[4+j]`) + // + // Uses the full `is_merkle_input_next = s0' * (s1' + s2' - s1'*s2')` (degree 3) + // so the gate fires exclusively on genuine Merkle input continuations. This + // sits the constraint at exactly the max degree of 9, trading 2 degrees of + // headroom for local soundness: no bus invariant is required to reject + // sponge-mislabeling attacks, because the `s0'` factor already forbids them. + // Gate: is_active(1) * is_output(2) * !is_boundary(1) * is_merkle_input_next(3) = 7 + // Constraint degree: gate(7) * inner(2) = 9 + { + let gate = chiplet.is_active.clone() + * rows.is_output.clone() + * not_boundary + * rows.is_merkle_input_next.clone(); + let builder = &mut builder.when(gate); + + // Forward propagation: direction_bit on output = direction_bit on next input. + builder.assert_eq(cols.direction_bit, cols_next.direction_bit); + + // Digest routing: for each j in 0..4, enforce + // h[j] = b * h_next[4+j] + (1-b) * h_next[j] + // h[j] = h_next[j] + b * (h_next[4+j] - h_next[j]) + // where b = direction_bit on the output row. + let b: AB::Expr = cols.direction_bit.into(); + let rate0_curr = cols.rate0(); + let rate0_next = cols_next.rate0(); + let rate1_next = cols_next.rate1(); + for j in 0..4 { + builder.assert_eq( + rate0_curr[j], + rate0_next[j] + b.clone() * (rate1_next[j] - rate0_next[j]), + ); + } + } + + // --- MRUPDATE domain separator (mrupdate_id progression) --- + // On controller→controller transitions: + // mrupdate_id_next = mrupdate_id + is_mv_input_next * is_boundary_next + // i.e. the domain separator ticks forward exactly when the next row is an + // MV boundary input (the start of an old-path MRUPDATE leg). This separates + // sibling-table entries from different MRUPDATE operations so siblings from + // one update can't be replayed in another. + // Degree: is_transition(3) * (diff + is_mv_input_next(3) * bnd'(1))(4) = 7. + let mrupdate_id: AB::Expr = cols.mrupdate_id.into(); + let mv_start_next = rows.is_mv_input_next * cols_next.is_boundary; + builder + .when(chiplet.is_transition.clone()) + .assert_eq(cols_next.mrupdate_id, mrupdate_id + mv_start_next); + + // ===================================================================== + // 5. OPERATION END + // + // Every operation ends on an output row carrying its return value: HOUT + // returns a 4-element digest, SOUT returns the full 12-element state. + // The final output of an operation has is_boundary = 1; intermediate + // outputs (merkle levels, sponge batch boundaries) have is_boundary = 0. + // ===================================================================== + + // --- HOUT return digest --- + // HOUT output rows return a 4-element digest. They have no tree position + // (`node_index = 0`) and no direction bit (`direction_bit = 0`). + builder + .when(chiplet.is_active.clone()) + .when(rows.is_hout.clone()) + .assert_zeros([cols.node_index, cols.direction_bit]); + + // --- SOUT return full state (final row) --- + // SOUT on the boundary row (final output of an HPERM) has direction_bit = 0. + // Intermediate SOUT rows (non-boundary) are unconstrained here. + builder + .when(chiplet.is_active.clone()) + .when(rows.is_sout) + .when(cols.is_boundary) + .assert_zero(cols.direction_bit); +} diff --git a/air/src/constraints/chiplets/kernel_rom.rs b/air/src/constraints/chiplets/kernel_rom.rs deleted file mode 100644 index b721e9ab3f..0000000000 --- a/air/src/constraints/chiplets/kernel_rom.rs +++ /dev/null @@ -1,178 +0,0 @@ -//! Kernel ROM chiplet constraints. -//! -//! The kernel ROM chiplet exposes the digest table used by kernel (system) calls. -//! This module only enforces shape constraints (binary selectors, digest contiguity, and the -//! start-of-block marker). Validity of syscall selection is enforced by decoder and chiplets' bus. -//! -//! ## Column layout (5 columns within chiplet) -//! -//! | Column | Purpose | -//! |---------|---------------------------------------------------| -//! | sfirst | 1 = first row of digest block, 0 = continuation | -//! | r0-r3 | 4-element kernel procedure digest | -//! -//! ## Operations -//! -//! - **KERNELPROCINIT** (sfirst=1): first row of a digest block (public input digests) -//! - **KERNELPROCCALL** (sfirst=0): continuation rows used by SYSCALL -//! -//! ## Constraints -//! -//! 1. sfirst must be binary -//! 2. Digest contiguity: when sfirst'=0 and s4'=0, digest values stay the same -//! 3. First row: when entering kernel ROM, sfirst' must be 1 - -use miden_core::field::PrimeCharacteristicRing; - -use super::selectors::{ace_chiplet_flag, kernel_rom_chiplet_flag}; -use crate::{ - Felt, MainTraceRow, - constraints::tagging::{ - TagGroup, TaggingAirBuilderExt, tagged_assert_zero, tagged_assert_zero_integrity, - }, -}; - -// CONSTANTS -// ================================================================================================ - -// Kernel ROM chiplet offset from CHIPLETS_OFFSET (after s0, s1, s2, s3, s4). -const KERNEL_ROM_OFFSET: usize = 5; - -// Column indices within the kernel ROM chiplet -const SFIRST_IDX: usize = 0; -const R0_IDX: usize = 1; -const R1_IDX: usize = 2; -const R2_IDX: usize = 3; -const R3_IDX: usize = 4; - -// TAGGING CONSTANTS -// ================================================================================================ - -pub(super) const KERNEL_ROM_BASE_ID: usize = - super::memory::MEMORY_BASE_ID + super::memory::MEMORY_COUNT + super::ace::ACE_COUNT; -const KERNEL_ROM_SFIRST_ID: usize = KERNEL_ROM_BASE_ID; -const KERNEL_ROM_DIGEST_BASE_ID: usize = KERNEL_ROM_BASE_ID + 1; -const KERNEL_ROM_FIRST_ROW_ID: usize = KERNEL_ROM_BASE_ID + 5; - -const KERNEL_ROM_SFIRST_NAMESPACE: &str = "chiplets.kernel_rom.sfirst.binary"; -const KERNEL_ROM_DIGEST_NAMESPACE: &str = "chiplets.kernel_rom.digest.contiguity"; -const KERNEL_ROM_FIRST_ROW_NAMESPACE: &str = "chiplets.kernel_rom.first_row.start"; - -const KERNEL_ROM_SFIRST_NAMES: [&str; 1] = [KERNEL_ROM_SFIRST_NAMESPACE; 1]; -const KERNEL_ROM_DIGEST_NAMES: [&str; 4] = [KERNEL_ROM_DIGEST_NAMESPACE; 4]; -const KERNEL_ROM_FIRST_ROW_NAMES: [&str; 1] = [KERNEL_ROM_FIRST_ROW_NAMESPACE; 1]; - -const KERNEL_ROM_SFIRST_TAGS: TagGroup = TagGroup { - base: KERNEL_ROM_SFIRST_ID, - names: &KERNEL_ROM_SFIRST_NAMES, -}; -const KERNEL_ROM_DIGEST_TAGS: TagGroup = TagGroup { - base: KERNEL_ROM_DIGEST_BASE_ID, - names: &KERNEL_ROM_DIGEST_NAMES, -}; -const KERNEL_ROM_FIRST_ROW_TAGS: TagGroup = TagGroup { - base: KERNEL_ROM_FIRST_ROW_ID, - names: &KERNEL_ROM_FIRST_ROW_NAMES, -}; - -// ENTRY POINTS -// ================================================================================================ - -/// Enforce kernel ROM chiplet constraints. -pub fn enforce_kernel_rom_constraints( - builder: &mut AB, - local: &MainTraceRow, - next: &MainTraceRow, -) where - AB: TaggingAirBuilderExt, -{ - // Chiplet selector columns; kernel ROM rows are selected by (s0..s4). - let s0: AB::Expr = local.chiplets[0].clone().into(); - let s1: AB::Expr = local.chiplets[1].clone().into(); - let s2: AB::Expr = local.chiplets[2].clone().into(); - let s3: AB::Expr = local.chiplets[3].clone().into(); - let s4: AB::Expr = local.chiplets[4].clone().into(); - let s3_next: AB::Expr = next.chiplets[3].clone().into(); - let s4_next: AB::Expr = next.chiplets[4].clone().into(); - - let kernel_rom_flag = - kernel_rom_chiplet_flag(s0.clone(), s1.clone(), s2.clone(), s3.clone(), s4.clone()); - let ace_flag = ace_chiplet_flag(s0.clone(), s1.clone(), s2.clone(), s3.clone()); - - // Load kernel ROM columns (sfirst + 4-word digest). - let sfirst: AB::Expr = load_kernel_rom_col::(local, SFIRST_IDX); - let sfirst_next: AB::Expr = load_kernel_rom_col::(next, SFIRST_IDX); - let r0: AB::Expr = load_kernel_rom_col::(local, R0_IDX); - let r0_next: AB::Expr = load_kernel_rom_col::(next, R0_IDX); - let r1: AB::Expr = load_kernel_rom_col::(local, R1_IDX); - let r1_next: AB::Expr = load_kernel_rom_col::(next, R1_IDX); - let r2: AB::Expr = load_kernel_rom_col::(local, R2_IDX); - let r2_next: AB::Expr = load_kernel_rom_col::(next, R2_IDX); - let r3: AB::Expr = load_kernel_rom_col::(local, R3_IDX); - let r3_next: AB::Expr = load_kernel_rom_col::(next, R3_IDX); - - let one: AB::Expr = AB::Expr::ONE; - - // Gate transition constraints by is_transition() to avoid last-row access. - // ========================================================================== - // SELECTOR CONSTRAINT - // ========================================================================== - - // sfirst must be binary - let mut idx = 0; - tagged_assert_zero_integrity( - builder, - &KERNEL_ROM_SFIRST_TAGS, - &mut idx, - kernel_rom_flag.clone() * sfirst.clone() * (sfirst.clone() - one.clone()), - ); - - // ========================================================================== - // DIGEST CONTIGUITY CONSTRAINTS - // ========================================================================== - - // When sfirst' = 0 (not the start of a new digest block) and s4' = 0 (not exiting kernel ROM), - // the digest values must remain unchanged. - let not_exiting = one.clone() - s4_next.clone(); - let not_new_block = one.clone() - sfirst_next.clone(); - let contiguity_condition = not_exiting * not_new_block; - - // Use a combined gate to share `kernel_rom_flag * contiguity_condition` across all 4 lanes. - let gate = kernel_rom_flag * contiguity_condition; - let mut idx = 0; - tagged_assert_zero(builder, &KERNEL_ROM_DIGEST_TAGS, &mut idx, gate.clone() * (r0_next - r0)); - tagged_assert_zero(builder, &KERNEL_ROM_DIGEST_TAGS, &mut idx, gate.clone() * (r1_next - r1)); - tagged_assert_zero(builder, &KERNEL_ROM_DIGEST_TAGS, &mut idx, gate.clone() * (r2_next - r2)); - tagged_assert_zero(builder, &KERNEL_ROM_DIGEST_TAGS, &mut idx, gate * (r3_next - r3)); - - // ========================================================================== - // FIRST ROW CONSTRAINT - // ========================================================================== - - // s0..s2 are stable once 1 (selector constraints), so ACE -> kernel ROM transition is - // determined by s3' = 1 and s4' = 0. - let kernel_rom_next = s3_next * (one.clone() - s4_next.clone()); - let flag_next_row_first_kernel_rom = ace_flag * kernel_rom_next; - - // First row of kernel ROM must have sfirst' = 1. - let mut idx = 0; - tagged_assert_zero( - builder, - &KERNEL_ROM_FIRST_ROW_TAGS, - &mut idx, - flag_next_row_first_kernel_rom * (sfirst_next - one), - ); -} - -// INTERNAL HELPERS -// ================================================================================================ - -/// Load a column from the kernel ROM section of chiplets. -fn load_kernel_rom_col(row: &MainTraceRow, col_idx: usize) -> AB::Expr -where - AB: TaggingAirBuilderExt, -{ - // Kernel ROM columns start after s0, s1, s2, s3, s4 (5 selectors) - let local_idx = KERNEL_ROM_OFFSET + col_idx; - row.chiplets[local_idx].clone().into() -} diff --git a/air/src/constraints/chiplets/memory.rs b/air/src/constraints/chiplets/memory.rs index 2aa0472357..64fecf2eec 100644 --- a/air/src/constraints/chiplets/memory.rs +++ b/air/src/constraints/chiplets/memory.rs @@ -14,623 +14,225 @@ //! | idx0, idx1 | Element index bits (0-3) | //! | clk | Clock cycle of operation | //! | v0-v3 | Memory word values | -//! | d0, d1 | Delta tracking columns | -//! | d_inv | Delta inverse | -//! | f_scw | Same context/word flag | +//! | d0, d1 | Lower/upper 16 bits of the active delta | +//! | d_inv | Inverse of the active delta (docs: column `t`) | +//! | f_sca | Same context/addr flag (`is_same_ctx_and_addr`) | +//! | w0 | Lower 16 bits of word index (word_addr / 4) | +//! | w1 | Upper 16 bits of word index (word_addr / 4) | //! -//! ## Address range checks (TODO) +//! ## Address range checks //! -//! The trace stores a word address plus idx bits, i.e. `addr = 4 * w_addr + idx`. -//! To fully range-check addresses, we plan to commit to 16-bit limbs of `w_addr` -//! (w0, w1) and enforce: -//! addr = 4 * (w0 + 2^16 * w1) + idx0 + 2 * idx1. -//! Range checks should include `w0`, `w1`, and `4 * w1`; the extra term -//! prevents wraparound, and Goldilocks satisfies P > 2^18 so this is sound. - -use core::ops::{Add, Mul, Sub}; +//! The constraint `word_addr = 4 * (w0 + 2^16 * w1)` decomposes the word address +//! into 16-bit limbs. Combined with range checks on `w0`, `w1`, and `4 * w1` via +//! the wiring bus, this proves all memory addresses are valid 32-bit values. +//! The `4 * w1` check prevents Goldilocks field wraparound (P > 2^18). use miden_core::field::PrimeCharacteristicRing; -use miden_crypto::stark::air::LiftedAirBuilder; +use miden_crypto::stark::air::AirBuilder; -use super::selectors::memory_chiplet_flag; +use super::selectors::ChipletFlags; use crate::{ - Felt, MainTraceRow, - constraints::tagging::{TagGroup, TaggingAirBuilderExt, tagged_assert_zero_integrity}, - trace::{ - CHIPLETS_OFFSET, - chiplets::{ - MEMORY_CLK_COL_IDX, MEMORY_CTX_COL_IDX, MEMORY_D_INV_COL_IDX, MEMORY_D0_COL_IDX, - MEMORY_D1_COL_IDX, MEMORY_FLAG_SAME_CONTEXT_AND_WORD, MEMORY_IDX0_COL_IDX, - MEMORY_IDX1_COL_IDX, MEMORY_IS_READ_COL_IDX, MEMORY_IS_WORD_ACCESS_COL_IDX, - MEMORY_V_COL_RANGE, MEMORY_WORD_COL_IDX, - }, - }, -}; - -// TAGGING IDS -// ================================================================================================ - -pub const MEMORY_BASE_ID: usize = super::bitwise::BITWISE_BASE_ID + super::bitwise::BITWISE_COUNT; -pub const MEMORY_COUNT: usize = 21; -const MEMORY_BINARY_BASE_ID: usize = MEMORY_BASE_ID; -const MEMORY_WORD_IDX_BASE_ID: usize = MEMORY_BASE_ID + 4; -const MEMORY_FIRST_ROW_BASE_ID: usize = MEMORY_BASE_ID + 6; -const MEMORY_DELTA_INV_BASE_ID: usize = MEMORY_BASE_ID + 10; -const MEMORY_DELTA_TRANSITION_ID: usize = MEMORY_BASE_ID + 14; -const MEMORY_SCW_FLAG_ID: usize = MEMORY_BASE_ID + 15; -const MEMORY_SCW_READS_ID: usize = MEMORY_BASE_ID + 16; -const MEMORY_VALUE_CONSIST_BASE_ID: usize = MEMORY_BASE_ID + 17; - -const MEMORY_BINARY_NAMESPACE: &str = "chiplets.memory.binary"; -const MEMORY_WORD_IDX_NAMESPACE: &str = "chiplets.memory.word_idx.zero"; -const MEMORY_FIRST_ROW_NAMESPACE: &str = "chiplets.memory.first_row.zero"; -const MEMORY_DELTA_INV_NAMESPACE: &str = "chiplets.memory.delta.inv"; -const MEMORY_DELTA_TRANSITION_NAMESPACE: &str = "chiplets.memory.delta.transition"; -const MEMORY_SCW_FLAG_NAMESPACE: &str = "chiplets.memory.scw.flag"; -const MEMORY_SCW_READS_NAMESPACE: &str = "chiplets.memory.scw.reads"; -const MEMORY_VALUE_CONSIST_NAMESPACE: &str = "chiplets.memory.value.consistency"; - -const MEMORY_BINARY_NAMES: [&str; 4] = [MEMORY_BINARY_NAMESPACE; 4]; -const MEMORY_WORD_IDX_NAMES: [&str; 2] = [MEMORY_WORD_IDX_NAMESPACE; 2]; -const MEMORY_FIRST_ROW_NAMES: [&str; 4] = [MEMORY_FIRST_ROW_NAMESPACE; 4]; -const MEMORY_DELTA_INV_NAMES: [&str; 4] = [MEMORY_DELTA_INV_NAMESPACE; 4]; -const MEMORY_DELTA_TRANSITION_NAMES: [&str; 1] = [MEMORY_DELTA_TRANSITION_NAMESPACE; 1]; -const MEMORY_SCW_FLAG_NAMES: [&str; 1] = [MEMORY_SCW_FLAG_NAMESPACE; 1]; -const MEMORY_SCW_READS_NAMES: [&str; 1] = [MEMORY_SCW_READS_NAMESPACE; 1]; -const MEMORY_VALUE_CONSIST_NAMES: [&str; 4] = [MEMORY_VALUE_CONSIST_NAMESPACE; 4]; - -const MEMORY_BINARY_TAGS: TagGroup = TagGroup { - base: MEMORY_BINARY_BASE_ID, - names: &MEMORY_BINARY_NAMES, -}; -const MEMORY_WORD_IDX_TAGS: TagGroup = TagGroup { - base: MEMORY_WORD_IDX_BASE_ID, - names: &MEMORY_WORD_IDX_NAMES, -}; -const MEMORY_FIRST_ROW_TAGS: TagGroup = TagGroup { - base: MEMORY_FIRST_ROW_BASE_ID, - names: &MEMORY_FIRST_ROW_NAMES, -}; -const MEMORY_DELTA_INV_TAGS: TagGroup = TagGroup { - base: MEMORY_DELTA_INV_BASE_ID, - names: &MEMORY_DELTA_INV_NAMES, -}; -const MEMORY_DELTA_TRANSITION_TAGS: TagGroup = TagGroup { - base: MEMORY_DELTA_TRANSITION_ID, - names: &MEMORY_DELTA_TRANSITION_NAMES, -}; -const MEMORY_SCW_FLAG_TAGS: TagGroup = TagGroup { - base: MEMORY_SCW_FLAG_ID, - names: &MEMORY_SCW_FLAG_NAMES, -}; -const MEMORY_SCW_READS_TAGS: TagGroup = TagGroup { - base: MEMORY_SCW_READS_ID, - names: &MEMORY_SCW_READS_NAMES, -}; -const MEMORY_VALUE_CONSIST_TAGS: TagGroup = TagGroup { - base: MEMORY_VALUE_CONSIST_BASE_ID, - names: &MEMORY_VALUE_CONSIST_NAMES, + MainCols, MidenAirBuilder, + constraints::{chiplets::columns::MemoryCols, constants::TWO_POW_16, utils::BoolNot}, }; // ENTRY POINTS // ================================================================================================ /// Enforce all memory chiplet constraints. -pub fn enforce_memory_constraints( - builder: &mut AB, - local: &MainTraceRow, - next: &MainTraceRow, -) where - AB: TaggingAirBuilderExt, -{ - let s0: AB::Expr = local.chiplets[0].clone().into(); - let s1: AB::Expr = local.chiplets[1].clone().into(); - let s1_next: AB::Expr = next.chiplets[1].clone().into(); - let s2_next: AB::Expr = next.chiplets[2].clone().into(); - - let is_transition: AB::Expr = builder.is_transition(); - - enforce_memory_constraints_all_rows(builder, local, next); - - let flag_next_row_first_memory = is_transition.clone() - * flag_next_row_first_memory(s0.clone(), s1.clone(), s1_next, s2_next.clone()); - enforce_memory_constraints_first_row(builder, local, next, flag_next_row_first_memory); - - let flag_memory_active_not_last = - is_transition * flag_memory_active_not_last_row(s0, s1, s2_next); - enforce_memory_constraints_all_rows_except_last( - builder, - local, - next, - flag_memory_active_not_last, - ); -} - -/// Enforce memory chiplet constraints that apply to all rows. -/// -/// This enforces: -/// - Binary constraints for selectors and indices -pub fn enforce_memory_constraints_all_rows( - builder: &mut AB, - local: &MainTraceRow, - _next: &MainTraceRow, -) where - AB: TaggingAirBuilderExt, -{ - // Compute memory active flag from top-level selectors - let s0: AB::Expr = local.chiplets[0].clone().into(); - let s1: AB::Expr = local.chiplets[1].clone().into(); - let s2: AB::Expr = local.chiplets[2].clone().into(); - let memory_flag = memory_chiplet_flag(s0, s1, s2); - - // Load memory columns using typed struct - let cols: MemoryColumns = MemoryColumns::from_row::(local); - - let one: AB::Expr = AB::Expr::ONE; - - // Binary constraints - let gate = memory_flag.clone(); - let mut idx = 0; - tagged_assert_zero_integrity( - builder, - &MEMORY_BINARY_TAGS, - &mut idx, - gate.clone() * cols.is_read.clone() * (cols.is_read.clone() - one.clone()), - ); - tagged_assert_zero_integrity( - builder, - &MEMORY_BINARY_TAGS, - &mut idx, - gate.clone() * cols.is_word.clone() * (cols.is_word.clone() - one.clone()), - ); - tagged_assert_zero_integrity( - builder, - &MEMORY_BINARY_TAGS, - &mut idx, - gate.clone() * cols.idx0.clone() * (cols.idx0.clone() - one.clone()), - ); - tagged_assert_zero_integrity( - builder, - &MEMORY_BINARY_TAGS, - &mut idx, - gate * cols.idx1.clone() * (cols.idx1.clone() - one), - ); - - // For word access, idx bits must be zero (only element accesses use idx0/idx1). - let word_gate = memory_flag.clone() * cols.is_word.clone(); - let mut idx = 0; - tagged_assert_zero_integrity( - builder, - &MEMORY_WORD_IDX_TAGS, - &mut idx, - word_gate.clone() * cols.idx0.clone(), - ); - tagged_assert_zero_integrity( - builder, - &MEMORY_WORD_IDX_TAGS, - &mut idx, - word_gate * cols.idx1.clone(), - ); -} - -/// Enforce memory first row initialization constraints. -/// -/// This constraint is enforced in the last row of the previous trace segment (bitwise). -/// When entering the memory chiplet, unwritten values must be 0. -pub fn enforce_memory_constraints_first_row( - builder: &mut AB, - _local: &MainTraceRow, - cols_first: &MainTraceRow, - flag_next_row_first_memory: AB::Expr, -) where - AB: TaggingAirBuilderExt, -{ - // Load first memory row columns using typed struct - let cols_next: MemoryColumns = MemoryColumns::from_row::(cols_first); - - let one: AB::Expr = AB::Expr::ONE; - - // Compute constraint flags for all 4 word elements - let [c0, c1, c2, c3] = cols_next.compute_value_constraint_flags(one.clone()); - - // First row: if v'[i] is not written to, then v'[i] = 0 - let gate = flag_next_row_first_memory; - let mut idx = 0; - tagged_assert_zero_integrity( - builder, - &MEMORY_FIRST_ROW_TAGS, - &mut idx, - gate.clone() * c0 * cols_next.values[0].clone(), - ); - tagged_assert_zero_integrity( - builder, - &MEMORY_FIRST_ROW_TAGS, - &mut idx, - gate.clone() * c1 * cols_next.values[1].clone(), - ); - tagged_assert_zero_integrity( - builder, - &MEMORY_FIRST_ROW_TAGS, - &mut idx, - gate.clone() * c2 * cols_next.values[2].clone(), - ); - tagged_assert_zero_integrity( - builder, - &MEMORY_FIRST_ROW_TAGS, - &mut idx, - gate * c3 * cols_next.values[3].clone(), - ); -} - -/// Enforce memory transition constraints (all rows except last). /// -/// This enforces: -/// - Delta inverse constraints -/// - Context/address/clock delta constraints -/// - Same context/word flag constraints -/// - Value consistency constraints -pub fn enforce_memory_constraints_all_rows_except_last( +/// The memory trace is ordered by (ctx, addr, clk). Consecutive rows are compared +/// via deltas to enforce monotonicity of this ordering. A select mechanism +/// using `ctx_changed` and `addr_changed` (docs: `n0`, `n1`) determines which delta +/// is active: context change takes precedence over address change, which takes +/// precedence over clock change. +pub fn enforce_memory_constraints( builder: &mut AB, - local: &MainTraceRow, - next: &MainTraceRow, - flag_memory_active_not_last: AB::Expr, + local: &MainCols, + next: &MainCols, + flags: &ChipletFlags, ) where - AB: TaggingAirBuilderExt, + AB: MidenAirBuilder, { - // Load columns using typed struct - let cols: MemoryColumns = MemoryColumns::from_row::(local); - let cols_next: MemoryColumns = MemoryColumns::from_row::(next); - - let one: AB::Expr = AB::Expr::ONE; - - let deltas = MemoryDeltas::new::(&cols, &cols_next, one.clone()); - - // ========================================================================== - // DELTA INVERSE CONSTRAINTS - // ========================================================================== - enforce_delta_inverse_constraints::( - builder, - flag_memory_active_not_last.clone(), - &deltas, - one.clone(), - ); - - // ========================================================================== - // DELTA CONSTRAINTS (monotonicity) - // ========================================================================== - let mut idx = 0; - tagged_assert_zero_integrity( - builder, - &MEMORY_DELTA_TRANSITION_TAGS, - &mut idx, - flag_memory_active_not_last.clone() - * (deltas.computed_delta.clone() - deltas.delta_next.clone()), - ); + let cols = local.memory(); + let cols_next = next.memory(); // ========================================================================== - // SAME CONTEXT/WORD FLAG + // BINARY CONSTRAINTS (all rows) // ========================================================================== - // f_scw' = !n0 * !n1 - let mut idx = 0; - tagged_assert_zero_integrity( - builder, - &MEMORY_SCW_FLAG_TAGS, - &mut idx, - flag_memory_active_not_last.clone() - * (cols_next.flag_same_ctx_word.clone() - - (one.clone() - deltas.n0.clone()) * (one.clone() - deltas.n1.clone())), - ); + // Selectors and indices must be binary. + { + let builder = &mut builder.when(flags.is_active.clone()); + builder.assert_bool(cols.is_read); + builder.assert_bool(cols.is_word); + builder.assert_bool(cols.idx0); + builder.assert_bool(cols.idx1); + + // For word access, idx bits must be zero (only element accesses use idx0/idx1). + { + let builder = &mut builder.when(cols.is_word); + builder.assert_zero(cols.idx0); + builder.assert_zero(cols.idx1); + } + } - // ========================================================================== - // SAME CONTEXT/WORD READ-ONLY CONSTRAINTS - // ========================================================================== - enforce_scw_readonly_constraint::( - builder, - flag_memory_active_not_last.clone(), - &cols, - &cols_next, - &deltas, - one.clone(), - ); + // not_written[i] = 1 when v'[i] is NOT being written and must be constrained. + // Computed once, shared between first-row initialization and value consistency. + let not_written = compute_not_written_flags::(cols_next); // ========================================================================== - // VALUE CONSISTENCY + // FIRST-ROW INITIALIZATION // ========================================================================== - - // Compute constraint flags for all 4 elements - let [c0, c1, c2, c3] = cols_next.compute_value_constraint_flags(one.clone()); - - // When v'[i] is not written to: - // - if f_scw' = 1: v'[i] = v[i] (copy from previous) - // - if f_scw' = 0: v'[i] = 0 (initialize to zero) - // Simplified: v'[i] = f_scw' * v[i] - let constrain_value = |c: AB::Expr, v: AB::Expr, v_next: AB::Expr| { - flag_memory_active_not_last.clone() - * c - * (v_next - cols_next.flag_same_ctx_word.clone() * v) - }; - - let mut idx = 0; - tagged_assert_zero_integrity( - builder, - &MEMORY_VALUE_CONSIST_TAGS, - &mut idx, - constrain_value(c0, cols.values[0].clone(), cols_next.values[0].clone()), - ); - tagged_assert_zero_integrity( - builder, - &MEMORY_VALUE_CONSIST_TAGS, - &mut idx, - constrain_value(c1, cols.values[1].clone(), cols_next.values[1].clone()), - ); - tagged_assert_zero_integrity( - builder, - &MEMORY_VALUE_CONSIST_TAGS, - &mut idx, - constrain_value(c2, cols.values[2].clone(), cols_next.values[2].clone()), - ); - tagged_assert_zero_integrity( - builder, - &MEMORY_VALUE_CONSIST_TAGS, - &mut idx, - constrain_value(c3, cols.values[3].clone(), cols_next.values[3].clone()), - ); -} - -// INTERNAL HELPERS -// ================================================================================================ - -/// Derived delta values for memory transitions. -/// -/// These capture the deltas, selection flags, and the computed monotonicity term -/// used across multiple constraint groups. -struct MemoryDeltas { - ctx_delta: E, - addr_delta: E, - clk_delta: E, - n0: E, - n1: E, - delta_next: E, - computed_delta: E, -} - -impl MemoryDeltas -where - E: Clone + Add + Sub + Mul, -{ - fn new(cols: &MemoryColumns, cols_next: &MemoryColumns, one: E) -> Self - where - AB: LiftedAirBuilder, - AB::Expr: Into, + // Enforced at the bitwise→memory boundary. When entering the memory chiplet, + // values not being written must be zero. { - let ctx_delta = cols_next.ctx.clone() - cols.ctx.clone(); - let addr_delta = cols_next.word_addr.clone() - cols.word_addr.clone(); - let clk_delta = cols_next.clk.clone() - cols.clk.clone(); - let two_pow_16: E = AB::Expr::from_u32(1 << 16).into(); - - // n0 = ctx_delta * d_inv' - // n1 = addr_delta * d_inv' - let n0 = ctx_delta.clone() * cols_next.d_inv.clone(); - let n1 = addr_delta.clone() * cols_next.d_inv.clone(); - - // delta_next = d1' * 2^16 + d0' - let delta_next = cols_next.d1.clone() * two_pow_16 + cols_next.d0.clone(); - - // n0 * ctx_delta + !n0 * (n1 * addr_delta + !n1 * clk_delta) = delta_next - let computed_delta = n0.clone() * ctx_delta.clone() - + (one.clone() - n0.clone()) - * (n1.clone() * addr_delta.clone() + (one - n1.clone()) * clk_delta.clone()); - - Self { - ctx_delta, - addr_delta, - clk_delta, - n0, - n1, - delta_next, - computed_delta, + let builder = &mut builder.when(flags.next_is_first.clone()); + for (i, nw) in not_written.iter().enumerate() { + builder.when(nw.clone()).assert_zero(cols_next.values[i]); } } -} -/// Typed access to memory chiplet columns. -/// -/// This struct provides named access to memory columns, eliminating error-prone -/// index arithmetic. Created from a `MainTraceRow` reference. -pub struct MemoryColumns { - /// Read/write selector: 1=read, 0=write - pub is_read: E, - /// Element/word access: 0=element, 1=word - pub is_word: E, - /// Context ID - pub ctx: E, - /// Word address - pub word_addr: E, - /// First bit of element index - pub idx0: E, - /// Second bit of element index - pub idx1: E, - /// Clock cycle - pub clk: E, - /// Memory word values (4 elements) - pub values: [E; 4], - /// Delta low 16 bits - pub d0: E, - /// Delta high 16 bits - pub d1: E, - /// Delta inverse - pub d_inv: E, - /// Same context/word flag - pub flag_same_ctx_word: E, -} - -impl MemoryColumns { - /// Extract memory columns from a main trace row. - pub fn from_row(row: &MainTraceRow) -> Self - where - AB: LiftedAirBuilder, - AB::Var: Into + Clone, + // ========================================================================== + // TRANSITION CONSTRAINTS (all rows except last) + // ========================================================================== + // Enforces: delta inverse, monotonicity, same-context/addr flag, read-only, + // and value consistency. + let builder = &mut builder.when(flags.is_transition.clone()); + + // --- delta inverse --- + // d_inv (docs: column `t`) is shared across all three delta levels (ctx, addr, clk). + // The assert_bool + assert_zero pairs below form conditional inverses that force d_inv + // to the correct value at each level. + let d_inv_next = cols_next.d_inv; + + // Context: prover sets d_inv = 1/ctx_delta → ctx_changed = 1. + let ctx_delta = cols_next.ctx - cols.ctx; + let ctx_changed = ctx_delta.clone() * d_inv_next; + let same_ctx = ctx_changed.not(); + // ctx_changed must be boolean. When ctx_delta ≠ 0, this forces ctx_changed ∈ {0, 1}. + // If ctx_changed were 0 (same_ctx = 1), the assert_zero(ctx_delta) below would + // require ctx_delta = 0 — contradiction. So ctx_changed = 1, forcing d_inv = 1/ctx_delta. + builder.assert_bool(ctx_changed.clone()); + + // Address: prover sets d_inv = 1/addr_delta → addr_changed = 1. + // Only meaningful when same_ctx = 1; when context changes, addr_changed = + // addr_delta/ctx_delta which is unconstrained, but always gated by same_ctx. + let addr_delta = cols_next.word_addr - cols.word_addr; + let addr_changed = addr_delta.clone() * d_inv_next; + let same_addr = addr_changed.not(); + + // When context is unchanged (same_ctx = 1): { - let load = |global_idx: usize| { - let local_idx = global_idx - CHIPLETS_OFFSET; - row.chiplets[local_idx].clone().into() - }; - - MemoryColumns { - is_read: load(MEMORY_IS_READ_COL_IDX), - is_word: load(MEMORY_IS_WORD_ACCESS_COL_IDX), - ctx: load(MEMORY_CTX_COL_IDX), - word_addr: load(MEMORY_WORD_COL_IDX), - idx0: load(MEMORY_IDX0_COL_IDX), - idx1: load(MEMORY_IDX1_COL_IDX), - clk: load(MEMORY_CLK_COL_IDX), - values: core::array::from_fn(|i| load(MEMORY_V_COL_RANGE.start + i)), - d0: load(MEMORY_D0_COL_IDX), - d1: load(MEMORY_D1_COL_IDX), - d_inv: load(MEMORY_D_INV_COL_IDX), - flag_same_ctx_word: load(MEMORY_FLAG_SAME_CONTEXT_AND_WORD), - } + let builder = &mut builder.when(same_ctx.clone()); + // Completes the ctx_changed enforcement: ctx_delta must be zero. + builder.assert_zero(ctx_delta.clone()); + // addr_changed must be boolean. Same enforcement as ctx_changed: when + // addr_delta ≠ 0, this + the assert_zero(addr_delta) below forces + // addr_changed = 1, i.e. d_inv = 1/addr_delta. + builder.assert_bool(addr_changed.clone()); + // Completes the addr_changed enforcement: addr_delta must be zero. + builder.when(same_addr.clone()).assert_zero(addr_delta.clone()); } - /// Compute constraint flags c_0, c_1, c_2, c_3 for value consistency constraints. - /// - /// c_i = 1 when v[i] needs to be constrained (not being written to), 0 otherwise. - /// - /// For each element i: - /// - Read operation: c_i = 1 (always constrain) - /// - Write operation, element access, element i selected: c_i = 0 (being written, no - /// constraining needed) - /// - Write operation, otherwise: c_i = 1 (not being written, constrain) - /// - /// Logic: c_i = is_read + is_write * is_element * !f_i - /// = is_read + (1 - is_read) * (1 - is_word) * (1 - f_i) - pub fn compute_value_constraint_flags(&self, one: One) -> [E; 4] - where - E: Add + Sub + Mul, - One: Into, + // --- same context/addr flag --- + // f_sca' = 1 when both context and word address are unchanged between rows. + // Stored in a dedicated column for degree reduction (same_ctx * same_addr is + // degree 4; the column lets downstream constraints use it at degree 1). + // Not constrained in the first row (intentional — first-row constraints use + // not_written flags directly, not f_sca). + let same_ctx_and_addr = cols_next.is_same_ctx_and_addr; + builder.assert_eq(same_ctx_and_addr, same_ctx.clone() * same_addr.clone()); + + // --- monotonicity --- + // The priority-selected delta must equal the range-checked decomposition. + // d0, d1 are range-checked 16-bit limbs, so delta_next >= 0. For ctx and addr, + // delta = 0 would contradict the flag being 1, so those deltas are strictly + // positive. For clk, delta = 0 is allowed (duplicate reads; see read-only). + // ctx changed → ctx_delta + // addr changed → addr_delta (reachable only when same context) + // neither → clk_delta + let clk_delta = cols_next.clk - cols.clk; + let computed_delta = { + let ctx_term = ctx_changed * ctx_delta; + let addr_term = addr_changed * addr_delta; + let clk_term = same_addr * clk_delta.clone(); + ctx_term + same_ctx * (addr_term + clk_term) + }; + let delta_next = cols_next.d1 * TWO_POW_16 + cols_next.d0; + builder.assert_eq(computed_delta, delta_next); + + // --- read-only constraint --- + // When context/addr are unchanged (f_sca'=1) and the clock doesn't advance, + // both operations must be reads. + // + // clk_no_change = 1 - clk_delta * d_inv is used as a when() gate. Unlike the ctx + // and addr levels, no constraint forces d_inv = 1/clk_delta. This is intentional: + // clk advances → prover must set d_inv = 1/clk_delta to get clk_no_change = 0, + // otherwise the gate stays active and blocks writes the prover needs. + // clk unchanged → clk_delta = 0, so clk_no_change = 1 regardless of d_inv. + // One-sided safe: a wrong d_inv can only block writes, never enable them. { - let one = one.into(); - - let is_write = one.clone() - self.is_read.clone(); - let is_element = one.clone() - self.is_word.clone(); + let clk_no_change = AB::Expr::ONE - clk_delta * d_inv_next; + let is_write = cols.is_read.into().not(); + let is_write_next = cols_next.is_read.into().not(); + let any_write = is_write + is_write_next; - // Element selection flags (f_i = 1 when idx0,idx1 select element i) - let f0 = (one.clone() - self.idx1.clone()) * (one.clone() - self.idx0.clone()); - let f1 = (one.clone() - self.idx1.clone()) * self.idx0.clone(); - let f2 = self.idx1.clone() * (one.clone() - self.idx0.clone()); - let f3 = self.idx1.clone() * self.idx0.clone(); - - // c_i = is_read + is_write * is_element * !f_i - let compute_c = |f_i: E| { - let not_f_i = one.clone() - f_i; - self.is_read.clone() + is_write.clone() * is_element.clone() * not_f_i - }; + builder.when(same_ctx_and_addr).when(clk_no_change).assert_zero(any_write); + } - [compute_c(f0), compute_c(f1), compute_c(f2), compute_c(f3)] + // --- value consistency --- + // Values not being written must follow the consistency rule: + // same context/addr (f_sca'=1): v'[i] = v[i] (copy from previous row) + // new context/addr (f_sca'=0): v'[i] = 0 (initialize to zero) + // Combined: v'[i] = f_sca' * v[i] + let values = cols.values; + let values_next = cols_next.values; + for (i, nw) in not_written.into_iter().enumerate() { + builder.when(nw).assert_eq(values_next[i], same_ctx_and_addr * values[i]); } } -/// Enforce delta inverse constraints for ctx/addr/clk monotonicity. -/// -/// n0 and n1 are binary flags computed via delta inverse: -/// - n0 = 1 iff ctx changes (ctx_delta != 0) -/// - n1 = 1 iff addr changes when ctx doesn't (addr_delta != 0 and ctx_delta = 0) -fn enforce_delta_inverse_constraints( - builder: &mut AB, - flag_memory_active_not_last: AB::Expr, - deltas: &MemoryDeltas, - one: AB::Expr, -) where - AB: TaggingAirBuilderExt, -{ - let n0 = deltas.n0.clone(); - let n1 = deltas.n1.clone(); - let ctx_delta = deltas.ctx_delta.clone(); - let addr_delta = deltas.addr_delta.clone(); - - // Extract negations for reuse - let not_n0 = one.clone() - n0.clone(); - let not_n1 = one.clone() - n1.clone(); - - let gate = flag_memory_active_not_last; - let gate_not_n0 = gate.clone() * not_n0.clone(); - - let mut idx = 0; - // n0 is binary - tagged_assert_zero_integrity( - builder, - &MEMORY_DELTA_INV_TAGS, - &mut idx, - gate * n0.clone() * (n0.clone() - one.clone()), - ); - // !n0 => ctx_delta = 0 - tagged_assert_zero_integrity( - builder, - &MEMORY_DELTA_INV_TAGS, - &mut idx, - gate_not_n0.clone() * ctx_delta.clone(), - ); - // !n0 and n1 is binary - tagged_assert_zero_integrity( - builder, - &MEMORY_DELTA_INV_TAGS, - &mut idx, - gate_not_n0.clone() * n1.clone() * (n1.clone() - one.clone()), - ); - // !n0 and !n1 => addr_delta = 0 - tagged_assert_zero_integrity( - builder, - &MEMORY_DELTA_INV_TAGS, - &mut idx, - gate_not_n0 * not_n1 * addr_delta.clone(), - ); -} +// INTERNAL HELPERS +// ================================================================================================ -/// Enforce read-only access when context and word address are unchanged. -fn enforce_scw_readonly_constraint( - builder: &mut AB, - flag_memory_active_not_last: AB::Expr, - cols: &MemoryColumns, - cols_next: &MemoryColumns, - deltas: &MemoryDeltas, - one: AB::Expr, -) where - AB: TaggingAirBuilderExt, +/// Compute "not written" flags for each of the 4 word elements. +/// +/// Returns `not_written[i]`: 1 when `v[i]` is NOT the write target (must be constrained), +/// 0 when `v[i]` IS being written (unconstrained). +/// +/// The three operation modes: +/// - **Read** (`is_read=1`): all flags = 1 (reads don't change any value) +/// - **Word write** (`is_word=1`): all flags = 0 (all 4 elements are written) +/// - **Element write** (`is_word=0, is_read=0`): flag = 0 for the selected element, 1 for the other +/// three +/// +/// Corresponds to `c_i` in the docs, with `selected[i]` ≡ `f_i`. +/// +/// Formula: `not_written[i] = is_read + is_write * is_element * !selected[i]` +fn compute_not_written_flags(cols: &MemoryCols) -> [AB::Expr; 4] +where + AB: MidenAirBuilder, { - // If ctx/word are unchanged and clk_delta = 0, both rows must be reads. - // Constraint: f_scw' * (1 - clk_delta * d_inv') * (is_write + is_write') = 0 - - let clk_no_change = one.clone() - deltas.clk_delta.clone() * cols_next.d_inv.clone(); - - let is_write = one.clone() - cols.is_read.clone(); - let is_write_next = one.clone() - cols_next.is_read.clone(); - let any_write = is_write + is_write_next; - - let mut idx = 0; - tagged_assert_zero_integrity( - builder, - &MEMORY_SCW_READS_TAGS, - &mut idx, - flag_memory_active_not_last - * cols_next.flag_same_ctx_word.clone() - * clk_no_change - * any_write, - ); -} - -/// Memory chiplet flag for current row active and continuing to next row. -pub fn flag_memory_active_not_last_row(s0: E, s1: E, s2_next: E) -> E { - // Memory active when s0 = s1 = 1 and not transitioning out (s2' = 0) - s0 * s1 * (E::ONE - s2_next) -} - -/// Flag for transitioning into memory chiplet (first row of memory). -pub fn flag_next_row_first_memory( - s0: E, - s1: E, - s1_next: E, - s2_next: E, -) -> E { - // Current row is bitwise (!s1), next row is memory (s1' & !s2') - (E::ONE - s1) * s0.clone() * s1_next * (E::ONE - s2_next) + let is_read = cols.is_read; + let is_write = is_read.into().not(); + + let is_word = cols.is_word; + let is_element = is_word.into().not(); + + // One-hot element selection: selected[i] = 1 when idx = 2*idx1 + idx0 equals i. + let idx0 = cols.idx0; + let idx1 = cols.idx1; + let not_idx0 = idx0.into().not(); + let not_idx1 = idx1.into().not(); + + let selected = [ + not_idx1.clone() * not_idx0.clone(), // element 0: idx = 0b00 + not_idx1 * idx0, // element 1: idx = 0b01 + idx1 * not_idx0, // element 2: idx = 0b10 + idx1 * idx0, // element 3: idx = 0b11 + ]; + + // not_written[i] = is_read + is_write * is_element * !selected[i] + let is_element_write = is_write * is_element; + selected.map(|s_i| is_read + is_element_write.clone() * s_i.not()) } diff --git a/air/src/constraints/chiplets/mod.rs b/air/src/constraints/chiplets/mod.rs index 4f52c9f23c..37d3eb57a2 100644 --- a/air/src/constraints/chiplets/mod.rs +++ b/air/src/constraints/chiplets/mod.rs @@ -1,26 +1,28 @@ -//! Chiplets constraints module (partial). +//! Chiplets constraints module. //! //! Currently we implement: -//! - chiplet selector constraints -//! - hasher chiplet main-trace constraints +//! - chiplet selector constraints (including hasher internal selectors) +//! - permutation sub-chiplet main-trace constraints +//! - controller sub-chiplet main-trace constraints //! - bitwise chiplet main-trace constraints //! - memory chiplet main-trace constraints //! - ACE chiplet main-trace constraints -//! - kernel ROM chiplet main-trace constraints //! -//! Chiplet bus constraints are enforced in the `chiplets::bus` module. +//! Chiplet LogUp lookup-argument constraints are emitted by +//! [`crate::constraints::lookup::chiplet_air::ChipletLookupAir`] and wired through +//! `ProcessorAir`'s `LookupAir` impl from `ProcessorAir::eval`. pub mod ace; pub mod bitwise; -pub mod bus; -pub mod hasher; -pub mod kernel_rom; +pub mod columns; +pub mod hasher_control; pub mod memory; +pub mod permutation; pub mod selectors; -use miden_crypto::stark::air::LiftedAirBuilder; +use selectors::ChipletSelectors; -use crate::{Felt, MainTraceRow}; +use crate::{MainCols, MidenAirBuilder}; // ENTRY POINTS // ================================================================================================ @@ -28,15 +30,20 @@ use crate::{Felt, MainTraceRow}; /// Enforces chiplets main-trace constraints. pub fn enforce_main( builder: &mut AB, - local: &MainTraceRow, - next: &MainTraceRow, + local: &MainCols, + next: &MainCols, + selectors: &ChipletSelectors, ) where - AB: LiftedAirBuilder, + AB: MidenAirBuilder, { - selectors::enforce_chiplet_selectors(builder, local, next); - hasher::enforce_hasher_constraints(builder, local, next); - bitwise::enforce_bitwise_constraints(builder, local, next); - memory::enforce_memory_constraints(builder, local, next); - ace::enforce_ace_constraints(builder, local, next); - kernel_rom::enforce_kernel_rom_constraints(builder, local, next); + // Selector constraints (including hasher internal selectors) are enforced in + // build_chiplet_selectors (called from lib.rs). + + // Hasher sub-chiplets: permutation + controller. + permutation::enforce_permutation_constraints(builder, local, next, &selectors.permutation); + hasher_control::enforce_controller_constraints(builder, local, next, &selectors.controller); + + bitwise::enforce_bitwise_constraints(builder, local, next, &selectors.bitwise); + memory::enforce_memory_constraints(builder, local, next, &selectors.memory); + ace::enforce_ace_constraints_all_rows(builder, local, next, &selectors.ace); } diff --git a/air/src/constraints/chiplets/permutation/mod.rs b/air/src/constraints/chiplets/permutation/mod.rs new file mode 100644 index 0000000000..36e81bc210 --- /dev/null +++ b/air/src/constraints/chiplets/permutation/mod.rs @@ -0,0 +1,112 @@ +//! Permutation sub-chiplet constraints. +//! +//! The permutation sub-chiplet executes Poseidon2 permutations as 16-row cycles. +//! It is active when `s_perm = 1` (the permutation segment selector). +//! +//! ## Sub-modules +//! +//! - [`state`]: Poseidon2 round transition constraints +//! +//! ## Column Layout (via [`PermutationCols`]) +//! +//! | Column | Purpose | +//! |--------------|---------| +//! | w0, w1, w2 | S-box witnesses (same physical columns as hasher selectors) | +//! | h[0..12) | Poseidon2 state (RATE0, RATE1, CAP) | +//! | multiplicity | Request multiplicity (same physical column as node_index) | +//! | s_perm | Permutation segment selector (consumed by chiplet selectors) | + +pub mod state; + +use core::borrow::Borrow; + +use miden_crypto::stark::air::AirBuilder; + +use crate::{ + MainCols, MidenAirBuilder, + constraints::chiplets::{ + columns::{HasherPeriodicCols, PeriodicCols}, + selectors::ChipletFlags, + }, +}; + +// ENTRY POINT +// ================================================================================================ + +/// Enforce all permutation sub-chiplet constraints. +/// +/// Receives pre-computed [`ChipletFlags`] from `build_chiplet_selectors`. The `s_perm` +/// column is never referenced directly by constraint code. +pub fn enforce_permutation_constraints( + builder: &mut AB, + local: &MainCols, + next: &MainCols, + flags: &ChipletFlags, +) where + AB: MidenAirBuilder, +{ + let periodic_hasher: HasherPeriodicCols = { + let periodic: &PeriodicCols = builder.periodic_values().borrow(); + periodic.hasher + }; + + let cols = local.permutation(); + let cols_next = next.permutation(); + + // not_cycle_end: 1 on perm-cycle rows 0-14, 0 on the cycle boundary row 15. + let not_cycle_end: AB::Expr = [ + periodic_hasher.is_init_ext, + periodic_hasher.is_ext, + periodic_hasher.is_packed_int, + periodic_hasher.is_int_ext, + ] + .map(Into::into) + .into_iter() + .sum(); + + // --- Poseidon2 permutation step constraints --- + // Gate by is_active (= s_perm, degree 1) alone. This is sound because + // the tri-state selector constraints confine s_perm to hasher rows. + // Keeping the gate at degree 1 is critical: the S-box has degree 7, and + // with the periodic selector (degree 1), the total constraint degree is + // 1 + 1 + 7 = 9, which matches the system's max degree. + state::enforce_permutation_steps( + builder, + flags.is_active.clone(), + cols, + cols_next, + &periodic_hasher, + ); + + // --- Structural confinement on perm rows --- + // is_boundary, direction_bit, and mrupdate_id are unused on permutation rows + // and must be zero to avoid accidental coupling with controller-side logic. + builder.when(flags.is_active.clone()).assert_zeros(cols.unused_padding()); + + // --- Multiplicity constancy within perm cycles --- + // On perm rows that are NOT the cycle boundary (row 15), multiplicity must stay + // constant. This ensures each 16-row cycle has a single multiplicity value. + // Degree: is_active(1) * not_cycle_end(1) * diff(1) = 3. + builder + .when(flags.is_active.clone()) + .when(not_cycle_end.clone()) + .assert_eq(cols_next.multiplicity, cols.multiplicity); + + // --- Cycle boundary alignment --- + // The permutation section must be aligned to the 16-row Poseidon2 cycle: the + // first perm row must land on cycle row 0 and the last on cycle row 15. + // Together these guarantee every permutation spans exactly one complete cycle, + // so the periodic column selectors assign the correct round type to each row. + // + // Entry alignment: the row before the first perm row (= last controller row) + // must be on cycle row 15. `flags.next_is_first` = `ctrl.is_last * s_perm'`, + // which equals `ctrl.is_last` because the transition rules force `s_perm' = 1` + // when `ctrl.is_last` fires. + // Degree: next_is_first(3) * not_cycle_end(1) = 4. + builder.when(flags.next_is_first.clone()).assert_zero(not_cycle_end.clone()); + + // Exit safety: the last permutation row must be on cycle row 15. + // This prevents cross-chiplet next-row reads from firing under perm gates. + // Degree: is_last(2) * not_cycle_end(1) = 3. + builder.when(flags.is_last.clone()).assert_zero(not_cycle_end); +} diff --git a/air/src/constraints/chiplets/permutation/state.rs b/air/src/constraints/chiplets/permutation/state.rs new file mode 100644 index 0000000000..c187a4d011 --- /dev/null +++ b/air/src/constraints/chiplets/permutation/state.rs @@ -0,0 +1,336 @@ +//! Permutation chiplet state transition constraints. +//! +//! This module enforces the Poseidon2 permutation constraints for the permutation sub-chiplet. +//! The permutation operates on a 16-row cycle with five types of steps: +//! +//! - **Row 0 (init+ext1)**: Merged init linear layer + first external round +//! - **Rows 1-3, 12-14 (external)**: Single external round: add RCs, S-box^7, M_E +//! - **Rows 4-10 (packed internal)**: 3 internal rounds packed per row using witnesses as S-box +//! outputs +//! - **Row 11 (int+ext)**: Last internal round + first trailing external round +//! - **Row 15 (boundary)**: No step constraint (cycle boundary, final permutation state) +//! +//! ## Poseidon2 Parameters +//! +//! - State width: 12 field elements +//! - External rounds: 8 (4 initial + 4 terminal) +//! - Internal rounds: 22 +//! - S-box: x^7 + +use miden_core::{chiplets::hasher::Hasher, field::PrimeCharacteristicRing}; +use miden_crypto::stark::air::AirBuilder; + +use crate::{ + MidenAirBuilder, + constraints::chiplets::columns::{HasherPeriodicCols, PermutationCols}, + trace::chiplets::hasher::STATE_WIDTH, +}; + +// CONSTRAINT HELPERS +// ================================================================================================ + +/// Enforces Poseidon2 permutation step constraints on the 16-row packed cycle. +/// +/// These constraints are gated by `perm_gate = flags.is_active`, so they only +/// fire on permutation segment rows. +/// +/// ## Step Types +/// +/// 1. **Init+ext1 (row 0)**: `h' = M_E(S(M_E(h) + ark))` — degree 9 +/// 2. **Single ext (rows 1-3, 12-14)**: `h' = M_E(S(h + ark))` — degree 9 +/// 3. **Packed 3x internal (rows 4-10)**: witnesses + affine next-state — degree 9 / 3 +/// 4. **Int+ext (row 11)**: witness + `h' = M_E(S(y + ark))` — degree 9 +/// 5. **Boundary (row 15)**: No constraint +/// +/// The witness columns `w[0..2]` correspond to the S-box outputs on permutation rows. +pub fn enforce_permutation_steps( + builder: &mut AB, + perm_gate: AB::Expr, + cols: &PermutationCols, + cols_next: &PermutationCols, + periodic: &HasherPeriodicCols, +) where + AB: MidenAirBuilder, +{ + let h: [AB::Expr; STATE_WIDTH] = core::array::from_fn(|i| cols.state[i].into()); + let h_next: [AB::Expr; STATE_WIDTH] = core::array::from_fn(|i| cols_next.state[i].into()); + let w: [AB::Expr; 3] = core::array::from_fn(|i| cols.witnesses[i].into()); + + // Step-type selectors + let is_init_ext: AB::Expr = periodic.is_init_ext.into(); + let is_ext: AB::Expr = periodic.is_ext.into(); + let is_packed_int: AB::Expr = periodic.is_packed_int.into(); + let is_int_ext: AB::Expr = periodic.is_int_ext.into(); + + // Shared round constants + let ark: [AB::Expr; STATE_WIDTH] = core::array::from_fn(|i| periodic.ark[i].into()); + + // Lift Felt constants needed by pure math helpers. + let mat_diag: [AB::Expr; STATE_WIDTH] = core::array::from_fn(|i| Hasher::MAT_DIAG[i].into()); + let ark_int_21: AB::Expr = Hasher::ARK_INT[21].into(); + + // ------------------------------------------------------------------------- + // 0. Unused witness zeroing + // + // Unused witness columns are forced to zero. On non-packed rows, this means: + // - rows 0-3, 12-15: w0 = w1 = w2 = 0 + // - row 11: w1 = w2 = 0 + // - rows 4-10: w0, w1, w2 unconstrained here (checked by packed witness equations) + // + // These constraints are primarily defensive. They make permutation rows inert when + // witnesses are reused and reduce accidental coupling with controller-side selector + // logic. + // + // Gate degrees: + // - perm_gate(1) * (1 - is_packed_int - is_int_ext)(1) = 2 for w0 + // - perm_gate(1) * (1 - is_packed_int)(1) = 2 for w1,w2 + // Constraint degree: gate(2) * witness(1) = 3 + // ------------------------------------------------------------------------- + // w0 unused on rows that are neither packed-int nor int+ext. + builder + .when(perm_gate.clone() * (AB::Expr::ONE - is_packed_int.clone() - is_int_ext.clone())) + .assert_zero(w[0].clone()); + // w1, w2 unused on rows that are not packed-int. + { + let builder = + &mut builder.when(perm_gate.clone() * (AB::Expr::ONE - is_packed_int.clone())); + builder.assert_zero(w[1].clone()); + builder.assert_zero(w[2].clone()); + } + + // ------------------------------------------------------------------------- + // 1. Init+ext1 (row 0): h' = M_E(S(M_E(h) + ark)) + // Gate degree: perm_gate(1) * is_init_ext(1) = 2 + // Constraint degree: gate(2) * sbox(7) = 9 + // ------------------------------------------------------------------------- + { + let expected = apply_init_plus_ext(&h, &ark); + let builder = &mut builder.when(perm_gate.clone() * is_init_ext); + for i in 0..STATE_WIDTH { + builder.assert_eq(h_next[i].clone(), expected[i].clone()); + } + } + + // ------------------------------------------------------------------------- + // 2. Single external round (rows 1-3, 12-14): h' = M_E(S(h + ark)) + // Gate degree: perm_gate(1) * is_ext(1) = 2 + // Constraint degree: gate(2) * sbox(7) = 9 + // ------------------------------------------------------------------------- + { + let ext_with_rc: [AB::Expr; STATE_WIDTH] = + core::array::from_fn(|i| h[i].clone() + ark[i].clone()); + let ext_with_sbox: [AB::Expr; STATE_WIDTH] = + core::array::from_fn(|i| ext_with_rc[i].clone().exp_const_u64::<7>()); + let expected = apply_matmul_external(&ext_with_sbox); + + let builder = &mut builder.when(perm_gate.clone() * is_ext); + for i in 0..STATE_WIDTH { + builder.assert_eq(h_next[i].clone(), expected[i].clone()); + } + } + + // ------------------------------------------------------------------------- + // 3. Packed 3x internal (rows 4-10): witness checks + affine next-state + // Gate degree: perm_gate(1) * is_packed_int(1) = 2 + // Witness constraint degree: gate(2) * sbox(7) = 9 + // Next-state constraint degree: gate(2) * affine(1) = 3 + // ------------------------------------------------------------------------- + { + // ark[0..2] hold the 3 internal round constants on packed-int rows + let ark_int_3: [AB::Expr; 3] = core::array::from_fn(|i| ark[i].clone()); + let (expected, witness_checks) = apply_packed_internals(&h, &w, &ark_int_3, &mat_diag); + + let builder = &mut builder.when(perm_gate.clone() * is_packed_int); + // 3 witness constraints + for wc in &witness_checks { + builder.assert_zero(wc.clone()); + } + // 12 next-state constraints + for i in 0..STATE_WIDTH { + builder.assert_eq(h_next[i].clone(), expected[i].clone()); + } + } + + // ------------------------------------------------------------------------- + // 4. Int+ext merged (row 11): 1 internal (ARK_INT[21] hardcoded) + 1 external + // Gate degree: perm_gate(1) * is_int_ext(1) = 2 + // Witness constraint degree: gate(2) * sbox(7) = 9 + // Next-state constraint degree: gate(2) * sbox(7) = 9 + // ------------------------------------------------------------------------- + { + let (expected, witness_check) = + apply_internal_plus_ext(&h, &w[0], ark_int_21, &ark, &mat_diag); + + let builder = &mut builder.when(perm_gate * is_int_ext); + // 1 witness constraint + builder.assert_zero(witness_check); + // 12 next-state constraints + for i in 0..STATE_WIDTH { + builder.assert_eq(h_next[i].clone(), expected[i].clone()); + } + } +} + +// ============================================================================= +// LINEAR ALGEBRA HELPERS +// ============================================================================= + +/// Applies the external linear layer M_E to the state. +/// +/// The external layer consists of: +/// 1. Apply M4 to each 4-element block +/// 2. Add cross-block sums to each element +fn apply_matmul_external(state: &[E; STATE_WIDTH]) -> [E; STATE_WIDTH] { + // Apply M4 to each 4-element block + let b0 = matmul_m4(core::array::from_fn(|i| state[i].clone())); + let b1 = matmul_m4(core::array::from_fn(|i| state[4 + i].clone())); + let b2 = matmul_m4(core::array::from_fn(|i| state[8 + i].clone())); + + // Compute cross-block sums + let stored0 = b0[0].clone() + b1[0].clone() + b2[0].clone(); + let stored1 = b0[1].clone() + b1[1].clone() + b2[1].clone(); + let stored2 = b0[2].clone() + b1[2].clone() + b2[2].clone(); + let stored3 = b0[3].clone() + b1[3].clone() + b2[3].clone(); + + // Add sums to each element + [ + b0[0].clone() + stored0.clone(), + b0[1].clone() + stored1.clone(), + b0[2].clone() + stored2.clone(), + b0[3].clone() + stored3.clone(), + b1[0].clone() + stored0.clone(), + b1[1].clone() + stored1.clone(), + b1[2].clone() + stored2.clone(), + b1[3].clone() + stored3.clone(), + b2[0].clone() + stored0, + b2[1].clone() + stored1, + b2[2].clone() + stored2, + b2[3].clone() + stored3, + ] +} + +/// Applies the 4x4 matrix M4 used in Poseidon2's external linear layer. +fn matmul_m4(input: [E; 4]) -> [E; 4] { + let [a, b, c, d] = input; + + let t01 = a.clone() + b.clone(); + let t23 = c.clone() + d.clone(); + let t0123 = t01.clone() + t23.clone(); + let t01123 = t0123.clone() + b; + let t01233 = t0123 + d; + + let out0 = t01123.clone() + t01; + let out1 = t01123 + c.double(); + let out2 = t01233.clone() + t23; + let out3 = t01233 + a.double(); + + [out0, out1, out2, out3] +} + +/// Applies the internal linear layer M_I to the state. +/// +/// M_I = I + diag(MAT_DIAG) where all rows share the same sum. +/// The `mat_diag` parameter provides `Hasher::MAT_DIAG` pre-lifted to the expression type. +fn apply_matmul_internal( + state: &[E; STATE_WIDTH], + mat_diag: &[E; STATE_WIDTH], +) -> [E; STATE_WIDTH] { + // Sum of all state elements + let sum = E::sum_array::(state); + // result[i] = state[i] * MAT_DIAG[i] + sum + core::array::from_fn(|i| state[i].clone() * mat_diag[i].clone() + sum.clone()) +} + +// ============================================================================= +// PACKED ROUND HELPERS +// ============================================================================= + +/// Computes the expected next state for the merged init linear + first external round. +/// +/// h' = M_E(S(M_E(h) + ark_ext)) +/// +/// The init step applies M_E to the input, then the first external round adds round +/// constants, applies the full S-box, and applies M_E again. This is a single S-box +/// layer over affine expressions, so the constraint degree is 7. +pub fn apply_init_plus_ext( + h: &[E; STATE_WIDTH], + ark_ext: &[E; STATE_WIDTH], +) -> [E; STATE_WIDTH] { + // Apply M_E to get the pre-round state + let pre = apply_matmul_external(h); + + // Add round constants, apply S-box, apply M_E + let with_rc: [E; STATE_WIDTH] = core::array::from_fn(|i| pre[i].clone() + ark_ext[i].clone()); + let with_sbox: [E; STATE_WIDTH] = + core::array::from_fn(|i| with_rc[i].clone().exp_const_u64::<7>()); + apply_matmul_external(&with_sbox) +} + +/// Computes the expected next state and witness checks for 3 packed internal rounds. +/// +/// Each internal round applies: add RC to lane 0, S-box lane 0, then M_I. +/// The S-box output for each round is provided as an explicit witness (w0, w1, w2), +/// which keeps the intermediate states affine and the constraint degree at 7. +/// +/// Returns: +/// - `next_state`: expected state after all 3 rounds (affine in trace columns, degree 1) +/// - `witness_checks`: 3 expressions that must be zero (each degree 7): `wk - (y(k)_0 + +/// ark_int[k])^7` +pub fn apply_packed_internals( + h: &[E; STATE_WIDTH], + w: &[E; 3], + ark_int: &[E; 3], + mat_diag: &[E; STATE_WIDTH], +) -> ([E; STATE_WIDTH], [E; 3]) { + let mut state = h.clone(); + let mut witness_checks: [E; 3] = core::array::from_fn(|_| E::ZERO); + + for k in 0..3 { + // Witness check: wk = (state[0] + ark_int[k])^7 + let sbox_input = state[0].clone() + ark_int[k].clone(); + witness_checks[k] = w[k].clone() - sbox_input.exp_const_u64::<7>(); + + // Substitute witness for lane 0 and apply M_I + state[0] = w[k].clone(); + state = apply_matmul_internal(&state, mat_diag); + } + + (state, witness_checks) +} + +/// Computes the expected next state and witness check for one internal round followed +/// by one external round. +/// +/// Used for the int22+ext5 merged row (row 11). The internal round constant ARK_INT[21] +/// is passed as a concrete Felt rather than read from a periodic column. This is valid +/// because row 11 is the only row gated by `is_int_ext` -- no other row needs a different +/// value under the same gate. A periodic column would waste 15 zero entries to deliver +/// one value. +/// +/// Returns: +/// - `next_state`: expected state after int + ext (degree 7 in trace columns) +/// - `witness_check`: `w0 - (h[0] + ark_int_const)^7` (degree 7) +pub fn apply_internal_plus_ext( + h: &[E; STATE_WIDTH], + w0: &E, + ark_int_const: E, + ark_ext: &[E; STATE_WIDTH], + mat_diag: &[E; STATE_WIDTH], +) -> ([E; STATE_WIDTH], E) { + // Internal round: witness check and state update + let sbox_input = h[0].clone() + ark_int_const; + let witness_check = w0.clone() - sbox_input.exp_const_u64::<7>(); + + let mut int_state = h.clone(); + int_state[0] = w0.clone(); + let intermediate = apply_matmul_internal(&int_state, mat_diag); + + // External round: add RC, S-box all lanes, M_E + let with_rc: [E; STATE_WIDTH] = + core::array::from_fn(|i| intermediate[i].clone() + ark_ext[i].clone()); + let with_sbox: [E; STATE_WIDTH] = + core::array::from_fn(|i| with_rc[i].clone().exp_const_u64::<7>()); + let next_state = apply_matmul_external(&with_sbox); + + (next_state, witness_check) +} diff --git a/air/src/constraints/chiplets/selectors.rs b/air/src/constraints/chiplets/selectors.rs index 2810da7bcb..80c12cc4c2 100644 --- a/air/src/constraints/chiplets/selectors.rs +++ b/air/src/constraints/chiplets/selectors.rs @@ -1,204 +1,310 @@ -//! Chiplet selector system constraints. +//! Chiplet selector system constraints and precomputed flags. //! -//! This module implements the hierarchical chiplet selector system that determines -//! which chiplet is active at any given row. +//! This module implements the chiplet selector system that determines which chiplet is +//! active at any given row, and provides precomputed flags for gating chiplet-specific +//! constraints. //! //! ## Selector Hierarchy //! -//! The chiplet system uses 5 selector columns `s[0..4]` to identify active chiplets: +//! The chiplet system uses two physical selector columns (`s_ctrl = chiplets[0]` and +//! `s_perm = chiplets[20]`) plus the virtual `s0 = 1 - (s_ctrl + s_perm)` to partition +//! rows into three top-level regions. The remaining selectors `s1..s4` subdivide the +//! `s0` region into the remaining chiplets. //! -//! | Chiplet | Active when | Selector pattern | -//! |-------------|--------------------------------|------------------| -//! | Hasher | `!s0` | `(0, *, *, *, *)` | -//! | Bitwise | `s0 * !s1` | `(1, 0, *, *, *)` | -//! | Memory | `s0 * s1 * !s2` | `(1, 1, 0, *, *)` | -//! | ACE | `s0 * s1 * s2 * !s3` | `(1, 1, 1, 0, *)` | -//! | Kernel ROM | `s0 * s1 * s2 * s3 * !s4` | `(1, 1, 1, 1, 0)` | +//! | Chiplet | Active when | +//! |-------------|--------------------------------| +//! | Controller | `s_ctrl` | +//! | Permutation | `s_perm` | +//! | Bitwise | `s0 * !s1` | +//! | Memory | `s0 * s1 * !s2` | +//! | ACE | `s0 * s1 * s2 * !s3` | +//! | Kernel ROM | `s0 * s1 * s2 * s3 * !s4` | +//! +//! ## Selector Transition Rules +//! +//! - `s_ctrl`, `s_perm`, and `s_ctrl + s_perm` are boolean (at most one is active) +//! - `s_ctrl = 1 → s_ctrl' + s_perm' = 1` (a controller row must be followed by another controller +//! row or a permutation row) +//! - `s_perm = 1 → s_ctrl' = 0` (a permutation row cannot be followed by a controller row; it can +//! only continue as permutation or transition to s0) +//! - `s0 = 1 → s_ctrl' = 0 ∧ s_perm' = 0` (once in the s0 region, stay there) +//! +//! These force the trace ordering: `ctrl...ctrl, perm...perm, s0...s0`. +//! +//! ## Precomputed Flags +//! +//! Each chiplet gets a [`ChipletFlags`] struct with four flags: +//! - `is_active`: 1 when this chiplet owns the current row +//! - `is_transition`: active on both current and next row (bakes in `is_transition()`) +//! - `is_last`: last row of this chiplet's section (`is_active * s_n'`) +//! - `next_is_first`: next row is the first of this chiplet (`is_last[n-1] * (1 - s_n')`) +//! +//! For controller and permutation, `is_active` is the direct physical selector (`s_ctrl` or +//! `s_perm`). For the remaining chiplets under `s0`, `is_active` uses the subtraction trick +//! (`prefix - prefix * s_n`). //! //! ## Constraints //! -//! 1. **Binary constraints**: Each selector is binary when it could be active -//! 2. **Stability constraints**: Once a selector becomes 1, it stays 1 (no 1→0 transitions) +//! 1. **Tri-state partition**: `s_ctrl`, `s_perm`, `(s_ctrl + s_perm)` are boolean +//! 2. **Transition rules**: ctrl→ctrl|perm, perm→perm|s0, s0→s0 +//! 3. **Binary constraints**: `s1..s4` are binary when their prefix is active +//! 4. **Stability constraints**: Once `s1..s4` become 1, they stay 1 (no 1→0 transitions) +//! 5. **Last-row invariant**: `s_ctrl = 0`, `s1 = s2 = s3 = s4 = 1` on the final row +//! +//! The last-row invariant ensures every chiplet's `is_active` flag is zero on the last +//! row. Combined with the `(1 - s_n')` factor in the precomputed flags, this makes +//! chiplet-gated constraints automatically vanish on the last row without needing +//! explicit `when_transition()` guards. use miden_core::field::PrimeCharacteristicRing; -use miden_crypto::stark::air::{AirBuilder, LiftedAirBuilder}; +use miden_crypto::stark::air::AirBuilder; -use crate::{ - Felt, MainTraceRow, - constraints::tagging::{TaggingAirBuilderExt, ids::TAG_CHIPLETS_BASE}, -}; +use crate::{MainCols, MidenAirBuilder, constraints::utils::BoolNot}; -// TAGGING IDS +// CHIPLET FLAGS // ================================================================================================ -/// Base ID for chiplet selector constraints. -const CHIPLET_SELECTORS_BASE_ID: usize = TAG_CHIPLETS_BASE; - -/// Constraint namespaces in assertion order. -const CHIPLET_SELECTORS_NAMES: [&str; 10] = [ - "chiplets.selectors.s0.binary", - "chiplets.selectors.s1.binary", - "chiplets.selectors.s2.binary", - "chiplets.selectors.s3.binary", - "chiplets.selectors.s4.binary", - "chiplets.selectors.s0.stability", - "chiplets.selectors.s1.stability", - "chiplets.selectors.s2.stability", - "chiplets.selectors.s3.stability", - "chiplets.selectors.s4.stability", -]; - -// ENTRY POINTS +/// Precomputed flags for a single chiplet. +#[derive(Clone)] +pub struct ChipletFlags { + /// 1 when this chiplet owns the current row. + pub is_active: E, + /// `is_transition() * prefix * (1 - s_n')` — bakes in the transition flag. + pub is_transition: E, + /// `is_active * s_n'` — last row of this chiplet's section. + pub is_last: E, + /// `is_last[n-1] * (1 - s_n')` — next row is the first row of this chiplet. + pub next_is_first: E, +} + +/// Precomputed flags for all chiplets. +#[derive(Clone)] +pub struct ChipletSelectors { + pub controller: ChipletFlags, + pub permutation: ChipletFlags, + pub bitwise: ChipletFlags, + pub memory: ChipletFlags, + pub ace: ChipletFlags, +} + +// ENTRY POINT // ================================================================================================ -/// Enforce chiplet selector constraints. +/// Enforce chiplet selector constraints and build precomputed flags. /// /// This enforces: -/// 1. Binary constraints for each selector level -/// 2. Stability constraints (no 1→0 transitions) -pub fn enforce_chiplet_selectors( +/// 1. Tri-state partition constraints for `s_ctrl`, `s_perm`, virtual `s0` +/// 2. Transition rules (ctrl→ctrl|perm, perm→perm|s0, s0→s0) +/// 3. Binary and stability constraints for `s1..s4` under `s0` +/// 4. Last-row invariant (`s_ctrl = 0`, `s1..s4 = 1`) +/// 5. Hasher domain-specific constraints (sub-selector booleanity, pairing, cycle alignment) +/// +/// Returns [`ChipletSelectors`] with precomputed flags for gating chiplet constraints. +pub fn build_chiplet_selectors( builder: &mut AB, - local: &MainTraceRow, - next: &MainTraceRow, -) where - AB: LiftedAirBuilder, + local: &MainCols, + next: &MainCols, +) -> ChipletSelectors +where + AB: MidenAirBuilder, { - // Load selector columns (chiplets[0..5] are the selectors) - let s0: AB::Expr = local.chiplets[0].clone().into(); - let s1: AB::Expr = local.chiplets[1].clone().into(); - let s2: AB::Expr = local.chiplets[2].clone().into(); - let s3: AB::Expr = local.chiplets[3].clone().into(); - let s4: AB::Expr = local.chiplets[4].clone().into(); - - let s0_next: AB::Expr = next.chiplets[0].clone().into(); - let s1_next: AB::Expr = next.chiplets[1].clone().into(); - let s2_next: AB::Expr = next.chiplets[2].clone().into(); - let s3_next: AB::Expr = next.chiplets[3].clone().into(); - let s4_next: AB::Expr = next.chiplets[4].clone().into(); - - let one: AB::Expr = AB::Expr::ONE; - - // ========================================================================== - // BINARY CONSTRAINTS - // ========================================================================== - // Each selector is binary when it could be active - - // s0 is always binary - builder.tagged(CHIPLET_SELECTORS_BASE_ID, CHIPLET_SELECTORS_NAMES[0], |builder| { - builder.assert_zero(s0.clone() * (s0.clone() - one.clone())); - }); - - // s1 is binary when s0 = 1 (bitwise, memory, ACE, or kernel ROM could be active) - builder.tagged(CHIPLET_SELECTORS_BASE_ID + 1, CHIPLET_SELECTORS_NAMES[1], |builder| { - builder.when(s0.clone()).assert_zero(s1.clone() * (s1.clone() - one.clone())); - }); - - // s2 is binary when s0 = 1 and s1 = 1 (memory, ACE, or kernel ROM could be active) - builder.tagged(CHIPLET_SELECTORS_BASE_ID + 2, CHIPLET_SELECTORS_NAMES[2], |builder| { - builder - .when(s0.clone()) - .when(s1.clone()) - .assert_zero(s2.clone() * (s2.clone() - one.clone())); - }); - - // s3 is binary when s0 = s1 = s2 = 1 (ACE or kernel ROM could be active) - builder.tagged(CHIPLET_SELECTORS_BASE_ID + 3, CHIPLET_SELECTORS_NAMES[3], |builder| { - builder - .when(s0.clone()) - .when(s1.clone()) - .when(s2.clone()) - .assert_zero(s3.clone() * (s3.clone() - one.clone())); - }); - - // s4 is binary when s0 = s1 = s2 = s3 = 1 (kernel ROM could be active) - builder.tagged(CHIPLET_SELECTORS_BASE_ID + 4, CHIPLET_SELECTORS_NAMES[4], |builder| { - builder - .when(s0.clone()) - .when(s1.clone()) - .when(s2.clone()) - .when(s3.clone()) - .assert_zero(s4.clone() * (s4.clone() - one.clone())); - }); - - // ========================================================================== - // STABILITY CONSTRAINTS (transition only) - // ========================================================================== - // Once a selector becomes 1, it must stay 1 (forbids 1→0 transitions) - - // s0' = s0 when s0 = 1 - builder.tagged(CHIPLET_SELECTORS_BASE_ID + 5, CHIPLET_SELECTORS_NAMES[5], |builder| { - builder - .when_transition() - .when(s0.clone()) - .assert_zero(s0_next.clone() - s0.clone()); - }); - - // s1' = s1 when s0 = 1 and s1 = 1 - builder.tagged(CHIPLET_SELECTORS_BASE_ID + 6, CHIPLET_SELECTORS_NAMES[6], |builder| { - builder - .when_transition() - .when(s0.clone()) - .when(s1.clone()) - .assert_zero(s1_next.clone() - s1.clone()); - }); - - // s2' = s2 when s0 = s1 = s2 = 1 - builder.tagged(CHIPLET_SELECTORS_BASE_ID + 7, CHIPLET_SELECTORS_NAMES[7], |builder| { - builder - .when_transition() - .when(s0.clone()) - .when(s1.clone()) - .when(s2.clone()) - .assert_zero(s2_next.clone() - s2.clone()); - }); - - // s3' = s3 when s0 = s1 = s2 = s3 = 1 - builder.tagged(CHIPLET_SELECTORS_BASE_ID + 8, CHIPLET_SELECTORS_NAMES[8], |builder| { - builder - .when_transition() - .when(s0.clone()) - .when(s1.clone()) - .when(s2.clone()) - .when(s3.clone()) - .assert_zero(s3_next.clone() - s3.clone()); - }); - - // s4' = s4 when s0 = s1 = s2 = s3 = s4 = 1 - builder.tagged(CHIPLET_SELECTORS_BASE_ID + 9, CHIPLET_SELECTORS_NAMES[9], |builder| { - builder - .when_transition() - .when(s0) - .when(s1) - .when(s2) - .when(s3) - .when(s4.clone()) - .assert_zero(s4_next - s4); - }); -} + // ========================================================================= + // LOAD SELECTOR COLUMNS + // ========================================================================= -// INTERNAL HELPERS -// ================================================================================================ + // [s_ctrl, s_perm, s1, s2, s3, s4] + let sel = local.chiplet_selectors(); + let sel_next = next.chiplet_selectors(); -/// Bitwise chiplet active flag: `s0 * !s1`. -#[inline] -pub fn bitwise_chiplet_flag(s0: E, s1: E) -> E { - s0 * (E::ONE - s1) -} + // s_ctrl = chiplets[0]: 1 on controller rows, 0 on perm/non-hasher rows. + let s_ctrl: AB::Expr = sel[0].into(); + let s_ctrl_next: AB::Expr = sel_next[0].into(); -/// Memory chiplet active flag: `s0 * s1 * !s2`. -#[inline] -pub fn memory_chiplet_flag(s0: E, s1: E, s2: E) -> E { - s0 * s1 * (E::ONE - s2) -} + // s_perm: 1 on permutation rows, 0 elsewhere. + let s_perm: AB::Expr = sel[1].into(); + let s_perm_next: AB::Expr = sel_next[1].into(); -/// ACE chiplet active flag: `s0 * s1 * s2 * !s3`. -#[inline] -pub fn ace_chiplet_flag(s0: E, s1: E, s2: E, s3: E) -> E { - s0 * s1 * s2 * (E::ONE - s3) -} + // s_ctrl_or_s_perm: 1 on any hasher row (controller or permutation), 0 on s0 rows. + let s_ctrl_or_s_perm = s_ctrl.clone() + s_perm.clone(); + let s_ctrl_or_s_perm_next = s_ctrl_next.clone() + s_perm_next.clone(); + + // s1..s4: remaining chiplet selectors. + let s1: AB::Expr = sel[2].into(); + let s2: AB::Expr = sel[3].into(); + let s3: AB::Expr = sel[4].into(); + let s4: AB::Expr = sel[5].into(); + + let s1_next: AB::Expr = sel_next[2].into(); + let s2_next: AB::Expr = sel_next[3].into(); + let s3_next: AB::Expr = sel_next[4].into(); + let s4_next: AB::Expr = sel_next[5].into(); + + // Virtual s0 = 1 - (s_ctrl + s_perm): same semantics as old chiplets[0]. + // 0 on controller and perm rows, 1 on non-hasher rows. + let s0: AB::Expr = s_ctrl_or_s_perm.not(); + + // ========================================================================= + // TRI-STATE SELECTOR CONSTRAINTS + // ========================================================================= + + // s_ctrl and s_perm are each boolean, and at most one can be active (their + // sum is also boolean, so they cannot both be 1 simultaneously). + builder.assert_bool(s_ctrl.clone()); + builder.assert_bool(s_perm.clone()); + builder.assert_bool(s_ctrl_or_s_perm); + + // Transition rules: enforce the trace ordering ctrl...ctrl, perm...perm, s0...s0. + { + let builder = &mut builder.when_transition(); + + // A controller row must be followed by another controller or permutation row. + // s_ctrl * (1 - (s_ctrl' + s_perm')) = 0. + builder.when(s_ctrl.clone()).assert_one(s_ctrl_or_s_perm_next); + + // A permutation row cannot be followed by a controller row. + // s_perm * s_ctrl' = 0. + builder.when(s_perm.clone()).assert_zero(s_ctrl_next.clone()); + + // Once in the s0 region, neither s_ctrl nor s_perm can appear again. + // s0 * s_ctrl' = 0, s0 * s_perm' = 0. + { + let builder = &mut builder.when(s0.clone()); + builder.assert_zero(s_ctrl_next.clone()); + builder.assert_zero(s_perm_next.clone()); + } + } + + // ========================================================================= + // REMAINING CHIPLET SELECTOR CONSTRAINTS (s1..s4 under virtual s0) + // ========================================================================= + + // Cumulative products gate each selector on its prefix being active. + let s01 = s0.clone() * s1.clone(); + let s012 = s01.clone() * s2.clone(); + let s0123 = s012.clone() * s3.clone(); + + // s1..s4 booleanity, gated by their prefix under s0. + builder.when(s0.clone()).assert_bool(s1.clone()); + builder.when(s01.clone()).assert_bool(s2.clone()); + builder.when(s012.clone()).assert_bool(s3.clone()); + builder.when(s0123.clone()).assert_bool(s4.clone()); + + // s1..s4 stability: once set to 1, they stay 1 (forbids 1→0 transitions). + // Gated by the cumulative product including the target selector, so the gate + // is only active when the selector is already 1 — permitting the 0→1 + // transition at section boundaries while forbidding 1→0. + let s01234 = s0123.clone() * s4.clone(); + { + let builder = &mut builder.when_transition(); + builder.when(s01.clone()).assert_eq(s1_next.clone(), s1.clone()); + builder.when(s012.clone()).assert_eq(s2_next.clone(), s2.clone()); + builder.when(s0123.clone()).assert_eq(s3_next.clone(), s3.clone()); + builder.when(s01234).assert_eq(s4_next, s4.clone()); + } + + // ========================================================================= + // LAST-ROW INVARIANT + // ========================================================================= + // On the last row: s_ctrl = s_perm = 0 and s1 = s2 = s3 = s4 = 1 (kernel_rom + // section). Virtual s0 = 1 follows from s_ctrl = s_perm = 0. + // This ensures every chiplet's is_active flag is zero on the last row. + // Combined with the (1 - s_n') factor in precomputed flags, chiplet-gated + // constraints automatically vanish without explicit when_transition() guards. + { + let builder = &mut builder.when_last_row(); + builder.assert_zero(s_ctrl.clone()); + builder.assert_zero(s_perm.clone()); + builder.assert_one(s1); + builder.assert_one(s2); + builder.assert_one(s3); + builder.assert_one(s4); + } + + // ========================================================================= + // PRECOMPUTE FLAGS + // ========================================================================= + + let not_s1_next = s1_next.not(); + let not_s2_next = s2_next.not(); + let not_s3_next = s3_next.not(); + + let is_transition_flag: AB::Expr = builder.is_transition(); + + // --- Controller flags (direct physical selector s_ctrl) --- + // is_active = s_ctrl (deg 1) + // is_transition = is_transition_flag * s_ctrl * s_ctrl' (deg 3) + // is_last = s_ctrl * (1 - s_ctrl') (deg 2) + let ctrl_is_active = s_ctrl.clone(); + let ctrl_is_transition = is_transition_flag.clone() * s_ctrl.clone() * s_ctrl_next.clone(); + let ctrl_is_last = s_ctrl * s_ctrl_next.not(); + let ctrl_next_is_first = AB::Expr::ZERO; // controller is first section + + // --- Permutation flags (direct physical selector s_perm) --- + // is_active = s_perm (deg 1) + // is_transition = is_transition_flag * s_perm * s_perm' (deg 3) + // is_last = s_perm * (1 - s_perm') (deg 2) + // next_is_first = ctrl_is_last * s_perm' (deg 3) + let perm_is_active = s_perm.clone(); + let perm_is_transition = is_transition_flag.clone() * s_perm.clone() * s_perm_next.clone(); + let perm_is_last = s_perm * s_perm_next.not(); + let perm_next_is_first = ctrl_is_last.clone() * s_perm_next; + + // --- Remaining chiplet active flags (subtraction trick: prefix - prefix * s_n) --- + let is_bitwise = s0.clone() - s01.clone(); + let is_memory = s01.clone() - s012.clone(); + let is_ace = s012.clone() - s0123; + + // --- Remaining chiplet last-row flags: is_active * s_n' --- + let is_bitwise_last = is_bitwise.clone() * s1_next; + let is_memory_last = is_memory.clone() * s2_next; + let is_ace_last = is_ace.clone() * s3_next; + + // --- Remaining chiplet next-is-first flags: is_last[n-1] * (1 - s_n') --- + let next_is_bitwise_first = perm_is_last.clone() * not_s1_next.clone(); + let next_is_memory_first = is_bitwise_last.clone() * not_s2_next.clone(); + let next_is_ace_first = is_memory_last.clone() * not_s3_next.clone(); + + // --- Remaining chiplet transition flags --- + // Each sub-s0 chiplet fires its transition flag when the current row is in that + // chiplet's section (the prefix product) and the next row hasn't yet advanced + // past it (the `1 - s_n'` factor). We don't need an explicit `(1 - s_ctrl' - + // s_perm')` factor because the tri-state transition rule already enforces + // `s0 = 1 → s_ctrl' = 0 ∧ s_perm' = 0`, so on valid traces that factor is + // always 1 whenever the prefix is active. + let bitwise_transition = is_transition_flag.clone() * s0 * not_s1_next; + let memory_transition = is_transition_flag.clone() * s01 * not_s2_next; + let ace_transition = is_transition_flag * s012 * not_s3_next; -/// Kernel ROM chiplet active flag: `s0 * s1 * s2 * s3 * !s4`. -#[inline] -pub fn kernel_rom_chiplet_flag(s0: E, s1: E, s2: E, s3: E, s4: E) -> E { - s0 * s1 * s2 * s3 * (E::ONE - s4) + ChipletSelectors { + controller: ChipletFlags { + is_active: ctrl_is_active, + is_transition: ctrl_is_transition, + is_last: ctrl_is_last, + next_is_first: ctrl_next_is_first, + }, + permutation: ChipletFlags { + is_active: perm_is_active, + is_transition: perm_is_transition, + is_last: perm_is_last, + next_is_first: perm_next_is_first, + }, + bitwise: ChipletFlags { + is_active: is_bitwise, + is_transition: bitwise_transition, + is_last: is_bitwise_last, + next_is_first: next_is_bitwise_first, + }, + memory: ChipletFlags { + is_active: is_memory, + is_transition: memory_transition, + is_last: is_memory_last, + next_is_first: next_is_memory_first, + }, + ace: ChipletFlags { + is_active: is_ace, + is_transition: ace_transition, + is_last: is_ace_last, + next_is_first: next_is_ace_first, + }, + } } diff --git a/air/src/constraints/columns.rs b/air/src/constraints/columns.rs new file mode 100644 index 0000000000..3d33c0ce27 --- /dev/null +++ b/air/src/constraints/columns.rs @@ -0,0 +1,249 @@ +//! Column layout types for the main and auxiliary execution traces. +//! +//! These `#[repr(C)]` structs provide typed, named access to trace columns. +//! They are borrowed zero-copy from raw `[T; WIDTH]` slices and are used +//! exclusively by constraint code. They are independent of trace storage +//! (`MainTrace`, `TraceStorage`, etc.). + +use core::{ + borrow::{Borrow, BorrowMut}, + mem::size_of, +}; + +use super::{ + chiplets::columns::{ + AceCols, AceEvalCols, AceReadCols, BitwiseCols, ControllerCols, KernelRomCols, MemoryCols, + PermutationCols, borrow_chiplet, + }, + decoder::columns::DecoderCols, + range::columns::RangeCols, + stack::columns::StackCols, + system::columns::SystemCols, +}; +use crate::trace::{CHIPLETS_WIDTH, TRACE_WIDTH}; + +// MAIN TRACE COLUMN STRUCT +// ================================================================================================ + +/// Column layout of the main execution trace (71 columns). +/// +/// This `#[repr(C)]` struct provides typed, named access to every column. It can be +/// borrowed zero-copy from a raw `[T; TRACE_WIDTH]` slice via `Borrow>`. +/// +/// Chiplet columns are not public because the 20 columns are a union — their interpretation +/// depends on which chiplet is active. Access goes through typed accessors like +/// [`MainCols::permutation()`], [`MainCols::controller()`], [`MainCols::bitwise()`], etc. +/// +/// The `s_perm` column is separated from the chiplets array because it is consumed +/// exclusively by the chiplet selector system, not by any chiplet's constraint code. +#[repr(C)] +pub struct MainCols { + pub system: SystemCols, + pub decoder: DecoderCols, + pub stack: StackCols, + pub range: RangeCols, + pub(crate) chiplets: [T; CHIPLETS_WIDTH - 1], + /// Permutation segment selector: consumed by `build_chiplet_selectors`. + pub s_perm: T, +} + +impl MainCols { + /// Returns the 6 chiplet selector columns `[s_ctrl, s_perm, s1, s2, s3, s4]`. + /// + /// `s_ctrl = chiplets[0]` and `s_perm` are the two physical selectors + /// for the controller and permutation sub-chiplets. `s1..s4` subdivide the + /// remaining chiplets under the virtual `s0 = 1 - (s_ctrl + s_perm)`. + pub fn chiplet_selectors(&self) -> [T; 6] + where + T: Copy, + { + [ + self.chiplets[0], + self.s_perm, + self.chiplets[1], + self.chiplets[2], + self.chiplets[3], + self.chiplets[4], + ] + } + + /// Returns a typed borrow of the bitwise chiplet columns (chiplets\[2..15\]). + pub fn bitwise(&self) -> &BitwiseCols { + borrow_chiplet(&self.chiplets[2..15]) + } + + /// Returns a typed borrow of the memory chiplet columns (chiplets\[3..18\]). + pub fn memory(&self) -> &MemoryCols { + borrow_chiplet(&self.chiplets[3..18]) + } + + /// Returns a typed borrow of the ACE chiplet columns (chiplets\[4..20\]). + /// + /// Spans `chiplets[4..20]` (16 cols). Since `chiplets` has 20 elements (indices + /// 0..19), this is `chiplets[4..20]` = `chiplets[4..]` (all 16 remaining). + pub fn ace(&self) -> &AceCols { + borrow_chiplet(&self.chiplets[4..]) + } + + /// Returns a typed borrow of the kernel ROM chiplet columns (chiplets\[5..10\]). + pub fn kernel_rom(&self) -> &KernelRomCols { + borrow_chiplet(&self.chiplets[5..10]) + } + + /// Returns a typed borrow of the permutation sub-chiplet columns (chiplets\[1..20\]). + pub fn permutation(&self) -> &PermutationCols { + borrow_chiplet(&self.chiplets[1..]) + } + + /// Returns a typed borrow of the controller sub-chiplet columns (chiplets\[1..20\]). + pub fn controller(&self) -> &ControllerCols { + borrow_chiplet(&self.chiplets[1..]) + } +} + +impl Borrow> for [T] { + fn borrow(&self) -> &MainCols { + debug_assert_eq!(self.len(), TRACE_WIDTH); + let (prefix, shorts, suffix) = unsafe { self.align_to::>() }; + debug_assert!(prefix.is_empty() && suffix.is_empty() && shorts.len() == 1); + &shorts[0] + } +} + +impl BorrowMut> for [T] { + fn borrow_mut(&mut self) -> &mut MainCols { + debug_assert_eq!(self.len(), TRACE_WIDTH); + let (prefix, shorts, suffix) = unsafe { self.align_to_mut::>() }; + debug_assert!(prefix.is_empty() && suffix.is_empty() && shorts.len() == 1); + &mut shorts[0] + } +} + +// CONST INDEX MAP +// ================================================================================================ + +/// Generates an array `[0, 1, 2, ..., N-1]` at compile time. +pub const fn indices_arr() -> [usize; N] { + let mut arr = [0; N]; + let mut i = 0; + while i < N { + arr[i] = i; + i += 1; + } + arr +} + +/// Number of columns in the main trace (71), derived from the struct layout. +pub const NUM_MAIN_COLS: usize = size_of::>(); + +/// Compile-time index map: each field holds its column index. +/// +/// Example: `MAIN_COL_MAP.decoder.addr == 6`, `MAIN_COL_MAP.stack.top[0] == 30`. +#[allow(dead_code)] +pub const MAIN_COL_MAP: MainCols = { + assert!(NUM_MAIN_COLS == TRACE_WIDTH); + unsafe { core::mem::transmute(indices_arr::()) } +}; + +// COLUMN COUNTS +// ================================================================================================ +// +// The auxiliary trace is the LogUp lookup-argument segment built by +// [`crate::ProcessorAir`]'s `AuxBuilder` impl (see `air/src/constraints/lookup/`). +// Its 7-column layout is described entirely by `ProcessorAir::column_shape`. + +pub const NUM_SYSTEM_COLS: usize = size_of::>(); +pub const NUM_DECODER_COLS: usize = size_of::>(); +pub const NUM_STACK_COLS: usize = size_of::>(); +pub const NUM_RANGE_COLS: usize = size_of::>(); +pub const NUM_BITWISE_COLS: usize = size_of::>(); +pub const NUM_MEMORY_COLS: usize = size_of::>(); +pub const NUM_ACE_COLS: usize = size_of::>(); +pub const NUM_ACE_READ_COLS: usize = size_of::>(); +pub const NUM_ACE_EVAL_COLS: usize = size_of::>(); +pub const NUM_KERNEL_ROM_COLS: usize = size_of::>(); + +const _: () = assert!(NUM_MAIN_COLS == TRACE_WIDTH); +const _: () = assert!(NUM_SYSTEM_COLS == 6); +const _: () = assert!(NUM_DECODER_COLS == 24); +const _: () = assert!(NUM_STACK_COLS == 19); +const _: () = assert!(NUM_RANGE_COLS == 2); +const _: () = assert!(NUM_BITWISE_COLS == 13); +const _: () = assert!(NUM_MEMORY_COLS == 15); +const _: () = assert!(NUM_ACE_COLS == 16); +const _: () = assert!(NUM_ACE_READ_COLS == 4); +const _: () = assert!(NUM_ACE_EVAL_COLS == 4); +const _: () = assert!(NUM_KERNEL_ROM_COLS == 5); + +// TESTS +// ================================================================================================ + +#[cfg(test)] +mod tests { + use super::*; + use crate::trace::{ + CHIPLETS_OFFSET, CLK_COL_IDX, CTX_COL_IDX, DECODER_TRACE_OFFSET, FN_HASH_OFFSET, + STACK_TRACE_OFFSET, decoder, range, stack, + }; + + // --- Main trace column map vs offset constants ----------------------------------------------- + + #[test] + fn col_map_system() { + assert_eq!(MAIN_COL_MAP.system.clk, CLK_COL_IDX); + assert_eq!(MAIN_COL_MAP.system.ctx, CTX_COL_IDX); + assert_eq!(MAIN_COL_MAP.system.fn_hash[0], FN_HASH_OFFSET); + assert_eq!(MAIN_COL_MAP.system.fn_hash[3], FN_HASH_OFFSET + 3); + } + + #[test] + fn col_map_decoder() { + assert_eq!(MAIN_COL_MAP.decoder.addr, DECODER_TRACE_OFFSET + decoder::ADDR_COL_IDX); + assert_eq!(MAIN_COL_MAP.decoder.op_bits[0], DECODER_TRACE_OFFSET + decoder::OP_BITS_OFFSET); + assert_eq!( + MAIN_COL_MAP.decoder.op_bits[6], + DECODER_TRACE_OFFSET + decoder::OP_BITS_OFFSET + 6 + ); + assert_eq!( + MAIN_COL_MAP.decoder.hasher_state[0], + DECODER_TRACE_OFFSET + decoder::HASHER_STATE_OFFSET + ); + assert_eq!(MAIN_COL_MAP.decoder.in_span, DECODER_TRACE_OFFSET + decoder::IN_SPAN_COL_IDX); + assert_eq!( + MAIN_COL_MAP.decoder.group_count, + DECODER_TRACE_OFFSET + decoder::GROUP_COUNT_COL_IDX + ); + assert_eq!(MAIN_COL_MAP.decoder.op_index, DECODER_TRACE_OFFSET + decoder::OP_INDEX_COL_IDX); + assert_eq!( + MAIN_COL_MAP.decoder.batch_flags[0], + DECODER_TRACE_OFFSET + decoder::OP_BATCH_FLAGS_OFFSET + ); + assert_eq!( + MAIN_COL_MAP.decoder.extra[0], + DECODER_TRACE_OFFSET + decoder::OP_BITS_EXTRA_COLS_OFFSET + ); + } + + #[test] + fn col_map_stack() { + assert_eq!(MAIN_COL_MAP.stack.top[0], STACK_TRACE_OFFSET + stack::STACK_TOP_OFFSET); + assert_eq!(MAIN_COL_MAP.stack.top[15], STACK_TRACE_OFFSET + 15); + assert_eq!(MAIN_COL_MAP.stack.b0, STACK_TRACE_OFFSET + stack::B0_COL_IDX); + assert_eq!(MAIN_COL_MAP.stack.b1, STACK_TRACE_OFFSET + stack::B1_COL_IDX); + assert_eq!(MAIN_COL_MAP.stack.h0, STACK_TRACE_OFFSET + stack::H0_COL_IDX); + } + + #[test] + fn col_map_range() { + assert_eq!(MAIN_COL_MAP.range.multiplicity, range::M_COL_IDX); + assert_eq!(MAIN_COL_MAP.range.value, range::V_COL_IDX); + } + + #[test] + fn col_map_chiplets() { + assert_eq!(MAIN_COL_MAP.chiplets[0], CHIPLETS_OFFSET); + assert_eq!(MAIN_COL_MAP.chiplets[19], CHIPLETS_OFFSET + 19); + // s_perm is a separate field after chiplets[0..20] + assert_eq!(MAIN_COL_MAP.s_perm, CHIPLETS_OFFSET + 20); + } +} diff --git a/air/src/constraints/constants.rs b/air/src/constraints/constants.rs new file mode 100644 index 0000000000..c75e5721e1 --- /dev/null +++ b/air/src/constraints/constants.rs @@ -0,0 +1,27 @@ +//! Shared field constants for constraint code. + +use miden_core::field::PrimeCharacteristicRing; + +use crate::Felt; + +pub const F_1: Felt = Felt::ONE; +#[allow(dead_code)] +pub const F_NEG_1: Felt = Felt::NEG_ONE; +pub const F_2: Felt = Felt::TWO; +pub const F_3: Felt = Felt::new_unchecked(3); +pub const F_4: Felt = Felt::new_unchecked(4); +pub const F_7: Felt = Felt::new_unchecked(7); +pub const F_8: Felt = Felt::new_unchecked(8); +pub const F_9: Felt = Felt::new_unchecked(9); +pub const F_16: Felt = Felt::new_unchecked(16); +pub const F_27: Felt = Felt::new_unchecked(27); +pub const F_81: Felt = Felt::new_unchecked(81); +pub const F_128: Felt = Felt::new_unchecked(128); +pub const F_243: Felt = Felt::new_unchecked(243); +pub const F_729: Felt = Felt::new_unchecked(729); +pub const F_2187: Felt = Felt::new_unchecked(2187); +pub const TWO_POW_16: Felt = Felt::new_unchecked(1 << 16); +pub const TWO_POW_16_MINUS_1: Felt = Felt::new_unchecked(65535); +pub const TWO_POW_32: Felt = Felt::new_unchecked(1 << 32); +pub const TWO_POW_32_MINUS_1: Felt = Felt::new_unchecked((1u64 << 32) - 1); +pub const TWO_POW_48: Felt = Felt::new_unchecked(1 << 48); diff --git a/air/src/constraints/decoder/bus.rs b/air/src/constraints/decoder/bus.rs deleted file mode 100644 index 84806c08e9..0000000000 --- a/air/src/constraints/decoder/bus.rs +++ /dev/null @@ -1,898 +0,0 @@ -//! Decoder bus constraints (p1/p2/p3). -//! -//! This module enforces the running‑product relations for the decoder’s three auxiliary tables: -//! - p1: block stack (nesting and call context) -//! - p2: block hash queue (blocks awaiting execution) -//! - p3: op group queue (groups produced by SPAN/RESPAN) -//! -//! ## What is enforced here -//! - The per‑row running‑product equation for each table: `pX' * requests = pX * responses`. -//! - The request/response terms are built from per‑opcode insert/remove messages. -//! -//! ## What is *not* enforced here -//! - Initial/final boundary conditions. The wrapper AIR fixes the first row to the identity element -//! and constrains the last row via `aux_finals`. We intentionally do not duplicate those -//! constraints here. -//! -//! ## Message encoding -//! Each table message is encoded as: -//! `alpha + sum_i beta^i * element[i]` -//! This matches the multiset protocol used by the processor. -//! -//! ## References -//! - Processor tables: `processor/src/decoder/aux_trace/block_stack_table.rs` (p1), -//! `processor/src/decoder/aux_trace/block_hash_table.rs` (p2), -//! `processor/src/decoder/aux_trace/op_group_table.rs` (p3). -//! - air‑script constraints: `constraints/decoder.air`. - -use miden_core::field::PrimeCharacteristicRing; -use miden_crypto::stark::air::{ExtensionBuilder, LiftedAirBuilder, WindowAccess}; - -use crate::{ - MainTraceRow, - constraints::{ - bus::indices::P1_BLOCK_STACK, - op_flags::OpFlags, - tagging::{TaggingAirBuilderExt, ids::TAG_DECODER_BUS_BASE}, - }, - trace::Challenges, -}; - -// CONSTANTS -// ================================================================================================ - -/// Base ID for decoder bus constraints. -const DECODER_BUS_BASE_ID: usize = TAG_DECODER_BUS_BASE; - -/// Decoder bus constraint namespaces in assertion order. -const DECODER_BUS_NAMES: [&str; 3] = [ - "decoder.bus.p1.transition", - "decoder.bus.p2.transition", - "decoder.bus.p3.transition", -]; - -/// Weights for opcode bit decoding: b0 + 2*b1 + ... + 64*b6. -const OP_BIT_WEIGHTS: [u16; 7] = [1, 2, 4, 8, 16, 32, 64]; - -/// Encoders for block stack table (p1) messages. -struct BlockStackEncoders<'a, AB: LiftedAirBuilder> { - challenges: &'a Challenges, -} - -impl<'a, AB: LiftedAirBuilder> BlockStackEncoders<'a, AB> { - fn new(challenges: &'a Challenges) -> Self { - Self { challenges } - } - - /// Encodes `[block_id, parent_id, is_loop]`. - fn simple(&self, block_id: &AB::Expr, parent_id: &AB::Expr, is_loop: &AB::Expr) -> AB::ExprEF { - self.challenges.encode([block_id.clone(), parent_id.clone(), is_loop.clone()]) - } - - /// Encodes `[block_id, parent_id, is_loop, ctx, depth, overflow, fn_hash[0..4]]`. - fn full( - &self, - block_id: &AB::Expr, - parent_id: &AB::Expr, - is_loop: &AB::Expr, - ctx: &AB::Expr, - depth: &AB::Expr, - overflow: &AB::Expr, - fh: &[AB::Expr; 4], - ) -> AB::ExprEF { - self.challenges.encode([ - block_id.clone(), - parent_id.clone(), - is_loop.clone(), - ctx.clone(), - depth.clone(), - overflow.clone(), - fh[0].clone(), - fh[1].clone(), - fh[2].clone(), - fh[3].clone(), - ]) - } -} - -/// Encoder for block hash table (p2) messages. -struct BlockHashEncoder<'a, AB: LiftedAirBuilder> { - challenges: &'a Challenges, -} - -impl<'a, AB: LiftedAirBuilder> BlockHashEncoder<'a, AB> { - fn new(challenges: &'a Challenges) -> Self { - Self { challenges } - } - - /// Encodes `[parent_id, hash[0..4], is_first_child, is_loop_body]`. - fn encode( - &self, - parent: &AB::Expr, - hash: [&AB::Expr; 4], - first_child: &AB::Expr, - loop_body: &AB::Expr, - ) -> AB::ExprEF { - self.challenges.encode([ - parent.clone(), - hash[0].clone(), - hash[1].clone(), - hash[2].clone(), - hash[3].clone(), - first_child.clone(), - loop_body.clone(), - ]) - } -} - -/// Encoder for op group table (p3) messages. -struct OpGroupEncoder<'a, AB: LiftedAirBuilder> { - challenges: &'a Challenges, -} - -impl<'a, AB: LiftedAirBuilder> OpGroupEncoder<'a, AB> { - fn new(challenges: &'a Challenges) -> Self { - Self { challenges } - } - - /// Encodes `[block_id, group_count, op_value]`. - fn encode(&self, block_id: &AB::Expr, group_count: &AB::Expr, value: &AB::Expr) -> AB::ExprEF { - self.challenges.encode([block_id.clone(), group_count.clone(), value.clone()]) - } -} - -/// Decoder column indices (relative to decoder trace). -mod decoder_cols { - /// Block address column. - pub const ADDR: usize = 0; - /// Hasher state offset within decoder trace. - pub const HASHER_STATE_OFFSET: usize = 8; - /// is_loop_flag column (hasher_state[5]). - pub const IS_LOOP_FLAG: usize = HASHER_STATE_OFFSET + 5; - /// is_call_flag column (hasher_state[6]). - pub const IS_CALL_FLAG: usize = HASHER_STATE_OFFSET + 6; - /// is_syscall_flag column (hasher_state[7]). - pub const IS_SYSCALL_FLAG: usize = HASHER_STATE_OFFSET + 7; -} - -/// Stack column indices (relative to stack trace). -mod stack_cols { - /// B0 column - stack depth. - pub const B0: usize = 16; - /// B1 column - overflow address. - pub const B1: usize = 17; -} - -/// Op group table column indices (relative to decoder trace). -mod op_group_cols { - /// HASHER_STATE_RANGE.end (hasher state is 8 columns starting at offset 8). - const HASHER_STATE_END: usize = super::decoder_cols::HASHER_STATE_OFFSET + 8; - - /// is_in_span flag column. - pub const IS_IN_SPAN: usize = HASHER_STATE_END; - - /// Group count column. - pub const GROUP_COUNT: usize = IS_IN_SPAN + 1; - - /// Op index column (not used directly here but defines layout). - const OP_INDEX: usize = GROUP_COUNT + 1; - - /// Batch flag columns (c0, c1, c2). - const BATCH_FLAGS_OFFSET: usize = OP_INDEX + 1; - pub const BATCH_FLAG_0: usize = BATCH_FLAGS_OFFSET; - pub const BATCH_FLAG_1: usize = BATCH_FLAGS_OFFSET + 1; - pub const BATCH_FLAG_2: usize = BATCH_FLAGS_OFFSET + 2; -} - -// HELPERS -// ================================================================================================ - -/// Decodes opcode bits from a trace row into an opcode value. -fn opcode_from_row(row: &MainTraceRow) -> AB::Expr -where - AB: LiftedAirBuilder, -{ - OP_BIT_WEIGHTS.iter().enumerate().fold(AB::Expr::ZERO, |acc, (i, weight)| { - let bit: AB::Expr = row.decoder[1 + i].clone().into(); - acc + bit * AB::Expr::from_u16(*weight) - }) -} - -// ENTRY POINTS -// ================================================================================================ - -/// Enforces all decoder bus constraints (p1, p2, p3). -pub fn enforce_bus( - builder: &mut AB, - local: &MainTraceRow, - next: &MainTraceRow, - op_flags: &OpFlags, - challenges: &Challenges, -) where - AB: LiftedAirBuilder, -{ - enforce_block_stack_table_constraint(builder, local, next, op_flags, challenges); - enforce_block_hash_table_constraint(builder, local, next, op_flags, challenges); - enforce_op_group_table_constraint(builder, local, next, op_flags, challenges); -} - -// CONSTRAINT HELPERS -// ================================================================================================ - -// BLOCK STACK TABLE (p1) -// ================================================================================================ - -/// Enforces the block stack table (p1) bus constraint. -/// -/// The block stack table tracks block nesting state. Entries are added when blocks start -/// and removed when blocks end or transition (RESPAN). -/// -/// Context fields are populated as follows: -/// - JOIN/SPLIT/SPAN/DYN/RESPAN: ctx/depth/overflow/fn_hash are zero and is_loop = 0. -/// - LOOP: is_loop = s0 (other context fields still zero). -/// - CALL/SYSCALL: ctx/system_ctx, depth=stack_b0, overflow=stack_b1, fn_hash[0..3]. -/// - DYNCALL: ctx/system_ctx, depth=h4, overflow=h5, fn_hash[0..3]. -/// -/// ## Constraint Structure -/// -/// ```text -/// p1' * (u_end + u_respan + 1 - (f_end + f_respan)) = -/// p1 * (v_join + v_split + v_loop + v_span + v_respan + v_dyn + v_dyncall + v_call + v_syscall -/// + 1 - (f_join + f_split + f_loop + f_span + f_respan + f_dyn + f_dyncall + f_call + f_syscall)) -/// ``` -/// -/// Where: -/// - `v_xxx = f_xxx * message_xxx` (insertion contribution, degree 7+1=8) -/// - `u_xxx = f_xxx * message_xxx` (removal contribution, degree 7+1=8) -/// - Full constraint degree: 1 + 8 = 9 -/// -/// ## Message Format -/// -/// Messages are linear combinations: `alpha[0]*1 + alpha[1]*block_id + alpha[2]*parent_id + ...` -/// - Simple blocks: 4 elements `[1, block_id, parent_id, is_loop]` -/// - CALL/SYSCALL/DYNCALL: 11 elements with context `[..., ctx, fmp, b0, b1, fn_hash[0..4]]` -pub fn enforce_block_stack_table_constraint( - builder: &mut AB, - local: &MainTraceRow, - next: &MainTraceRow, - op_flags: &OpFlags, - challenges: &Challenges, -) where - AB: LiftedAirBuilder, -{ - // Auxiliary trace must be present - - // Extract auxiliary trace values - let (p1_local, p1_next) = { - let aux = builder.permutation(); - let aux_local = aux.current_slice(); - let aux_next = aux.next_slice(); - (aux_local[P1_BLOCK_STACK], aux_next[P1_BLOCK_STACK]) - }; - - let one = AB::Expr::ONE; - let zero = AB::Expr::ZERO; - let one_ef = AB::ExprEF::ONE; - - // Helper to convert trace value to base field expression - let to_expr = |v: AB::Var| -> AB::Expr { v.into() }; - - // ========================================================================= - // TRACE VALUE EXTRACTION - // ========================================================================= - - // Block addresses - let addr_local = to_expr(local.decoder[decoder_cols::ADDR].clone()); - let addr_next = to_expr(next.decoder[decoder_cols::ADDR].clone()); - - // Hasher state element 1 (for RESPAN parent_id) - let h1_next = to_expr(next.decoder[decoder_cols::HASHER_STATE_OFFSET + 1].clone()); - - // Stack top (for LOOP is_loop condition) - let s0 = to_expr(local.stack[0].clone()); - - // Context info for CALL/SYSCALL/DYNCALL insertions (from current row) - let ctx_local = to_expr(local.ctx.clone()); - let b0_local = to_expr(local.stack[stack_cols::B0].clone()); - let b1_local = to_expr(local.stack[stack_cols::B1].clone()); - let fn_hash_local: [AB::Expr; 4] = [ - to_expr(local.fn_hash[0].clone()), - to_expr(local.fn_hash[1].clone()), - to_expr(local.fn_hash[2].clone()), - to_expr(local.fn_hash[3].clone()), - ]; - - // Hasher state for DYNCALL (h4, h5 contain post-shift stack state) - let h4_local = to_expr(local.decoder[decoder_cols::HASHER_STATE_OFFSET + 4].clone()); - let h5_local = to_expr(local.decoder[decoder_cols::HASHER_STATE_OFFSET + 5].clone()); - - // Flags for END context detection - let is_loop_flag = to_expr(local.decoder[decoder_cols::IS_LOOP_FLAG].clone()); - let is_call_flag = to_expr(local.decoder[decoder_cols::IS_CALL_FLAG].clone()); - let is_syscall_flag = to_expr(local.decoder[decoder_cols::IS_SYSCALL_FLAG].clone()); - - // Context info for END after CALL/SYSCALL (from next row) - let ctx_next = to_expr(next.ctx.clone()); - let b0_next = to_expr(next.stack[stack_cols::B0].clone()); - let b1_next = to_expr(next.stack[stack_cols::B1].clone()); - let fn_hash_next: [AB::Expr; 4] = [ - to_expr(next.fn_hash[0].clone()), - to_expr(next.fn_hash[1].clone()), - to_expr(next.fn_hash[2].clone()), - to_expr(next.fn_hash[3].clone()), - ]; - - // ========================================================================= - // MESSAGE BUILDERS - // ========================================================================= - - let encoders = BlockStackEncoders::::new(challenges); - - // ========================================================================= - // INSERTION CONTRIBUTIONS (v_xxx = f_xxx * message) - // ========================================================================= - - // Operation flags for control-flow instructions. - let is_join = op_flags.join(); - let is_split = op_flags.split(); - let is_span = op_flags.span(); - let is_dyn = op_flags.dyn_op(); - let is_loop = op_flags.loop_op(); - let is_respan = op_flags.respan(); - let is_call = op_flags.call(); - let is_syscall = op_flags.syscall(); - let is_dyncall = op_flags.dyncall(); - let is_end = op_flags.end(); - - // JOIN/SPLIT/SPAN/DYN: insert(addr', addr, 0, 0, 0, 0, 0, 0, 0, 0) - let msg_simple = encoders.simple(&addr_next, &addr_local, &zero); - let v_join = msg_simple.clone() * is_join.clone(); - let v_split = msg_simple.clone() * is_split.clone(); - let v_span = msg_simple.clone() * is_span.clone(); - let v_dyn = msg_simple.clone() * is_dyn.clone(); - - // LOOP: insert(addr', addr, s0, 0, 0, 0, 0, 0, 0, 0) - let msg_loop = encoders.simple(&addr_next, &addr_local, &s0); - let v_loop = msg_loop * is_loop.clone(); - - // RESPAN: insert(addr', h1', 0, 0, 0, 0, 0, 0, 0, 0) - let msg_respan_insert = encoders.simple(&addr_next, &h1_next, &zero); - let v_respan = msg_respan_insert * is_respan.clone(); - - // CALL/SYSCALL: insert(addr', addr, 0, ctx, fmp, b0, b1, fn_hash[0..4]) - let msg_call = encoders.full( - &addr_next, - &addr_local, - &zero, - &ctx_local, - &b0_local, - &b1_local, - &fn_hash_local, - ); - let v_call = msg_call.clone() * is_call.clone(); - let v_syscall = msg_call * is_syscall.clone(); - - // DYNCALL: insert(addr', addr, 0, ctx, h4, h5, fn_hash[0..4]) - let msg_dyncall = encoders.full( - &addr_next, - &addr_local, - &zero, - &ctx_local, - &h4_local, - &h5_local, - &fn_hash_local, - ); - let v_dyncall = msg_dyncall * is_dyncall.clone(); - - // Sum of insertion flags - let insert_flag_sum = is_join.clone() - + is_split.clone() - + is_span.clone() - + is_dyn.clone() - + is_loop.clone() - + is_respan.clone() - + is_call.clone() - + is_syscall.clone() - + is_dyncall.clone(); - - // Total insertion contribution - let insertion_sum = - v_join + v_split + v_span + v_dyn + v_loop + v_respan + v_call + v_syscall + v_dyncall; - - // Response side: insertion_sum + (1 - insert_flag_sum) - let response = insertion_sum + (one_ef.clone() - insert_flag_sum); - - // ========================================================================= - // REMOVAL CONTRIBUTIONS (u_xxx = f_xxx * message) - // ========================================================================= - - // RESPAN removal: remove(addr, h1', 0, 0, 0, 0, 0, 0, 0, 0) - let msg_respan_remove = encoders.simple(&addr_local, &h1_next, &zero); - let u_respan = msg_respan_remove * is_respan.clone(); - - // END for simple blocks: remove(addr, addr', is_loop_flag, 0, 0, 0, 0, 0, 0, 0) - let is_simple_end = one.clone() - is_call_flag.clone() - is_syscall_flag.clone(); - let msg_end_simple = encoders.simple(&addr_local, &addr_next, &is_loop_flag); - let end_simple_gate = is_end.clone() * is_simple_end; - let u_end_simple = msg_end_simple * end_simple_gate; - - // END for CALL/SYSCALL: remove(addr, addr', is_loop_flag, ctx', b0', b1', fn_hash'[0..4]) - // Note: The is_loop value is the is_loop_flag from the current row (same as simple END) - // Context values come from the next row's dedicated columns (not hasher state) - let is_call_or_syscall = is_call_flag.clone() + is_syscall_flag.clone(); - let msg_end_call = encoders.full( - &addr_local, - &addr_next, - &is_loop_flag, - &ctx_next, - &b0_next, - &b1_next, - &fn_hash_next, - ); - let end_call_gate = is_end.clone() * is_call_or_syscall; - let u_end_call = msg_end_call * end_call_gate; - - // Total END contribution - let u_end = u_end_simple + u_end_call; - - // Sum of removal flags - let remove_flag_sum = is_end.clone() + is_respan.clone(); - - // Total removal contribution - let removal_sum = u_end + u_respan; - - // Request side: removal_sum + (1 - remove_flag_sum) - let request = removal_sum + (one_ef.clone() - remove_flag_sum); - - // ========================================================================= - // RUNNING PRODUCT CONSTRAINT - // ========================================================================= - - // p1' * request = p1 * response - let lhs: AB::ExprEF = p1_next.into() * request; - let rhs: AB::ExprEF = p1_local.into() * response; - - builder.tagged(DECODER_BUS_BASE_ID, DECODER_BUS_NAMES[0], |builder| { - builder.when_transition().assert_zero_ext(lhs - rhs); - }); -} - -// BLOCK HASH TABLE (p2) -// ================================================================================================ - -/// Enforces the block hash table (p2) bus constraint. -/// -/// The block hash table tracks blocks awaiting execution. The program hash is added at -/// initialization and removed when the program completes. -/// -/// Message layout: `[parent_id, hash[0..3], is_first_child, is_loop_body]`. -/// - JOIN: inserts two children (left and right halves of the hasher state). -/// - SPLIT: inserts one child selected by s0 (left if s0=1, right if s0=0). -/// - LOOP/REPEAT: inserts loop body hash with is_loop_body = 1. -/// - DYN/DYNCALL/CALL/SYSCALL: insert the single child hash from h0..h3. -/// - END: removes the parent hash from h0..h3 using is_first_child/is_loop_body. -/// -/// ## Operations -/// -/// **Responses (additions)**: JOIN (2x), SPLIT, LOOP (conditional), REPEAT, DYN, DYNCALL, CALL, -/// SYSCALL **Requests (removals)**: END -/// -/// ## Message Format -/// -/// `[1, parent_block_id, hash[0], hash[1], hash[2], hash[3], is_first_child, is_loop_body]` -/// -/// ## Constraint Structure -/// -/// ```text -/// p2' * request = p2 * response -/// -/// response = f_join * (msg_left * msg_right) -/// + f_split * msg_split -/// + f_loop * (s0 * msg_loop + (1 - s0)) -/// + f_repeat * msg_repeat -/// + f_dyn * msg_dyn + f_dyncall * msg_dyncall + f_call * msg_call + f_syscall * msg_syscall -/// + (1 - f_join - f_split - f_loop - f_repeat - f_dyn - f_dyncall - f_call - f_syscall) -/// -/// request = f_end * msg_end + (1 - f_end) -/// ``` -pub fn enforce_block_hash_table_constraint( - builder: &mut AB, - local: &MainTraceRow, - next: &MainTraceRow, - op_flags: &OpFlags, - challenges: &Challenges, -) where - AB: LiftedAirBuilder, -{ - // Auxiliary trace must be present - - // Extract auxiliary trace values - let (p2_local, p2_next) = { - let aux = builder.permutation(); - let aux_local = aux.current_slice(); - let aux_next = aux.next_slice(); - ( - aux_local[crate::constraints::bus::indices::P2_BLOCK_HASH], - aux_next[crate::constraints::bus::indices::P2_BLOCK_HASH], - ) - }; - - let one = AB::Expr::ONE; - let zero = AB::Expr::ZERO; - let one_ef = AB::ExprEF::ONE; - - // Helper to convert trace value to base field expression - let to_expr = |v: AB::Var| -> AB::Expr { v.into() }; - - // ========================================================================= - // TRACE VALUE EXTRACTION - // ========================================================================= - - // Parent block ID (next row's address for all insertions) - let parent_id = to_expr(next.decoder[decoder_cols::ADDR].clone()); - - // Hasher state for child hashes - // First half: h[0..4] - let h0 = to_expr(local.decoder[decoder_cols::HASHER_STATE_OFFSET].clone()); - let h1 = to_expr(local.decoder[decoder_cols::HASHER_STATE_OFFSET + 1].clone()); - let h2 = to_expr(local.decoder[decoder_cols::HASHER_STATE_OFFSET + 2].clone()); - let h3 = to_expr(local.decoder[decoder_cols::HASHER_STATE_OFFSET + 3].clone()); - // Second half: h[4..8] - let h4 = to_expr(local.decoder[decoder_cols::HASHER_STATE_OFFSET + 4].clone()); - let h5 = to_expr(local.decoder[decoder_cols::HASHER_STATE_OFFSET + 5].clone()); - let h6 = to_expr(local.decoder[decoder_cols::HASHER_STATE_OFFSET + 6].clone()); - let h7 = to_expr(local.decoder[decoder_cols::HASHER_STATE_OFFSET + 7].clone()); - - // Stack top (for SPLIT and LOOP conditions) - let s0: AB::Expr = to_expr(local.stack[0].clone()); - - // For END: block hash comes from current row's hasher state first half - let end_parent_id = to_expr(next.decoder[decoder_cols::ADDR].clone()); - let end_hash_0 = h0.clone(); - let end_hash_1 = h1.clone(); - let end_hash_2 = h2.clone(); - let end_hash_3 = h3.clone(); - - // is_loop_body flag for END (stored at hasher_state[4] = IS_LOOP_BODY_FLAG) - let is_loop_body_flag = to_expr(local.decoder[decoder_cols::HASHER_STATE_OFFSET + 4].clone()); - - // is_first_child detection for END: - // A block is first_child if the NEXT row's opcode is NOT (END, REPEAT, or HALT). - // From processor: is_first_child = !(next_op in {END, REPEAT, HALT}) - // We compute op flags from the next row and check these three opcodes. - // - // Note: END (112), REPEAT (116), HALT (124) are all degree-4 operations, - // so is_first_child has degree 4. - let accessor_next = - crate::constraints::op_flags::ExprDecoderAccess::::new(next); - let op_flags_next = OpFlags::new(accessor_next); - - let is_end_next = op_flags_next.end(); - let is_repeat_next = op_flags_next.repeat(); - let is_halt_next = op_flags_next.halt(); - - // is_first_child = 1 when next op is NOT end/repeat/halt - let is_not_first_child = is_end_next + is_repeat_next + is_halt_next; - let is_first_child = one.clone() - is_not_first_child; - - // ========================================================================= - // MESSAGE BUILDERS - // ========================================================================= - - let encoder = BlockHashEncoder::::new(challenges); - - // ========================================================================= - // OPERATION FLAGS - // ========================================================================= - - let is_join = op_flags.join(); - let is_split = op_flags.split(); - let is_loop = op_flags.loop_op(); - let is_repeat = op_flags.repeat(); - let is_dyn = op_flags.dyn_op(); - let is_dyncall = op_flags.dyncall(); - let is_call = op_flags.call(); - let is_syscall = op_flags.syscall(); - let is_end = op_flags.end(); - - // ========================================================================= - // RESPONSE CONTRIBUTIONS (insertions) - // ========================================================================= - - // JOIN: Insert both children - // Left child (is_first_child=1): hash from first half - let msg_join_left = encoder.encode(&parent_id, [&h0, &h1, &h2, &h3], &one, &zero); - // Right child (is_first_child=0): hash from second half - let msg_join_right = encoder.encode(&parent_id, [&h4, &h5, &h6, &h7], &zero, &zero); - let v_join = (msg_join_left * msg_join_right) * is_join.clone(); - - // SPLIT: Insert selected child based on s0 - // If s0=1: left child (h0-h3), else right child (h4-h7) - let split_h0 = s0.clone() * h0.clone() + (one.clone() - s0.clone()) * h4.clone(); - let split_h1 = s0.clone() * h1.clone() + (one.clone() - s0.clone()) * h5.clone(); - let split_h2 = s0.clone() * h2.clone() + (one.clone() - s0.clone()) * h6.clone(); - let split_h3 = s0.clone() * h3.clone() + (one.clone() - s0.clone()) * h7.clone(); - let msg_split = - encoder.encode(&parent_id, [&split_h0, &split_h1, &split_h2, &split_h3], &zero, &zero); - let v_split = msg_split * is_split.clone(); - - // LOOP: Conditionally insert body if s0=1 - let msg_loop = encoder.encode(&parent_id, [&h0, &h1, &h2, &h3], &zero, &one); - // When s0=1: insert msg_loop; when s0=0: multiply by 1 (no insertion) - let v_loop = (msg_loop * s0.clone() + (one_ef.clone() - s0.clone())) * is_loop.clone(); - - // REPEAT: Insert loop body - let msg_repeat = encoder.encode(&parent_id, [&h0, &h1, &h2, &h3], &zero, &one); - let v_repeat = msg_repeat * is_repeat.clone(); - - // DYN/DYNCALL/CALL/SYSCALL: Insert child hash from first half - let msg_call_like = encoder.encode(&parent_id, [&h0, &h1, &h2, &h3], &zero, &zero); - let v_dyn = msg_call_like.clone() * is_dyn.clone(); - let v_dyncall = msg_call_like.clone() * is_dyncall.clone(); - let v_call = msg_call_like.clone() * is_call.clone(); - let v_syscall = msg_call_like * is_syscall.clone(); - - // Sum of insertion flags - let insert_flag_sum = is_join.clone() - + is_split.clone() - + is_loop.clone() - + is_repeat.clone() - + is_dyn.clone() - + is_dyncall.clone() - + is_call.clone() - + is_syscall.clone(); - - // Response side - let response = v_join - + v_split - + v_loop - + v_repeat - + v_dyn - + v_dyncall - + v_call - + v_syscall - + (one_ef.clone() - insert_flag_sum); - - // ========================================================================= - // REQUEST CONTRIBUTIONS (removals) - // ========================================================================= - - // END: Remove the block - // is_first_child is computed above from next row's opcode flags - let msg_end = encoder.encode( - &end_parent_id, - [&end_hash_0, &end_hash_1, &end_hash_2, &end_hash_3], - &is_first_child, - &is_loop_body_flag, - ); - let u_end = msg_end * is_end.clone(); - - // Request side - let request = u_end + (one_ef.clone() - is_end); - - // ========================================================================= - // RUNNING PRODUCT CONSTRAINT - // ========================================================================= - - // p2' * request = p2 * response - let lhs: AB::ExprEF = p2_next.into() * request; - let rhs: AB::ExprEF = p2_local.into() * response; - - builder.tagged(DECODER_BUS_BASE_ID + 1, DECODER_BUS_NAMES[1], |builder| { - builder.when_transition().assert_zero_ext(lhs - rhs); - }); -} - -// OP GROUP TABLE (p3) -// ================================================================================================ - -/// Enforces the op group table (p3) bus constraint. -/// -/// The op group table tracks operation groups within span blocks. Groups are added -/// when entering a span and removed as operations are executed. -/// -/// Message layout: `[block_id, group_count, op_value]`. -/// - Inserts happen on SPAN/RESPAN. Batch flags choose how many groups are emitted: g1 emits none, -/// g2 emits h1, g4 emits h1..h3, g8 emits h1..h7. -/// - Removals happen when group_count decrements inside a span (sp=1, gc' < gc). The removed -/// op_value is h0' * 128 + opcode' for non-PUSH, or s0' for PUSH. -/// -/// ## Operations -/// -/// **Responses (additions)**: SPAN, RESPAN (based on batch flags) -/// - 8-group batch: Insert h1-h7 (7 groups) -/// - 4-group batch: Insert h1-h3 (3 groups) -/// - 2-group batch: Insert h1 (1 group) -/// - 1-group batch: Insert nothing -/// -/// **Requests (removals)**: When delta_group_count * is_in_span = 1 -/// -/// ## Message Format -/// -/// `[1, block_id, group_count, op_value]` -/// -/// ## Constraint Structure (from docs/src/design/decoder/constraints.md) -/// -/// ```text -/// p3' * (f_dg * u + 1 - f_dg) = p3 * (f_g1 + f_g2 * v_1 + f_g4 * ∏v_1..3 + f_g8 * ∏v_1..7 + 1 - (f_span + f_respan)) -/// ``` -/// -/// Where: -/// - f_dg = sp * (gc - gc') - flag for group removal -/// - u = removal message -/// - f_g1, f_g2, f_g4, f_g8 = batch size flags -/// - v_i = insertion message for group i -/// -/// ## Degree Analysis -/// -/// - f_g8 * prod_7: degree 1 + 7 = 8 -/// - f_g4 * prod_3: degree 3 + 3 = 6 -/// - f_span: degree 6 -/// - f_dg * u: degree 2 + 7 = 9 (u includes is_push which is degree ~5) -/// - Total constraint: degree 9 -pub fn enforce_op_group_table_constraint( - builder: &mut AB, - local: &MainTraceRow, - next: &MainTraceRow, - op_flags: &OpFlags, - challenges: &Challenges, -) where - AB: LiftedAirBuilder, -{ - // Auxiliary trace must be present - - // Extract auxiliary trace values - let (p3_local, p3_next) = { - let aux = builder.permutation(); - let aux_local = aux.current_slice(); - let aux_next = aux.next_slice(); - ( - aux_local[crate::constraints::bus::indices::P3_OP_GROUP], - aux_next[crate::constraints::bus::indices::P3_OP_GROUP], - ) - }; - - let one = AB::Expr::ONE; - let one_ef = AB::ExprEF::ONE; - - // Helper to convert trace value to base field expression - let to_expr = |v: AB::Var| -> AB::Expr { v.into() }; - - // ========================================================================= - // TRACE VALUE EXTRACTION - // ========================================================================= - - // Block ID (next row's address for insertions, current for removals) - let block_id_insert = to_expr(next.decoder[decoder_cols::ADDR].clone()); - let block_id_remove = to_expr(local.decoder[decoder_cols::ADDR].clone()); - - // Group count - let gc = to_expr(local.decoder[op_group_cols::GROUP_COUNT].clone()); - let gc_next = to_expr(next.decoder[op_group_cols::GROUP_COUNT].clone()); - - // Hasher state for group values (h1-h7, h0 is decoded immediately) - let h1 = to_expr(local.decoder[decoder_cols::HASHER_STATE_OFFSET + 1].clone()); - let h2 = to_expr(local.decoder[decoder_cols::HASHER_STATE_OFFSET + 2].clone()); - let h3 = to_expr(local.decoder[decoder_cols::HASHER_STATE_OFFSET + 3].clone()); - let h4 = to_expr(local.decoder[decoder_cols::HASHER_STATE_OFFSET + 4].clone()); - let h5 = to_expr(local.decoder[decoder_cols::HASHER_STATE_OFFSET + 5].clone()); - let h6 = to_expr(local.decoder[decoder_cols::HASHER_STATE_OFFSET + 6].clone()); - let h7 = to_expr(local.decoder[decoder_cols::HASHER_STATE_OFFSET + 7].clone()); - - // Batch flag columns (c0, c1, c2) - let c0 = to_expr(local.decoder[op_group_cols::BATCH_FLAG_0].clone()); - let c1 = to_expr(local.decoder[op_group_cols::BATCH_FLAG_1].clone()); - let c2 = to_expr(local.decoder[op_group_cols::BATCH_FLAG_2].clone()); - - // For removal: h0' and s0' from next row - let h0_next = to_expr(next.decoder[decoder_cols::HASHER_STATE_OFFSET].clone()); - let s0_next = to_expr(next.stack[0].clone()); - - // is_in_span flag (sp) - let sp = to_expr(local.decoder[op_group_cols::IS_IN_SPAN].clone()); - - // ========================================================================= - // MESSAGE BUILDER - // ========================================================================= - - let encoder = OpGroupEncoder::::new(challenges); - - // ========================================================================= - // OPERATION FLAGS - // ========================================================================= - - let is_push = op_flags.push(); - - // ========================================================================= - // BATCH FLAGS - // ========================================================================= - - // Compute batch flags from c0, c1, c2 based on trace constants: - // OP_BATCH_8_GROUPS = [1, 0, 0] -> f_g8 = c0 - // OP_BATCH_4_GROUPS = [0, 1, 0] -> f_g4 = (1-c0) * c1 * (1-c2) - // OP_BATCH_2_GROUPS = [0, 0, 1] -> f_g2 = (1-c0) * (1-c1) * c2 - // OP_BATCH_1_GROUPS = [0, 1, 1] -> f_g1 = (1-c0) * c1 * c2 - let f_g8 = c0.clone(); - let f_g4 = (one.clone() - c0.clone()) * c1.clone() * (one.clone() - c2.clone()); - let f_g2 = (one.clone() - c0.clone()) * (one.clone() - c1.clone()) * c2.clone(); - - // ========================================================================= - // CONSTANTS - // ========================================================================= - - // Build base field constants. - let two = AB::Expr::from_u16(2); - let three = AB::Expr::from_u16(3); - let four = AB::Expr::from_u16(4); - let five = AB::Expr::from_u16(5); - let six = AB::Expr::from_u16(6); - let seven = AB::Expr::from_u16(7); - let onetwentyeight = AB::Expr::from_u16(128); - - // ========================================================================= - // RESPONSE (insertions during SPAN/RESPAN) - // ========================================================================= - - // Build messages for each group: v_i = msg(block_id', gc - i, h_i) - let v_1 = encoder.encode(&block_id_insert, &(gc.clone() - one.clone()), &h1); - let v_2 = encoder.encode(&block_id_insert, &(gc.clone() - two.clone()), &h2); - let v_3 = encoder.encode(&block_id_insert, &(gc.clone() - three.clone()), &h3); - let v_4 = encoder.encode(&block_id_insert, &(gc.clone() - four.clone()), &h4); - let v_5 = encoder.encode(&block_id_insert, &(gc.clone() - five.clone()), &h5); - let v_6 = encoder.encode(&block_id_insert, &(gc.clone() - six.clone()), &h6); - let v_7 = encoder.encode(&block_id_insert, &(gc.clone() - seven.clone()), &h7); - - // Compute products for each batch size - let prod_3 = v_1.clone() * v_2.clone() * v_3.clone(); - let prod_7 = v_1.clone() * v_2 * v_3 * v_4 * v_5 * v_6 * v_7; - - // Response formula: - // response = f_g2 * v_1 + f_g4 * ∏(v_1..v_3) + f_g8 * ∏(v_1..v_7) + (1 - (f_g2 + f_g4 + f_g8)) - // - // This omits the explicit f_span/f_respan gating in the rest term; it is safe because - // decoder constraints enforce (1 - f_span_respan) * (c0 + c1 + c2) = 0, so all batch - // flags are zero outside SPAN/RESPAN rows. This keeps the max degree at 9 and matches - // the sum-form bus expansion used in air-script. - let response = (v_1.clone() * f_g2.clone()) - + (prod_3 * f_g4.clone()) - + (prod_7 * f_g8.clone()) - + (one_ef.clone() - (f_g2 + f_g4 + f_g8)); - - // ========================================================================= - // REQUEST (removals when group count decrements inside span) - // ========================================================================= - - // f_dg = sp * (gc - gc') - flag for decrementing group count - // This is non-zero when inside a span (sp=1) and group count decreased - let delta_gc = gc.clone() - gc_next; - let f_dg = sp * delta_gc; - - // Compute op_code' from next row's opcode bits (b0' + 2*b1' + ... + 64*b6'). - let op_code_next = opcode_from_row::(next); - - // Removal value formula: - // u = (h0' * 128 + op_code') * (1 - is_push) + s0' * is_push - // - // When PUSH: the immediate value is on the stack (s0') - // Otherwise: the group value is h0' * 128 + op_code' - let group_value_non_push = h0_next * onetwentyeight + op_code_next; - let group_value = is_push.clone() * s0_next + (one.clone() - is_push) * group_value_non_push; - - // Removal message: u = msg(block_id, gc, group_value) - let u = encoder.encode(&block_id_remove, &gc, &group_value); - - // Request formula: f_dg * u + (1 - f_dg) - let request = u * f_dg.clone() + (one_ef.clone() - f_dg); - - // ========================================================================= - // RUNNING PRODUCT CONSTRAINT - // ========================================================================= - - // p3' * request = p3 * response - let lhs: AB::ExprEF = p3_next.into() * request; - let rhs: AB::ExprEF = p3_local.into() * response; - - builder.tagged(DECODER_BUS_BASE_ID + 2, DECODER_BUS_NAMES[2], |builder| { - builder.when_transition().assert_zero_ext(lhs - rhs); - }); -} diff --git a/air/src/constraints/decoder/columns.rs b/air/src/constraints/decoder/columns.rs new file mode 100644 index 0000000000..3bb607a577 --- /dev/null +++ b/air/src/constraints/decoder/columns.rs @@ -0,0 +1,58 @@ +use crate::trace::decoder::{ + NUM_HASHER_COLUMNS, NUM_OP_BATCH_FLAGS, NUM_OP_BITS, NUM_OP_BITS_EXTRA_COLS, + NUM_USER_OP_HELPERS, +}; + +/// Decoder columns in the main execution trace (24 columns). +#[repr(C)] +pub struct DecoderCols { + /// Block address (hasher table row pointer). + pub addr: T, + /// Opcode bits b0-b6. + pub op_bits: [T; NUM_OP_BITS], + /// Hasher state h0-h7 (shared between decoding and MAST node hashing). + pub hasher_state: [T; NUM_HASHER_COLUMNS], + /// In-span flag (1 inside a basic block). + pub in_span: T, + /// Remaining operation group count. + pub group_count: T, + /// Position within operation group (0-8). + pub op_index: T, + /// Operation batch flags c0, c1, c2. + pub batch_flags: [T; NUM_OP_BATCH_FLAGS], + /// Degree-reduction extra columns e0, e1. + pub extra: [T; NUM_OP_BITS_EXTRA_COLS], +} + +impl DecoderCols { + /// Returns the 6 user-op helper registers (hasher_state[2..8]). + pub fn user_op_helpers(&self) -> [T; NUM_USER_OP_HELPERS] { + [ + self.hasher_state[2], + self.hasher_state[3], + self.hasher_state[4], + self.hasher_state[5], + self.hasher_state[6], + self.hasher_state[7], + ] + } + + /// Returns the 4 end-block flags (hasher_state[4..8]). + pub fn end_block_flags(&self) -> EndBlockFlags { + EndBlockFlags { + is_loop_body: self.hasher_state[4], + is_loop: self.hasher_state[5], + is_call: self.hasher_state[6], + is_syscall: self.hasher_state[7], + } + } +} + +/// Named end-block flag overlay for `hasher_state[4..8]`. +#[repr(C)] +pub struct EndBlockFlags { + pub is_loop_body: T, + pub is_loop: T, + pub is_call: T, + pub is_syscall: T, +} diff --git a/air/src/constraints/decoder/mod.rs b/air/src/constraints/decoder/mod.rs index 010e1b6b71..17d0c840db 100644 --- a/air/src/constraints/decoder/mod.rs +++ b/air/src/constraints/decoder/mod.rs @@ -5,21 +5,29 @@ //! //! ## Constraint Categories //! -//! 1. **Op Bit Constraints**: Ensure operation bits are binary -//! 2. **Op Bits Extra Columns**: Ensure degree reduction columns are correctly computed -//! 3. **Batch Flag Constraints**: Ensure batch flags are binary and properly set -//! 4. **In-Span Constraints**: Ensure in-span flag transitions correctly -//! 5. **Group Count Constraints**: Ensure group count transitions correctly +//! 1. **In-span constraints**: Ensure the in-span flag transitions correctly. +//! 2. **Op-bit binary constraints**: Ensure operation bits are binary. +//! 3. **Extra columns (e0, e1)**: Degree-reduction columns for operation flag computation. +//! 4. **Opcode-bit group constraints**: Eliminate unused opcode prefixes. +//! 5. **General opcode-semantic constraints**: Per-operation invariants (SPLIT/LOOP, DYN, REPEAT, +//! END, HALT). +//! 6. **Group count constraints**: Group-count transitions inside basic blocks. +//! 7. **Op group decoding (h0) constraints**: Base-128 opcode packing in h0. +//! 8. **Op index constraints**: Position tracking within an operation group. +//! 9. **Batch flag constraints**: Batch size encoding and unused-lane zeroing. +//! 10. **Block address (addr) constraints**: Hasher-table address management. +//! 11. **Control flow constraint**: Mutual exclusivity of `in_span` and `f_ctrl`. //! //! ## Mental Model //! //! The decoder trace is the control-flow spine of the VM. Each row is either: -//! - **inside a basic block** (sp = 1) where ops execute and counters advance, or -//! - **a control-flow row** (sp = 0) that starts/ends/reshapes a block. +//! - **inside a basic block** (`in_span` = 1) where ops execute and counters advance, or +//! - **a control-flow row** (`in_span` = 0) that starts/ends/reshapes a block. //! //! The constraints below enforce three linked ideas: //! 1. **Opcode decoding is well-formed** (op bits and degree-reduction columns are consistent). -//! 2. **Span state is coherent** (sp, group_count, op_index evolve exactly as control-flow allows). +//! 2. **Span state is coherent** (`in_span`, `group_count`, `op_index` evolve exactly as +//! control-flow allows). //! 3. **Hasher lanes match batch semantics** (batch flags and h0..h7 encode the pending groups). //! //! Read the sections in that order: first the binary/format checks, then the span state machine, @@ -27,889 +35,481 @@ //! //! ## Decoder Trace Layout //! -//! The decoder trace consists of the following columns: -//! - `addr`: Block address (row address in hasher table) -//! - `b0-b6`: 7 operation bits encoding the opcode -//! - `h0-h7`: 8 hasher state columns (shared between decoding and program hashing) -//! - `sp`: In-span flag (1 when inside basic block, 0 otherwise) -//! - `gc`: Group count (remaining operation groups in current span) -//! - `ox`: Operation index (position within current operation group, 0-8) -//! - `c0, c1, c2`: Batch flags (encode number of groups in current batch) -//! - `e0, e1`: Extra columns for degree reduction - -use miden_core::field::PrimeCharacteristicRing; -use miden_crypto::stark::air::{AirBuilder, LiftedAirBuilder}; +//! ```text +//! addr | b0 b1 b2 b3 b4 b5 b6 | h0 h1 h2 h3 h4 h5 h6 h7 | sp | gc | ox | c0 c1 c2 | e0 e1 +//! (1) (7 op bits) (8 hasher state) (1) (1) (1) (3) (2) +//! ``` +//! +//! ### Hasher state dual-purpose (`h0`–`h7`) +//! +//! The 8 hasher-state columns serve different roles depending on the current operation: +//! +//! | Context | h0 | h1..h3 | h4 | h5 | h6 | h7 | +//! |-------------|------------|-----------|----------------|---------|---------|------------| +//! | SPAN/RESPAN | packed ops | op groups | op group | op group| op group| op group | +//! | END | block hash₀| hash₁..₃ | is_loop_body | is_loop | is_call | is_syscall | +//! | User ops | packed ops | op groups | user_op_helper | ... | ... | ... | +//! +//! ## Operation Flag Degrees +//! +//! | Operation | Flag | Degree | +//! |-----------|:------------:|:------:| +//! | JOIN | f_join | 5 | +//! | SPLIT | f_split | 5 | +//! | LOOP | f_loop | 5 | +//! | REPEAT | f_repeat | 4 | +//! | SPAN | f_span | 5 | +//! | RESPAN | f_respan | 4 | +//! | DYN | f_dyn | 5 | +//! | END | f_end | 4 | +//! | HALT | f_halt | 4 | +//! | PUSH | f_push | 5 | +//! | f_ctrl | (composite) | 5 | + +pub mod columns; + +use miden_crypto::stark::air::AirBuilder; use crate::{ - MainTraceRow, + Felt, MainCols, MidenAirBuilder, constraints::{ - op_flags::{ExprDecoderAccess, OpFlags}, - tagging::{ - TagGroup, TaggingAirBuilderExt, ids::TAG_DECODER_BASE, tagged_assert_zero, - tagged_assert_zero_integrity, - }, + constants::{F_1, F_128}, + decoder::columns::DecoderCols, + op_flags::OpFlags, + utils::{BoolNot, horner_eval_bits}, }, - trace::decoder as decoder_cols, -}; - -pub mod bus; -#[cfg(test)] -pub mod tests; - -// CONSTANTS -// ================================================================================================ - -/// Index offset for block address column within decoder (column 0). -const ADDR_OFFSET: usize = 0; - -/// Index offsets within the decoder array for op bits (b0-b6). -/// Op bits start at index 1 in the decoder (after addr at index 0). -const OP_BITS_OFFSET: usize = 1; - -/// Hash cycle length for Poseidon2 (32 rows per permutation). -const HASH_CYCLE_LEN: u64 = 32; - -/// Number of operation bits. -const NUM_OP_BITS: usize = 7; - -/// Index offset for in-span column within decoder. -const IN_SPAN_OFFSET: usize = 16; - -/// Index offset for group count column within decoder. -const GROUP_COUNT_OFFSET: usize = 17; - -/// Index offset for operation index column within decoder. -const OP_INDEX_OFFSET: usize = 18; - -/// Index offset for batch flags within decoder. -const BATCH_FLAGS_OFFSET: usize = 19; - -/// Number of batch flag columns. -const NUM_BATCH_FLAGS: usize = 3; - -/// Index offset for extra columns (e0, e1) within decoder. -const EXTRA_COLS_OFFSET: usize = 22; - -/// Number of decoder constraints, in the order of `DECODER_NAMES`. -/// - 7 op bits binary constraints -/// - 2 extra columns constraints (e0, e1) -/// - 3 op-bit group constraints (u32 b0, very-high b0/b1) -/// - 3 batch flags binary constraints -/// - 14 general constraints -/// - 1 in-span boundary constraint (first row sp = 0) -/// - 1 in-span binary constraint -/// - 2 in-span transition constraints (after SPAN/RESPAN, sp' = 1) -/// - 5 group count constraints -/// - 2 op group decoding constraints -/// - 4 op index constraints -/// - 9 op batch flag constraints -/// - 3 block address constraints -/// - 1 control flow constraint (1 - sp - f_ctrl = 0) -#[allow(dead_code)] -pub const NUM_CONSTRAINTS: usize = 57; - -/// Base ID for decoder constraints (inclusive). -const DECODER_BASE_ID: usize = TAG_DECODER_BASE; - -/// Decoder constraint namespaces in assertion order. -const DECODER_NAMES: [&str; NUM_CONSTRAINTS] = [ - // in-span constraints (boundary first, then transition rules) - "decoder.in_span.first_row", - "decoder.in_span.binary", - "decoder.in_span.span", - "decoder.in_span.respan", - // op bits binary (b0..b6) - "decoder.op_bits.b0.binary", - "decoder.op_bits.b1.binary", - "decoder.op_bits.b2.binary", - "decoder.op_bits.b3.binary", - "decoder.op_bits.b4.binary", - "decoder.op_bits.b5.binary", - "decoder.op_bits.b6.binary", - // extra columns (e0, e1) - "decoder.extra.e0", - "decoder.extra.e1", - // op-bit group constraints - "decoder.op_bits.u32_prefix.b0", - "decoder.op_bits.very_high.b0", - "decoder.op_bits.very_high.b1", - // batch flags binary (c0..c2) - "decoder.batch_flags.c0.binary", - "decoder.batch_flags.c1.binary", - "decoder.batch_flags.c2.binary", - // general constraints - "decoder.general.split_loop.s0.binary", - "decoder.general.dyn.h4.zero", - "decoder.general.dyn.h5.zero", - "decoder.general.dyn.h6.zero", - "decoder.general.dyn.h7.zero", - "decoder.general.repeat.s0.one", - "decoder.general.repeat.h4.one", - "decoder.general.end.loop.s0.zero", - "decoder.general.end_repeat.h0.carry", - "decoder.general.end_repeat.h1.carry", - "decoder.general.end_repeat.h2.carry", - "decoder.general.end_repeat.h3.carry", - "decoder.general.end_repeat.h4.carry", - "decoder.general.halt.next", - // group count constraints - "decoder.group_count.delta.binary", - "decoder.group_count.decrement.h0_or_imm", - "decoder.group_count.span_decrement", - "decoder.group_count.end_or_respan.hold", - "decoder.group_count.end.zero", - // op group decoding constraints - "decoder.op_group.shift", - "decoder.op_group.end_or_respan.h0.zero", - // op index constraints - "decoder.op_index.span_respan.reset", - "decoder.op_index.new_group.reset", - "decoder.op_index.increment", - "decoder.op_index.range", - // batch flag constraints and zeroing rules - "decoder.batch_flags.span_sum", - "decoder.batch_flags.zero_when_not_span", - "decoder.batch_flags.h4.zero", - "decoder.batch_flags.h5.zero", - "decoder.batch_flags.h6.zero", - "decoder.batch_flags.h7.zero", - "decoder.batch_flags.h2.zero", - "decoder.batch_flags.h3.zero", - "decoder.batch_flags.h1.zero", - // block address constraints - "decoder.addr.hold_in_span", - "decoder.addr.respan.increment", - "decoder.addr.halt.zero", - // control flow constraint - "decoder.control_flow.sp_complement", -]; - -/// Tag metadata for this constraint group. -const DECODER_TAGS: TagGroup = TagGroup { - base: DECODER_BASE_ID, - names: &DECODER_NAMES, + trace::chiplets::hasher::CONTROLLER_ROWS_PER_PERM_FELT, }; -// Relative offsets into DECODER_NAMES by constraint group. -const IN_SPAN_BASE: usize = 0; -const OP_BITS_BASE: usize = IN_SPAN_BASE + 4; -const EXTRA_BASE: usize = OP_BITS_BASE + NUM_OP_BITS; -const OP_BIT_GROUP_BASE: usize = EXTRA_BASE + 2; -const BATCH_FLAGS_BINARY_BASE: usize = OP_BIT_GROUP_BASE + 3; -const GENERAL_BASE: usize = BATCH_FLAGS_BINARY_BASE + NUM_BATCH_FLAGS; -const GROUP_COUNT_BASE: usize = GENERAL_BASE + 14; -const OP_GROUP_DECODING_BASE: usize = GROUP_COUNT_BASE + 5; -const OP_INDEX_BASE: usize = OP_GROUP_DECODING_BASE + 2; -const BATCH_FLAGS_BASE: usize = OP_INDEX_BASE + 4; -const ADDR_BASE: usize = BATCH_FLAGS_BASE + 9; -const CONTROL_FLOW_BASE: usize = ADDR_BASE + 3; - -/// The degrees of the decoder constraints. -#[allow(dead_code)] -pub const CONSTRAINT_DEGREES: [usize; NUM_CONSTRAINTS] = [ - 2, 2, 2, 2, 2, 2, 2, // op bits binary (degree 2) - 4, 3, // e0 (degree 4), e1 (degree 3) - 4, 3, 3, // u32 b0, very-high b0/b1 - 2, 2, 2, // batch flags binary (degree 2) - 7, 6, 6, 6, 6, // general: split/loop top binary, dyn h4..h7 = 0 - 5, 5, // general: repeat top=1, repeat in-loop - 6, // general: end + is_loop + s0 - 9, 9, 9, 9, 9, // general: end + repeat' copies h0..h4 - 8, // general: halt -> halt' - 1, // sp first row (degree 1) - 2, // sp binary (degree 2) - 6, 5, // sp transition for SPAN (deg 5+1=6), RESPAN (deg 4+1=5) - 3, // gc delta bounded (degree 3: sp * delta * (delta - 1)) - 8, // gc decrement implies (h0=0 or is_push=1) - 6, // gc decrement on SPAN/RESPAN/PUSH - 5, // gc stays when next is END or RESPAN - 5, // gc zero at END - 6, // op group decoding: h0 shift by op' - 6, // op group decoding: h0 must be 0 before END/RESPAN - 6, // ox reset on SPAN/RESPAN (degree 6) - 6, // ox reset on new group (degree 6: sp * ng * ox') - 7, // ox increment inside basic block (degree 7) - 9, // ox range [0,8] (degree 9) - 5, // batch flags sum (span/respan -> one of g1/g2/g4/g8) - 6, // batch flags zero when not span/respan - 4, 4, 4, 4, // h4..h7 zero when <=4 groups - 4, 4, // h2..h3 zero when <=2 groups - 4, // h1 zero when <=1 group - 2, // addr unchanged inside basic block (degree 2) - 5, // addr increment on RESPAN (degree 5) - 5, // addr zero at HALT (degree 5) - 5, // control flow: 1 - sp - f_ctrl = 0 -]; - -// SMALL HELPERS -// ================================================================================================ - -/// Asserts a value is binary (0 or 1): `x * (x - 1) = 0`. -fn assert_binary(builder: &mut AB, idx: usize, value: AB::Expr) -where - AB: TaggingAirBuilderExt, -{ - assert_zero_integrity(builder, idx, value.clone() * (value - AB::Expr::ONE)); -} - -/// Computes the opcode value from op bits: `b0 + 2*b1 + ... + 64*b6`. -fn op_bits_to_value(bits: &[AB::Expr; NUM_OP_BITS]) -> AB::Expr -where - AB: LiftedAirBuilder, -{ - bits.iter().enumerate().fold(AB::Expr::ZERO, |acc, (i, bit)| { - acc + bit.clone() * AB::Expr::from_u16(1u16 << i) - }) -} - // ENTRY POINTS // ================================================================================================ /// Enforces decoder main-trace constraints (entry point). pub fn enforce_main( builder: &mut AB, - local: &MainTraceRow, - next: &MainTraceRow, + local: &MainCols, + next: &MainCols, op_flags: &OpFlags, ) where - AB: TaggingAirBuilderExt, + AB: MidenAirBuilder, { - // Load decoder columns using typed struct - let cols: DecoderColumns = DecoderColumns::from_row::(local); - let cols_next: DecoderColumns = DecoderColumns::from_row::(next); - let op_flags_next = OpFlags::new(ExprDecoderAccess::::new(next)); - - enforce_in_span_constraints(builder, &cols, &cols_next, op_flags); - enforce_op_bits_binary(builder, &cols); - enforce_extra_columns(builder, &cols); - enforce_op_bit_group_constraints(builder, &cols); - enforce_batch_flags_binary(builder, &cols); - enforce_general_constraints(builder, local, next, op_flags, &op_flags_next); - enforce_group_count_constraints(builder, &cols, &cols_next, local, op_flags, &op_flags_next); - enforce_op_group_decoding_constraints( - builder, - &cols, - &cols_next, - local, - next, - op_flags, - &op_flags_next, - ); - enforce_op_index_constraints(builder, &cols, &cols_next, op_flags); - enforce_batch_flags_constraints(builder, &cols, local, op_flags); - enforce_block_address_constraints(builder, &cols, &cols_next, op_flags); - enforce_control_flow_constraints(builder, &cols, op_flags); -} - -// INTERNAL HELPERS -// ================================================================================================ - -/// Typed access to decoder columns. -/// -/// This struct provides named access to decoder columns, eliminating error-prone -/// index arithmetic. Created from a `MainTraceRow` reference. -/// -/// ## Layout -/// - `addr`: Block address (row address in hasher table) -/// - `op_bits[0..7]`: Operation bits b0-b6 encoding the opcode -/// - `in_span`: In-span flag (sp) - 1 when inside basic block -/// - `group_count`: Group count (gc) - remaining operation groups -/// - `op_index`: Operation index (ox) - position within group (0-8) -/// - `batch_flags[0..3]`: Batch flags c0, c1, c2 -/// - `extra[0..2]`: Extra columns e0, e1 for degree reduction -/// -/// Note: the 8 decoder hasher-state lanes live in the decoder trace but are not included here. -/// Constraints which depend on these lanes access them directly via `MainTraceRow` accessors. -pub struct DecoderColumns { - /// Block address (row address in hasher table) - pub addr: E, - /// Operation bits b0-b6 (7 bits encoding the opcode) - pub op_bits: [E; NUM_OP_BITS], - /// In-span flag (1 when inside basic block, 0 otherwise) - pub in_span: E, - /// Group count (remaining operation groups in current span) - pub group_count: E, - /// Operation index (position within current operation group, 0-8) - pub op_index: E, - /// Batch flags c0, c1, c2 (encode number of groups in current batch) - pub batch_flags: [E; NUM_BATCH_FLAGS], - /// Extra columns e0, e1 for degree reduction - pub extra: [E; 2], -} + // --- Destructure current-row decoder columns ------------------------------------------------ + let DecoderCols { + addr, + op_bits, + hasher_state, + in_span, + group_count, + op_index, + batch_flags, + extra, + } = local.decoder; + // b2 and b3 are not used directly in decoder constraints — they are consumed only + // by the op_flags module for individual opcode discrimination. + let [b0, b1, _, _, b4, b5, b6] = op_bits; + let [bc0, bc1, bc2] = batch_flags; + let [e0, e1] = extra; + let h0 = hasher_state[0]; + + // End-block flags occupy hasher_state[4..8] during END operations. + let end_flags = local.decoder.end_block_flags(); + let is_loop_body = end_flags.is_loop_body; + let is_loop = end_flags.is_loop; + + // --- Destructure next-row decoder columns --------------------------------------------------- + let DecoderCols { + addr: addr_next, + op_bits: op_bits_next, + hasher_state: hasher_state_next, + in_span: in_span_next, + group_count: group_count_next, + op_index: op_index_next, + .. + } = next.decoder; + let h0_next = hasher_state_next[0]; + + // --- Cached derived expressions ------------------------------------------------------------- + // These values appear in multiple constraint sections below. + + // The change in group count across one row. + // Inside a span, delta_group_count is constrained to be boolean (0 or 1). + // When delta_group_count = 1, a group has been consumed (either a completed op group or a PUSH + // immediate). When delta_group_count = 0, the current group is still being decoded. + let delta_group_count: AB::Expr = group_count - group_count_next; + + // PUSH is the only operation with an immediate value. When PUSH executes, it consumes + // an op group from h0 to read the immediate value pushed onto the stack, causing + // delta_group_count = 1. However, this is NOT a "new group start" for decoding purposes — the + // distinction matters for the new_group flag: new_group = delta_group_count - is_push. + let is_push = op_flags.push(); -impl DecoderColumns { - /// Extract decoder columns from a main trace row. - pub fn from_row(row: &MainTraceRow) -> Self - where - AB: LiftedAirBuilder, - AB::Var: Into + Clone, + // ============================================= + // In-span constraints + // ============================================= + // The in_span flag indicates whether we are inside a basic block: + // in_span = 1 when executing user operations, + // in_span = 0 on control-flow rows (SPAN, RESPAN, END, JOIN, SPLIT, LOOP, etc.). + // + // in_span is pinned to 1 - f_ctrl on every row by the control-flow constraint at + // the end of this function (in_span + f_ctrl = 1), so in_span cannot become 1 + // without a preceding SPAN or RESPAN that sets in_span' = 1 on the next row. + + // Execution starts outside any basic block. + builder.when_first_row().assert_zero(in_span); + + // The in-span flag is binary. + builder.assert_bool(in_span); + + // After SPAN, next row enters a basic block. + builder.when_transition().when(op_flags.span()).assert_one(in_span_next); + + // After RESPAN, next row stays in a basic block. + builder.when_transition().when(op_flags.respan()).assert_one(in_span_next); + + // ============================================= + // Op-bit binary constraints + // ============================================= + // Each opcode bit must be 0 or 1. + builder.assert_bools(op_bits); + + // ============================================= + // Extra columns (e0, e1) — degree reduction + // ============================================= + // Without these columns, operation flags for the upper opcode groups (U32, VeryHigh) + // would require products of up to 7 bits (degree 7), exceeding the constraint system's + // degree budget. By precomputing e0 and e1 in the trace and constraining them here, + // the op_flags module can reference these degree-1 columns instead. + // + // e0 = b6 · (1 - b5) · b4 selects the "101" prefix (degree-5 ops) + // e1 = b6 · b5 selects the "11" prefix (degree-4 ops) + + // e0 must equal b6 · (1 - b5) · b4. + let e0_expected = b6 * b5.into().not() * b4; + builder.assert_eq(e0, e0_expected); + + // e1 must equal b6 · b5. + let e1_expected = b6 * b5; + builder.assert_eq(e1, e1_expected); + + // ============================================= + // Opcode-bit group constraints + // ============================================= + // Certain opcode prefixes have unused bit positions that must be zero to prevent + // invalid opcodes from being encoded. Both opcode groups use e0/e1 for degree reduction: + // + // Prefix | b6 b5 b4 | Meaning | Constraint + // --------+----------+------------+------------ + // U32 | 1 0 0 | 8 U32 ops | b0 = 0 + // VeryHi | 1 1 * | 8 hi ops | b0 = b1 = 0 + // + // The U32 prefix is computed as b6·(1-b5)·(1-b4) = b6 - e1 - e0 (degree 1). + // The VeryHi prefix is b6·b5 = e1 (degree 1). + + // When U32 prefix is active, b0 must be zero. + builder.when(b6 - e1 - e0).assert_zero(b0); + + // When VeryHi prefix is active, both b0 and b1 must be zero. { - DecoderColumns { - addr: row.decoder[ADDR_OFFSET].clone().into(), - op_bits: core::array::from_fn(|i| row.decoder[OP_BITS_OFFSET + i].clone().into()), - in_span: row.decoder[IN_SPAN_OFFSET].clone().into(), - group_count: row.decoder[GROUP_COUNT_OFFSET].clone().into(), - op_index: row.decoder[OP_INDEX_OFFSET].clone().into(), - batch_flags: core::array::from_fn(|i| { - row.decoder[BATCH_FLAGS_OFFSET + i].clone().into() - }), - extra: core::array::from_fn(|i| row.decoder[EXTRA_COLS_OFFSET + i].clone().into()), - } + let builder = &mut builder.when(e1); + builder.assert_zero(b0); + builder.assert_zero(b1); } -} - -// CONSTRAINT HELPERS -// ================================================================================================ -/// Enforces in-span (sp) constraints. -/// -/// The in-span flag indicates whether we're inside a basic block: -/// - sp = 1 when executing operations inside a basic block -/// - sp = 0 for SPAN, RESPAN, END, and control-flow operations -/// -/// This is the entry point to the decoder state machine. Once sp is set by SPAN/RESPAN, -/// the rest of the decoder constraints (gc, ox, batch flags) are interpreted relative to -/// being inside that span. -/// -/// Constraints: -/// 1. sp is binary: sp * (sp - 1) = 0 -/// 2. After SPAN operation, sp' = 1: span_flag * (1 - sp') = 0 -/// 3. After RESPAN operation, sp' = 1: respan_flag * (1 - sp') = 0 -fn enforce_in_span_constraints( - builder: &mut AB, - cols: &DecoderColumns, - cols_next: &DecoderColumns, - op_flags: &OpFlags, -) where - AB: TaggingAirBuilderExt, -{ - let sp = cols.in_span.clone(); - let sp_next = cols_next.in_span.clone(); - - // Boundary: execution starts outside any basic block. - assert_zero_first_row(builder, IN_SPAN_BASE, sp.clone()); - - // Constraint 1: sp is binary, so span state is well-formed. - let sp_binary = sp.clone() * (sp - AB::Expr::ONE); - assert_zero_integrity(builder, IN_SPAN_BASE + 1, sp_binary); - - // Constraint 2: After SPAN, the next row must be inside a span. - // span_flag * (1 - sp') = 0 - let span_flag = op_flags.span(); - assert_zero_transition( - builder, - IN_SPAN_BASE + 2, - span_flag * (AB::Expr::ONE - sp_next.clone()), - ); - - // Constraint 3: After RESPAN, the next row must be inside a span. - // respan_flag * (1 - sp') = 0 - let respan_flag = op_flags.respan(); - assert_zero_transition(builder, IN_SPAN_BASE + 3, respan_flag * (AB::Expr::ONE - sp_next)); -} - -/// Enforces that all operation bits (b0-b6) are binary (0 or 1). -/// -/// For each bit bi: bi * (bi - 1) = 0 -fn enforce_op_bits_binary(builder: &mut AB, cols: &DecoderColumns) -where - AB: TaggingAirBuilderExt, -{ - for i in 0..NUM_OP_BITS { - // Each opcode bit must be 0 or 1 to make decoding deterministic. - assert_binary(builder, OP_BITS_BASE + i, cols.op_bits[i].clone()); + // ============================================= + // General opcode-semantic constraints + // ============================================= + // Per-operation invariants that don't fit into the generic counter/decoding sections. + // + // Operation | Constraint | Why + // ----------+-------------------------------------+------------------------------------ + // SPLIT | s0 in {0, 1} | s0 selects true/false branch + // LOOP | s0 in {0, 1} | s0 determines enter (1) / skip (0) + // DYN | h4 = h5 = h6 = h7 = 0 | callee digest lives in h0..h3 only + // REPEAT | s0 = 1 | loop condition must be true + // REPEAT | is_loop_body (h4) = 1 | must be inside an active loop body + // END+loop | is_loop (h5) => s0 = 0 | exiting loop: condition became false + // END+REP' | h0'..h4' = h0..h4 | carry block hash + loop flag for re-entry + // HALT | f_halt => f_halt' | absorbing / terminal state + + // SPLIT/LOOP: branch selector must be binary. + let branch_condition = local.stack.get(0); + builder + .when(op_flags.split() + op_flags.loop_op()) + .assert_bool(branch_condition); + + // DYN: the upper hasher lanes must be zero so the callee digest in h0..h3 is the + // only input to the hash chiplet. + { + let builder = &mut builder.when(op_flags.dyn_op()); + let hasher_zeros = [hasher_state[4], hasher_state[5], hasher_state[6], hasher_state[7]]; + builder.assert_zeros(hasher_zeros) } -} - -/// Enforces that the extra columns (e0, e1) are correctly computed from op bits. -/// -/// These columns are used for degree reduction in operation flag computation: -/// - e0 = b6 * (1 - b5) * b4 -/// - e1 = b6 * b5 -fn enforce_extra_columns(builder: &mut AB, cols: &DecoderColumns) -where - AB: TaggingAirBuilderExt, -{ - let b4 = cols.op_bits[4].clone(); - let b5 = cols.op_bits[5].clone(); - let b6 = cols.op_bits[6].clone(); - - let e0 = cols.extra[0].clone(); - let e1 = cols.extra[1].clone(); - - // e0 = b6 * (1 - b5) * b4. - // This extra register exists to reduce the degree of op-flag selectors for the - // `101...` opcode group (see docs/src/design/stack/op_constraints.md). - let expected_e0 = b6.clone() * (AB::Expr::ONE - b5.clone()) * b4; - assert_zero_integrity(builder, EXTRA_BASE, e0 - expected_e0); - - // e1 = b6 * b5. - // This extra register exists to reduce the degree of op-flag selectors for the - // `11...` opcode group (see docs/src/design/stack/op_constraints.md). - let expected_e1 = b6 * b5; - assert_zero_integrity(builder, EXTRA_BASE + 1, e1 - expected_e1); -} - -/// Enforces opcode-bit constraints for grouped opcode families. -/// -/// - U32 ops (prefix `100`) must have b0 = 0. -/// - Very-high-degree ops (prefix `11`) must have b0 = b1 = 0. -fn enforce_op_bit_group_constraints(builder: &mut AB, cols: &DecoderColumns) -where - AB: TaggingAirBuilderExt, -{ - let b0 = cols.op_bits[0].clone(); - let b1 = cols.op_bits[1].clone(); - let b4 = cols.op_bits[4].clone(); - let b5 = cols.op_bits[5].clone(); - let b6 = cols.op_bits[6].clone(); - - // U32 prefix pattern: b6=1, b5=0, b4=0. Under this prefix, b0 must be 0 to - // eliminate invalid opcodes in the U32 opcode subset. - let u32_prefix = b6.clone() * (AB::Expr::ONE - b5.clone()) * (AB::Expr::ONE - b4); - assert_zero_integrity(builder, OP_BIT_GROUP_BASE, u32_prefix * b0.clone()); - - // Very-high prefix pattern: b6=1, b5=1. Under this prefix, b0 and b1 must be 0 - // to eliminate invalid opcodes in the very-high opcode subset. - let very_high_prefix = b6 * b5; - assert_zero_integrity(builder, OP_BIT_GROUP_BASE + 1, very_high_prefix.clone() * b0); - assert_zero_integrity(builder, OP_BIT_GROUP_BASE + 2, very_high_prefix * b1); -} -/// Enforces that batch flags (c0, c1, c2) are binary. -/// -/// For each flag ci: ci * (ci - 1) = 0 -fn enforce_batch_flags_binary(builder: &mut AB, cols: &DecoderColumns) -where - AB: TaggingAirBuilderExt, -{ - for i in 0..NUM_BATCH_FLAGS { - // Batch flags are selectors; they must be boolean. - assert_binary(builder, BATCH_FLAGS_BINARY_BASE + i, cols.batch_flags[i].clone()); + // REPEAT: top-of-stack must be 1 (loop condition true) and we must be inside an + // active loop body (is_loop_body = h4 = 1). + { + let loop_condition = local.stack.get(0); + let builder = &mut builder.when(op_flags.repeat()); + builder.assert_one(loop_condition); + builder.assert_one(is_loop_body); } -} -/// Enforces general decoder constraints derived from opcode semantics. -/// -/// These are the opcode-specific rules that aren't captured by the generic counters: -/// - SPLIT/LOOP: s0 must be binary (branch selector) -/// - DYN: upper hasher lanes are zero (callee hash lives in lower half) -/// - REPEAT: must be inside loop body and s0 = 1 -/// - END + REPEAT': carry hasher state forward -/// - HALT: absorbing -fn enforce_general_constraints( - builder: &mut AB, - local: &MainTraceRow, - next: &MainTraceRow, - op_flags: &OpFlags, - op_flags_next: &OpFlags, -) where - AB: TaggingAirBuilderExt, -{ - let s0: AB::Expr = local.stack[0].clone().into(); - - // SPLIT/LOOP: top stack value must be binary (branch selector). - let split_or_loop = op_flags.split() + op_flags.loop_op(); - let s0_binary = s0.clone() * (s0.clone() - AB::Expr::ONE); - assert_zero_integrity(builder, GENERAL_BASE, split_or_loop * s0_binary); - - // DYN: the first half holds the callee digest; the second half must be zero. - let f_dyn = op_flags.dyn_op(); - for i in 0..4 { - let hi: AB::Expr = local.decoder[decoder_cols::HASHER_STATE_OFFSET + 4 + i].clone().into(); - assert_zero_integrity(builder, GENERAL_BASE + 1 + i, f_dyn.clone() * hi); - } + // END inside a loop: when ending a loop block (is_loop = h5 = 1), top-of-stack must + // be 0 — the loop exits because the condition became false. + let loop_condition = local.stack.get(0); + builder.when(op_flags.end()).when(is_loop).assert_zero(loop_condition); - // REPEAT: top stack must be 1 and we must be in a loop body (h4=1). - let f_repeat = op_flags.repeat(); - let h4: AB::Expr = local.decoder[decoder_cols::IS_LOOP_BODY_FLAG_COL_IDX].clone().into(); - assert_zero_integrity( - builder, - GENERAL_BASE + 5, - f_repeat.clone() * (AB::Expr::ONE - s0.clone()), - ); - assert_zero_integrity(builder, GENERAL_BASE + 6, f_repeat * (AB::Expr::ONE - h4)); - - // END inside a loop: if is_loop flag is set, top stack must be 0. - let f_end = op_flags.end(); - let h5: AB::Expr = local.decoder[decoder_cols::IS_LOOP_FLAG_COL_IDX].clone().into(); - assert_zero_integrity(builder, GENERAL_BASE + 7, f_end.clone() * h5 * s0); - - // END followed by REPEAT: carry h0..h4 into the next row. - let f_repeat_next = op_flags_next.repeat(); - for i in 0..5 { - let hi: AB::Expr = local.decoder[decoder_cols::HASHER_STATE_OFFSET + i].clone().into(); - let hi_next: AB::Expr = next.decoder[decoder_cols::HASHER_STATE_OFFSET + i].clone().into(); - assert_zero_transition( - builder, - GENERAL_BASE + 8 + i, - f_end.clone() * f_repeat_next.clone() * (hi_next - hi), - ); + // END followed by REPEAT: carry the block hash (h0..h3) and the is_loop_body flag + // (h4) into the next row so the loop body can be re-entered. + { + let gate = builder.is_transition() * op_flags.end() * op_flags.repeat_next(); + let builder = &mut builder.when(gate); + for i in 0..5 { + builder.assert_eq(hasher_state_next[i], hasher_state[i]); + } } - // HALT is absorbing: it can only be followed by HALT. - let f_halt = op_flags.halt(); - let f_halt_next = op_flags_next.halt(); - assert_zero_transition(builder, GENERAL_BASE + 13, f_halt * (AB::Expr::ONE - f_halt_next)); -} - -/// Enforces group count (gc) constraints. -/// -/// The group count tracks remaining operation groups in the current basic block: -/// - gc starts at the total number of groups when SPAN/RESPAN is executed -/// - gc decrements by 1 when processing SPAN, RESPAN, or completing a group -/// - gc must be 0 when END is executed -/// -/// Intuition: -/// - `delta_gc = gc - gc'` is the number of groups consumed on this row. -/// - Inside a span, delta_gc can only be 0 or 1. -/// - SPAN/RESPAN/PUSH must consume a group immediately, so delta_gc must be 1. -/// -/// Constraints: -/// 1. Inside basic block, gc can only stay same or decrement by 1: sp * delta_gc * (delta_gc - 1) = -/// 0 (where delta_gc = gc - gc') -/// 2. When END is executed, gc must be 0: end_flag * gc = 0 -/// 3. During SPAN/RESPAN, gc must decrement by 1: (span_flag + respan_flag) * (1 - delta_gc) = 0 -fn enforce_group_count_constraints( - builder: &mut AB, - cols: &DecoderColumns, - cols_next: &DecoderColumns, - local: &MainTraceRow, - op_flags: &OpFlags, - op_flags_next: &OpFlags, -) where - AB: TaggingAirBuilderExt, -{ - let sp = cols.in_span.clone(); - let gc = cols.group_count.clone(); - let gc_next = cols_next.group_count.clone(); - let h0: AB::Expr = local.decoder[decoder_cols::HASHER_STATE_OFFSET].clone().into(); - - // delta_gc = gc - gc' (how much gc decrements; expected to be 0 or 1) - let delta_gc = gc.clone() - gc_next; - - // is_push = push flag (PUSH is the only operation with immediate value) - let is_push = op_flags.push(); - - // Constraint 1: Inside a span, gc can only stay the same or decrement by 1. - // sp * delta_gc * (delta_gc - 1) = 0 - // This ensures: if sp=1 and delta_gc != 0, then delta_gc must equal 1 - assert_zero_transition( - builder, - GROUP_COUNT_BASE, - sp.clone() * delta_gc.clone() * (delta_gc.clone() - AB::Expr::ONE), - ); - - // Constraint 2: If gc decrements and this is not a PUSH-immediate row, - // then h0 must be zero (no immediate value packed into the group). - // sp * delta_gc * (1 - is_push) * h0 = 0 - assert_zero_transition( - builder, - GROUP_COUNT_BASE + 1, - sp.clone() * delta_gc.clone() * (AB::Expr::ONE - is_push.clone()) * h0, - ); - - // Constraint 3: SPAN/RESPAN/PUSH must consume a group immediately. - // (span_flag + respan_flag + is_push) * (delta_gc - 1) = 0 - let span_flag = op_flags.span(); - let respan_flag = op_flags.respan(); - assert_zero_transition( - builder, - GROUP_COUNT_BASE + 2, - (span_flag + respan_flag + is_push) * (delta_gc.clone() - AB::Expr::ONE), - ); - - // Constraint 4: If the next op is END or RESPAN, gc cannot decrement on this row. - // delta_gc * (end' + respan') = 0 - let end_next = op_flags_next.end(); - let respan_next = op_flags_next.respan(); - assert_zero_transition( - builder, - GROUP_COUNT_BASE + 3, - delta_gc.clone() * (end_next + respan_next), - ); - - // Constraint 5: END closes the span, so gc must be 0. - // end_flag * gc = 0 - let end_flag = op_flags.end(); - assert_zero_integrity(builder, GROUP_COUNT_BASE + 4, end_flag * gc); -} - -/// Enforces op group decoding constraints for the `h0` register. -/// -/// `h0` is a packed buffer of pending op groups. When a group is started or continued, -/// the next opcode is shifted into `h0` (base 2^7, because opcodes fit in 7 bits). -/// When the next op is END or RESPAN, the buffer must be empty (h0 = 0). -fn enforce_op_group_decoding_constraints( - builder: &mut AB, - cols: &DecoderColumns, - cols_next: &DecoderColumns, - local: &MainTraceRow, - next: &MainTraceRow, - op_flags: &OpFlags, - op_flags_next: &OpFlags, -) where - AB: TaggingAirBuilderExt, -{ - let sp = cols.in_span.clone(); - let sp_next = cols_next.in_span.clone(); - - let gc = cols.group_count.clone(); - let gc_next = cols_next.group_count.clone(); - let delta_gc = gc - gc_next; - - let f_span = op_flags.span(); - let f_respan = op_flags.respan(); - let is_push = op_flags.push(); - - // f_sgc is set when gc stays the same inside a basic block. - let f_sgc = sp.clone() * sp_next * (AB::Expr::ONE - delta_gc.clone()); - - let h0: AB::Expr = local.decoder[decoder_cols::HASHER_STATE_OFFSET].clone().into(); - let h0_next: AB::Expr = next.decoder[decoder_cols::HASHER_STATE_OFFSET].clone().into(); - - // Compute op' from next-row op bits (b0' + 2*b1' + ... + 64*b6'). - let op_next = op_bits_to_value::(&cols_next.op_bits); - - // When SPAN/RESPAN/PUSH or when gc doesn't change, shift h0 by op'. - // (h0 - h0' * 2^7 - op') = 0 under the combined flag. - let op_group_base = AB::Expr::from_u16(1u16 << 7); - let h0_shift = h0.clone() - h0_next * op_group_base - op_next; - assert_zero_transition( - builder, - OP_GROUP_DECODING_BASE, - (f_span + f_respan + is_push + f_sgc) * h0_shift, - ); - - // If the next op is END or RESPAN, the current h0 must be 0 (no pending group). - let end_next = op_flags_next.end(); - let respan_next = op_flags_next.respan(); - assert_zero_transition(builder, OP_GROUP_DECODING_BASE + 1, sp * (end_next + respan_next) * h0); -} + // HALT is absorbing: once entered, the VM stays in HALT for all remaining rows. + builder.when_transition().when(op_flags.halt()).assert_one(op_flags.halt_next()); + + // ============================================= + // Group count constraints + // ============================================= + // The group_count column tracks remaining operation groups in the current basic block. + // + // ## Lifecycle + // + // 1. SPAN/RESPAN: the prover sets group_count non-deterministically to the batch's group count. + // The constraint below forces delta_group_count = 1 on these rows. + // 2. Normal execution: each time a group is fully decoded (h0 reaches 0) or a PUSH consumes an + // immediate, group_count decrements by 1 (delta_group_count = 1). + // 3. END: group_count must be 0 — all groups in the span have been consumed. + + // Inside a span, group_count changes by at most 1. When it does change and this is not a PUSH, + // h0 must already be 0 (the group was fully decoded). + { + let gate = builder.is_transition() * in_span; + let builder = &mut builder.when(gate); + builder.assert_bool(delta_group_count.clone()); + builder.when(delta_group_count.clone()).when(is_push.not()).assert_zero(h0); + } -/// Enforces op index (ox) constraints. -/// -/// The op index tracks the position of the current operation within its operation group: -/// - ox ranges from 0 to 8 (9 operations per group) -/// - ox resets to 0 when entering a new group (SPAN, RESPAN, or group boundary) -/// - ox increments by 1 for each operation within a group -/// -/// Intuition: -/// - `ng = delta_gc - is_push` is 1 when a new group starts (excluding PUSH-immediate rows). -/// - When a new group starts, ox' must be 0. -/// - Otherwise, ox increments by 1 while sp stays 1. -/// -/// Constraints: -/// 1. After SPAN/RESPAN, ox' = 0: (span_flag + respan_flag) * ox' = 0 -/// 2. When starting new group inside basic block (gc decrements), ox' = 0: sp * delta_gc * ox' = 0 -/// 3. When inside basic block and not starting new group, ox increments by 1: sp * sp' * (1 - -/// delta_gc) * (ox' - ox - 1) = 0 -/// 4. Op index must be in range [0, 8]: ox * (ox-1) * (ox-2) * (ox-3) * (ox-4) * (ox-5) * (ox-6) * -/// (ox-7) * (ox-8) = 0 -fn enforce_op_index_constraints( - builder: &mut AB, - cols: &DecoderColumns, - cols_next: &DecoderColumns, - op_flags: &OpFlags, -) where - AB: TaggingAirBuilderExt, -{ - let sp = cols.in_span.clone(); - let sp_next = cols_next.in_span.clone(); - let gc = cols.group_count.clone(); - let gc_next = cols_next.group_count.clone(); - let ox = cols.op_index.clone(); - let ox_next = cols_next.op_index.clone(); + // SPAN, RESPAN, and PUSH each consume exactly one group (delta_group_count = 1). + builder + .when_transition() + .when(op_flags.span() + op_flags.respan() + is_push.clone()) + .assert_one(delta_group_count.clone()); + + // If delta_group_count = 1 on this row, the next row cannot be END or RESPAN — those ops need + // a fresh batch or span closure, not a mid-batch decrement. + builder + .when_transition() + .when(delta_group_count.clone()) + .assert_zero(op_flags.end_next() + op_flags.respan_next()); + + // By the time END executes, all groups must have been consumed. + builder.when(op_flags.end()).assert_zero(group_count); + + // ============================================= + // Op group decoding (h0) constraints + // ============================================= + // Register h0 holds the current operation group as a base-128 packed integer. + // Operations are packed least-significant first (each opcode is 7 bits): + // + // h0 = op_0 + 128·op_1 + 128²·op_2 + ... + 128^(k-1)·op_(k-1) + // + // Each step, the VM peels off the lowest 7 bits of h0 — these bits equal the + // opcode that will appear in op_bits on the *next* row (op'). What remains + // after removing op' becomes h0': + // + // h0 = h0' · 128 + op' (no field division needed) + // + // ## same_group_count flag + // + // same_group_count = in_span · in_span' · (1 - delta_group_count) + // + // This is 1 when we are inside a span on BOTH this and the next row AND the group + // count did not change — meaning we are still decoding ops from the same group. + // Note: same_group_count is mutually exclusive with f_span, f_respan, and is_push + // because those three always set delta_group_count = 1. + // + // ## h0_active flag + // + // h0_active = f_span + f_respan + is_push + same_group_count + // + // The h0 shift constraint fires in exactly 4 situations: + // - f_span/f_respan: a new batch was just loaded; h0 has the first group. + // - is_push: PUSH consumed an immediate; h0 shifts to reveal the next op. + // - same_group_count: normal op execution within a group; h0 shifts by one opcode. + { + let f_span = op_flags.span(); + let f_respan = op_flags.respan(); - // delta_gc = gc - gc' (how much gc decrements; 1 when entering new group) - let delta_gc = gc.clone() - gc_next; + let same_group_count: AB::Expr = in_span * in_span_next * delta_group_count.not(); + let op_next: AB::Expr = horner_eval_bits(&op_bits_next); - // is_push = push flag (PUSH is the only operation with immediate value) - let is_push = op_flags.push(); + // When h0 is active, verify the base-128 shift. + let h0_shift = h0 - h0_next * F_128 - op_next; + let h0_active = f_span + f_respan + is_push.clone() + same_group_count; + builder.when_transition().when(h0_active).assert_zero(h0_shift); - // ng = delta_gc - is_push - // This equals 1 when we're starting a new operation group (not due to immediate op) - let ng = delta_gc - is_push; - - let span_flag = op_flags.span(); - let respan_flag = op_flags.respan(); - - // Constraint 1: SPAN/RESPAN start a fresh group, so ox' = 0. - // (span_flag + respan_flag) * ox' = 0 - assert_zero_transition(builder, OP_INDEX_BASE, (span_flag + respan_flag) * ox_next.clone()); - - // Constraint 2: When a new group starts inside a span, ox' = 0. - // sp * ng * ox' = 0 - assert_zero_transition(builder, OP_INDEX_BASE + 1, sp.clone() * ng.clone() * ox_next.clone()); - - // Constraint 3: When staying in the same group, ox increments by 1. - // sp * sp' * (1 - ng) * (ox' - ox - 1) = 0 - let delta_ox = ox_next - ox.clone() - AB::Expr::ONE; - assert_zero_transition( - builder, - OP_INDEX_BASE + 2, - sp * sp_next * (AB::Expr::ONE - ng) * delta_ox, - ); - - // Constraint 4: ox must be in range [0, 8] (9 ops per group). - // ∏_{i=0}^{8}(ox - i) = 0 - let mut range_check = ox.clone(); - for i in 1..=8u64 { - range_check *= ox.clone() - AB::Expr::from_u16(i as u16); + // Before END or RESPAN, h0 must be empty (all ops in the group consumed). + let end_or_respan_next = op_flags.end_next() + op_flags.respan_next(); + builder.when_transition().when(in_span).when(end_or_respan_next).assert_zero(h0); } - assert_zero_integrity(builder, OP_INDEX_BASE + 3, range_check); -} -/// Enforces op batch flag constraints and associated hasher-state zeroing rules. -/// -/// Batch flags encode how many groups were emitted by SPAN/RESPAN: -/// - g8, g4, g2, g1 correspond to batches of 8, 4, 2, or 1 groups. The hasher lanes h1..h7 store -/// the group values; unused lanes must be zeroed. -fn enforce_batch_flags_constraints( - builder: &mut AB, - cols: &DecoderColumns, - local: &MainTraceRow, - op_flags: &OpFlags, -) where - AB: TaggingAirBuilderExt, -{ - let bc0 = cols.batch_flags[0].clone(); - let bc1 = cols.batch_flags[1].clone(); - let bc2 = cols.batch_flags[2].clone(); - - // Batch flag decoding matches trace::decoder batch encodings. - let f_g8 = bc0.clone(); - let f_g4 = (AB::Expr::ONE - bc0.clone()) * bc1.clone() * (AB::Expr::ONE - bc2.clone()); - let f_g2 = (AB::Expr::ONE - bc0.clone()) * (AB::Expr::ONE - bc1.clone()) * bc2.clone(); - let f_g1 = (AB::Expr::ONE - bc0) * bc1 * bc2; - - let f_span = op_flags.span(); - let f_respan = op_flags.respan(); - let span_or_respan = f_span + f_respan; - - // When SPAN or RESPAN, exactly one batch flag must be set. - assert_zero_integrity( - builder, - BATCH_FLAGS_BASE, - span_or_respan.clone() - (f_g1.clone() + f_g2.clone() + f_g4.clone() + f_g8), - ); - - // When not SPAN/RESPAN, all batch flags must be zero. - assert_zero_integrity( - builder, - BATCH_FLAGS_BASE + 1, - (AB::Expr::ONE - span_or_respan) - * (cols.batch_flags[0].clone() - + cols.batch_flags[1].clone() - + cols.batch_flags[2].clone()), - ); - - // When batch has <=4 groups, h4..h7 must be zero (unused lanes). - let small_batch = f_g1.clone() + f_g2.clone() + f_g4.clone(); - for i in 0..4 { - let hi: AB::Expr = local.decoder[decoder_cols::HASHER_STATE_OFFSET + 4 + i].clone().into(); - assert_zero_integrity(builder, BATCH_FLAGS_BASE + 2 + i, small_batch.clone() * hi); - } - - // When batch has <=2 groups, h2..h3 must be zero (unused lanes). - let tiny_batch = f_g1.clone() + f_g2.clone(); - for i in 0..2 { - let hi: AB::Expr = local.decoder[decoder_cols::HASHER_STATE_OFFSET + 2 + i].clone().into(); - assert_zero_integrity(builder, BATCH_FLAGS_BASE + 6 + i, tiny_batch.clone() * hi); + // ============================================= + // Op index constraints + // ============================================= + // The op_index column tracks the position of the current operation within its operation + // group. op_index ranges from 0 to 8 (up to 9 operations per group), resets to 0 when + // entering a new group, and increments by 1 for each operation within a group. + // + // ## new_group flag + // + // new_group = delta_group_count - is_push + // + // When new_group = 1, a genuine new group is starting: group_count decremented and it + // was NOT because of a PUSH immediate. When new_group = 0, we are still in the same + // group (either group_count didn't change, or it changed only because of PUSH). + { + let new_group: AB::Expr = delta_group_count - is_push; + + // SPAN/RESPAN start a fresh batch, so op_index' = 0. + builder + .when_transition() + .when(op_flags.span() + op_flags.respan()) + .assert_zero(op_index_next); + + // When a new group starts inside a span, op_index' = 0. + // Gated by in_span to exclude SPAN/RESPAN rows (which are handled above). + builder + .when_transition() + .when(in_span) + .when(new_group.clone()) + .assert_zero(op_index_next); + + // When staying in the same group inside a span, op_index increments by 1. + // Gated by in_span_next to exclude the row before END/RESPAN (where in_span' = 0). + builder + .when_transition() + .when(in_span) + .when(in_span_next) + .when(new_group.not()) + .assert_eq(op_index_next, op_index + F_1); + + // op_index must be in [0, 8] — 9 ops per group max. + let mut range_check: AB::Expr = op_index.into(); + for i in 1..=8u64 { + range_check *= op_index - Felt::new_unchecked(i); + } + builder.assert_zero(range_check); } - // When batch has 1 group, h1 must be zero (unused lane). - let h1: AB::Expr = local.decoder[decoder_cols::HASHER_STATE_OFFSET + 1].clone().into(); - assert_zero_integrity(builder, BATCH_FLAGS_BASE + 8, f_g1 * h1); -} - -/// Enforces block address (addr) constraints. -/// -/// The block address identifies the current code block in the hasher table: -/// - addr stays constant inside a basic block (sp = 1) -/// - addr increments by HASH_CYCLE_LEN (32) after RESPAN -/// - addr must be 0 when HALT is executed -/// -/// This ties the span state to the hasher table position. -/// -/// Constraints: -/// 1. Inside basic block, address unchanged: sp * (addr' - addr) = 0 -/// 2. RESPAN increments address by HASH_CYCLE_LEN: respan_flag * (addr' - addr - HASH_CYCLE_LEN) = -/// 0 -/// 3. HALT has addr = 0: halt_flag * addr = 0 -fn enforce_block_address_constraints( - builder: &mut AB, - cols: &DecoderColumns, - cols_next: &DecoderColumns, - op_flags: &OpFlags, -) where - AB: TaggingAirBuilderExt, -{ - let sp = cols.in_span.clone(); - let addr = cols.addr.clone(); - let addr_next = cols_next.addr.clone(); - - // Constraint 1: Inside a span, address must stay the same. - // sp * (addr' - addr) = 0 - assert_zero_transition(builder, ADDR_BASE, sp * (addr_next.clone() - addr.clone())); - - // Constraint 2: RESPAN moves to the next hash block (Poseidon2 = 32 rows). - // respan_flag * (addr' - addr - HASH_CYCLE_LEN) = 0 - let hash_cycle_len: AB::Expr = AB::Expr::from_u16(HASH_CYCLE_LEN as u16); - let respan_flag = op_flags.respan(); - assert_zero_transition( - builder, - ADDR_BASE + 1, - respan_flag * (addr_next - addr.clone() - hash_cycle_len), - ); - - // Constraint 3: HALT forces addr = 0. - // halt_flag * addr = 0 - let halt_flag = op_flags.halt(); - assert_zero_integrity(builder, ADDR_BASE + 2, halt_flag * addr); -} - -/// Enforces control flow constraints. -/// -/// When outside a basic block (sp = 0), only control flow operations can execute. -/// This is expressed as: fctrl = 1 - sp, or equivalently: (1 - sp) * (1 - fctrl) = 0 -/// -/// Control flow operations include: -/// - SPAN, JOIN, SPLIT, LOOP (block start operations) -/// - END, REPEAT, RESPAN, HALT (block transition operations) -/// - DYN, DYNCALL, CALL, SYSCALL (procedure invocations) -/// -/// Constraints: -/// 1. When sp = 0, control_flow must be 1: (1 - sp) * (1 - fctrl) = 0 -fn enforce_control_flow_constraints( - builder: &mut AB, - cols: &DecoderColumns, - op_flags: &OpFlags, -) where - AB: TaggingAirBuilderExt, -{ - let sp = cols.in_span.clone(); - - // Constraint: sp and control_flow must be complementary. - // 1 - sp - fctrl = 0 - let ctrl_flag = op_flags.control_flow(); - assert_zero_integrity(builder, CONTROL_FLOW_BASE, AB::Expr::ONE - sp - ctrl_flag); -} + // ============================================= + // Batch flag constraints + // ============================================= + // Batch flags (c0, c1, c2) encode the number of op groups in the current batch. + // This matters for the last batch in a basic block (or the only batch), since all + // other batches must be completely full (8 groups). + // + // The flags are mutually exclusive (exactly one is set during SPAN/RESPAN). + // Unused hasher lanes must be zero to prevent the prover from smuggling + // arbitrary values through unused group slots. The zeroed lanes cascade: + // + // Groups | Zeroed lanes + // -------+-------------- + // 8 | (none) + // 4 | h4..h7 + // 2 | h2..h7 + // 1 | h1..h7 + { + // Batch flag bits must be binary. + builder.assert_bools([bc0, bc1, bc2]); + + // 8 groups: c0 = 1 (c1, c2 don't matter). + let groups_8 = bc0; + // 4 groups: c0 = 0, c1 = 1, c2 = 0. + let not_bc0 = bc0.into().not(); + let groups_4 = not_bc0.clone() * bc1 * bc2.into().not(); + // 2 groups: c0 = 0, c1 = 0, c2 = 1. + let groups_2 = not_bc0.clone() * bc1.into().not() * bc2; + // 1 group: c0 = 0, c1 = 1, c2 = 1. + let groups_1 = not_bc0 * bc1 * bc2; + + // Combined flags for the cascading lane-zeroing constraints. + let groups_1_or_2 = groups_1.clone() + groups_2; + let groups_1_or_2_or_4 = groups_1_or_2.clone() + groups_4; + + let span_or_respan = op_flags.span() + op_flags.respan(); + + // During SPAN/RESPAN, exactly one batch flag must be set. + builder.assert_eq(span_or_respan.clone(), groups_1_or_2_or_4.clone() + groups_8); + + // Outside SPAN/RESPAN, all batch flags must be zero. + builder.when(span_or_respan.not()).assert_zero(bc0 + bc1 + bc2); + + // Fewer than 8 groups: h4..h7 are unused and must be zero. + { + let builder = &mut builder.when(groups_1_or_2_or_4); + for i in 0..4 { + builder.assert_zero(hasher_state[4 + i]); + } + } -fn assert_zero_transition(builder: &mut AB, idx: usize, expr: AB::Expr) { - let mut idx = idx; - tagged_assert_zero(builder, &DECODER_TAGS, &mut idx, expr); -} + // Fewer than 4 groups: h2..h3 are also unused. + { + let builder = &mut builder.when(groups_1_or_2); + for i in 0..2 { + builder.assert_zero(hasher_state[2 + i]); + } + } -fn assert_zero_integrity(builder: &mut AB, idx: usize, expr: AB::Expr) { - let mut idx = idx; - tagged_assert_zero_integrity(builder, &DECODER_TAGS, &mut idx, expr); -} + // Only 1 group: h1 is also unused. + builder.when(groups_1).assert_zero(hasher_state[1]); + } -fn assert_zero_first_row(builder: &mut AB, idx: usize, expr: AB::Expr) { - let id = DECODER_BASE_ID + idx; - let name = DECODER_NAMES[idx]; - builder.tagged(id, name, |builder| { - builder.when_first_row().assert_zero(expr); - }); + // ============================================= + // Block address (addr) constraints + // ============================================= + // The block address links decoder rows to the hasher table, which computes Poseidon2 + // hashes of MAST node contents. Each hash uses a controller input/output pair + // (CONTROLLER_ROWS_PER_PERMUTATION = 2 rows in the hasher table). + // + // When RESPAN starts a new batch within the same span, the hasher table needs a new + // controller pair, so addr increments by CONTROLLER_ROWS_PER_PERMUTATION. + + // Inside a basic block, addr must stay the same (all ops in one batch share the same + // hasher-table address). + builder.when_transition().when(in_span).assert_eq(addr_next, addr); + + // RESPAN moves to the next hash block (addr += CONTROLLER_ROWS_PER_PERMUTATION). + builder + .when_transition() + .when(op_flags.respan()) + .assert_eq(addr_next, addr + CONTROLLER_ROWS_PER_PERM_FELT); + + // HALT forces addr = 0 (execution ends at the root block). + builder.when(op_flags.halt()).assert_zero(addr); + + // ============================================= + // Control flow constraint + // ============================================= + // Every row is either inside a basic block (in_span = 1) or executing a control-flow + // operation (f_ctrl = 1). These two states are mutually exclusive and exhaustive. + // + // f_ctrl covers: JOIN, SPLIT, LOOP, SPAN, RESPAN, END, REPEAT, HALT, DYN, DYNCALL, + // CALL, SYSCALL. + // + // This also implies in_span = 1 - f_ctrl, so in_span is automatically 0 on + // control-flow rows and 1 otherwise (given that in_span is binary, enforced above). + builder.assert_one(in_span + op_flags.control_flow()); + + // Last-row boundary: the final row must be HALT. The processor pads the trace with + // HALT rows and the absorbing transition constraint keeps them there; this constraint + // makes it explicit in the AIR. + // + // TODO: with HALT guaranteed on the last row, some `when_transition()` guards in this + // module may be redundant (HALT is absorbing and addr = 0). Audit which can be removed. + builder.when_last_row().assert_one(op_flags.halt()); } diff --git a/air/src/constraints/decoder/tests.rs b/air/src/constraints/decoder/tests.rs index 8d31c70abd..e69de29bb2 100644 --- a/air/src/constraints/decoder/tests.rs +++ b/air/src/constraints/decoder/tests.rs @@ -1,18 +0,0 @@ -//! Tests for decoder constraints. - -use super::{CONSTRAINT_DEGREES, NUM_CONSTRAINTS}; - -// CONSTRAINT COUNT TEST -// ================================================================================================ - -#[test] -fn test_array_sizes() { - // 7 op bits binary + 2 extra columns + 3 op-bit group constraints + 3 batch flags - // + 14 general constraints - // + 1 sp binary + 2 sp transitions + 5 group count constraints - // + 2 op group decoding + 4 op index constraints + 9 batch flag constraints - // + 3 block address constraints + 1 control flow constraint - // + 1 additional decoder constraint (see DECODER_NAMES) - assert_eq!(NUM_CONSTRAINTS, 57); - assert_eq!(CONSTRAINT_DEGREES.len(), NUM_CONSTRAINTS); -} diff --git a/air/src/constraints/ext_field.rs b/air/src/constraints/ext_field.rs index f1398cb97d..2e100bef23 100644 --- a/air/src/constraints/ext_field.rs +++ b/air/src/constraints/ext_field.rs @@ -1,42 +1,59 @@ //! Quadratic extension expression helpers (F_p[u] / u^2 - 7). //! //! This keeps constraint code readable when manipulating extension elements in terms of -//! base-field expressions. +//! base-field expressions. All arithmetic requires `E: PrimeCharacteristicRing`. use core::ops::{Add, Mul, Sub}; use miden_core::field::PrimeCharacteristicRing; +use miden_crypto::stark::air::AirBuilder; // Quadratic non-residue for the extension: u^2 = 7. const W: u16 = 7; /// Quadratic extension element represented as (c0 + c1 * u). -#[derive(Clone, Debug)] +/// +/// `#[repr(C)]` guarantees layout-compatible with `[E; 2]`, so this can be used +/// inside `#[repr(C)]` column structs in place of `[T; 2]`. +#[derive(Clone, Copy, Debug)] +#[repr(C)] pub struct QuadFeltExpr(pub E, pub E); +// CONSTRUCTORS AND CONVERSIONS +// ================================================================================================ + impl QuadFeltExpr { - /// Constructs a new extension element from two base-field values. - pub fn new>(c0: &V, c1: &V) -> Self { - Self(c0.clone().into(), c1.clone().into()) + /// Constructs a new extension element from two base-field components. + /// + /// Accepts any type convertible to `E`, e.g. `Var` when `E = Expr`. + pub fn new(c0: impl Into, c1: impl Into) -> Self { + Self(c0.into(), c1.into()) } /// Returns the base-field components `[c0, c1]`. pub fn into_parts(self) -> [E; 2] { [self.0, self.1] } + + /// Converts `QuadFeltExpr` into `QuadFeltExpr` (e.g. Var -> Expr). + /// + /// A blanket `From` impl is not possible because `From> for QuadFeltExpr` + /// conflicts with std's `impl From for T` when `V == E`. + pub fn into_expr(self) -> QuadFeltExpr + where + E: Into, + { + QuadFeltExpr(self.0.into(), self.1.into()) + } } -impl QuadFeltExpr -where - E: Clone + Add + Mul + PrimeCharacteristicRing, -{ - /// Returns `self * other`. - pub fn mul(self, rhs: Self) -> Self { - let w = E::from_u16(W); - // (a0 + a1·u)(b0 + b1·u) = (a0·b0 + 7·a1·b1) + (a0·b1 + a1·b0)·u - let c0 = self.0.clone() * rhs.0.clone() + w * (self.1.clone() * rhs.1.clone()); - let c1 = self.0 * rhs.1 + self.1 * rhs.0; - Self(c0, c1) +// EXTENSION FIELD ARITHMETIC +// ================================================================================================ + +impl QuadFeltExpr { + /// Returns `self + self`. + pub fn double(self) -> Self { + Self(self.0.double(), self.1.double()) } /// Returns `self * self`. @@ -47,14 +64,25 @@ where let a1_sq = self.1.clone() * self.1.clone(); let a0_a1 = self.0 * self.1; let c0 = a0_sq + w * a1_sq; - let c1 = a0_a1.clone() + a0_a1; + let c1 = a0_a1.double(); + Self(c0, c1) + } + + /// Extension multiplication: (a0 + a1·u)(b0 + b1·u) in F_p[u]/(u² - 7). + fn ext_mul(self, rhs: Self) -> Self { + let w = E::from_u16(W); + let c0 = self.0.clone() * rhs.0.clone() + w * (self.1.clone() * rhs.1.clone()); + let c1 = self.0 * rhs.1 + self.1 * rhs.0; Self(c0, c1) } } +// QFE-QFE ARITHMETIC TRAIT IMPLS +// ================================================================================================ + impl Add for QuadFeltExpr where - E: Add, + E: PrimeCharacteristicRing, { type Output = Self; @@ -65,7 +93,7 @@ where impl Sub for QuadFeltExpr where - E: Sub, + E: PrimeCharacteristicRing, { type Output = Self; @@ -74,42 +102,45 @@ where } } -impl Add for QuadFeltExpr +impl Mul for QuadFeltExpr where - E: Add, + E: PrimeCharacteristicRing, { type Output = Self; - fn add(self, rhs: E) -> Self { - Self(self.0 + rhs, self.1) + fn mul(self, rhs: Self) -> Self { + self.ext_mul(rhs) } } -impl Sub for QuadFeltExpr +// SCALAR ARITHMETIC +// ================================================================================================ + +impl Add for QuadFeltExpr where - E: Sub, + E: PrimeCharacteristicRing, { type Output = Self; - fn sub(self, rhs: E) -> Self { - Self(self.0 - rhs, self.1) + fn add(self, rhs: E) -> Self { + Self(self.0 + rhs, self.1) } } -impl Mul for QuadFeltExpr +impl Sub for QuadFeltExpr where - E: Clone + Add + Mul + PrimeCharacteristicRing, + E: PrimeCharacteristicRing, { type Output = Self; - fn mul(self, rhs: Self) -> Self { - QuadFeltExpr::mul(self, rhs) + fn sub(self, rhs: E) -> Self { + Self(self.0 - rhs, self.1) } } impl Mul for QuadFeltExpr where - E: Clone + Mul, + E: PrimeCharacteristicRing, { type Output = Self; @@ -117,3 +148,17 @@ where Self(self.0 * rhs.clone(), self.1 * rhs) } } + +// QUAD FELT AIR BUILDER EXTENSION +// ================================================================================================ + +/// Extension trait for asserting equality of quadratic extension field expressions. +pub trait QuadFeltAirBuilder: AirBuilder { + /// Asserts `lhs == rhs` component-wise for quadratic extension field elements. + fn assert_eq_quad(&mut self, lhs: QuadFeltExpr, rhs: QuadFeltExpr) { + self.assert_eq(lhs.0, rhs.0); + self.assert_eq(lhs.1, rhs.1); + } +} + +impl QuadFeltAirBuilder for AB {} diff --git a/air/src/constraints/lookup/buses/block_hash_and_op_group.rs b/air/src/constraints/lookup/buses/block_hash_and_op_group.rs new file mode 100644 index 0000000000..30f2c1538d --- /dev/null +++ b/air/src/constraints/lookup/buses/block_hash_and_op_group.rs @@ -0,0 +1,286 @@ +//! Merged block-hash + op-group column: block-hash queue (G_block_hash) + op-group table +//! (G_op_group) as one mutually-exclusive group. +//! +//! - **G_block_hash** (block-hash queue) fires only on control-flow opcodes: JOIN, SPLIT, +//! LOOP/REPEAT, DYN/DYNCALL/CALL/SYSCALL, END. +//! - **G_op_group** (op-group table) fires only on SPAN/RESPAN (insertion side) or in-span decode +//! rows (removal side). +//! +//! Control-flow opcodes are never in-span, and SPAN/RESPAN are not in G_block_hash's +//! variant list, so no row fires both buses. The merged group's +//! `(deg(V_g), deg(U_g))` is the elementwise max of the two individual buses: +//! `(max(6, 7), max(8, 8)) = (7, 8)`, giving a column transition of +//! `max(1 + 8, 7) = 9` — the same saturated cost the two original columns had +//! individually, but using **one** column instead of two, saving one accumulator column in +//! `ProcessorAir::num_columns` (LookupAir impl). +//! +//! The emitter uses the plain `col.group` path (no cached encoding) for both buses; the +//! merged group's degree is unchanged under either mode. The cached-encoding optimization +//! can be reintroduced later if symbolic expression growth becomes a bottleneck. + +use core::array; + +use miden_core::field::PrimeCharacteristicRing; + +use crate::{ + constraints::{ + lookup::{ + main_air::{MainBusContext, MainLookupBuilder}, + messages::{BlockHashMsg, OpGroupMsg}, + }, + utils::{BoolNot, horner_eval_bits}, + }, + lookup::{Deg, LookupBatch, LookupColumn, LookupGroup}, +}; + +/// Upper bound on fractions this emitter pushes into its column per row. +/// +/// G_block_hash (control-flow opcodes): largest branch is JOIN's 2-add batch. +/// G_op_group (SPAN/RESPAN insertions + in-span decode removal): largest branch is g8's +/// 7-add batch. Insertions (batch-setup rows) and the removal (in-span decode rows) are +/// mutually exclusive by construction. +/// The module header establishes G_block_hash and G_op_group are row-disjoint — control-flow +/// opcodes are never in-span, and SPAN/RESPAN aren't control-flow. So the per-row max is +/// `max(2, 7) = 7`. +pub(in crate::constraints::lookup) const MAX_INTERACTIONS_PER_ROW: usize = 7; + +/// Emit the merged block-hash queue (G_block_hash) + op-group table (G_op_group) column as a +/// single mutually-exclusive group. +#[allow(clippy::too_many_lines)] +pub(in crate::constraints::lookup) fn emit_block_hash_and_op_group( + builder: &mut LB, + ctx: &MainBusContext, +) where + LB: MainLookupBuilder, +{ + let local = ctx.local; + let next = ctx.next; + let op_flags = &ctx.op_flags; + + let dec = &local.decoder; + let dec_next = &next.decoder; + let stk = &local.stack; + let stk_next = &next.stack; + + let addr = dec.addr; + let addr_next = dec_next.addr; + // `dec.hasher_state` is the rate portion of the sponge, split into two halves of 4: + // `h_0 = h[0..4]` (first child) and `h_1 = h[4..8]` (second child). + let h_0: [LB::Var; 4] = array::from_fn(|i| dec.hasher_state[i]); + let h_1: [LB::Var; 4] = array::from_fn(|i| dec.hasher_state[4 + i]); + let s0 = stk.get(0); + + // G_block_hash per-row-type flags. `f_loop_body` / `f_child` are sums of single-use + // op flags, bound locally since each is consumed once inside its `.add(...)` call. + let f_join = op_flags.join(); + let f_split = op_flags.split(); + let f_loop_body = op_flags.loop_op() * s0 + op_flags.repeat(); + let f_child = op_flags.dyn_op() + op_flags.dyncall() + op_flags.call() + op_flags.syscall(); + let f_end = op_flags.end(); + let f_push = op_flags.push(); + + // G_op_group per-batch-size selectors — `c0` is used in three places (g8 gate, g4's + // `(1 - c0)`, g2's `(1 - c0)`), `c1`/`c2` in two places each. Kept as named `LB::Expr` + // bindings per the style rule (used 2+ times). + let c0: LB::Expr = dec.batch_flags[0].into(); + let c1: LB::Expr = dec.batch_flags[1].into(); + let c2: LB::Expr = dec.batch_flags[2].into(); + + // `group_count` is consumed by the 3 insertion batches AND the removal, so 4+ places. + let gc: LB::Expr = dec.group_count.into(); + + // G_op_group removal flag: `in_span · (gc - gc_next)`. Computed once outside the + // removal closure because it's the `flag` argument of `g.remove`, not part of the + // message construction. + let in_span: LB::Expr = dec.in_span.into(); + let gc_next: LB::Expr = dec_next.group_count.into(); + let f_rem = in_span * (gc.clone() - gc_next); + + builder.next_column( + |col| { + col.group( + "merged_interactions", + |g| { + // =================== G_block_hash BLOCK HASH QUEUE =================== + + // JOIN: two children — `h_0` first, `h_1` second. + g.batch( + "join", + f_join, + |b| { + let parent: LB::Expr = addr_next.into(); + let first_hash = h_0.map(LB::Expr::from); + let second_hash = h_1.map(LB::Expr::from); + b.add( + "join_first_child", + BlockHashMsg::FirstChild { + parent: parent.clone(), + child_hash: first_hash, + }, + Deg { v: 5, u: 6 }, + ); + b.add( + "join_second_child", + BlockHashMsg::Child { parent, child_hash: second_hash }, + Deg { v: 5, u: 6 }, + ); + }, + Deg { v: 6, u: 7 }, // (V, U) = (1 + 5, 2 + 5) + ); + + // SPLIT: `s0`-muxed selection between `h_0` and `h_1`. + g.add( + "split", + f_split, + || { + let parent = addr_next.into(); + let s0: LB::Expr = s0.into(); + let one_minus_s0 = s0.not(); + let child_hash = array::from_fn(|i| { + s0.clone() * h_0[i].into() + one_minus_s0.clone() * h_1[i].into() + }); + BlockHashMsg::Child { parent, child_hash } + }, + Deg { v: 5, u: 7 }, + ); + + // LOOP/REPEAT body: first child is `h_0`. + g.add( + "loop_repeat", + f_loop_body, + || { + let parent = addr_next.into(); + let child_hash = h_0.map(LB::Expr::from); + BlockHashMsg::LoopBody { parent, child_hash } + }, + Deg { v: 6, u: 7 }, + ); + + // DYN/DYNCALL/CALL/SYSCALL: single child at `h_0`. + g.add( + "dyn_dyncall_call_syscall", + f_child, + || { + let parent = addr_next.into(); + let child_hash = h_0.map(LB::Expr::from); + BlockHashMsg::Child { parent, child_hash } + }, + Deg { v: 5, u: 6 }, + ); + + // END: pop the queue entry. `is_first_child` distinguishes the head-of-queue + // case via the next-row control-flow flags, and `is_loop_body` comes from the + // typed END overlay on the current row. + g.remove( + "end", + f_end, + || { + let parent = addr_next.into(); + let child_hash = h_0.map(LB::Expr::from); + // RESPAN can directly follow END (the decoder only blocks the + // pair conditionally on `delta_group_count`), so include + // `respan_next` here — otherwise an END→RESPAN pair encodes a + // false-positive `is_first_child = 1` and unbalances the bus. + let is_first_child = LB::Expr::ONE + - op_flags.end_next() + - op_flags.repeat_next() + - op_flags.respan_next() + - op_flags.halt_next(); + let is_loop_body = dec.end_block_flags().is_loop_body.into(); + BlockHashMsg::End { + parent, + child_hash, + is_first_child, + is_loop_body, + } + }, + Deg { v: 4, u: 8 }, + ); + + // =================== G_op_group OP GROUP TABLE =================== + + // g8: c0 triggers a 7-add batch (groups 1..=7). Groups 1..=3 come from `h_0` + // and groups 4..=7 from `h_1`. + let gc8 = gc.clone(); + g.batch( + "g8_batch", + c0.clone(), + move |b| { + let batch_id: LB::Expr = addr_next.into(); + for i in 1u16..=3 { + let group_value = h_0[i as usize].into(); + b.add( + "g8_group", + OpGroupMsg::new(&batch_id, gc8.clone(), i, group_value), + Deg { v: 1, u: 2 }, + ); + } + for i in 4u16..=7 { + let group_value = h_1[(i - 4) as usize].into(); + b.add( + "g8_group", + OpGroupMsg::new(&batch_id, gc8.clone(), i, group_value), + Deg { v: 1, u: 2 }, + ); + } + }, + Deg { v: 7, u: 8 }, // (V, U) = (6 + 1, 7 + 1) + ); + + // g4: (1 - c0) · c1 · (1 - c2) triggers a 3-add batch (groups 1..=3 from + // `h_0`). + let gc4 = gc.clone(); + g.batch( + "g4_batch", + c0.not() * c1.clone() * c2.not(), + move |b| { + let batch_id: LB::Expr = addr_next.into(); + for i in 1u16..=3 { + let group_value = h_0[i as usize].into(); + b.add( + "g4_group", + OpGroupMsg::new(&batch_id, gc4.clone(), i, group_value), + Deg { v: 3, u: 4 }, + ); + } + }, + Deg { v: 5, u: 6 }, // (V, U) = (2 + 3, 3 + 3) + ); + + // g2: (1 - c0) · (1 - c1) · c2 is a single add for group 1 (from `h_0[1]`). + let gc2 = gc.clone(); + let f_g2 = c0.not() * c1.not() * c2; + g.add( + "g2", + f_g2, + move || { + let batch_id: LB::Expr = addr_next.into(); + let group_value = h_0[1].into(); + OpGroupMsg::new(&batch_id, gc2, 1, group_value) + }, + Deg { v: 3, u: 4 }, + ); + + // Removal: `in_span · (gc - gc_next)`-gated muxed removal whose group_value is + // `is_push · stk_next[0] + (1 - is_push) · (h0_next · 128 + opcode_next)`. + g.remove( + "op_group_removal", + f_rem, + move || { + let opcode_next = horner_eval_bits::<7, _, LB::Expr>(&dec_next.op_bits); + let stk_next_0: LB::Expr = stk_next.get(0).into(); + let h0_next: LB::Expr = dec_next.hasher_state[0].into(); + let group_value = f_push.clone() * stk_next_0 + + f_push.not() * (h0_next * LB::Expr::from_u16(128) + opcode_next); + let batch_id = addr.into(); + OpGroupMsg { batch_id, group_pos: gc, group_value } + }, + Deg { v: 2, u: 8 }, + ); + }, + Deg { v: 7, u: 8 }, + ); + }, + Deg { v: 7, u: 8 }, + ); +} diff --git a/air/src/constraints/lookup/buses/block_stack_and_range_logcap.rs b/air/src/constraints/lookup/buses/block_stack_and_range_logcap.rs new file mode 100644 index 0000000000..a5708af4b5 --- /dev/null +++ b/air/src/constraints/lookup/buses/block_stack_and_range_logcap.rs @@ -0,0 +1,379 @@ +//! Packs four buses onto one main-trace lookup column: +//! +//! - Block-stack table: control-flow block nesting. +//! - u32 range-check removes: gated by u32 opcodes. +//! - Log-precompile capacity: gated by the log precompile opcode. +//! - Range-table response: always active and isolated in its own group. +//! +//! Soundness of the merge relies on the three buses using distinct `bus_prefix[bus]` bases +//! (so their rationals remain linearly independent in the extension field) and on all +//! opcode-gated interactions being mutually exclusive in the main group. +//! +//! # Structure +//! +//! One [`super::super::LookupBuilder::column`] call with two sibling +//! [`super::super::LookupColumn::group`] calls: +//! +//! - **Main group** (opcode-gated, mutually exclusive by opcode): +//! - Block-stack table: JOIN/SPLIT/SPAN/DYN, LOOP, DYNCALL, CALL/SYSCALL, two END cases, RESPAN +//! batch (7 branches, mutually exclusive via decoder opcode flags). +//! - u32 range-check batch: 4 removes gated by `u32_rc_op`. +//! - Log-precompile capacity batch: 1 remove + 1 add gated by `log_precompile`. +//! - **Sibling group** (always on): +//! - Range-table response: a single insert with runtime multiplicity `range_m`, gated by `ONE` so +//! it fires on every row. Lives in its own group because it overlaps (row-wise) with every +//! opcode-gated interaction above and would break the simple-group mutual-exclusion invariant. +//! +//! # Mutual exclusivity +//! +//! The main group is sound under simple-group accumulation because all its gates are +//! mutually exclusive decoder-opcode flags. The three bus families live in disjoint +//! opcode sets: +//! +//! - Block-stack: {JOIN, SPLIT, SPAN, DYN, LOOP, DYNCALL, CALL, SYSCALL, END, RESPAN} +//! - u32: {U32SPLIT, U32ASSERT2, U32ADD, U32SUB, U32MUL, U32DIV, U32MOD, U32AND, U32XOR, U32ADD3, +//! U32MADD, …} — prefix_100 in the opcode encoding. +//! - LOGPRECOMPILE: {LOGPRECOMPILE} — a single opcode. +//! +//! No row can fire two of these simultaneously. The END-simple / END-call/syscall split +//! inside block-stack is mutually exclusive via the `is_call + is_syscall ≤ 1` end-flag +//! invariant. +//! +//! # Degree budget +//! +//! Main group contribution table: +//! +//! | Interaction | Gate deg | Payload | U contrib | V contrib | +//! |---|---|---|---|---| +//! | JOIN/SPLIT/SPAN/DYN simple add | 5 | Simple, denom 1 | 6 | 5 | +//! | LOOP simple add | 5 | Simple, denom 1 | 6 | 5 | +//! | DYNCALL simple add (Full msg) | 5 | Full, denom 1 | 6 | 5 | +//! | CALL/SYSCALL simple add (Full msg) | 4 | Full, denom 1 | 5 | 4 | +//! | END simple remove | 5 | Simple, denom 1 | 6 | 5 | +//! | END call/syscall remove (Full msg) | 5 | Full, denom 1 | 6 | 5 | +//! | RESPAN batch (k=2, f=respan deg 4) | — | Simple | 6 | 5 | +//! | u32rc batch (k=4, f=u32_rc_op deg 3) | — | Range, denom 1 | **7** | **6** | +//! | logpre batch (k=2, f=log_precompile deg 5) | — | LogCap, denom 1 | **7** | **6** | +//! +//! Main group max: `U_g = 7, V_g = 6`. +//! +//! Sibling range-table group: `g.insert(ONE, range_m, RangeMsg)` — gate deg 0, mult deg 1, +//! denom deg 1. `U_g = 1, V_g = 1`. +//! +//! Column fold (cross-mul rule `U_col = ∏ U_gi`, `V_col = Σᵢ V_gi · ∏_{j≠i} U_gj`): +//! +//! - `deg(U_col) = 7 + 1 = 8` +//! - `deg(V_col) = max(6 + 1, 1 + 7) = 8` +//! - **Transition = `max(1 + 8, 8) = 9`**, 0 headroom. + +use core::array; + +use miden_core::field::PrimeCharacteristicRing; + +use crate::{ + constraints::lookup::{ + main_air::{MainBusContext, MainLookupBuilder}, + messages::{BlockStackMsg, LogCapacityMsg, RangeMsg}, + }, + lookup::{Deg, LookupBatch, LookupColumn, LookupGroup}, + trace::log_precompile::{HELPER_CAP_PREV_RANGE, STACK_CAP_NEXT_RANGE}, +}; + +/// Upper bound on fractions this emitter pushes into its column per row. +/// +/// Main group per-row max is `max(1, 1, 1, 1, 1, 1, 2 (RESPAN), 4 (u32rc), 2 (logpre)) = 4` +/// — the u32rc 4-remove batch is the dominant branch. +/// Sibling range-table group always contributes 1 fraction. +/// Both groups run unconditionally (the main group fires at most one branch per row but +/// the per-column accumulator allocates the worst-case slot budget), so the per-row max is +/// the sum: `4 + 1 = 5`. +pub(in crate::constraints::lookup) const MAX_INTERACTIONS_PER_ROW: usize = 5; + +/// Emit the merged block-stack + u32rc + logpre + range-table column. +#[allow(clippy::too_many_lines)] +pub(in crate::constraints::lookup) fn emit_block_stack_and_range_logcap( + builder: &mut LB, + ctx: &MainBusContext, +) where + LB: MainLookupBuilder, +{ + let local = ctx.local; + let next = ctx.next; + let op_flags = &ctx.op_flags; + + let dec = &local.decoder; + let dec_next = &next.decoder; + let stk = &local.stack; + let stk_next = &next.stack; + + // ---- Block-stack captures (from block_stack.rs) ---- + // + // `dec.hasher_state` holds `[h0..h7]` with `h[4..8]` doubling as the end-block flags + // (see `end_block_flags()`). DYNCALL reads `h[4]`/`h[5]` as `fmp`/`depth`; the END + // variants read `is_loop`/`is_call`/`is_syscall` through the typed `EndBlockFlags` + // overlay. + let addr = dec.addr; + let addr_next = dec_next.addr; + let h4 = dec.hasher_state[4]; + let h5 = dec.hasher_state[5]; + let h1_next = dec_next.hasher_state[1]; + let end_flags = dec.end_block_flags(); + + let s0 = stk.get(0); + let b0 = stk.b0; + let b1 = stk.b1; + let b0_next = stk_next.b0; + let b1_next = stk_next.b1; + + let sys_ctx = local.system.ctx; + let sys_ctx_next = next.system.ctx; + + // `fn_hash` is used twice (DYNCALL, CALL/SYSCALL) and `fn_hash_next` once + // (END-after-CALL/SYSCALL). + let fn_hash = local.system.fn_hash; + let fn_hash_next = next.system.fn_hash; + + let range_m = local.range.multiplicity; + let range_v = local.range.value; + + // ---- u32rc + logpre captures (from range_logcap.rs) ---- + + let user_helpers = dec.user_op_helpers(); + let f_u32rc = op_flags.u32_rc_op(); + let f_log_precompile = op_flags.log_precompile(); + + // u32rc helpers: first 4 of the 6 user_op_helpers. + let u32rc_helpers: [LB::Var; 4] = array::from_fn(|i| user_helpers[i]); + + // LOGPRECOMPILE capacity add/remove payloads. + let cap_prev: [LB::Var; 4] = array::from_fn(|i| user_helpers[HELPER_CAP_PREV_RANGE.start + i]); + let cap_next: [LB::Var; 4] = array::from_fn(|i| stk_next.get(STACK_CAP_NEXT_RANGE.start + i)); + + builder.next_column( + |col| { + // ──────────── Main group: all opcode-gated interactions ──────────── + col.group( + "main_interactions", + |g| { + // ---- Block-stack table (BusId::BlockStackTable) ---- + + // JOIN/SPLIT/SPAN/DYN: simple push with `is_loop = 0`. + let f = + op_flags.join() + op_flags.split() + op_flags.span() + op_flags.dyn_op(); + g.add( + "join_split_span_dyn", + f, + || { + let block_id = addr_next.into(); + let parent_id = addr.into(); + let is_loop = LB::Expr::ZERO; + BlockStackMsg::Simple { block_id, parent_id, is_loop } + }, + Deg { v: 5, u: 6 }, + ); + + // LOOP: push with is_loop = s0. + g.add( + "loop", + op_flags.loop_op(), + || { + let block_id = addr_next.into(); + let parent_id = addr.into(); + let is_loop = s0.into(); + BlockStackMsg::Simple { block_id, parent_id, is_loop } + }, + Deg { v: 5, u: 6 }, + ); + + // DYNCALL: full push with h[4]/h[5] as fmp/depth. + g.add( + "dyncall", + op_flags.dyncall(), + || { + let block_id = addr_next.into(); + let parent_id = addr.into(); + let is_loop = LB::Expr::ZERO; + let ctx = sys_ctx.into(); + let fmp = h4.into(); + let depth = h5.into(); + let fn_hash = fn_hash.map(LB::Expr::from); + BlockStackMsg::Full { + block_id, + parent_id, + is_loop, + ctx, + fmp, + depth, + fn_hash, + } + }, + Deg { v: 5, u: 6 }, + ); + + // CALL/SYSCALL: full push saving the caller context. + let f = op_flags.call() + op_flags.syscall(); + g.add( + "call_syscall", + f, + || { + let block_id = addr_next.into(); + let parent_id = addr.into(); + let is_loop = LB::Expr::ZERO; + let ctx = sys_ctx.into(); + let fmp = b0.into(); + let depth = b1.into(); + let fn_hash = fn_hash.map(LB::Expr::from); + BlockStackMsg::Full { + block_id, + parent_id, + is_loop, + ctx, + fmp, + depth, + fn_hash, + } + }, + Deg { v: 4, u: 5 }, + ); + + // END (simple blocks): pop with the stored is_loop. + let f = op_flags.end() + * (LB::Expr::ONE - end_flags.is_call.into() - end_flags.is_syscall.into()); + g.remove( + "end_simple", + f, + || { + let block_id = addr.into(); + let parent_id = addr_next.into(); + let is_loop = end_flags.is_loop.into(); + BlockStackMsg::Simple { block_id, parent_id, is_loop } + }, + Deg { v: 5, u: 6 }, + ); + + // END (after CALL/SYSCALL): pop with restored caller context. + let f = + op_flags.end() * (end_flags.is_call.into() + end_flags.is_syscall.into()); + g.remove( + "end_call_syscall", + f, + || { + let block_id = addr.into(); + let parent_id = addr_next.into(); + let is_loop = end_flags.is_loop.into(); + let ctx = sys_ctx_next.into(); + let fmp = b0_next.into(); + let depth = b1_next.into(); + let fn_hash = fn_hash_next.map(LB::Expr::from); + BlockStackMsg::Full { + block_id, + parent_id, + is_loop, + ctx, + fmp, + depth, + fn_hash, + } + }, + Deg { v: 5, u: 6 }, + ); + + // RESPAN: simultaneous push + pop — one batch under the RESPAN flag. + g.batch( + "respan", + op_flags.respan(), + |b| { + let block_id_add = addr_next.into(); + let parent_id_add = h1_next.into(); + let is_loop_add = LB::Expr::ZERO; + b.add( + "respan_add", + BlockStackMsg::Simple { + block_id: block_id_add, + parent_id: parent_id_add, + is_loop: is_loop_add, + }, + Deg { v: 4, u: 5 }, + ); + let block_id_rem = addr.into(); + let parent_id_rem = h1_next.into(); + let is_loop_rem = LB::Expr::ZERO; + b.remove( + "respan_remove", + BlockStackMsg::Simple { + block_id: block_id_rem, + parent_id: parent_id_rem, + is_loop: is_loop_rem, + }, + Deg { v: 4, u: 5 }, + ); + }, + Deg { v: 5, u: 6 }, // (V, U) = (1 + 4, 2 + 4) + ); + + // ---- u32 range-check removes (BusId::RangeCheck) ---- + // Four simultaneous range-check removals under the u32rc flag. Mutually + // exclusive with all block-stack branches (u32 ops are disjoint from + // control-flow ops) and with logpre (disjoint from LOGPRECOMPILE). + g.batch( + "u32_range_check", + f_u32rc, + move |b| { + for helper in u32rc_helpers { + let value = helper.into(); + b.remove("u32rc_remove", RangeMsg { value }, Deg { v: 3, u: 4 }); + } + }, + Deg { v: 6, u: 7 }, // (V, U) = (3 + 3, 4 + 3) + ); + + // ---- Log-precompile capacity update (BusId::LogPrecompileTranscript) ---- + // Remove the previous capacity, add the next. Mutually exclusive with all + // block-stack branches and with u32rc. + g.batch( + "log_precompile_capacity", + f_log_precompile, + move |b| { + let capacity_prev = cap_prev.map(LB::Expr::from); + b.remove( + "logpre_cap_remove", + LogCapacityMsg { capacity: capacity_prev }, + Deg { v: 5, u: 6 }, + ); + let capacity_next = cap_next.map(LB::Expr::from); + b.add( + "logpre_cap_add", + LogCapacityMsg { capacity: capacity_next }, + Deg { v: 5, u: 6 }, + ); + }, + Deg { v: 6, u: 7 }, // (V, U) = (1 + 5, 2 + 5) + ); + }, + Deg { v: 6, u: 7 }, + ); + + // Always-active insertion with multiplicity `range_m`. Lives in its own group + // because its gate (`ONE`) makes it fire on every row, overlapping with every + // opcode-gated interaction in the main group — which would break the simple-group + // mutual-exclusion invariant if they shared a group. + col.group( + "range_table", + |g| { + g.insert( + "range_response", + LB::Expr::ONE, + range_m.into(), + || { + let value = range_v.into(); + RangeMsg { value } + }, + Deg { v: 1, u: 1 }, + ); + }, + Deg { v: 1, u: 1 }, + ); + }, + Deg { v: 8, u: 8 }, + ); +} diff --git a/air/src/constraints/lookup/buses/chiplet_requests.rs b/air/src/constraints/lookup/buses/chiplet_requests.rs new file mode 100644 index 0000000000..6b64d4a34c --- /dev/null +++ b/air/src/constraints/lookup/buses/chiplet_requests.rs @@ -0,0 +1,651 @@ +//! Chiplet requests bus ([`BusId::Chiplets`]). +//! +//! Decoder-side requests into the hasher, bitwise, memory, ACE init, and kernel ROM chiplets. +//! +//! Every interaction is folded into a single [`super::super::LookupColumn::group`] call. +//! The cached-encoding optimization can be reintroduced later if symbolic expression growth +//! becomes a bottleneck. + +use core::array; + +use miden_core::{FMP_ADDR, FMP_INIT_VALUE, field::PrimeCharacteristicRing, operations::opcodes}; + +use crate::{ + constraints::lookup::{ + main_air::{MainBusContext, MainLookupBuilder}, + messages::{AceInitMsg, BitwiseMsg, HasherMsg, KernelRomMsg, MemoryMsg}, + }, + lookup::{Deg, LookupBatch, LookupColumn, LookupGroup}, + trace::{ + chiplets::hasher::CONTROLLER_ROWS_PER_PERMUTATION, + log_precompile::{ + HELPER_ADDR_IDX, HELPER_CAP_PREV_RANGE, STACK_CAP_NEXT_RANGE, STACK_COMM_RANGE, + STACK_R0_RANGE, STACK_R1_RANGE, STACK_TAG_RANGE, + }, + }, +}; + +/// Upper bound on fractions this emitter pushes into its column per row. +/// +/// Every branch here is gated by one mutually exclusive decoder-opcode flag. The heaviest +/// branch is MRUPDATE, whose batch emits 4 removes (merkle_old_init + return_hash + +/// merkle_new_init + return_hash). No other single branch exceeds 4. +pub(in crate::constraints::lookup) const MAX_INTERACTIONS_PER_ROW: usize = 4; + +/// Emit the chiplet requests bus. +#[allow(clippy::too_many_lines)] +pub(in crate::constraints::lookup) fn emit_chiplet_requests( + builder: &mut LB, + main_ctx: &MainBusContext, +) where + LB: MainLookupBuilder, +{ + let local = main_ctx.local; + let next = main_ctx.next; + let op_flags = &main_ctx.op_flags; + + let dec = &local.decoder; + let stk = &local.stack; + let stk_next = &next.stack; + let user_helpers = dec.user_op_helpers(); + + let addr = dec.addr; + let addr_next = next.decoder.addr; + let h = dec.hasher_state; + let helper0 = user_helpers[0]; + let clk = local.system.clk; + let sys_ctx = local.system.ctx; + let sys_ctx_next = next.system.ctx; + let s0 = stk.get(0); + let s1 = stk.get(1); + let stk_next_0 = stk_next.get(0); + let log_addr = user_helpers[HELPER_ADDR_IDX]; + + // Constants reused across HPERM / MPVERIFY / MRUPDATE / END / LOGPRECOMPILE. + // Strides are measured in controller-trace rows (2 per permutation), not physical + // hasher sub-chiplet rows — the address must cancel against `clk + 1` on the hasher + // controller output row. + let last_off: LB::Expr = LB::Expr::from_u16((CONTROLLER_ROWS_PER_PERMUTATION - 1) as u16); + let cycle_len: LB::Expr = LB::Expr::from_u16(CONTROLLER_ROWS_PER_PERMUTATION as u16); + + // Shared (ctx, addr, clk) triple for MLOAD / MSTORE / MLOADW / MSTOREW: all read from + // `s0` with the current system context and clock. + let mem_ctx: LB::Expr = sys_ctx.into(); + let mem_clk: LB::Expr = clk.into(); + let mem_addr: LB::Expr = s0.into(); + + builder.next_column( + |col| { + col.group( + "decoder_requests", + |g| { + // --- Control-block removes (JOIN / SPLIT / LOOP / SPAN; CALL / SYSCALL + // share the payload but live in batches below). SPAN encodes opcode 0 + // at the β¹² slot. + let mut control_remove = |name, flag, opcode: u8| { + g.remove( + name, + flag, + move || { + let parent = addr_next.into(); + let h = h.map(LB::Expr::from); + HasherMsg::control_block(parent, &h, opcode) + }, + Deg { v: 5, u: 6 }, + ); + }; + control_remove("join", op_flags.join(), opcodes::JOIN); + control_remove("split", op_flags.split(), opcodes::SPLIT); + control_remove("loop", op_flags.loop_op(), opcodes::LOOP); + control_remove("span", op_flags.span(), 0); + + // CALL: control-block remove + FMP write under a fresh header (ctx_next / + // FMP_ADDR / clk). + g.batch( + "call", + op_flags.call(), + move |b| { + let parent = addr_next.into(); + let h = h.map(LB::Expr::from); + b.remove( + "call_ctrl_block", + HasherMsg::control_block(parent, &h, opcodes::CALL), + Deg { v: 4, u: 5 }, + ); + b.remove( + "call_fmp_write", + MemoryMsg::write_element( + sys_ctx_next.into(), + FMP_ADDR.into(), + clk.into(), + FMP_INIT_VALUE.into(), + ), + Deg { v: 4, u: 5 }, + ); + }, + Deg { v: 5, u: 6 }, // (V, U) = (1 + 4, 2 + 4) + ); + + // SYSCALL: control-block remove + kernel-ROM call with the h[0..4] digest. + g.batch( + "syscall", + op_flags.syscall(), + move |b| { + let parent = addr_next.into(); + let digest = array::from_fn(|i| h[i].into()); + let h = h.map(LB::Expr::from); + b.remove( + "syscall_ctrl_block", + HasherMsg::control_block(parent, &h, opcodes::SYSCALL), + Deg { v: 4, u: 5 }, + ); + b.remove( + "syscall_kernel_rom", + KernelRomMsg::call(digest), + Deg { v: 4, u: 5 }, + ); + }, + Deg { v: 5, u: 6 }, // (V, U) = (1 + 4, 2 + 4) + ); + + // --- RESPAN --- + // Uses `addr_next` directly: in the controller/perm split, the next row's + // decoder `addr` already points at the continuation input + // row, so no offset is needed. + g.remove( + "respan", + op_flags.respan(), + move || { + let parent = addr_next.into(); + let h = h.map(LB::Expr::from); + HasherMsg::absorption(parent, h) + }, + Deg { v: 4, u: 5 }, + ); + + // --- END --- + { + let last_off = last_off.clone(); + g.remove( + "end", + op_flags.end(), + move || { + let addr: LB::Expr = addr.into(); + let parent = addr + last_off; + let h = array::from_fn(|i| h[i].into()); + HasherMsg::return_hash(parent, h) + }, + Deg { v: 4, u: 5 }, + ); + } + + // --- DYN --- + { + let mem_ctx = mem_ctx.clone(); + let mem_clk = mem_clk.clone(); + let mem_addr = mem_addr.clone(); + g.batch( + "dyn", + op_flags.dyn_op(), + move |b| { + let parent = addr_next.into(); + let zeros8: [LB::Expr; 8] = array::from_fn(|_| LB::Expr::ZERO); + b.remove( + "dyn_ctrl_block", + HasherMsg::control_block(parent, &zeros8, opcodes::DYN), + Deg { v: 5, u: 6 }, + ); + let word = array::from_fn(|i| h[i].into()); + b.remove( + "dyn_mem_read", + MemoryMsg::read_word(mem_ctx, mem_addr, mem_clk, word), + Deg { v: 5, u: 6 }, + ); + }, + Deg { v: 6, u: 7 }, // (V, U) = (1 + 5, 2 + 5) + ); + } + + // --- DYNCALL --- + { + let mem_ctx = mem_ctx.clone(); + let mem_clk = mem_clk.clone(); + let mem_addr = mem_addr.clone(); + g.batch( + "dyncall", + op_flags.dyncall(), + move |b| { + let parent = addr_next.into(); + let zeros8: [LB::Expr; 8] = array::from_fn(|_| LB::Expr::ZERO); + b.remove( + "dyncall_ctrl_block", + HasherMsg::control_block(parent, &zeros8, opcodes::DYNCALL), + Deg { v: 5, u: 6 }, + ); + let word = array::from_fn(|i| h[i].into()); + b.remove( + "dyncall_mem_read", + MemoryMsg::read_word(mem_ctx, mem_addr, mem_clk.clone(), word), + Deg { v: 5, u: 6 }, + ); + b.remove( + "dyncall_fmp_write", + MemoryMsg::write_element( + sys_ctx_next.into(), + FMP_ADDR.into(), + mem_clk, + FMP_INIT_VALUE.into(), + ), + Deg { v: 5, u: 6 }, + ); + }, + Deg { v: 7, u: 8 }, // (V, U) = (2 + 5, 3 + 5) + ); + } + + // --- HPERM --- + { + let last_off = last_off.clone(); + g.batch( + "hperm", + op_flags.hperm(), + move |b| { + let helper0: LB::Expr = helper0.into(); + let stk_state = array::from_fn(|i| stk.get(i).into()); + let stk_next_state = array::from_fn(|i| stk_next.get(i).into()); + b.remove( + "hperm_init", + HasherMsg::linear_hash_init(helper0.clone(), stk_state), + Deg { v: 5, u: 6 }, + ); + let return_addr = helper0 + last_off; + b.remove( + "hperm_return", + HasherMsg::return_state(return_addr, stk_next_state), + Deg { v: 5, u: 6 }, + ); + }, + Deg { v: 6, u: 7 }, // (V, U) = (1 + 5, 2 + 5) + ); + } + + // --- MPVERIFY --- + { + let cycle_len = cycle_len.clone(); + g.batch( + "mpverify", + op_flags.mpverify(), + move |b| { + let helper0: LB::Expr = helper0.into(); + let mp_index = stk.get(5).into(); + let mp_depth: LB::Expr = stk.get(4).into(); + let stk_word_0 = array::from_fn(|i| stk.get(i).into()); + let old_root = array::from_fn(|i| stk.get(6 + i).into()); + b.remove( + "mpverify_init", + HasherMsg::merkle_verify_init( + helper0.clone(), + mp_index, + stk_word_0, + ), + Deg { v: 5, u: 6 }, + ); + let return_addr = helper0 + mp_depth * cycle_len - LB::Expr::ONE; + b.remove( + "mpverify_return", + HasherMsg::return_hash(return_addr, old_root), + Deg { v: 5, u: 6 }, + ); + }, + Deg { v: 6, u: 7 }, // (V, U) = (1 + 5, 2 + 5) + ); + } + + // --- MRUPDATE --- + { + let cycle_len = cycle_len.clone(); + g.batch( + "mrupdate", + op_flags.mrupdate(), + move |b| { + let helper0: LB::Expr = helper0.into(); + let mr_index: LB::Expr = stk.get(5).into(); + let mr_depth: LB::Expr = stk.get(4).into(); + let stk_word_0 = array::from_fn(|i| stk.get(i).into()); + let stk_next_word_0 = array::from_fn(|i| stk_next.get(i).into()); + let old_root = array::from_fn(|i| stk.get(6 + i).into()); + let new_node = array::from_fn(|i| stk.get(10 + i).into()); + b.remove( + "mrupdate_old_init", + HasherMsg::merkle_old_init( + helper0.clone(), + mr_index.clone(), + stk_word_0, + ), + Deg { v: 4, u: 5 }, + ); + let old_return_addr = helper0.clone() + + mr_depth.clone() * cycle_len.clone() + - LB::Expr::ONE; + b.remove( + "mrupdate_old_return", + HasherMsg::return_hash(old_return_addr, old_root), + Deg { v: 4, u: 5 }, + ); + let new_init_addr = + helper0.clone() + mr_depth.clone() * cycle_len.clone(); + b.remove( + "mrupdate_new_init", + HasherMsg::merkle_new_init(new_init_addr, mr_index, new_node), + Deg { v: 4, u: 5 }, + ); + let new_return_addr = helper0 + + mr_depth * (cycle_len.clone() + cycle_len) + - LB::Expr::ONE; + b.remove( + "mrupdate_new_return", + HasherMsg::return_hash(new_return_addr, stk_next_word_0), + Deg { v: 4, u: 5 }, + ); + }, + Deg { v: 7, u: 8 }, // (V, U) = (3 + 4, 4 + 4) + ); + } + + // --- MLOAD / MSTORE / MLOADW / MSTOREW --- + // Shared (ctx, addr, clk) triple: reads the current system context, s0, + // and clk. + { + let (c, a, k) = (mem_ctx.clone(), mem_addr.clone(), mem_clk.clone()); + g.remove( + "mload", + op_flags.mload(), + move || MemoryMsg::read_element(c, a, k, stk_next_0.into()), + Deg { v: 7, u: 8 }, + ); + } + { + let (c, a, k) = (mem_ctx.clone(), mem_addr.clone(), mem_clk.clone()); + g.remove( + "mstore", + op_flags.mstore(), + move || MemoryMsg::write_element(c, a, k, s1.into()), + Deg { v: 7, u: 8 }, + ); + } + { + let (c, a, k) = (mem_ctx.clone(), mem_addr.clone(), mem_clk.clone()); + g.remove( + "mloadw", + op_flags.mloadw(), + move || { + let word = array::from_fn(|i| stk_next.get(i).into()); + MemoryMsg::read_word(c, a, k, word) + }, + Deg { v: 7, u: 8 }, + ); + } + g.remove( + "mstorew", + op_flags.mstorew(), + move || { + let word = [ + s1.into(), + stk.get(2).into(), + stk.get(3).into(), + stk.get(4).into(), + ]; + MemoryMsg::write_word(mem_ctx, mem_addr, mem_clk, word) + }, + Deg { v: 7, u: 8 }, + ); + + // --- MSTREAM / PIPE --- + // Two-word memory ops. Address `stack[12]` holds the word-addressable target; + // the two words live at `addr` and `addr + 4`. + // + // MSTREAM reads 8 elements from memory into `next.stack[0..8]` + // (MEMORY_READ_WORD). PIPE writes 8 elements from + // `next.stack[0..8]` into memory (MEMORY_WRITE_WORD). + let stream_addr = stk.get(12); + g.batch( + "mstream", + op_flags.mstream(), + move |b| { + let addr0: LB::Expr = stream_addr.into(); + let addr1: LB::Expr = addr0.clone() + LB::Expr::from_u16(4); + let word0: [LB::Expr; 4] = array::from_fn(|i| stk_next.get(i).into()); + let word1: [LB::Expr; 4] = + array::from_fn(|i| stk_next.get(4 + i).into()); + b.remove( + "mstream_word0", + MemoryMsg::read_word(sys_ctx.into(), addr0, clk.into(), word0), + Deg { v: 5, u: 6 }, + ); + b.remove( + "mstream_word1", + MemoryMsg::read_word(sys_ctx.into(), addr1, clk.into(), word1), + Deg { v: 5, u: 6 }, + ); + }, + Deg { v: 6, u: 7 }, // (V, U) = (1 + 5, 2 + 5) + ); + g.batch( + "pipe", + op_flags.pipe(), + move |b| { + let addr0: LB::Expr = stream_addr.into(); + let addr1: LB::Expr = addr0.clone() + LB::Expr::from_u16(4); + let word0: [LB::Expr; 4] = array::from_fn(|i| stk_next.get(i).into()); + let word1: [LB::Expr; 4] = + array::from_fn(|i| stk_next.get(4 + i).into()); + b.remove( + "pipe_word0", + MemoryMsg::write_word(sys_ctx.into(), addr0, clk.into(), word0), + Deg { v: 5, u: 6 }, + ); + b.remove( + "pipe_word1", + MemoryMsg::write_word(sys_ctx.into(), addr1, clk.into(), word1), + Deg { v: 5, u: 6 }, + ); + }, + Deg { v: 6, u: 7 }, // (V, U) = (1 + 5, 2 + 5) + ); + + // --- CRYPTOSTREAM --- + // Two word reads (plaintext from src_ptr, src_ptr + 4) followed by two word + // writes (ciphertext to dst_ptr, dst_ptr + 4). The rate lives on + // `local.stack[0..8]`, and the ciphertext on `next.stack[0..8]`; the + // plaintext is recovered algebraically as `cipher - rate`. + let src_ptr = stk.get(12); + let dst_ptr = stk.get(13); + g.batch( + "cryptostream", + op_flags.cryptostream(), + move |b| { + let src0: LB::Expr = src_ptr.into(); + let src1: LB::Expr = src0.clone() + LB::Expr::from_u16(4); + let dst0: LB::Expr = dst_ptr.into(); + let dst1: LB::Expr = dst0.clone() + LB::Expr::from_u16(4); + let rate: [LB::Expr; 8] = array::from_fn(|i| stk.get(i).into()); + let cipher: [LB::Expr; 8] = array::from_fn(|i| stk_next.get(i).into()); + let plain: [LB::Expr; 8] = + array::from_fn(|i| cipher[i].clone() - rate[i].clone()); + let plain_word0: [LB::Expr; 4] = array::from_fn(|i| plain[i].clone()); + let plain_word1: [LB::Expr; 4] = + array::from_fn(|i| plain[4 + i].clone()); + let cipher_word0: [LB::Expr; 4] = array::from_fn(|i| cipher[i].clone()); + let cipher_word1: [LB::Expr; 4] = + array::from_fn(|i| cipher[4 + i].clone()); + b.remove( + "cryptostream_read0", + MemoryMsg::read_word(sys_ctx.into(), src0, clk.into(), plain_word0), + Deg { v: 4, u: 5 }, + ); + b.remove( + "cryptostream_read1", + MemoryMsg::read_word(sys_ctx.into(), src1, clk.into(), plain_word1), + Deg { v: 4, u: 5 }, + ); + b.remove( + "cryptostream_write0", + MemoryMsg::write_word( + sys_ctx.into(), + dst0, + clk.into(), + cipher_word0, + ), + Deg { v: 4, u: 5 }, + ); + b.remove( + "cryptostream_write1", + MemoryMsg::write_word( + sys_ctx.into(), + dst1, + clk.into(), + cipher_word1, + ), + Deg { v: 4, u: 5 }, + ); + }, + Deg { v: 7, u: 8 }, // (V, U) = (3 + 4, 4 + 4) + ); + + // --- HORNERBASE / HORNEREXT --- + // Both ops read the evaluation point α from memory at `stack[13]`. HORNERBASE + // reads two base-field elements (α₀ at `addr`, α₁ at `addr + 1`); HORNEREXT + // reads a single word `[α₀, α₁, k₀, k₁]` at `addr`. α is held in helpers[0..2] + // for both ops (HORNEREXT additionally parks k₀, k₁ in helpers[2..4]). + let alpha_ptr = stk.get(13); + g.batch( + "hornerbase", + op_flags.hornerbase(), + move |b| { + let addr0: LB::Expr = alpha_ptr.into(); + let addr1: LB::Expr = addr0.clone() + LB::Expr::from_u16(1); + let eval0: LB::Expr = user_helpers[0].into(); + let eval1: LB::Expr = user_helpers[1].into(); + b.remove( + "hornerbase_alpha0", + MemoryMsg::read_element(sys_ctx.into(), addr0, clk.into(), eval0), + Deg { v: 5, u: 6 }, + ); + b.remove( + "hornerbase_alpha1", + MemoryMsg::read_element(sys_ctx.into(), addr1, clk.into(), eval1), + Deg { v: 5, u: 6 }, + ); + }, + Deg { v: 6, u: 7 }, // (V, U) = (1 + 5, 2 + 5) + ); + g.remove( + "hornerext", + op_flags.hornerext(), + move || { + let addr: LB::Expr = alpha_ptr.into(); + let word: [LB::Expr; 4] = [ + user_helpers[0].into(), + user_helpers[1].into(), + user_helpers[2].into(), + user_helpers[3].into(), + ]; + MemoryMsg::read_word(sys_ctx.into(), addr, clk.into(), word) + }, + Deg { v: 5, u: 6 }, + ); + + // --- U32AND / U32XOR --- + g.remove( + "u32and", + op_flags.u32and(), + move || { + let a = s0.into(); + let b = s1.into(); + let c = stk_next_0.into(); + BitwiseMsg::and(a, b, c) + }, + Deg { v: 7, u: 8 }, + ); + g.remove( + "u32xor", + op_flags.u32xor(), + move || { + let a = s0.into(); + let b = s1.into(); + let c = stk_next_0.into(); + BitwiseMsg::xor(a, b, c) + }, + Deg { v: 7, u: 8 }, + ); + + // --- EVALCIRCUIT --- + g.remove( + "evalcircuit", + op_flags.evalcircuit(), + move || { + let clk = clk.into(); + let ctx = sys_ctx.into(); + let ptr = s0.into(); + let num_read = s1.into(); + let num_eval = stk.get(2).into(); + AceInitMsg { clk, ctx, ptr, num_read, num_eval } + }, + Deg { v: 5, u: 6 }, + ); + + // --- LOGPRECOMPILE --- + g.batch( + "logprecompile", + op_flags.log_precompile(), + move |b| { + let log_addr: LB::Expr = log_addr.into(); + let logpre_in: [LB::Expr; 12] = [ + stk.get(STACK_COMM_RANGE.start).into(), + stk.get(STACK_COMM_RANGE.start + 1).into(), + stk.get(STACK_COMM_RANGE.start + 2).into(), + stk.get(STACK_COMM_RANGE.start + 3).into(), + stk.get(STACK_TAG_RANGE.start).into(), + stk.get(STACK_TAG_RANGE.start + 1).into(), + stk.get(STACK_TAG_RANGE.start + 2).into(), + stk.get(STACK_TAG_RANGE.start + 3).into(), + user_helpers[HELPER_CAP_PREV_RANGE.start].into(), + user_helpers[HELPER_CAP_PREV_RANGE.start + 1].into(), + user_helpers[HELPER_CAP_PREV_RANGE.start + 2].into(), + user_helpers[HELPER_CAP_PREV_RANGE.start + 3].into(), + ]; + let logpre_out: [LB::Expr; 12] = [ + stk_next.get(STACK_R0_RANGE.start).into(), + stk_next.get(STACK_R0_RANGE.start + 1).into(), + stk_next.get(STACK_R0_RANGE.start + 2).into(), + stk_next.get(STACK_R0_RANGE.start + 3).into(), + stk_next.get(STACK_R1_RANGE.start).into(), + stk_next.get(STACK_R1_RANGE.start + 1).into(), + stk_next.get(STACK_R1_RANGE.start + 2).into(), + stk_next.get(STACK_R1_RANGE.start + 3).into(), + stk_next.get(STACK_CAP_NEXT_RANGE.start).into(), + stk_next.get(STACK_CAP_NEXT_RANGE.start + 1).into(), + stk_next.get(STACK_CAP_NEXT_RANGE.start + 2).into(), + stk_next.get(STACK_CAP_NEXT_RANGE.start + 3).into(), + ]; + b.remove( + "logprecompile_init", + HasherMsg::linear_hash_init(log_addr.clone(), logpre_in), + Deg { v: 5, u: 6 }, + ); + let return_addr = log_addr + last_off; + b.remove( + "logprecompile_return", + HasherMsg::return_state(return_addr, logpre_out), + Deg { v: 5, u: 6 }, + ); + }, + Deg { v: 6, u: 7 }, // (V, U) = (1 + 5, 2 + 5) + ); + }, + Deg { v: 7, u: 8 }, + ); + }, + Deg { v: 7, u: 8 }, + ); +} diff --git a/air/src/constraints/lookup/buses/chiplet_responses.rs b/air/src/constraints/lookup/buses/chiplet_responses.rs new file mode 100644 index 0000000000..7014f24d20 --- /dev/null +++ b/air/src/constraints/lookup/buses/chiplet_responses.rs @@ -0,0 +1,331 @@ +//! Chiplet responses bus ([`BusId::Chiplets`]). +//! +//! Chiplet-side responses from the hasher, bitwise, memory, ACE, and kernel ROM chiplets, +//! all sharing one LogUp column. +//! +//! The 7 hasher response variants are gated on hasher controller rows +//! (`chiplet_active.controller = 1`) via the per-variant `(s0, s1, s2, is_boundary)` +//! combinations. Non-hasher variants (bitwise / memory / ACE init / kernel ROM) are gated +//! by the matching `chiplet_active.{bitwise, memory, ace, kernel_rom}` flag. +//! +//! Memory uses the runtime-muxed [`MemoryResponseMsg`] encoding (label + is_word mux) +//! rather than splitting into 4 per-label variants — this keeps the response-column +//! transition degree at 8 (a per-variant split would bump it to 9). + +use core::{array, borrow::Borrow}; + +use miden_core::field::PrimeCharacteristicRing; + +use crate::{ + constraints::{ + chiplets::columns::PeriodicCols, + lookup::{ + chiplet_air::{ChipletBusContext, ChipletLookupBuilder}, + messages::{ + AceInitMsg, BitwiseMsg, BusId, HasherMsg, HasherPayload, KernelRomMsg, + MemoryResponseMsg, + }, + }, + utils::BoolNot, + }, + lookup::{Deg, LookupBatch, LookupColumn, LookupGroup}, +}; + +/// Upper bound on fractions this emitter pushes into its column per row. +/// +/// All adds gate on per-chiplet `chiplet_active.*` flags which are mutually exclusive (at +/// most one chiplet runs per row). Within the hasher branch, the 7 variants are gated by +/// mutually exclusive `(s0, s1, s2, is_boundary)` combinations. The kernel-ROM branch +/// emits two fractions per active row: an INIT-labeled remove (multiplicity 1) plus a +/// CALL-labeled add with multiplicity equal to the row's `multiplicity` column. Every +/// other chiplet emits exactly one fraction when active. Per-row max: 2. +pub(in crate::constraints::lookup) const MAX_INTERACTIONS_PER_ROW: usize = 2; + +/// Emit the chiplet responses bus. +#[allow(clippy::too_many_lines)] +pub(in crate::constraints::lookup) fn emit_chiplet_responses( + builder: &mut LB, + ctx: &ChipletBusContext, +) where + LB: ChipletLookupBuilder, +{ + let local = ctx.local; + let next = ctx.next; + + // Read the typed periodic column view (used for bitwise k_transition). + let k_transition: LB::Expr = { + let periodic: &PeriodicCols = builder.periodic_values().borrow(); + periodic.bitwise.k_transition.into() + }; + + // Typed chiplet-data overlays. + let ctrl = local.controller(); + let ctrl_next = next.controller(); + let bw = local.bitwise(); + let mem = local.memory(); + let ace = local.ace(); + let krom = local.kernel_rom(); + + // Hasher-internal sub-selectors (valid on controller rows). Used many times below + // via their negated siblings, so kept as named expressions. + let hs0: LB::Expr = ctrl.s0.into(); + let hs1: LB::Expr = ctrl.s1.into(); + let hs2: LB::Expr = ctrl.s2.into(); + let is_boundary: LB::Expr = ctrl.is_boundary.into(); + let not_hs0 = hs0.not(); + let not_hs1 = hs1.not(); + let not_hs2 = hs2.not(); + + let state: [LB::Var; 12] = ctrl.state; + let rate_0: [LB::Var; 4] = array::from_fn(|i| ctrl.state[i]); + let rate_1: [LB::Var; 4] = array::from_fn(|i| ctrl.state[4 + i]); + + // --- Hasher response flags --- + // All gated by `chiplet_active.controller`; composed with the per-row-type + // `(s0, s1, s2, is_boundary)` combinations. + let controller_flag = ctx.chiplet_active.controller.clone(); + + // Sponge start: input (hs0=1), hs1=hs2=0, is_boundary=1. Full 12-lane state. + let f_sponge_start: LB::Expr = controller_flag.clone() + * hs0.clone() + * not_hs1.clone() + * not_hs2.clone() + * is_boundary.clone(); + + // Sponge RESPAN: input, hs1=hs2=0, is_boundary=0. Rate-only 8 lanes. + let f_sponge_respan: LB::Expr = controller_flag.clone() + * hs0.clone() + * not_hs1.clone() + * not_hs2.clone() + * is_boundary.not(); + + // Merkle tree input rows (is_boundary=1): + // f_mp = ctrl · hs0 · (1-hs1) · hs2 · is_boundary + // f_mv = ctrl · hs0 · hs1 · (1-hs2) · is_boundary + // f_mu = ctrl · hs0 · hs1 · hs2 · is_boundary + let f_mp: LB::Expr = + controller_flag.clone() * hs0.clone() * not_hs1.clone() * hs2.clone() * is_boundary.clone(); + let f_mv: LB::Expr = + controller_flag.clone() * hs0.clone() * hs1.clone() * not_hs2.clone() * is_boundary.clone(); + let f_mu: LB::Expr = controller_flag.clone() * hs0 * hs1 * hs2.clone() * is_boundary.clone(); + + // HOUT output: hs0=hs1=hs2=0 (always responds on digest). Degree 4 (no is_boundary). + let f_hout: LB::Expr = controller_flag.clone() * not_hs0.clone() * not_hs1.clone() * not_hs2; + + // SOUT output with is_boundary=1 only (HPERM return). + let f_sout: LB::Expr = controller_flag * not_hs0 * not_hs1 * hs2 * is_boundary; + + // --- Non-hasher flags --- + + // Bitwise: responds only on the last row of the 8-row cycle (k_transition = 0). + let is_bitwise_responding: LB::Expr = ctx.chiplet_active.bitwise.clone() * k_transition.not(); + + // ACE init: responds only on ACE start rows. + let is_ace_init: LB::Expr = ctx.chiplet_active.ace.clone() * ace.s_start.into(); + + // --- Emit everything into a single LogUp column --- + + // All hasher response variants encode their row at `clk + 1` (so they cancel against + // the matching request at `clk`). + let clk_plus_one: LB::Expr = local.system.clk.into() + LB::Expr::ONE; + + // Local helpers: convert the copied Var arrays into Expr arrays. + let full_state = || -> [LB::Expr; 12] { state.map(Into::into) }; + let full_rate = || -> [LB::Expr; 8] { + array::from_fn(|i| if i < 4 { rate_0[i].into() } else { rate_1[i - 4].into() }) + }; + + builder.next_column( + |col| { + col.group( + "chiplet_responses", + |g| { + // Sponge start: full 12-lane state, node_index = 0. + g.add( + "sponge_start", + f_sponge_start, + || HasherMsg { + kind: BusId::HasherLinearHashInit, + addr: clk_plus_one.clone(), + node_index: LB::Expr::ZERO, + payload: HasherPayload::State(full_state()), + }, + Deg { v: 5, u: 6 }, + ); + + // Sponge RESPAN: rate-only 8 lanes, node_index = 0. + g.add( + "sponge_respan", + f_sponge_respan, + || HasherMsg { + kind: BusId::HasherAbsorption, + addr: clk_plus_one.clone(), + node_index: LB::Expr::ZERO, + payload: HasherPayload::Rate(full_rate()), + }, + Deg { v: 5, u: 6 }, + ); + + // Merkle leaf-word inputs for MP_VERIFY / MR_UPDATE_OLD / MR_UPDATE_NEW. + // Each fires on its own controller flag; all three encode + // `leaf = (1-bit)·rate_0 + bit·rate_1` with `bit = node_index - + // 2·node_index_next` (the current Merkle direction bit). + for (name, flag, kind) in [ + ("mp_verify_input", f_mp, BusId::HasherMerkleVerifyInit), + ("mr_update_old_input", f_mv, BusId::HasherMerkleOldInit), + ("mr_update_new_input", f_mu, BusId::HasherMerkleNewInit), + ] { + g.add( + name, + flag, + || { + let addr = clk_plus_one.clone(); + let node_index: LB::Expr = ctrl.node_index.into(); + let bit: LB::Expr = + node_index.clone() - ctrl_next.node_index.into().double(); + let one_minus_bit = bit.not(); + let word: [LB::Expr; 4] = array::from_fn(|i| { + one_minus_bit.clone() * rate_0[i].into() + + bit.clone() * rate_1[i].into() + }); + HasherMsg { + kind, + addr, + node_index, + payload: HasherPayload::Word(word), + } + }, + Deg { v: 5, u: 7 }, + ); + } + + // HOUT: digest = rate_0. + g.add( + "hout", + f_hout, + || { + let addr = clk_plus_one.clone(); + let node_index: LB::Expr = ctrl.node_index.into(); + let word: [LB::Expr; 4] = rate_0.map(LB::Expr::from); + HasherMsg { + kind: BusId::HasherReturnHash, + addr, + node_index, + payload: HasherPayload::Word(word), + } + }, + Deg { v: 4, u: 5 }, + ); + + // SOUT: full 12-lane state (HPERM return), node_index = 0. + g.add( + "sout", + f_sout, + || HasherMsg { + kind: BusId::HasherReturnState, + addr: clk_plus_one.clone(), + node_index: LB::Expr::ZERO, + payload: HasherPayload::State(full_state()), + }, + Deg { v: 5, u: 6 }, + ); + + // Bitwise: runtime op selector bit. + g.add( + "bitwise", + is_bitwise_responding, + || { + let bw_op: LB::Expr = bw.op_flag.into(); + BitwiseMsg { + op: bw_op, + a: bw.a.into(), + b: bw.b.into(), + result: bw.output.into(), + } + }, + Deg { v: 3, u: 4 }, + ); + + // Memory response: runtime (is_read, is_word) mux keeps column transition at 8. + g.add( + "memory", + ctx.chiplet_active.memory.clone(), + || { + let mem_is_read: LB::Expr = mem.is_read.into(); + let is_word: LB::Expr = mem.is_word.into(); + let mem_idx0: LB::Expr = mem.idx0.into(); + let mem_idx1: LB::Expr = mem.idx1.into(); + + let addr = mem.word_addr.into() + + mem_idx1.clone() * LB::Expr::from_u16(2) + + mem_idx0.clone(); + + let word: [LB::Expr; 4] = mem.values.map(LB::Expr::from); + let element = word[0].clone() * mem_idx0.not() * mem_idx1.not() + + word[1].clone() * mem_idx0.clone() * mem_idx1.not() + + word[2].clone() * mem_idx0.not() * mem_idx1.clone() + + word[3].clone() * mem_idx0 * mem_idx1; + + MemoryResponseMsg { + is_read: mem_is_read, + ctx: mem.ctx.into(), + addr, + clk: mem.clk.into(), + is_word, + element, + word, + } + }, + Deg { v: 3, u: 7 }, + ); + + // ACE init. + g.add( + "ace_init", + is_ace_init, + || { + let num_eval = ace.read().num_eval.into() + LB::Expr::ONE; + let num_read = ace.id_0.into() + LB::Expr::ONE - num_eval.clone(); + AceInitMsg { + clk: ace.clk.into(), + ctx: ace.ctx.into(), + ptr: ace.ptr.into(), + num_read, + num_eval, + } + }, + Deg { v: 5, u: 6 }, + ); + + // Kernel ROM: two fractions per active row. + // INIT remove (multiplicity 1) is balanced by the boundary correction. + // CALL add carries the syscall multiplicity. + let kernel_gate = ctx.chiplet_active.kernel_rom.clone(); + g.batch( + "kernel_rom", + kernel_gate, + |b| { + let krom_mult: LB::Expr = krom.multiplicity.into(); + let digest: [LB::Expr; 4] = krom.root.map(LB::Expr::from); + + b.remove( + "kernel_rom_init", + KernelRomMsg::init(digest.clone()), + Deg { v: 5, u: 6 }, + ); + b.insert( + "kernel_rom_call", + krom_mult, + KernelRomMsg::call(digest), + Deg { v: 6, u: 6 }, + ); + }, + Deg { v: 7, u: 7 }, // (V, U) = (2 + 5, 2 + 5); kernel_rom flag deg 5 + ); + }, + Deg { v: 7, u: 7 }, + ); + }, + Deg { v: 7, u: 7 }, + ); +} diff --git a/air/src/constraints/lookup/buses/hash_kernel.rs b/air/src/constraints/lookup/buses/hash_kernel.rs new file mode 100644 index 0000000000..bde13d57c3 --- /dev/null +++ b/air/src/constraints/lookup/buses/hash_kernel.rs @@ -0,0 +1,258 @@ +//! Hash-kernel virtual table bus. Shares one column across +//! `BusId::{SiblingTable, RangeCheck}` plus the shared chiplets column for ACE reads. +//! +//! Combines three tables on a single LogUp column: +//! +//! 1. **Sibling table** (`BusId::SiblingTable`) — Merkle update siblings. On hasher controller +//! input rows with `s0·s1 = 1`, `s2` distinguishes MU (new path, removes siblings) from MV (old +//! path, adds siblings). The direction bit `b = node_index − 2·node_index_next` selects which +//! half of `rate = [rate_0, rate_1]` holds the sibling, giving four gated interactions (two add, +//! two remove). +//! 2. **ACE memory reads** (chiplet-responses column) — on ACE chiplet rows, the block selector +//! distinguishes word reads (`f_ace_read`) from element reads used by EVAL rows (`f_ace_eval`). +//! Both are removed from the chiplets bus. +//! 3. **Memory-side range checks** (`BusId::RangeCheck`) — on memory chiplet rows, a five-remove +//! batch consumes the two delta limbs `d0`/`d1` and the three word-address decomposition values +//! `w0`, `w1`, and `4·w1`. Together these enforce `d0, d1, w0, w1 ∈ [0, 2^16)` plus `w1 ∈ [0, +//! 2^14)` (via the `4·w1` check), which bounds `word_addr = 4·(w0 + 2^16·w1)` to the 32-bit +//! memory address space. +//! +//! Per-chiplet gating flows through [`ChipletBusContext::chiplet_active`]: the controller +//! input gate is `chiplet_active.controller`, the ACE row gate is `chiplet_active.ace`, and +//! the memory row gate is `chiplet_active.memory`. Hasher sub-selectors, hasher state, +//! `node_index`, and `mrupdate_id` come from the typed +//! [`local.controller()`](crate::constraints::columns::MainCols::controller) overlay; +//! memory delta limbs come from [`local.memory()`](crate::constraints::columns::MainCols::memory). +//! `w0` / `w1` are not in the typed `MemoryCols` view (their physical columns live in +//! `chiplets[18..20]`, past the end of the memory overlay, shared with the ACE chiplet +//! column space), so they are read directly from the raw chiplet slice. + +use core::array; + +use miden_core::field::PrimeCharacteristicRing; + +use crate::{ + constraints::{ + lookup::{ + chiplet_air::{ChipletBusContext, ChipletLookupBuilder}, + messages::{MemoryMsg, RangeMsg, SiblingBit, SiblingMsg}, + }, + utils::BoolNot, + }, + lookup::{Deg, LookupBatch, LookupColumn, LookupGroup}, + trace::{ + CHIPLETS_OFFSET, + chiplets::{ + MEMORY_WORD_ADDR_HI_COL_IDX, MEMORY_WORD_ADDR_LO_COL_IDX, + ace::{ACE_INSTRUCTION_ID1_OFFSET, ACE_INSTRUCTION_ID2_OFFSET}, + }, + }, +}; + +/// Upper bound on fractions this emitter pushes into its column per row. +/// +/// Three row-type-disjoint interaction sets, mutually exclusive via the chiplet tri-state: +/// - **Sibling-table** on hasher controller rows (`chiplet_active.controller`): the MV/MU split is +/// mutually exclusive (`s2` vs `1-s2`) and the direction bit cuts within each side, so at most +/// one of the four fires per row → 1 fraction. +/// - **ACE memory reads** on ACE rows (`chiplet_active.ace`): `f_ace_read` / `f_ace_eval` are +/// mutually exclusive via `block_sel` → 1 fraction. +/// - **Memory-side range checks** on memory rows (`chiplet_active.memory`): a 5-remove batch (`d0`, +/// `d1`, `w0`, `w1`, `4·w1`) fires unconditionally when the outer batch flag is active → 5 +/// fractions. +/// +/// Row-type disjointness means only one set fires per row, so the per-row max is +/// `max(1, 1, 5) = 5`. +pub(in crate::constraints::lookup) const MAX_INTERACTIONS_PER_ROW: usize = 5; + +/// Emit the hash-kernel virtual table bus. +#[allow(clippy::too_many_lines)] +pub(in crate::constraints::lookup) fn emit_hash_kernel_table( + builder: &mut LB, + ctx: &ChipletBusContext, +) where + LB: ChipletLookupBuilder, +{ + let local = ctx.local; + let next = ctx.next; + + // --- Sibling-table setup --- + + // Typed hasher-controller overlay: sub-selectors `s0/s1/s2`, state lanes, `node_index`, + // `mrupdate_id`. Next-row `node_index` for the direction-bit computation. + let ctrl = local.controller(); + let ctrl_next = next.controller(); + + let hs0: LB::Expr = ctrl.s0.into(); + let hs1: LB::Expr = ctrl.s1.into(); + let hs2: LB::Expr = ctrl.s2.into(); + + // MU/MV controller-row flags for sibling-table participation. Both share `s0 * s1 = 1`; + // they differ on `s2` (MU: `s2 = 1`, MV: `s2 = 0`) and fire at each Merkle path step. + let controller_flag = ctx.chiplet_active.controller.clone(); + let f_mu_all: LB::Expr = controller_flag.clone() * hs0.clone() * hs1.clone() * hs2.clone(); + let f_mv_all: LB::Expr = controller_flag * hs0 * hs1 * hs2.not(); + + // Hasher state is split by convention into `rate_0 (4), rate_1 (4), cap (4)` — + // sibling messages only use the rate halves. + let rate_0: [LB::Var; 4] = array::from_fn(|i| ctrl.state[i]); + let rate_1: [LB::Var; 4] = array::from_fn(|i| ctrl.state[4 + i]); + let mrupdate_id = ctrl.mrupdate_id; + let node_index = ctrl.node_index; + + // Direction bit `b = node_index − 2·node_index_next`. The bit / one_minus_bit combine + // multiplicatively into the sibling flags below — they're computed once and cloned into + // each `g.add` / `g.remove` flag argument. + let node_index_next: LB::Expr = ctrl_next.node_index.into(); + let bit: LB::Expr = node_index.into() - node_index_next.double(); + let one_minus_bit: LB::Expr = bit.not(); + + // --- ACE memory-read setup --- + + // Typed ACE chiplet overlay. + let ace = local.ace(); + let block_sel: LB::Expr = ace.s_block.into(); + + // ACE row gate comes from the shared `chiplet_active` snapshot; per-mode split by + // `block_sel`. + let is_ace_row = ctx.chiplet_active.ace.clone(); + let f_ace_read: LB::Expr = is_ace_row.clone() * block_sel.not(); + let f_ace_eval: LB::Expr = is_ace_row * block_sel; + + let ace_clk = ace.clk; + let ace_ctx = ace.ctx; + let ace_ptr = ace.ptr; + let ace_v0 = ace.v_0; + let ace_v1 = ace.v_1; + let ace_id_1 = ace.id_1; + let ace_id_2 = ace.eval().id_2; + let ace_eval_op = ace.eval_op; + + // --- Memory-side range-check setup --- + + let mem_active = ctx.chiplet_active.memory.clone(); + let mem = local.memory(); + let mem_d0 = mem.d0; + let mem_d1 = mem.d1; + let mem_w0 = local.chiplets[MEMORY_WORD_ADDR_LO_COL_IDX - CHIPLETS_OFFSET]; + let mem_w1 = local.chiplets[MEMORY_WORD_ADDR_HI_COL_IDX - CHIPLETS_OFFSET]; + + builder.next_column( + |col| { + col.group( + "sibling_ace_memory", + |g| { + // --- SIBLING TABLE --- + // MV adds (old path), MU removes (new path); each splits on the Merkle + // direction bit into a BitZero (sibling at rate_1) and BitOne (sibling + // at rate_0) branch. Four mutually exclusive interactions total. + for (op_name, is_add, f_all, bit_tag, bit_gate) in [ + ( + "sibling_mv_b0", + true, + f_mv_all.clone(), + SiblingBit::Zero, + one_minus_bit.clone(), + ), + ("sibling_mv_b1", true, f_mv_all, SiblingBit::One, bit.clone()), + ("sibling_mu_b0", false, f_mu_all.clone(), SiblingBit::Zero, one_minus_bit), + ("sibling_mu_b1", false, f_mu_all, SiblingBit::One, bit), + ] { + let gate = f_all * bit_gate; + let build = move || { + let mrupdate_id: LB::Expr = mrupdate_id.into(); + let node_index: LB::Expr = node_index.into(); + let h = match bit_tag { + SiblingBit::Zero => array::from_fn(|i| rate_1[i].into()), + SiblingBit::One => array::from_fn(|i| rate_0[i].into()), + }; + SiblingMsg { bit: bit_tag, mrupdate_id, node_index, h } + }; + if is_add { + g.add(op_name, gate, build, Deg { v: 5, u: 6 }); + } else { + g.remove(op_name, gate, build, Deg { v: 5, u: 6 }); + } + } + + // --- ACE MEMORY READS (chiplet-responses column) --- + // Word read on READ rows. + g.remove( + "ace_mem_read_word", + f_ace_read, + move || { + let clk = ace_clk.into(); + let ctx = ace_ctx.into(); + let addr = ace_ptr.into(); + let word = [ + ace_v0.0.into(), + ace_v0.1.into(), + ace_v1.0.into(), + ace_v1.1.into(), + ]; + MemoryMsg::read_word(ctx, addr, clk, word) + }, + Deg { v: 5, u: 6 }, + ); + + // Element read on EVAL rows. + g.remove( + "ace_mem_eval_element", + f_ace_eval, + move || { + let clk = ace_clk.into(); + let ctx = ace_ctx.into(); + let addr = ace_ptr.into(); + let id_1: LB::Expr = ace_id_1.into(); + let id_2: LB::Expr = ace_id_2.into(); + let eval_op: LB::Expr = ace_eval_op.into(); + let element = id_1 + + id_2 * LB::Expr::from(ACE_INSTRUCTION_ID1_OFFSET) + + (eval_op + LB::Expr::ONE) + * LB::Expr::from(ACE_INSTRUCTION_ID2_OFFSET); + MemoryMsg::read_element(ctx, addr, clk, element) + }, + Deg { v: 5, u: 6 }, + ); + + // --- MEMORY-SIDE RANGE CHECKS (BusId::RangeCheck) --- + // Five removes per memory-active row: + // - `d0`, `d1` — the two 16-bit delta limbs used by the memory chiplet's + // sorted-access constraints. + // - `w0`, `w1`, `4·w1` — the word-address decomposition limbs. The `4·w1` check + // additionally enforces `w1 ∈ [0, 2^14)`, which bounds `word_addr = 4·(w0 + + // 2^16·w1) < 2^32`. + g.batch( + "memory_range_checks", + mem_active, + move |b| { + b.remove( + "mem_d0", + RangeMsg { value: mem_d0.into() }, + Deg { v: 3, u: 4 }, + ); + b.remove( + "mem_d1", + RangeMsg { value: mem_d1.into() }, + Deg { v: 3, u: 4 }, + ); + let w0: LB::Expr = mem_w0.into(); + let w1: LB::Expr = mem_w1.into(); + let w1_mul4 = w1.clone() * LB::Expr::from_u16(4); + b.remove("mem_w0", RangeMsg { value: w0 }, Deg { v: 3, u: 4 }); + b.remove("mem_w1", RangeMsg { value: w1 }, Deg { v: 3, u: 4 }); + b.remove( + "mem_w1_mul4", + RangeMsg { value: w1_mul4 }, + Deg { v: 3, u: 4 }, + ); + }, + Deg { v: 7, u: 8 }, // (V, U) = (4 + 3, 5 + 3); mem_active flag deg 3 + ); + }, + Deg { v: 7, u: 8 }, + ); + }, + Deg { v: 7, u: 8 }, + ); +} diff --git a/air/src/constraints/lookup/buses/lookup_op_flags.rs b/air/src/constraints/lookup/buses/lookup_op_flags.rs new file mode 100644 index 0000000000..af4d4718fc --- /dev/null +++ b/air/src/constraints/lookup/buses/lookup_op_flags.rs @@ -0,0 +1,596 @@ +//! Bus-scoped operation flags for the LogUp lookup argument. +//! +//! [`LookupOpFlags`] is a narrower cousin of [`crate::constraints::op_flags::OpFlags`] that +//! carries only the ~32 flags the bus emitters in [`super`] actually read — enough to gate +//! every interaction without materialising the ~150-field surface `OpFlags` exposes to the +//! stack / decoder / chiplet constraint code. +//! +//! The two construction paths live side by side: +//! +//! - [`from_main_cols`](LookupOpFlags::from_main_cols) — polynomial, shared by the constraint-path +//! adapter and the debug builders. Mirrors the relevant parts of +//! [`OpFlags::new`](crate::constraints::op_flags::OpFlags::new) but skips every prefix product +//! that would feed only unused flags. +//! - [`from_boolean_row`](LookupOpFlags::from_boolean_row) — prover-path override that decodes the +//! 7-bit opcode as a `u8` and flips exactly one flag per row. Saves a further factor by +//! sidestepping Felt arithmetic altogether on the discrete flags. +//! +//! The method-accessor shape intentionally mirrors `OpFlags` so the bus emitters read +//! `op_flags.join()` / `op_flags.overflow()` etc. without caring which constructor ran. + +use core::array; + +use miden_core::{ + Felt, + field::{Algebra, PrimeCharacteristicRing}, + operations::opcodes, +}; + +use crate::constraints::{ + decoder::columns::DecoderCols, op_flags::get_op_index, stack::columns::StackCols, +}; + +// LOOKUP OP FLAGS +// ================================================================================================ + +/// Subset of [`OpFlags`](crate::constraints::op_flags::OpFlags) consumed by the LogUp bus +/// emitters. +/// +/// Parameterised by the expression type `E` so the same struct serves the symbolic constraint +/// path and the concrete-row prover path. Only one flag is non-zero on any valid row, same as +/// `OpFlags`. +pub struct LookupOpFlags { + // -- Degree-4 individual ops (current row) -------------------------------------------------- + end: E, + repeat: E, + respan: E, + call: E, + syscall: E, + mrupdate: E, + cryptostream: E, + + // -- Degree-5 individual ops ---------------------------------------------------------------- + join: E, + split: E, + span: E, + loop_op: E, + dyn_op: E, + dyncall: E, + push: E, + hperm: E, + mpverify: E, + mstream: E, + pipe: E, + evalcircuit: E, + log_precompile: E, + hornerbase: E, + hornerext: E, + + // -- Degree-7 individual ops ---------------------------------------------------------------- + mload: E, + mstore: E, + mloadw: E, + mstorew: E, + u32and: E, + u32xor: E, + + // -- Next-row control flow (degree 4) ------------------------------------------------------- + end_next: E, + repeat_next: E, + respan_next: E, + halt_next: E, + + // -- Composite flags ------------------------------------------------------------------------ + left_shift: E, + right_shift: E, + overflow: E, + u32_rc_op: E, +} + +// CONSTRUCTORS +// ================================================================================================ + +impl LookupOpFlags +where + E: PrimeCharacteristicRing + Clone, +{ + /// Polynomial constructor used by the constraint-path adapter and the debug builders. + /// + /// Mirrors the structure of [`OpFlags::new`](crate::constraints::op_flags::OpFlags::new) + /// but computes only the prefix products needed for the ~32 bus-consumed flags. The + /// shared `b32 / b321 / b3210 / b432` prefix tables are still built once up-front so + /// the per-flag cost is a single multiplication each. + pub fn from_main_cols( + decoder: &DecoderCols, + stack: &StackCols, + decoder_next: &DecoderCols, + ) -> Self + where + V: Copy, + E: Algebra, + { + // -- Bit selectors: bits[k][0] = 1 - b_k, bits[k][1] = b_k -------------------------- + let bits: [[E; 2]; 7] = array::from_fn(|k| { + let val = decoder.op_bits[k]; + [E::ONE - val, val.into()] + }); + + // -- Shared prefix product tables (same shape as OpFlags::new) ---------------------- + let b32: [E; 4] = array::from_fn(|i| bits[3][i >> 1].clone() * bits[2][i & 1].clone()); + let b321: [E; 8] = array::from_fn(|i| b32[i >> 1].clone() * bits[1][i & 1].clone()); + let b3210: [E; 16] = array::from_fn(|i| b321[i >> 1].clone() * bits[0][i & 1].clone()); + let b432: [E; 8] = array::from_fn(|i| bits[4][i >> 2].clone() * b32[i & 3].clone()); + + // -- Degree-7 subset -------------------------------------------------------------- + // deg-7 flag(op) = b654[op >> 4] * b321[(op >> 1) & 7] * bits[0][op & 1]. + // All six bus-consumed deg-7 opcodes have b6=0, so we only need b654[0] (b5=0,b4=0) + // for MLOAD and b654[2] (b5=1,b4=0) for the rest. + let b654_0 = bits[6][0].clone() * bits[5][0].clone() * bits[4][0].clone(); + let b654_2 = bits[6][0].clone() * bits[5][1].clone() * bits[4][0].clone(); + let deg7 = |b654: &E, op: u8| -> E { + let op = op as usize; + b654.clone() * b321[(op >> 1) & 7].clone() * bits[0][op & 1].clone() + }; + let mload = deg7(&b654_0, opcodes::MLOAD); + let u32and = deg7(&b654_2, opcodes::U32AND); + let u32xor = deg7(&b654_2, opcodes::U32XOR); + let mloadw = deg7(&b654_2, opcodes::MLOADW); + let mstore = deg7(&b654_2, opcodes::MSTORE); + let mstorew = deg7(&b654_2, opcodes::MSTOREW); + + // -- Degree-5 subset -------------------------------------------------------------- + let deg5_extra: E = decoder.extra[0].into(); + let deg5 = |op: u8| -> E { deg5_extra.clone() * b3210[get_op_index(op)].clone() }; + let hperm = deg5(opcodes::HPERM); + let mpverify = deg5(opcodes::MPVERIFY); + let pipe = deg5(opcodes::PIPE); + let mstream = deg5(opcodes::MSTREAM); + let split = deg5(opcodes::SPLIT); + let loop_op = deg5(opcodes::LOOP); + let span = deg5(opcodes::SPAN); + let join = deg5(opcodes::JOIN); + let dyn_op = deg5(opcodes::DYN); + let push = deg5(opcodes::PUSH); + let dyncall = deg5(opcodes::DYNCALL); + let evalcircuit = deg5(opcodes::EVALCIRCUIT); + let log_precompile = deg5(opcodes::LOGPRECOMPILE); + let hornerbase = deg5(opcodes::HORNERBASE); + let hornerext = deg5(opcodes::HORNEREXT); + + // -- Degree-4 subset -------------------------------------------------------------- + let deg4_extra: E = decoder.extra[1].into(); + let deg4 = |op: u8| -> E { b432[get_op_index(op)].clone() * deg4_extra.clone() }; + let end = deg4(opcodes::END); + let repeat = deg4(opcodes::REPEAT); + let respan = deg4(opcodes::RESPAN); + let call = deg4(opcodes::CALL); + let syscall = deg4(opcodes::SYSCALL); + let mrupdate = deg4(opcodes::MRUPDATE); + let cryptostream = deg4(opcodes::CRYPTOSTREAM); + + // -- Next-row control flow (END / REPEAT / RESPAN / HALT) -------------------------- + // prefix = extra[1]' * b4' = b6'*b5'*b4'. Distinguishes among the four deg-4 ops + // under the `0b0111_xxxx` family via (b3', b2'). + let (end_next, repeat_next, respan_next, halt_next) = { + let prefix: E = decoder_next.extra[1].into(); + let prefix = prefix * decoder_next.op_bits[4]; + let b3n: E = decoder_next.op_bits[3].into(); + let b2n: E = decoder_next.op_bits[2].into(); + let nb3n = E::ONE - b3n.clone(); + let nb2n = E::ONE - b2n.clone(); + ( + prefix.clone() * nb3n.clone() * nb2n.clone(), // END: nb3' * nb2' + prefix.clone() * nb3n * b2n.clone(), // REPEAT: nb3' * b2' + prefix.clone() * b3n.clone() * nb2n, // RESPAN: b3' * nb2' + prefix * b3n * b2n, // HALT: b3' * b2' + ) + }; + + // -- Composite flags -------------------------------------------------------------- + // u32_rc_op = prefix_100 = b6*(1-b5)*(1-b4), degree 3. + let u32_rc_op = bits[6][1].clone() * bits[5][0].clone() * bits[4][0].clone(); + + // right_shift_scalar (degree 6): prefix_011 + PUSH + U32SPLIT. + // U32SPLIT is a degree-6 op: u32_rc_op * b321[get_op_index(U32SPLIT)]. + let u32split = u32_rc_op.clone() * b321[get_op_index(opcodes::U32SPLIT)].clone(); + let prefix_01 = bits[6][0].clone() * bits[5][1].clone(); + let prefix_011 = prefix_01.clone() * bits[4][1].clone(); + let right_shift = prefix_011 + push.clone() + u32split; + + // left_shift_scalar (degree 5): + // prefix_010 + u32_add3_madd_group + SPLIT + LOOP + REPEAT + END*is_loop + DYN. + // DYNCALL intentionally excluded (see OpFlags::left_shift doc). + let prefix_010 = prefix_01 * bits[4][0].clone(); + let u32_add3_madd_group = u32_rc_op.clone() * bits[3][1].clone() * bits[2][1].clone(); + let is_loop = decoder.end_block_flags().is_loop; + let end_loop = end.clone() * is_loop; + let left_shift = prefix_010 + + u32_add3_madd_group + + split.clone() + + loop_op.clone() + + repeat.clone() + + end_loop + + dyn_op.clone(); + + // overflow = (b0 - 16) * h0, degree 2 (uses stack columns, not decoder). + let b0: E = stack.b0.into(); + let overflow = (b0 - E::from_u64(16)) * stack.h0; + + Self { + end, + repeat, + respan, + call, + syscall, + mrupdate, + cryptostream, + join, + split, + span, + loop_op, + dyn_op, + dyncall, + push, + hperm, + mpverify, + mstream, + pipe, + evalcircuit, + log_precompile, + hornerbase, + hornerext, + mload, + mstore, + mloadw, + mstorew, + u32and, + u32xor, + end_next, + repeat_next, + respan_next, + halt_next, + left_shift, + right_shift, + overflow, + u32_rc_op, + } + } +} + +// BOOLEAN FAST PATH (PROVER) +// ================================================================================================ + +impl LookupOpFlags { + /// Concrete-row constructor used by the prover-path adapter. + /// + /// Decodes the 7-bit opcode from `decoder.op_bits` as a `u8` and flips exactly one + /// (or no) flag instead of materialising the polynomial products that + /// [`from_main_cols`](LookupOpFlags::from_main_cols) builds. Semantics match + /// `from_main_cols` on any valid trace — op_bits are 0/1 by the decoder's boolean + /// constraint, and the `is_loop` hasher slot that gates `left_shift`'s `end` term is + /// also 0/1 on valid traces. + /// + /// When `debug_assertions` is on, the output is cross-checked field-by-field against + /// `from_main_cols` so divergences surface immediately in tests. + pub fn from_boolean_row( + decoder: &DecoderCols, + stack: &StackCols, + decoder_next: &DecoderCols, + ) -> Self { + let opcode = decode_opcode_u8(&decoder.op_bits); + let opcode_next = decode_opcode_u8(&decoder_next.op_bits); + + let mut f = Self::all_zero(); + + // One match statement per row — branch-free in the hot case (inactive deg-7 rows + // fall through the default arm). + match opcode { + opcodes::JOIN => f.join = Felt::ONE, + opcodes::SPLIT => f.split = Felt::ONE, + opcodes::SPAN => f.span = Felt::ONE, + opcodes::LOOP => f.loop_op = Felt::ONE, + opcodes::DYN => f.dyn_op = Felt::ONE, + opcodes::DYNCALL => f.dyncall = Felt::ONE, + opcodes::PUSH => f.push = Felt::ONE, + opcodes::HPERM => f.hperm = Felt::ONE, + opcodes::MPVERIFY => f.mpverify = Felt::ONE, + opcodes::MSTREAM => f.mstream = Felt::ONE, + opcodes::PIPE => f.pipe = Felt::ONE, + opcodes::EVALCIRCUIT => f.evalcircuit = Felt::ONE, + opcodes::LOGPRECOMPILE => f.log_precompile = Felt::ONE, + opcodes::HORNERBASE => f.hornerbase = Felt::ONE, + opcodes::HORNEREXT => f.hornerext = Felt::ONE, + opcodes::END => f.end = Felt::ONE, + opcodes::REPEAT => f.repeat = Felt::ONE, + opcodes::RESPAN => f.respan = Felt::ONE, + opcodes::CALL => f.call = Felt::ONE, + opcodes::SYSCALL => f.syscall = Felt::ONE, + opcodes::MRUPDATE => f.mrupdate = Felt::ONE, + opcodes::CRYPTOSTREAM => f.cryptostream = Felt::ONE, + opcodes::MLOAD => f.mload = Felt::ONE, + opcodes::MSTORE => f.mstore = Felt::ONE, + opcodes::MLOADW => f.mloadw = Felt::ONE, + opcodes::MSTOREW => f.mstorew = Felt::ONE, + opcodes::U32AND => f.u32and = Felt::ONE, + opcodes::U32XOR => f.u32xor = Felt::ONE, + _ => {}, + } + match opcode_next { + opcodes::END => f.end_next = Felt::ONE, + opcodes::REPEAT => f.repeat_next = Felt::ONE, + opcodes::RESPAN => f.respan_next = Felt::ONE, + opcodes::HALT => f.halt_next = Felt::ONE, + _ => {}, + } + + // -- Composite flags via integer range tests ------------------------------------ + // u32_rc_op: 1 iff opcode is a degree-6 u32 op (opcodes 64..80). + f.u32_rc_op = bool_to_felt((64..80).contains(&opcode)); + // right_shift_scalar: prefix_011 (opcodes 48..64) + PUSH + U32SPLIT. + f.right_shift = bool_to_felt( + (48..64).contains(&opcode) || opcode == opcodes::PUSH || opcode == opcodes::U32SPLIT, + ); + // left_shift_scalar: prefix_010 (opcodes 32..48) + U32ADD3/U32MADD + SPLIT/LOOP/ + // REPEAT/DYN + END*is_loop. DYNCALL intentionally excluded — see OpFlags::left_shift. + let is_end_loop = opcode == opcodes::END && decoder.end_block_flags().is_loop == Felt::ONE; + f.left_shift = bool_to_felt( + (32..48).contains(&opcode) + || matches!( + opcode, + opcodes::U32ADD3 + | opcodes::U32MADD + | opcodes::SPLIT + | opcodes::LOOP + | opcodes::REPEAT + | opcodes::DYN + ) + || is_end_loop, + ); + + // overflow uses non-boolean stack columns, so keep the Felt expression. + f.overflow = (stack.b0 - Felt::from_u64(16)) * stack.h0; + + // -- Debug parity check ----------------------------------------------------------- + // Cross-check against the polynomial path. `from_main_cols` always produces + // identical output on valid traces — mismatches here indicate either (a) a bug in + // this fast path or (b) a non-boolean op_bits row, which the decoder constraint + // would also reject. + #[cfg(debug_assertions)] + f.assert_matches_polynomial(decoder, stack, decoder_next); + + f + } + + fn all_zero() -> Self { + Self { + end: Felt::ZERO, + repeat: Felt::ZERO, + respan: Felt::ZERO, + call: Felt::ZERO, + syscall: Felt::ZERO, + mrupdate: Felt::ZERO, + cryptostream: Felt::ZERO, + join: Felt::ZERO, + split: Felt::ZERO, + span: Felt::ZERO, + loop_op: Felt::ZERO, + dyn_op: Felt::ZERO, + dyncall: Felt::ZERO, + push: Felt::ZERO, + hperm: Felt::ZERO, + mpverify: Felt::ZERO, + mstream: Felt::ZERO, + pipe: Felt::ZERO, + evalcircuit: Felt::ZERO, + log_precompile: Felt::ZERO, + hornerbase: Felt::ZERO, + hornerext: Felt::ZERO, + mload: Felt::ZERO, + mstore: Felt::ZERO, + mloadw: Felt::ZERO, + mstorew: Felt::ZERO, + u32and: Felt::ZERO, + u32xor: Felt::ZERO, + end_next: Felt::ZERO, + repeat_next: Felt::ZERO, + respan_next: Felt::ZERO, + halt_next: Felt::ZERO, + left_shift: Felt::ZERO, + right_shift: Felt::ZERO, + overflow: Felt::ZERO, + u32_rc_op: Felt::ZERO, + } + } + + #[cfg(debug_assertions)] + fn assert_matches_polynomial( + &self, + decoder: &DecoderCols, + stack: &StackCols, + decoder_next: &DecoderCols, + ) { + let p = Self::from_main_cols::(decoder, stack, decoder_next); + // The deg-5/7 row flags can appear in out-of-range rows where op_bits aren't + // strictly boolean (e.g. the padded tail of a trace); only cross-check on + // genuinely boolean rows so this doesn't fire on harmless padding. + if !decoder.op_bits.iter().all(|b| *b == Felt::ZERO || *b == Felt::ONE) { + return; + } + macro_rules! check { + ($($name:ident),* $(,)?) => { + $( + debug_assert_eq!( + self.$name, p.$name, + concat!("LookupOpFlags parity: ", stringify!($name)), + ); + )* + }; + } + check!( + end, + repeat, + respan, + call, + syscall, + mrupdate, + cryptostream, + join, + split, + span, + loop_op, + dyn_op, + dyncall, + push, + hperm, + mpverify, + mstream, + pipe, + evalcircuit, + log_precompile, + hornerbase, + hornerext, + mload, + mstore, + mloadw, + mstorew, + u32and, + u32xor, + end_next, + repeat_next, + respan_next, + halt_next, + left_shift, + right_shift, + overflow, + u32_rc_op, + ); + } +} + +/// Decodes a 7-bit opcode out of boolean op-bit columns. On a valid trace every `op_bits[k]` +/// is in `{0, 1}`; anything else is undefined but also rejected by the decoder's boolean +/// constraints, so this isn't a safety-critical conversion. +#[inline] +fn decode_opcode_u8(op_bits: &[Felt; 7]) -> u8 { + let mut out = 0u8; + for (k, bit) in op_bits.iter().enumerate() { + out |= ((bit.as_canonical_u64() & 1) as u8) << k; + } + out +} + +#[inline] +fn bool_to_felt(b: bool) -> Felt { + if b { Felt::ONE } else { Felt::ZERO } +} + +// STATE ACCESSORS +// ================================================================================================ + +macro_rules! accessors { + ($( $(#[$meta:meta])* $name:ident ),* $(,)?) => { + impl LookupOpFlags { + $( + $(#[$meta])* + #[inline(always)] + pub fn $name(&self) -> E { + self.$name.clone() + } + )* + } + }; +} + +accessors!( + // Degree-4 individual ops + end, + repeat, + respan, + call, + syscall, + mrupdate, + cryptostream, + // Degree-5 individual ops + join, + split, + span, + loop_op, + dyn_op, + dyncall, + push, + hperm, + mpverify, + mstream, + pipe, + evalcircuit, + log_precompile, + hornerbase, + hornerext, + // Degree-7 individual ops + mload, + mstore, + mloadw, + mstorew, + u32and, + u32xor, + // Next-row control flow + end_next, + repeat_next, + respan_next, + halt_next, + // Composite flags + left_shift, + right_shift, + overflow, + u32_rc_op, +); + +// TESTS +// ================================================================================================ + +#[cfg(test)] +mod tests { + use miden_core::{ONE, ZERO, operations::Operation}; + + use super::LookupOpFlags; + use crate::constraints::op_flags::generate_test_row; + + /// Tests `u32_rc_op` flag for u32 operations. + #[test] + fn u32_rc_op_flag() { + // U32 operations that require range checks (degree 6). + let u32_ops = [ + Operation::U32add, + Operation::U32sub, + Operation::U32mul, + Operation::U32div, + Operation::U32split, + Operation::U32assert2(ZERO), + Operation::U32add3, + Operation::U32madd, + ]; + + for op in u32_ops { + let flags = flags_for_opcode(op.op_code().into()); + assert_eq!(flags.u32_rc_op(), ONE, "u32_rc_op should be ONE for {op:?}"); + } + + // Non-u32 operations. + let non_u32_ops = [ + Operation::Add, + Operation::Mul, + Operation::And, // Bitwise AND is degree 7, not u32. + ]; + + for op in non_u32_ops { + let flags = flags_for_opcode(op.op_code().into()); + assert_eq!(flags.u32_rc_op(), ZERO, "u32_rc_op should be ZERO for {op:?}"); + } + } + + fn flags_for_opcode(opcode: usize) -> LookupOpFlags { + let row = generate_test_row(opcode); + let row_next = generate_test_row(0); + LookupOpFlags::from_main_cols(&row.decoder, &row.stack, &row_next.decoder) + } +} diff --git a/air/src/constraints/lookup/buses/mod.rs b/air/src/constraints/lookup/buses/mod.rs new file mode 100644 index 0000000000..ffd0127bf8 --- /dev/null +++ b/air/src/constraints/lookup/buses/mod.rs @@ -0,0 +1,125 @@ +//! Per-bus emitters for the Miden VM's LogUp argument. +//! +//! The Miden VM's LogUp buses are emitted across 7 columns — most host a single bus, but +//! several host two or more linearly-independent buses sharing one running accumulator via +//! distinct `bus_prefix[bus]` additive bases (see per-bus module docs for the merges). +//! Each emitter is a crate-private `pub(in crate::constraints::lookup) fn emit_*` that +//! opens a single [`super::LookupBuilder::column`] closure and describes the bus's +//! interactions via [`super::LookupColumn::group`] or +//! [`super::LookupColumn::group_with_cached_encoding`]. +//! +//! The emitters are routed through two separate [`super::LookupAir`] implementors: +//! - [`super::main_air::MainLookupAir`] for the main-trace columns. +//! - [`super::chiplet_air::ChipletLookupAir`] for the chiplet-trace columns. +//! +//! [`crate::ProcessorAir`]'s `LookupAir` impl is a thin aggregator that calls both in sequence, +//! preserving the `enforce_main` / `enforce_chiplet` column order for downstream consumers +//! that want the full 7-column picture in a single `eval` call. +//! +//! ## Shared precompute contexts +//! +//! The main-trace and chiplet-trace contexts live next to their respective LookupAirs: +//! - [`super::main_air::MainBusContext`] — two-row window plus the shared +//! [`crate::constraints::op_flags::OpFlags`] instance consumed by the 4 main-trace emitters. +//! - [`super::chiplet_air::ChipletBusContext`] — two-row window plus the shared +//! [`ChipletActiveFlags`] snapshot consumed by the 3 chiplet-trace emitters. +//! +//! Each context is built once per `eval` through an extension-trait hook +//! ([`super::main_air::MainLookupBuilder::build_op_flags`] / +//! [`super::chiplet_air::ChipletLookupBuilder::build_chiplet_active`]), so a future +//! prover-side override can replace the polynomial construction with a cheaper boolean fast +//! path without touching any emitter code. [`ChipletActiveFlags`] itself lives in this +//! module because it's the pure-compute helper both the default chiplet hook and any +//! future override want to reach for; it does not depend on either `MainCols` context type. + +use miden_core::field::{Algebra, PrimeCharacteristicRing}; + +use crate::MainCols; + +pub(in crate::constraints::lookup) mod block_hash_and_op_group; +pub(in crate::constraints::lookup) mod block_stack_and_range_logcap; +pub(in crate::constraints::lookup) mod chiplet_requests; +pub(in crate::constraints::lookup) mod chiplet_responses; +pub(in crate::constraints::lookup) mod hash_kernel; +pub(in crate::constraints::lookup) mod lookup_op_flags; +pub(in crate::constraints::lookup) mod stack_overflow; +pub(in crate::constraints::lookup) mod wiring; + +pub(in crate::constraints::lookup) use lookup_op_flags::LookupOpFlags; + +// CHIPLET ACTIVE FLAGS +// ================================================================================================ + +/// Per-chiplet `is_active` expressions, mirroring the active-flag block of +/// [`build_chiplet_selectors`](super::super::chiplets::selectors::build_chiplet_selectors). +/// +/// These are the only chiplet-flag flavors the LogUp buses consume — +/// `is_transition` / `is_last` / `next_is_first` are used only by the constraint-path +/// chiplet code, not by the LogUp argument — so this type carries no other variants. +/// +/// The constructor is a pure compute function: it builds the same algebra as +/// `build_chiplet_selectors` but does NOT emit any `when` / `assert_*` calls, so it is +/// safe to run in parallel with the constraint-path chiplet selector pass. +pub(crate) struct ChipletActiveFlags { + /// `is_active` for the hasher controller sub-chiplet (= `s_ctrl`). + pub controller: E, + /// `is_active` for the hasher permutation sub-chiplet (= `s_perm`). + pub permutation: E, + /// `is_active` for the bitwise chiplet (= `s0 - s01`). + pub bitwise: E, + /// `is_active` for the memory chiplet (= `s01 - s012`). + pub memory: E, + /// `is_active` for the ACE chiplet (= `s012 - s0123`). + pub ace: E, + /// `is_active` for the kernel ROM chiplet (= `s0123 - s01234`). + pub kernel_rom: E, +} + +impl ChipletActiveFlags +where + E: PrimeCharacteristicRing + Clone, +{ + /// Build the chiplet active-flag snapshot from a `MainCols` borrow. + /// + /// Mirrors the active-flag block of + /// [`build_chiplet_selectors`](super::super::chiplets::selectors::build_chiplet_selectors): + /// - `s_ctrl = chiplets[0]`, `s_perm` + /// - virtual `s0 = 1 - s_ctrl - s_perm` + /// - prefix chain `s01 / s012 / s0123 / s01234` + /// - `is_bitwise = s0 - s01`, `is_memory = s01 - s012`, `is_ace = s012 - s0123`, `is_kernel_rom + /// = s0123 - s01234` + pub fn from_main_cols(local: &MainCols) -> Self + where + V: Copy, + E: Algebra, + { + let s_ctrl: E = local.chiplets[0].into(); + let s_perm: E = local.s_perm.into(); + let s1: E = local.chiplets[1].into(); + let s2: E = local.chiplets[2].into(); + let s3: E = local.chiplets[3].into(); + let s4: E = local.chiplets[4].into(); + + // Virtual non-hasher selector and prefix products. + let s0 = E::ONE - s_ctrl.clone() - s_perm.clone(); + let s01 = s0.clone() * s1; + let s012 = s01.clone() * s2; + let s0123 = s012.clone() * s3; + let s01234 = s0123.clone() * s4; + + // Active flags via the subtraction trick. + let bitwise = s0 - s01.clone(); + let memory = s01 - s012.clone(); + let ace = s012 - s0123.clone(); + let kernel_rom = s0123 - s01234; + + Self { + controller: s_ctrl, + permutation: s_perm, + bitwise, + memory, + ace, + kernel_rom, + } + } +} diff --git a/air/src/constraints/lookup/buses/stack_overflow.rs b/air/src/constraints/lookup/buses/stack_overflow.rs new file mode 100644 index 0000000000..208c7ffeaa --- /dev/null +++ b/air/src/constraints/lookup/buses/stack_overflow.rs @@ -0,0 +1,101 @@ +//! Stack overflow table bus (`BusId::StackOverflowTable`). +//! +//! Three mutually exclusive interactions: +//! +//! - **Right shift** (add): when an item is pushed past stack[15], record `(clk, s15, b1)` — the +//! cycle, the spilled value, and the link to the previous overflow row. +//! - **Left shift ∧ non-empty overflow** (remove): when an item is popped back from the overflow +//! table, consume the matching `(b1, s15', b1')` row. +//! - **DYNCALL ∧ non-empty overflow** (remove): DYNCALL is excluded from the `left_shift` +//! aggregate; it consumes `(b1, s15', hasher_state[5])` because the new overflow pointer after a +//! DYNCALL is staged in the decoder hasher state, not in `b1'` (which is reset). + +use crate::{ + constraints::lookup::{ + main_air::{MainBusContext, MainLookupBuilder}, + messages::StackOverflowMsg, + }, + lookup::{Deg, LookupColumn, LookupGroup}, +}; + +/// Upper bound on fractions this emitter pushes into its column per row. +/// +/// All three interactions gate on mutually exclusive opcode flags (right_shift, left_shift, +/// dyncall — DYNCALL is excluded from the `left_shift` aggregate by construction), so at +/// most one fires per row. +pub(in crate::constraints::lookup) const MAX_INTERACTIONS_PER_ROW: usize = 1; + +/// Emit the stack overflow table bus. +pub(in crate::constraints::lookup) fn emit_stack_overflow( + builder: &mut LB, + ctx: &MainBusContext, +) where + LB: MainLookupBuilder, +{ + let local = ctx.local; + let next = ctx.next; + let op_flags = &ctx.op_flags; + + let clk = local.system.clk; + let s15 = local.stack.get(15); + let s15_next = next.stack.get(15); + let b1 = local.stack.b1; + let b1_next = next.stack.b1; + let h5 = local.decoder.hasher_state[5]; + + // `op_flags.overflow() = (b0 - 16) * h0`, degree 2. Aliased once so each remove site + // does not re-clone the underlying expression. + let f_overflow = op_flags.overflow(); + let f_left_overflow = op_flags.left_shift() * f_overflow.clone(); + let f_dyncall_overflow = op_flags.dyncall() * f_overflow; + + builder.next_column( + |col| { + col.group( + "overflow_interactions", + |g| { + // Right shift: push `(clk, s15, b1)` onto the overflow table. + g.add( + "right_shift", + op_flags.right_shift(), + || StackOverflowMsg { + clk: clk.into(), + val: s15.into(), + prev: b1.into(), + }, + Deg { v: 6, u: 7 }, + ); + + // Left shift with non-empty overflow: pop `(b1, s15', b1')` off the overflow + // table. + g.remove( + "left_shift", + f_left_overflow, + || StackOverflowMsg { + clk: b1.into(), + val: s15_next.into(), + prev: b1_next.into(), + }, + Deg { v: 7, u: 8 }, + ); + + // DYNCALL with non-empty overflow: pop `(b1, s15', h5)`. The new overflow + // pointer lives in `hasher_state[5]` after a DYNCALL, since + // `b1'` is reset by the call. + g.remove( + "dyncall", + f_dyncall_overflow, + || StackOverflowMsg { + clk: b1.into(), + val: s15_next.into(), + prev: h5.into(), + }, + Deg { v: 7, u: 8 }, + ); + }, + Deg { v: 7, u: 8 }, + ); + }, + Deg { v: 7, u: 8 }, + ); +} diff --git a/air/src/constraints/lookup/buses/wiring.rs b/air/src/constraints/lookup/buses/wiring.rs new file mode 100644 index 0000000000..f0718abc3d --- /dev/null +++ b/air/src/constraints/lookup/buses/wiring.rs @@ -0,0 +1,278 @@ +//! `v_wiring` shared bus column (`BusId::{AceWiring, HasherPermLinkInput, +//! HasherPermLinkOutput}`). +//! +//! All three buses live inside **one** [`super::super::LookupColumn::group`] call. The chiplet +//! tri-state (`s_ctrl + s_perm + s0_virtual = 1`) makes ACE rows, hasher controller rows, +//! and hasher permutation rows pairwise mutually exclusive, so the simple-group +//! composition `U_g += (d_i − 1)·f_i`, `V_g += m_i·f_i` is sound: at most one of the five +//! interactions fires per row, and the column's running `(V, U)` takes MAX over per- +//! interaction degrees rather than summing them (which a sibling-group split would do). +//! Each bus's denominator uses a distinct `bus_prefix[bus]` additive base, so even +//! though they share the same accumulator their contributions are linearly independent in +//! the extension field and cannot cancel across buses. +//! +//! ## ACE wiring (`BusId::AceWiring`) +//! +//! Two READ/EVAL wire interactions gated by the ACE chiplet selector + its per-row block +//! selector, folded into a single `ace_flag`-gated batch with `sblock`-muxed multiplicities: +//! `wire_0` fires with the same multiplicity `m_0` on both READ and EVAL rows, so it +//! factors out; `wire_1` and `wire_2` get `sblock`-parameterized multiplicities that recover +//! the original rational at every row. This drops the outer selector from degree 5 +//! (`is_read`/`is_eval`) to degree 4 (`ace_flag`), bringing the batch's contribution to +//! `(deg(U_g), deg(V_g)) = (7, 8)`. +//! +//! Algebraic equivalence: +//! +//! ```text +//! is_read · (m_0/wire_0 + m_1/wire_1) +//! + is_eval · (m_0/wire_0 − 1/wire_1 − 1/wire_2) +//! = ace_flag · [ m_0/wire_0 +//! + ((1 − sblock)·m_1 − sblock)/wire_1 +//! + (−sblock)/wire_2 ] +//! ``` +//! +//! The `wire_2` payload reads the physical columns shared with the READ overlay's `m_1` +//! slot — under `sblock = 1` (EVAL) they hold `v_2`, and under `sblock = 0` (READ) the +//! `wire_2` interaction is fully suppressed via the `−sblock` multiplicity, so the +//! interpretation collapses to the READ-mode one. +//! +//! ## Hasher perm-link (`BusId::HasherPermLink{Input,Output}`) +//! +//! Binds hasher controller rows to permutation sub-chiplet rows. Without this bus the +//! permutation segment is structurally independent from the controller, and a malicious +//! prover could pair any controller `(state_in, state_out)` with any perm-cycle execution +//! (or skip the cycle entirely). Four mutually exclusive interactions split across two +//! domain-separated buses: +//! +//! - **Controller input** (`s_ctrl · is_input`, multiplicity `+1`) — controller side of a +//! (state_in, state_out) pair. Routed to `BusId::HasherPermLinkInput`. +//! - **Controller output** (`s_ctrl · is_output`, multiplicity `+1`). Routed to +//! `BusId::HasherPermLinkOutput`. +//! - **Permutation row 0** (`s_perm · is_init_ext`, multiplicity `−m`) — input boundary of a +//! Poseidon2 cycle. `m` is read from `PermutationCols.multiplicity` and is constant within the +//! cycle by [`crate::constraints::chiplets::permutation`]. Routed to +//! `BusId::HasherPermLinkInput`. +//! - **Permutation row 15** (`s_perm · (1 − periodic_sum)`, multiplicity `−m`) — output boundary of +//! the same cycle. Routed to `BusId::HasherPermLinkOutput`. +//! +//! The widest perm-link contribution is `f_ctrl_output` with gate degree 3 — strictly below +//! the ACE batch's `(7, 8)` — so merging into the same group leaves the column's transition +//! at `max(1 + 7, 8) = 8`. + +use core::{array, borrow::Borrow}; + +use miden_core::field::PrimeCharacteristicRing; + +use crate::{ + constraints::{ + chiplets::columns::PeriodicCols, + lookup::{ + chiplet_air::{ChipletBusContext, ChipletLookupBuilder}, + messages::{AceWireMsg, HasherPermLinkMsg}, + }, + utils::BoolNot, + }, + lookup::{Deg, LookupBatch, LookupColumn, LookupGroup}, +}; + +/// Upper bound on fractions this emitter pushes into its column per row. +/// +/// Single group hosts both buses. The chiplet tri-state makes ACE, hasher-controller, and +/// hasher-permutation rows pairwise mutually exclusive, so on any given row only one of: +/// - **ACE wiring batch** on ACE rows: 3 fractions (wire_0 / wire_1 / wire_2 push unconditionally +/// when the outer `ace_flag` fires). +/// - **Perm-link** on hasher controller rows: 1 fraction (one of ctrl_input / ctrl_output, split by +/// `s0`). +/// - **Perm-link** on hasher permutation rows: 1 fraction (one of row 0 / row 15, split by the +/// periodic cycle schedule). +/// +/// Per-row max is therefore `max(3, 1, 1) = 3`. +pub(in crate::constraints::lookup) const MAX_INTERACTIONS_PER_ROW: usize = 3; + +/// Emit the `v_wiring` shared column: ACE wiring + hasher perm-link. +pub(in crate::constraints::lookup) fn emit_v_wiring( + builder: &mut LB, + ctx: &ChipletBusContext, +) where + LB: ChipletLookupBuilder, +{ + let local = ctx.local; + + // ---- ACE wiring captures (Group 1) ---- + let ace_flag = ctx.chiplet_active.ace.clone(); + + // Typed ACE chiplet overlay. `read()` exposes `m_0` / `m_1`, `eval()` exposes `v_2`; + // wiring uses both overlays because its `sblock`-muxed multiplicities combine the + // READ and EVAL row interpretations onto one column. + let ace = local.ace(); + let ace_read = ace.read(); + let ace_eval = ace.eval(); + + // Prefixed with `ace_` where the shorter name would clash with the outer function + // parameter `ctx`. + let ace_clk = ace.clk; + let ace_ctx = ace.ctx; + let id_0 = ace.id_0; + let id_1 = ace.id_1; + let id_2 = ace_eval.id_2; + let v_0 = ace.v_0; + let v_1 = ace.v_1; + let v_2 = ace_eval.v_2; + let m_0 = ace_read.m_0; + let m_1 = ace_read.m_1; + + // `sblock` mixes into the wire_1 / wire_2 multiplicities; keep it as an `LB::Expr` + // since the `wire_1_mult` expression needs arithmetic against the already-converted + // `m_1`. + let sblock: LB::Expr = ace.s_block.into(); + + // ---- Perm-link captures (Group 2) ---- + + // Periodic Poseidon2 cycle selectors. `is_init_ext` is 1 on cycle row 0 only; the four + // selectors together cover rows 0..14, so `1 - sum` is 1 only on the cycle boundary + // row 15. The `permutation/mod.rs` cycle-alignment constraints pin perm row 0 to cycle + // row 0 and perm row 15 to cycle row 15. + let (perm_row0_select, perm_row15_select): (LB::Expr, LB::Expr) = { + let periodic: &PeriodicCols = builder.periodic_values().borrow(); + let h = periodic.hasher; + let is_init_ext: LB::Expr = h.is_init_ext.into(); + let is_ext: LB::Expr = h.is_ext.into(); + let is_packed_int: LB::Expr = h.is_packed_int.into(); + let is_int_ext: LB::Expr = h.is_int_ext.into(); + let not_cycle_end = is_init_ext.clone() + is_ext + is_packed_int + is_int_ext; + (is_init_ext, LB::Expr::ONE - not_cycle_end) + }; + + // Controller-side row-kind flags. `is_input = s0` (deg 1); `is_output = (1-s0)*(1-s1)` + // (deg 2). Padding rows (`s0=0, s1=1`) are excluded automatically by both expressions. + let ctrl = local.controller(); + let s0c: LB::Expr = ctrl.s0.into(); + let s1c: LB::Expr = ctrl.s1.into(); + let is_input = s0c.clone(); + let is_output = (LB::Expr::ONE - s0c) * (LB::Expr::ONE - s1c); + + let controller_flag = ctx.chiplet_active.controller.clone(); + let permutation_flag = ctx.chiplet_active.permutation.clone(); + + let f_ctrl_input = controller_flag.clone() * is_input; + let f_ctrl_output = controller_flag * is_output; + let f_perm_row0 = permutation_flag.clone() * perm_row0_select; + let f_perm_row15 = permutation_flag * perm_row15_select; + + let ctrl_state: [LB::Var; 12] = array::from_fn(|i| ctrl.state[i]); + let perm = local.permutation(); + let perm_state: [LB::Var; 12] = array::from_fn(|i| perm.state[i]); + let perm_mult = perm.multiplicity; + + builder.next_column( + |col| { + // Single group hosts both buses. ACE rows (`chiplet_active.ace`), controller rows + // (`chiplet_active.controller`), and permutation rows (`chiplet_active.permutation`) + // are pairwise mutually exclusive via the chiplet tri-state, so the simple-group + // composition is sound. Merging into one group takes MAX over per-interaction + // degrees instead of multiplying sibling `(V_g, U_g)` pairs — critical for keeping + // this column's transition inside the degree-9 budget. + col.group( + "ace_perm_link", + |g| { + // ---- ACE wiring (BusId::AceWiring) ---- + // + // Single `ace_flag`-gated batch with `sblock`-muxed multiplicities for wire_1 + // and wire_2. `wire_0`'s `m_0` is invariant across the READ/EVAL split, so it + // lives in the batch as a plain trace-column multiplicity. + g.batch( + "ace_wiring", + ace_flag, + move |b| { + let m_0: LB::Expr = m_0.into(); + let m_1: LB::Expr = m_1.into(); + let wire_1_mult = sblock.not() * m_1 - sblock.clone(); + let wire_2_mult = LB::Expr::ZERO - sblock; + + let wire_0 = AceWireMsg { + clk: ace_clk.into(), + ctx: ace_ctx.into(), + id: id_0.into(), + v0: v_0.0.into(), + v1: v_0.1.into(), + }; + b.insert("wire_0", m_0, wire_0, Deg { v: 5, u: 5 }); + + let wire_1 = AceWireMsg { + clk: ace_clk.into(), + ctx: ace_ctx.into(), + id: id_1.into(), + v0: v_1.0.into(), + v1: v_1.1.into(), + }; + b.insert("wire_1", wire_1_mult, wire_1, Deg { v: 6, u: 5 }); + + let wire_2 = AceWireMsg { + clk: ace_clk.into(), + ctx: ace_ctx.into(), + id: id_2.into(), + v0: v_2.0.into(), + v1: v_2.1.into(), + }; + b.insert("wire_2", wire_2_mult, wire_2, Deg { v: 5, u: 5 }); + }, + Deg { v: 8, u: 7 }, // (V, U) = (4 + 4, 3 + 4); ace_flag deg 4 + ); + + // ---- Hasher perm-link (BusId::HasherPermLink{Input,Output}) ---- + + // Controller input: +1 / encode(ctrl.state) on HasherPermLinkInput. + g.add( + "perm_ctrl_input", + f_ctrl_input, + move || { + let state: [LB::Expr; 12] = ctrl_state.map(Into::into); + HasherPermLinkMsg::Input { state } + }, + Deg { v: 2, u: 3 }, + ); + + // Controller output: +1 / encode(ctrl.state) on HasherPermLinkOutput. + g.add( + "perm_ctrl_output", + f_ctrl_output, + move || { + let state: [LB::Expr; 12] = ctrl_state.map(Into::into); + HasherPermLinkMsg::Output { state } + }, + Deg { v: 3, u: 4 }, + ); + + // Perm row 0: -m / encode(perm.state) on HasherPermLinkInput. Multiplicity is + // `0 - m` so the LogUp accumulator subtracts the fraction. + let perm_mult_input: LB::Expr = LB::Expr::ZERO - perm_mult.into(); + g.insert( + "perm_row0", + f_perm_row0, + perm_mult_input, + move || { + let state: [LB::Expr; 12] = perm_state.map(Into::into); + HasherPermLinkMsg::Input { state } + }, + Deg { v: 3, u: 3 }, + ); + + // Perm row 15: -m / encode(perm.state) on HasherPermLinkOutput. + let perm_mult_output: LB::Expr = LB::Expr::ZERO - perm_mult.into(); + g.insert( + "perm_row15", + f_perm_row15, + perm_mult_output, + move || { + let state: [LB::Expr; 12] = perm_state.map(Into::into); + HasherPermLinkMsg::Output { state } + }, + Deg { v: 3, u: 3 }, + ); + }, + Deg { v: 8, u: 7 }, + ); + }, + Deg { v: 8, u: 7 }, + ); +} diff --git a/air/src/constraints/lookup/chiplet_air.rs b/air/src/constraints/lookup/chiplet_air.rs new file mode 100644 index 0000000000..998df52320 --- /dev/null +++ b/air/src/constraints/lookup/chiplet_air.rs @@ -0,0 +1,149 @@ +//! Chiplet-trace LogUp lookup AIR. +//! +//! Owns the chiplet-trace side of the Miden VM's LogUp argument: three permutation +//! columns, one per `emit_*` function in [`super::buses`]. This module wires them together +//! via a single [`ChipletBusContext`] that carries the two-row window plus a shared +//! [`ChipletActiveFlags`] snapshot. +//! +//! Columns (in emission order): +//! - chiplet responses (memory / bitwise / hasher replies). +//! - hash-kernel virtual table. +//! - shared wiring column: ACE wiring + hasher perm-link. +//! +//! The [`ChipletLookupBuilder`] extension trait mirrors [`super::main_air::MainLookupBuilder`]: +//! it exposes a single construction hook so the prover path can eventually skip the dead +//! polynomial products in [`ChipletActiveFlags::from_main_cols`]. For now the default body +//! is the polynomial path and every adapter picks it up via an empty `impl` block. + +use core::borrow::Borrow; + +use miden_crypto::stark::air::WindowAccess; + +use super::{ + BusId, + buses::{ + ChipletActiveFlags, + chiplet_responses::{self, emit_chiplet_responses}, + hash_kernel::{self, emit_hash_kernel_table}, + wiring::{self, emit_v_wiring}, + }, +}; +use crate::{ + Felt, MainCols, + lookup::{LookupAir, LookupBuilder}, +}; + +// CHIPLET LOOKUP BUILDER +// ================================================================================================ + +/// Extension trait the chiplet-trace [`LookupAir`] requires from its [`LookupBuilder`]. +/// +/// Carries a single hook, [`build_chiplet_active`](Self::build_chiplet_active), for +/// constructing the shared [`ChipletActiveFlags`] snapshot consumed by the three +/// chiplet-trace bus emitters. Symmetric to [`super::main_air::MainLookupBuilder`]; see its +/// docs for the rationale behind the explicit-impl-no-blanket pattern. +pub(crate) trait ChipletLookupBuilder: LookupBuilder { + /// Build the shared [`ChipletActiveFlags`] snapshot for one `eval` call. + /// + /// Default body calls [`ChipletActiveFlags::from_main_cols`], matching the pre-split + /// behavior of `ChipletTraceContext::new`. Adapters override this when a cheaper + /// construction path is available (e.g. the prover path, where the selector columns + /// are concrete 0/1 and the active-flag subtractions can short-circuit). + fn build_chiplet_active(&self, local: &MainCols) -> ChipletActiveFlags { + ChipletActiveFlags::from_main_cols(local) + } +} + +// CHIPLET BUS CONTEXT +// ================================================================================================ + +/// Shared context for the three chiplet-trace bus emitters. +/// +/// Holds the two-row window plus a single [`ChipletActiveFlags`] snapshot built once per +/// `eval` through [`ChipletLookupBuilder::build_chiplet_active`]. Every emitter reads +/// `ctx.local`, `ctx.next`, and +/// `ctx.chiplet_active.{controller,permutation,bitwise,memory,ace,kernel_rom}` directly — +/// field access, no method indirection. +pub(crate) struct ChipletBusContext<'a, LB> +where + LB: LookupBuilder, +{ + /// Typed view of the current row. + pub local: &'a MainCols, + /// Typed view of the next row. + pub next: &'a MainCols, + /// Per-chiplet `is_active` flags, computed from `local`'s selector columns via the + /// builder-provided hook. + pub chiplet_active: ChipletActiveFlags, +} + +impl<'a, LB> ChipletBusContext<'a, LB> +where + LB: ChipletLookupBuilder, +{ + /// Build the shared chiplet-trace context for one `eval` call. + pub fn new(builder: &LB, local: &'a MainCols, next: &'a MainCols) -> Self { + let chiplet_active = builder.build_chiplet_active(local); + Self { local, next, chiplet_active } + } +} + +// CHIPLET LOOKUP AIR +// ================================================================================================ + +/// LogUp lookup argument over the chiplet trace. +/// +/// Zero-sized. Emits three permutation columns (see module docs for per-column contents), +/// matching the aggregated `LookupAir` impl on [`crate::ProcessorAir`]. The main-trace half +/// of the argument lives in [`super::main_air::MainLookupAir`]. +#[derive(Copy, Clone, Debug, Default)] +pub(crate) struct ChipletLookupAir; + +/// Per-column fraction stride, in emission order (see [`ChipletLookupAir`] docs). +pub(crate) const CHIPLET_COLUMN_SHAPE: [usize; 3] = [ + chiplet_responses::MAX_INTERACTIONS_PER_ROW, + hash_kernel::MAX_INTERACTIONS_PER_ROW, + wiring::MAX_INTERACTIONS_PER_ROW, +]; + +impl LookupAir for ChipletLookupAir +where + LB: ChipletLookupBuilder, +{ + fn num_columns(&self) -> usize { + CHIPLET_COLUMN_SHAPE.len() + } + + fn column_shape(&self) -> &[usize] { + &CHIPLET_COLUMN_SHAPE + } + + fn max_message_width(&self) -> usize { + // Must match `ProcessorAir::max_message_width` since this sub-AIR shares the + // aggregator's bus-prefix table. The widest chiplet-trace payload is + // `HasherMsg::State` on the responses column at 15 slots, but the aggregator's + // `MIDEN_MAX_MESSAGE_WIDTH = 16` is kept for MASM transcript alignment. + super::messages::MIDEN_MAX_MESSAGE_WIDTH + } + + fn num_bus_ids(&self) -> usize { + // Chiplet-trace emitters touch the shared chiplet responses column plus + // `BusId::{SiblingTable, RangeCheck, AceWiring, HasherPermLinkInput, + // HasherPermLinkOutput}`. The adapter's bus-prefix table is shared + // across every LookupAir it runs, so returning `BusId::COUNT` (the total bus-type + // count) is the safe upper bound. + BusId::COUNT + } + + fn eval(&self, builder: &mut LB) { + let main = builder.main(); + let local: &MainCols<_> = main.current_slice().borrow(); + let next: &MainCols<_> = main.next_slice().borrow(); + + let ctx = ChipletBusContext::new(&*builder, local, next); + + emit_chiplet_responses::(builder, &ctx); + emit_hash_kernel_table::(builder, &ctx); + emit_v_wiring::(builder, &ctx); + } +} diff --git a/air/src/constraints/lookup/extension_impls.rs b/air/src/constraints/lookup/extension_impls.rs new file mode 100644 index 0000000000..74f99dbe2a --- /dev/null +++ b/air/src/constraints/lookup/extension_impls.rs @@ -0,0 +1,87 @@ +//! Miden-side extension-trait impls pinning the generic +//! [`ConstraintLookupBuilder`] and [`ProverLookupBuilder`] adapters to the +//! Miden [`MainLookupBuilder`] / [`ChipletLookupBuilder`] traits. +//! +//! Both traits require `LookupBuilder`, so the impls live here +//! (Miden-side) rather than alongside the adapters — the generic adapter +//! code itself is field-polymorphic. +//! +//! The constraint-path adapter and the two debug builders pick up the default +//! polynomial bodies of [`MainLookupBuilder::build_op_flags`] and +//! [`ChipletLookupBuilder::build_chiplet_active`]. The prover-path adapter +//! overrides `build_op_flags` with +//! [`LookupOpFlags::from_boolean_row`](super::buses::LookupOpFlags::from_boolean_row), +//! which decodes the 7-bit opcode as a `u8` and flips exactly one flag per row +//! instead of materialising the polynomial products the symbolic path needs. +//! `build_chiplet_active` stays on the default — the chiplet selectors produce +//! only six outputs via four subtractions, so the boolean shortcut is noise. + +use miden_core::field::ExtensionField; +use miden_crypto::stark::air::LiftedAirBuilder; + +use super::{buses::LookupOpFlags, chiplet_air::ChipletLookupBuilder, main_air::MainLookupBuilder}; +use crate::{ + Felt, MainCols, + lookup::{ConstraintLookupBuilder, ProverLookupBuilder}, +}; + +// CONSTRAINT PATH +// ================================================================================================ + +impl<'ab, AB> MainLookupBuilder for ConstraintLookupBuilder<'ab, AB> where + AB: LiftedAirBuilder +{ +} + +impl<'ab, AB> ChipletLookupBuilder for ConstraintLookupBuilder<'ab, AB> where + AB: LiftedAirBuilder +{ +} + +// PROVER PATH +// ================================================================================================ + +impl<'a, EF> MainLookupBuilder for ProverLookupBuilder<'a, Felt, EF> +where + EF: ExtensionField, +{ + /// Override: use the boolean fast path instead of the default polynomial body. + /// + /// On the prover side `decoder.op_bits` are concrete 0/1 Felt values (enforced by the + /// decoder's boolean constraint), so a `u8` opcode decode + single-field write replaces + /// ~100 Felt multiplications in the shared prefix tree. Semantics match the default body + /// on any valid trace — a `debug_assertions` parity check inside `from_boolean_row` + /// surfaces divergences immediately. + fn build_op_flags( + &self, + local: &MainCols, + next: &MainCols, + ) -> LookupOpFlags { + LookupOpFlags::from_boolean_row(&local.decoder, &local.stack, &next.decoder) + } +} + +impl<'a, EF> ChipletLookupBuilder for ProverLookupBuilder<'a, Felt, EF> where + EF: ExtensionField +{ +} + +// DEBUG BUILDERS +// ================================================================================================ +// +// Empty impls for the Felt/QuadFelt-pinned debug builders. They pick up the default +// polynomial bodies of `build_op_flags` / `build_chiplet_active`; the builders only +// compile when the `debug` module is available (gated on `std`), so there's no need +// for a boolean fast-path override. + +#[cfg(feature = "std")] +mod debug_impls { + use super::{ChipletLookupBuilder, MainLookupBuilder}; + use crate::lookup::debug::{DebugTraceBuilder, ValidationBuilder}; + + impl<'ab, 'r> MainLookupBuilder for ValidationBuilder<'ab, 'r> {} + impl<'ab, 'r> ChipletLookupBuilder for ValidationBuilder<'ab, 'r> {} + + impl<'a> MainLookupBuilder for DebugTraceBuilder<'a> {} + impl<'a> ChipletLookupBuilder for DebugTraceBuilder<'a> {} +} diff --git a/air/src/constraints/lookup/main_air.rs b/air/src/constraints/lookup/main_air.rs new file mode 100644 index 0000000000..15d7106194 --- /dev/null +++ b/air/src/constraints/lookup/main_air.rs @@ -0,0 +1,168 @@ +//! Main-trace LogUp lookup AIR. +//! +//! Owns the main-trace side of the Miden VM's LogUp argument: four permutation columns, one +//! per `emit_*` function in [`super::buses`]. This module wires them together via a single +//! [`MainBusContext`] that carries the two-row window plus a shared [`OpFlags`] instance. +//! +//! Columns (in emission order): +//! - block-stack table + u32 range checks + log-precompile capacity + range-table response (merged +//! — see [`super::buses::block_stack_and_range_logcap`]). +//! - block-hash queue + op-group table. +//! - chiplet requests from the decoder. +//! - stack overflow table. +//! +//! The [`MainLookupBuilder`] extension trait exists so the `OpFlags` construction can diverge +//! between the constraint path (polynomial, today's default) and the prover path (boolean +//! fast path, planned). For now every adapter picks up the default polynomial body via an +//! empty `impl MainLookupBuilder for …` block — the structural split is the sole purpose of +//! this module today. + +use core::borrow::Borrow; + +use miden_crypto::stark::air::WindowAccess; + +use super::{ + BusId, + buses::{ + LookupOpFlags, + block_hash_and_op_group::{self, emit_block_hash_and_op_group}, + block_stack_and_range_logcap::{self, emit_block_stack_and_range_logcap}, + chiplet_requests::{self, emit_chiplet_requests}, + stack_overflow::{self, emit_stack_overflow}, + }, +}; +use crate::{ + Felt, MainCols, + lookup::{LookupAir, LookupBuilder}, +}; + +// MAIN LOOKUP BUILDER +// ================================================================================================ + +/// Extension trait the main-trace [`LookupAir`] requires from its [`LookupBuilder`]. +/// +/// Carries a single hook, [`build_op_flags`](Self::build_op_flags), for constructing the +/// shared [`LookupOpFlags`] instance that the four main-trace bus emitters consume. The +/// default body uses the polynomial path (today's behavior for both the constraint-path and +/// the prover-path adapters). A future prover-side optimization will override this method on +/// the prover adapter to skip the dead polynomial products that come from decoder bits +/// already being concrete 0/1 values; no other code moves. +/// +/// There is intentionally **no** blanket `impl MainLookupBuilder for LB` +/// — Rust coherence would then forbid the prover adapter from overriding the default body. +/// Each adapter implements this trait explicitly with an empty `impl` block that picks up +/// the default. +pub(crate) trait MainLookupBuilder: LookupBuilder { + /// Build the shared [`LookupOpFlags`] instance for one `eval` call. + /// + /// Default body calls [`LookupOpFlags::from_main_cols`], the polynomial path. Adapters + /// override this when a cheaper construction path is available (e.g. the prover path, + /// where decoder bits are concrete 0/1). + fn build_op_flags( + &self, + local: &MainCols, + next: &MainCols, + ) -> LookupOpFlags { + LookupOpFlags::from_main_cols(&local.decoder, &local.stack, &next.decoder) + } +} + +// MAIN BUS CONTEXT +// ================================================================================================ + +/// Shared context for the four main-trace bus emitters. +/// +/// Holds the two-row window plus a single [`LookupOpFlags`] instance built once per `eval` +/// through [`MainLookupBuilder::build_op_flags`]. Every emitter reads `ctx.local`, +/// `ctx.next`, and `ctx.op_flags.()` directly — no method indirection beyond the +/// single clone each accessor performs. +pub(crate) struct MainBusContext<'a, LB> +where + LB: LookupBuilder, +{ + /// Typed view of the current row. + pub local: &'a MainCols, + /// Typed view of the next row. + pub next: &'a MainCols, + /// Operation flags computed from `(local.decoder, local.stack, next.decoder)` via the + /// builder-provided hook. + pub op_flags: LookupOpFlags, +} + +impl<'a, LB> MainBusContext<'a, LB> +where + LB: MainLookupBuilder, +{ + /// Build the shared main-trace context for one `eval` call. + /// + /// Delegates the `LookupOpFlags` construction to the builder's + /// [`MainLookupBuilder::build_op_flags`] hook so the constraint-path and prover-path + /// adapters can diverge on construction cost without the emitters noticing. + pub fn new(builder: &LB, local: &'a MainCols, next: &'a MainCols) -> Self { + let op_flags = builder.build_op_flags(local, next); + Self { local, next, op_flags } + } +} + +// MAIN LOOKUP AIR +// ================================================================================================ + +/// LogUp lookup argument over the main trace. +/// +/// Zero-sized. Emits four permutation columns: the first packs block-stack + u32 range +/// checks + log-precompile capacity + range-table response; the second unions block-hash +/// queue and op-group table; the third hosts the decoder's chiplet requests; the fourth +/// hosts the stack overflow table. The chiplet-trace half of the argument lives in +/// [`super::chiplet_air::ChipletLookupAir`]. +#[derive(Copy, Clone, Debug, Default)] +pub(crate) struct MainLookupAir; + +/// Per-column fraction stride, in emission order (see [`MainLookupAir`] docs). +pub(crate) const MAIN_COLUMN_SHAPE: [usize; 4] = [ + block_stack_and_range_logcap::MAX_INTERACTIONS_PER_ROW, + block_hash_and_op_group::MAX_INTERACTIONS_PER_ROW, + chiplet_requests::MAX_INTERACTIONS_PER_ROW, + stack_overflow::MAX_INTERACTIONS_PER_ROW, +]; + +impl LookupAir for MainLookupAir +where + LB: MainLookupBuilder, +{ + fn num_columns(&self) -> usize { + MAIN_COLUMN_SHAPE.len() + } + + fn column_shape(&self) -> &[usize] { + &MAIN_COLUMN_SHAPE + } + + fn max_message_width(&self) -> usize { + // Must match `ProcessorAir::max_message_width` since this sub-AIR shares the + // aggregator's bus-prefix table. The widest main-trace payload is + // `HasherMsg::State` (linear_hash_init / return_state) at 15 slots, but the + // aggregator's `MIDEN_MAX_MESSAGE_WIDTH = 16` is kept for MASM transcript alignment. + super::messages::MIDEN_MAX_MESSAGE_WIDTH + } + + fn num_bus_ids(&self) -> usize { + // Main-trace emitters touch `BusId::{BlockStackTable, BlockHashTable, OpGroupTable, + // RangeCheck, LogPrecompileTranscript}` plus the shared chiplet-requests column. + // The adapter's bus-prefix table is shared across every LookupAir it runs, so + // returning `BusId::COUNT` (the total bus-type count) is the safe upper bound. + BusId::COUNT + } + + fn eval(&self, builder: &mut LB) { + let main = builder.main(); + let local: &MainCols<_> = main.current_slice().borrow(); + let next: &MainCols<_> = main.next_slice().borrow(); + + let ctx = MainBusContext::new(&*builder, local, next); + + emit_block_stack_and_range_logcap::(builder, &ctx); + emit_block_hash_and_op_group::(builder, &ctx); + emit_chiplet_requests::(builder, &ctx); + emit_stack_overflow::(builder, &ctx); + } +} diff --git a/air/src/constraints/lookup/messages.rs b/air/src/constraints/lookup/messages.rs new file mode 100644 index 0000000000..da4ff7e5c9 --- /dev/null +++ b/air/src/constraints/lookup/messages.rs @@ -0,0 +1,912 @@ +//! Message structs for LogUp bus interactions. +//! +//! Each struct represents a reduced denominator encoding: `α + Σ βⁱ · field_i`. +//! Fields are named for readability; the [`super::lookup::LookupMessage`] trait +//! (implemented further down in this file) provides the `encode` method that +//! produces the extension-field value. +//! +//! Chiplet messages are addressed by interaction-specific bus domains (one [`BusId`] +//! variant per semantic message kind). Constructors pick the interaction domain; payloads +//! start directly with the semantic fields (addr, ctx, etc.). +//! +//! All structs are generic over `E` (base-field expression type, typically `AB::Expr`). + +use miden_core::field::{Algebra, PrimeCharacteristicRing}; + +use crate::lookup::Challenges; + +// BUS IDENTIFIERS +// ================================================================================================ + +/// Width of the `beta_powers` table `Challenges` precomputes for Miden's bus +/// messages, i.e. the exponent of `gamma = beta^MIDEN_MAX_MESSAGE_WIDTH` used in +/// `bus_prefix[i] = alpha + (i + 1) * gamma`. +/// +/// Must match the Poseidon2 absorption loop in `crates/lib/core/asm/stark/` which +/// reads the same β-power table during recursive verification. +pub const MIDEN_MAX_MESSAGE_WIDTH: usize = 16; + +/// Domain-separated bus interaction identifier. +/// +/// Each variant identifies a distinct bus interaction type. When encoding a message, +/// the bus is cast to `usize` and indexes into +/// [`Challenges::bus_prefix`](crate::lookup::Challenges) to obtain the additive base +/// `bus_prefix[bus] = alpha + (bus + 1) * gamma`. +#[repr(usize)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum BusId { + // --- Out-of-circuit (boundary correction / reduced_aux_values) --- + /// Kernel ROM init: kernel procedure digests from variable-length public inputs. + KernelRomInit = 0, + /// Block hash table (decoder p2): root program hash boundary correction. + BlockHashTable = 1, + /// Log-precompile transcript: initial/final capacity state boundary correction. + LogPrecompileTranscript = 2, + + // --- In-circuit buses --- + KernelRomCall = 3, + HasherLinearHashInit = 4, + HasherReturnState = 5, + HasherAbsorption = 6, + HasherReturnHash = 7, + HasherMerkleVerifyInit = 8, + HasherMerkleOldInit = 9, + HasherMerkleNewInit = 10, + MemoryReadElement = 11, + MemoryWriteElement = 12, + MemoryReadWord = 13, + MemoryWriteWord = 14, + Bitwise = 15, + AceInit = 16, + /// Block stack table (decoder p1): tracks control flow block nesting. + BlockStackTable = 17, + /// Op group table (decoder p3): tracks operation batch consumption. + OpGroupTable = 18, + /// Stack overflow table. + StackOverflowTable = 19, + /// Sibling table: shares Merkle tree sibling nodes between old/new root computations. + SiblingTable = 20, + /// Range checker bus (LogUp). + RangeCheck = 21, + /// ACE wiring bus (LogUp). + AceWiring = 22, + /// Hasher perm-link input bus: pairs controller-input rows with perm-cycle row 0. + HasherPermLinkInput = 23, + /// Hasher perm-link output bus: pairs controller-output rows with perm-cycle row 15. + HasherPermLinkOutput = 24, +} + +impl BusId { + /// Last variant discriminant. Paired with the static assertion below, `COUNT` stays + /// in lockstep with the enum: adding a new variant with a higher discriminant bumps + /// `COUNT` automatically (and the assertion flags a missed update if the new variant's + /// discriminant isn't contiguous). + pub const COUNT: usize = Self::HasherPermLinkOutput as usize + 1; +} + +// Guard against an enum-update that skips a discriminant: any gap would inflate `COUNT` +// relative to the real variant count and silently resize the bus-prefix table. If this +// fires, either fill the gap or extend the check. +const _: () = assert!(BusId::HasherPermLinkOutput as usize == 24); + +// HASHER MESSAGES +// ================================================================================================ + +/// Hasher chiplet message: a [`BusId`] tag plus a variable-width payload. +/// +/// All hasher messages encode as `bus_prefix[kind] + [addr, node_index, ...payload]`; only +/// the payload width differs between variants. +#[derive(Clone, Debug)] +pub struct HasherMsg { + pub kind: BusId, + pub addr: E, + pub node_index: E, + pub payload: HasherPayload, +} + +/// Payload for a [`HasherMsg`]; width varies per interaction kind. +#[derive(Clone, Debug)] +pub enum HasherPayload { + /// 12-lane sponge state. + State([E; 12]), + /// 8-lane rate. + Rate([E; 8]), + /// 4-element word/digest. + Word([E; 4]), +} + +impl HasherMsg { + // --- State messages (14 payload elements: [addr, node_index, state[12]]) --- + + /// Linear hash / control block init: full 12-lane sponge state. + /// + /// Used by: HPERM input, LOGPRECOMPILE input. + pub fn linear_hash_init(addr: E, state: [E; 12]) -> Self { + Self { + kind: BusId::HasherLinearHashInit, + addr, + node_index: E::ZERO, + payload: HasherPayload::State(state), + } + } + + /// Control block init: 8 rate lanes + opcode at `capacity[1]`, zeros elsewhere. + /// + /// Used by: JOIN, SPLIT, LOOP, SPAN, CALL, SYSCALL, DYN, DYNCALL. + pub fn control_block(addr: E, rate: &[E; 8], opcode: u8) -> Self { + let state = [ + rate[0].clone(), + rate[1].clone(), + rate[2].clone(), + rate[3].clone(), + rate[4].clone(), + rate[5].clone(), + rate[6].clone(), + rate[7].clone(), + E::ZERO, + E::from_u16(opcode as u16), + E::ZERO, + E::ZERO, + ]; + Self { + kind: BusId::HasherLinearHashInit, + addr, + node_index: E::ZERO, + payload: HasherPayload::State(state), + } + } + + /// Return full sponge state after permutation. + /// + /// Used by: HPERM output, LOGPRECOMPILE output. + pub fn return_state(addr: E, state: [E; 12]) -> Self { + Self { + kind: BusId::HasherReturnState, + addr, + node_index: E::ZERO, + payload: HasherPayload::State(state), + } + } + + // --- Rate messages (10 payload elements: [addr, node_index, rate[8]]) --- + + /// Absorb new rate into running hash. + /// + /// Used by: RESPAN. + pub fn absorption(addr: E, rate: [E; 8]) -> Self { + Self { + kind: BusId::HasherAbsorption, + addr, + node_index: E::ZERO, + payload: HasherPayload::Rate(rate), + } + } + + // --- Word messages (6 payload elements: [addr, node_index, word[4]]) --- + + /// Return digest only (node_index = 0). + /// + /// Used by: END, MPVERIFY output, MRUPDATE output. + pub fn return_hash(addr: E, word: [E; 4]) -> Self { + Self { + kind: BusId::HasherReturnHash, + addr, + node_index: E::ZERO, + payload: HasherPayload::Word(word), + } + } + + /// Start Merkle path verification (with explicit node_index). + /// + /// Used by: MPVERIFY input. + pub fn merkle_verify_init(addr: E, node_index: E, word: [E; 4]) -> Self { + Self { + kind: BusId::HasherMerkleVerifyInit, + addr, + node_index, + payload: HasherPayload::Word(word), + } + } + + /// Start Merkle update, old path (with explicit node_index). + /// + /// Used by: MRUPDATE old input. + pub fn merkle_old_init(addr: E, node_index: E, word: [E; 4]) -> Self { + Self { + kind: BusId::HasherMerkleOldInit, + addr, + node_index, + payload: HasherPayload::Word(word), + } + } + + /// Start Merkle update, new path (with explicit node_index). + /// + /// Used by: MRUPDATE new input. + pub fn merkle_new_init(addr: E, node_index: E, word: [E; 4]) -> Self { + Self { + kind: BusId::HasherMerkleNewInit, + addr, + node_index, + payload: HasherPayload::Word(word), + } + } +} + +// MEMORY MESSAGES +// ================================================================================================ + +/// Memory chiplet message. Variants differ by payload size. +/// +/// Encodes as `bus_prefix[bus] + [ctx, addr, clk, ...payload]`. Use the [`MemoryMsg`] +/// associated functions (`read_element`, `write_element`, `read_word`, `write_word`) to +/// build messages with the correct interaction kind. +#[derive(Clone, Debug)] +pub enum MemoryMsg { + /// 5-element message: `[ctx, addr, clk, element]`. + Element { + bus: BusId, + ctx: E, + addr: E, + clk: E, + element: E, + }, + /// 8-element message: `[ctx, addr, clk, word[0..4]]`. + Word { + bus: BusId, + ctx: E, + addr: E, + clk: E, + word: [E; 4], + }, +} + +impl MemoryMsg { + /// Read a single element from memory. + pub fn read_element(ctx: E, addr: E, clk: E, element: E) -> Self { + Self::Element { + bus: BusId::MemoryReadElement, + ctx, + addr, + clk, + element, + } + } + + /// Write a single element to memory. + pub fn write_element(ctx: E, addr: E, clk: E, element: E) -> Self { + Self::Element { + bus: BusId::MemoryWriteElement, + ctx, + addr, + clk, + element, + } + } + + /// Read a 4-element word from memory. + pub fn read_word(ctx: E, addr: E, clk: E, word: [E; 4]) -> Self { + Self::Word { + bus: BusId::MemoryReadWord, + ctx, + addr, + clk, + word, + } + } + + /// Write a 4-element word to memory. + pub fn write_word(ctx: E, addr: E, clk: E, word: [E; 4]) -> Self { + Self::Word { + bus: BusId::MemoryWriteWord, + ctx, + addr, + clk, + word, + } + } +} + +// BITWISE MESSAGE +// ================================================================================================ + +/// Bitwise chiplet message (4 elements): `[op, a, b, result]`. +#[derive(Clone, Debug)] +pub struct BitwiseMsg { + pub op: E, + pub a: E, + pub b: E, + pub result: E, +} + +impl BitwiseMsg { + const AND_SELECTOR: u32 = 0; + const XOR_SELECTOR: u32 = 1; + + /// Bitwise AND message (op selector = 0). + pub fn and(a: E, b: E, result: E) -> Self { + Self { + op: E::from_u32(Self::AND_SELECTOR), + a, + b, + result, + } + } + + /// Bitwise XOR message (op selector = 1). + pub fn xor(a: E, b: E, result: E) -> Self { + Self { + op: E::from_u32(Self::XOR_SELECTOR), + a, + b, + result, + } + } +} + +// DECODER MESSAGES +// ================================================================================================ + +/// Block stack message: `[block_id, parent_id, is_loop, ctx, fmp, depth, fn_hash[4]]`. +/// +/// `Simple` — for blocks that don't save context (JOIN/SPLIT/SPAN/DYN/LOOP/RESPAN/END-simple). +/// Context fields are encoded as zeros. +/// +/// `Full` — for blocks that save/restore the caller's execution context +/// (CALL/SYSCALL/DYNCALL/END-call). +#[derive(Clone, Debug)] +pub enum BlockStackMsg { + Simple { + block_id: E, + parent_id: E, + is_loop: E, + }, + Full { + block_id: E, + parent_id: E, + is_loop: E, + ctx: E, + fmp: E, + depth: E, + fn_hash: [E; 4], + }, +} + +/// Block hash queue message (7 elements): +/// `[child_hash[4], parent, is_first_child, is_loop_body]`. +/// +/// `FirstChild` — first child of a JOIN (is_first_child = 1, is_loop_body = 0). +/// `Child` — non-first, non-loop child (is_first_child = 0, is_loop_body = 0). +/// `LoopBody` — loop body entry (is_first_child = 0, is_loop_body = 1). +/// `End` — removal at END; both flags are computed expressions. +#[derive(Clone, Debug)] +pub enum BlockHashMsg { + FirstChild { + parent: E, + child_hash: [E; 4], + }, + Child { + parent: E, + child_hash: [E; 4], + }, + LoopBody { + parent: E, + child_hash: [E; 4], + }, + End { + parent: E, + child_hash: [E; 4], + is_first_child: E, + is_loop_body: E, + }, +} + +/// Op group table message (3 elements): `[batch_id, group_pos, group_value]`. +#[derive(Clone, Debug)] +pub struct OpGroupMsg { + pub batch_id: E, + pub group_pos: E, + pub group_value: E, +} + +impl OpGroupMsg { + /// Create an op group message. Computes `group_pos = group_count - offset`. + pub fn new(batch_id: &E, group_count: V, offset: u16, group_value: E) -> Self + where + V: core::ops::Sub + Clone, + { + Self { + batch_id: batch_id.clone(), + group_pos: group_count - E::from_u16(offset), + group_value, + } + } +} + +// STACK MESSAGE +// ================================================================================================ + +/// Stack overflow table message (3 elements): `[clk, val, prev]`. +/// +/// `clk` is the cycle at which the value spilled past `stack[15]`, `val` is the spilled element, +/// and `prev` links to the previous overflow entry (the prior `b1`). +#[derive(Clone, Debug)] +pub struct StackOverflowMsg { + pub clk: E, + pub val: E, + pub prev: E, +} + +// HASHER PERM-LINK MESSAGE +// ================================================================================================ + +/// Hasher perm-link message (12 elements): `state[0..12]`. +/// +/// Binds hasher controller rows to permutation sub-chiplet rows. The `Input` variant pairs a +/// controller-input row with perm-cycle row 0 on `BusId::HasherPermLinkInput`; the `Output` +/// variant pairs a controller-output row with perm-cycle row 15 on +/// `BusId::HasherPermLinkOutput`. `state` carries all 12 sponge lanes (rate_0, rate_1, capacity). +#[derive(Clone, Debug)] +pub enum HasherPermLinkMsg { + Input { state: [E; 12] }, + Output { state: [E; 12] }, +} + +// KERNEL ROM MESSAGE +// ================================================================================================ + +/// Kernel ROM message (4 elements): `bus_prefix[bus] + [digest[4]]`. +/// +/// Two bus domains: INIT (one remove per declared procedure, balanced by the boundary +/// correction from public inputs) and CALL (one insert per SYSCALL, carrying the +/// multiplicity from kernel ROM column 0; balanced by decoder-emitted SYSCALL removes). +#[derive(Clone, Debug)] +pub struct KernelRomMsg { + bus: BusId, + pub digest: [E; 4], +} + +impl KernelRomMsg { + /// Kernel procedure call message (SYSCALL request side + chiplet CALL response). + pub fn call(digest: [E; 4]) -> Self { + Self { bus: BusId::KernelRomCall, digest } + } + + /// Kernel procedure init message (public-input boundary + chiplet INIT response). + pub fn init(digest: [E; 4]) -> Self { + Self { bus: BusId::KernelRomInit, digest } + } +} + +// ACE MESSAGE +// ================================================================================================ + +/// ACE circuit evaluation init message (5 elements): `[clk, ctx, ptr, num_read, num_eval]`. +#[derive(Clone, Debug)] +pub struct AceInitMsg { + pub clk: E, + pub ctx: E, + pub ptr: E, + pub num_read: E, + pub num_eval: E, +} + +// RANGE CHECK MESSAGE +// ================================================================================================ + +/// Range check message (1 element): `[value]`. +/// +/// The denominator is `α + β⁰ · value`. +#[derive(Clone, Debug)] +pub struct RangeMsg { + pub value: E, +} + +// LOG-PRECOMPILE CAPACITY MESSAGE +// ================================================================================================ + +/// Log-precompile capacity state message (4 elements): `cap[4]`. +#[derive(Clone, Debug)] +pub struct LogCapacityMsg { + pub capacity: [E; 4], +} + +// SIBLING TABLE MESSAGE +// ================================================================================================ + +// ACE WIRING MESSAGE +// ================================================================================================ + +/// ACE wiring bus message (5 elements): `[clk, ctx, id, v0, v1]`. +/// +/// Encodes a single wire entry for the ACE wiring bus. Each wire carries +/// an identifier and a two-coefficient extension-field value. +#[derive(Clone, Debug)] +pub struct AceWireMsg { + pub clk: E, + pub ctx: E, + pub id: E, + pub v0: E, + pub v1: E, +} + +// CHIPLET RESPONSE MESSAGES +// ================================================================================================ + +/// Memory chiplet response message with conditional element/word encoding. +/// +/// The chiplet-side memory response must select between element access (4 payload +/// elements: `[ctx, addr, clk, element]`) and word access (7 payload elements: +/// `[ctx, addr, clk, word[4]]`) based on `is_word`. The label, address, and element are +/// all pre-computed from the chiplet columns (including the idx0/idx1 element mux). +#[derive(Clone, Debug)] +pub struct MemoryResponseMsg { + pub is_read: E, + pub ctx: E, + pub addr: E, + pub clk: E, + pub is_word: E, + pub element: E, + pub word: [E; 4], +} + +// LOOKUP MESSAGE IMPLEMENTATIONS +// ================================================================================================ + +use crate::lookup::message::LookupMessage; + +// --- HasherMsg (interaction-specific bus ids) ---------------------------------------------------- + +impl LookupMessage for HasherMsg +where + E: PrimeCharacteristicRing + Clone, + EF: PrimeCharacteristicRing + Clone + Algebra, +{ + fn encode(&self, challenges: &Challenges) -> EF { + let mut acc = challenges.bus_prefix[self.kind as usize].clone(); + acc += challenges.inner_product_at(0, &[self.addr.clone(), self.node_index.clone()]); + let payload = match &self.payload { + HasherPayload::State(state) => state.as_slice(), + HasherPayload::Rate(rate) => rate.as_slice(), + HasherPayload::Word(word) => word.as_slice(), + }; + acc += challenges.inner_product_at(2, payload); + acc + } +} + +// --- MemoryMsg (interaction-specific bus ids) ---------------------------------------------------- + +impl LookupMessage for MemoryMsg +where + E: PrimeCharacteristicRing + Clone, + EF: PrimeCharacteristicRing + Clone + Algebra, +{ + fn encode(&self, challenges: &Challenges) -> EF { + let bus = match self { + Self::Element { bus, .. } | Self::Word { bus, .. } => *bus as usize, + }; + let mut acc = challenges.bus_prefix[bus].clone(); + match self { + Self::Element { ctx, addr, clk, element, .. } => { + acc += challenges.inner_product_at( + 0, + &[ctx.clone(), addr.clone(), clk.clone(), element.clone()], + ); + }, + Self::Word { ctx, addr, clk, word, .. } => { + acc += challenges.inner_product_at(0, &[ctx.clone(), addr.clone(), clk.clone()]); + acc += challenges.inner_product_at(3, word.as_slice()); + }, + } + acc + } +} + +// --- BitwiseMsg ---------------------------------------------------------------------------------- + +impl LookupMessage for BitwiseMsg +where + E: PrimeCharacteristicRing + Clone, + EF: PrimeCharacteristicRing + Clone + Algebra, +{ + fn encode(&self, challenges: &Challenges) -> EF { + challenges.encode( + BusId::Bitwise as usize, + [self.op.clone(), self.a.clone(), self.b.clone(), self.result.clone()], + ) + } +} + +// --- BlockStackMsg ------------------------------------------------------------------------------- + +impl LookupMessage for BlockStackMsg +where + E: PrimeCharacteristicRing + Clone, + EF: PrimeCharacteristicRing + Clone + Algebra, +{ + fn encode(&self, challenges: &Challenges) -> EF { + let mut acc = challenges.bus_prefix[BusId::BlockStackTable as usize].clone(); + match self { + // `Simple` zero-pads to 10 slots; slots `3..10` contribute `β^k · 0 = 0` so + // they are elided from the loop. + Self::Simple { block_id, parent_id, is_loop } => { + acc += challenges + .inner_product_at(0, &[block_id.clone(), parent_id.clone(), is_loop.clone()]); + }, + Self::Full { + block_id, + parent_id, + is_loop, + ctx, + fmp, + depth, + fn_hash, + } => { + acc += challenges.inner_product_at( + 0, + &[ + block_id.clone(), + parent_id.clone(), + is_loop.clone(), + ctx.clone(), + fmp.clone(), + depth.clone(), + ], + ); + acc += challenges.inner_product_at(6, fn_hash.as_slice()); + }, + } + acc + } +} + +// --- BlockHashMsg -------------------------------------------------------------------------------- + +impl LookupMessage for BlockHashMsg +where + E: PrimeCharacteristicRing + Clone, + EF: PrimeCharacteristicRing + Clone + Algebra, +{ + fn encode(&self, challenges: &Challenges) -> EF { + // Per-variant fan-in: produce the (parent, child_hash, is_first_child, is_loop_body) + // tuple, then emit a flat 7-slot payload laid out as + // `[child_hash[4], parent, is_first_child, is_loop_body]`. + let (parent, child_hash, is_first_child, is_loop_body) = match self { + Self::FirstChild { parent, child_hash } => (parent, child_hash, E::ONE, E::ZERO), + Self::Child { parent, child_hash } => (parent, child_hash, E::ZERO, E::ZERO), + Self::LoopBody { parent, child_hash } => (parent, child_hash, E::ZERO, E::ONE), + Self::End { + parent, + child_hash, + is_first_child, + is_loop_body, + } => (parent, child_hash, is_first_child.clone(), is_loop_body.clone()), + }; + challenges.encode( + BusId::BlockHashTable as usize, + [ + child_hash[0].clone(), + child_hash[1].clone(), + child_hash[2].clone(), + child_hash[3].clone(), + parent.clone(), + is_first_child, + is_loop_body, + ], + ) + } +} + +// --- OpGroupMsg ---------------------------------------------------------------------------------- + +impl LookupMessage for OpGroupMsg +where + E: PrimeCharacteristicRing + Clone, + EF: PrimeCharacteristicRing + Clone + Algebra, +{ + fn encode(&self, challenges: &Challenges) -> EF { + challenges.encode( + BusId::OpGroupTable as usize, + [self.batch_id.clone(), self.group_pos.clone(), self.group_value.clone()], + ) + } +} + +// --- StackOverflowMsg ---------------------------------------------------------------------------- + +impl LookupMessage for StackOverflowMsg +where + E: PrimeCharacteristicRing + Clone, + EF: PrimeCharacteristicRing + Clone + Algebra, +{ + fn encode(&self, challenges: &Challenges) -> EF { + challenges.encode( + BusId::StackOverflowTable as usize, + [self.clk.clone(), self.val.clone(), self.prev.clone()], + ) + } +} + +// --- KernelRomMsg -------------------------------------------------------------------------------- + +impl LookupMessage for KernelRomMsg +where + E: PrimeCharacteristicRing + Clone, + EF: PrimeCharacteristicRing + Clone + Algebra, +{ + fn encode(&self, challenges: &Challenges) -> EF { + challenges.encode(self.bus as usize, self.digest.clone()) + } +} + +// --- AceInitMsg ---------------------------------------------------------------------------------- + +impl LookupMessage for AceInitMsg +where + E: PrimeCharacteristicRing + Clone, + EF: PrimeCharacteristicRing + Clone + Algebra, +{ + fn encode(&self, challenges: &Challenges) -> EF { + challenges.encode( + BusId::AceInit as usize, + [ + self.clk.clone(), + self.ctx.clone(), + self.ptr.clone(), + self.num_read.clone(), + self.num_eval.clone(), + ], + ) + } +} + +// --- RangeMsg ------------------------------------------------------------------------------------ + +impl LookupMessage for RangeMsg +where + E: PrimeCharacteristicRing + Clone, + EF: PrimeCharacteristicRing + Clone + Algebra, +{ + fn encode(&self, challenges: &Challenges) -> EF { + challenges.encode(BusId::RangeCheck as usize, [self.value.clone()]) + } +} + +// --- LogCapacityMsg ------------------------------------------------------------------------------ + +impl LookupMessage for LogCapacityMsg +where + E: PrimeCharacteristicRing + Clone, + EF: PrimeCharacteristicRing + Clone + Algebra, +{ + fn encode(&self, challenges: &Challenges) -> EF { + challenges.encode(BusId::LogPrecompileTranscript as usize, self.capacity.clone()) + } +} + +// --- HasherPermLinkMsg --------------------------------------------------------------------------- + +impl LookupMessage for HasherPermLinkMsg +where + E: PrimeCharacteristicRing + Clone, + EF: PrimeCharacteristicRing + Clone + Algebra, +{ + fn encode(&self, challenges: &Challenges) -> EF { + let (bus, state) = match self { + Self::Input { state } => (BusId::HasherPermLinkInput, state), + Self::Output { state } => (BusId::HasherPermLinkOutput, state), + }; + challenges.encode(bus as usize, state.clone()) + } +} + +// --- AceWireMsg ---------------------------------------------------------------------------------- + +impl LookupMessage for AceWireMsg +where + E: PrimeCharacteristicRing + Clone, + EF: PrimeCharacteristicRing + Clone + Algebra, +{ + fn encode(&self, challenges: &Challenges) -> EF { + challenges.encode( + BusId::AceWiring as usize, + [ + self.clk.clone(), + self.ctx.clone(), + self.id.clone(), + self.v0.clone(), + self.v1.clone(), + ], + ) + } +} + +// LookupMessage impls for the response + sibling structs +// ================================================================================================ +// +// The `*ResponseMsg` structs below carry `LookupMessage` impls consumed by +// `lookup/buses/chiplet_responses.rs`. The runtime-muxed encoding (bus prefix muxed +// by `is_read`/`is_word` flags) keeps the response-column transition at degree 8. + +impl LookupMessage for MemoryResponseMsg +where + E: PrimeCharacteristicRing + Clone, + EF: PrimeCharacteristicRing + Clone + Algebra, +{ + fn encode(&self, challenges: &Challenges) -> EF { + let bp = &challenges.beta_powers; + let is_read = self.is_read.clone(); + let is_write: E = E::ONE - is_read.clone(); + let is_word = self.is_word.clone(); + let is_element: E = E::ONE - is_word.clone(); + + // Mux only the bus prefix; the payload (ctx, addr, clk, ...) is shared. Factored + // as a read/write select per access width so the four (read/write × element/word) + // cases stay audit-visible without blowing the polynomial degree. + let prefix_element = challenges.bus_prefix[BusId::MemoryReadElement as usize].clone() + * is_read.clone() + + challenges.bus_prefix[BusId::MemoryWriteElement as usize].clone() * is_write.clone(); + let prefix_word = challenges.bus_prefix[BusId::MemoryReadWord as usize].clone() * is_read + + challenges.bus_prefix[BusId::MemoryWriteWord as usize].clone() * is_write; + let prefix = prefix_element * is_element.clone() + prefix_word * is_word.clone(); + + let mut acc = prefix; + acc += bp[0].clone() * self.ctx.clone(); + acc += bp[1].clone() * self.addr.clone(); + acc += bp[2].clone() * self.clk.clone(); + + // Element payload (gated by is_element) vs word payload (gated by is_word). + acc += bp[3].clone() * self.element.clone() * is_element; + acc += challenges.inner_product_at(3, self.word.as_slice()) * is_word; + acc + } +} + +// SIBLING MESSAGES +// ================================================================================================ +// +// [`SiblingMsg`] carries the relevant hasher half alongside a [`SiblingBit`] tag and +// encodes against sparse β layouts (`[2, 7, 8, 9, 10]` and `[2, 3, 4, 5, 6]`) dictated by +// the responder-side hasher chiplet algebra. The trait is permissive about which β +// positions an `encode` body touches; contiguity is a convention, not a requirement. + +/// Sibling-table message for the Merkle sibling bus. +/// +/// The Merkle direction bit picks which half of the hasher rate block holds the sibling: +/// `bit = 0` → sibling at `h[4..8]`, payload lands in β positions `[1, 2, 7, 8, 9, 10]` +/// (mrupdate_id at β¹, node_index at β², rate1 at β⁷..β¹⁰); `bit = 1` → sibling at +/// `h[0..4]`, payload lands in β positions `[1, 2, 3, 4, 5, 6]`. +#[derive(Clone, Debug)] +pub struct SiblingMsg { + pub bit: SiblingBit, + pub mrupdate_id: E, + pub node_index: E, + pub h: [E; 4], +} + +/// Which half of the hasher rate block holds the sibling word for this row. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum SiblingBit { + /// `bit = 0` — sibling lives in the high rate half (`h[4..8]`). + Zero, + /// `bit = 1` — sibling lives in the low rate half (`h[0..4]`). + One, +} + +impl LookupMessage for SiblingMsg +where + E: PrimeCharacteristicRing + Clone, + EF: PrimeCharacteristicRing + Clone + Algebra, +{ + fn encode(&self, challenges: &Challenges) -> EF { + let mut acc = challenges.bus_prefix[BusId::SiblingTable as usize].clone(); + acc += challenges.inner_product_at(1, &[self.mrupdate_id.clone(), self.node_index.clone()]); + let base = match self.bit { + SiblingBit::Zero => 7, + SiblingBit::One => 3, + }; + acc += challenges.inner_product_at(base, self.h.as_slice()); + acc + } +} diff --git a/air/src/constraints/lookup/miden_air.rs b/air/src/constraints/lookup/miden_air.rs new file mode 100644 index 0000000000..5b6327f151 --- /dev/null +++ b/air/src/constraints/lookup/miden_air.rs @@ -0,0 +1,170 @@ +//! Miden-specific LogUp pieces consumed by `ProcessorAir`'s trait impls: the combined +//! 7-column fraction stride, the committed-finals count, and the +//! [`emit_miden_boundary`] helper. +//! +//! The `LookupAir` and `AuxBuilder` trait impls themselves live on [`crate::ProcessorAir`] +//! in `air/src/lib.rs`; this module just supplies the constants and the boundary emitter +//! they share. + +use alloc::vec::Vec; + +use miden_core::{WORD_SIZE, field::PrimeCharacteristicRing}; + +use super::{ + chiplet_air::CHIPLET_COLUMN_SHAPE, + main_air::MAIN_COLUMN_SHAPE, + messages::{BlockHashMsg, KernelRomMsg, LogCapacityMsg}, +}; +use crate::{PV_PROGRAM_HASH, PV_TRANSCRIPT_STATE, lookup::BoundaryBuilder}; + +// COLUMN SHAPE AND COMMITTED-FINALS COUNT +// ================================================================================================ + +/// Full 7-column fraction stride: 4 main + 3 chiplet, in `ProcessorAir::eval` order (main +/// columns first, then chiplet columns — see the per-half docs in +/// [`super::main_air::MainLookupAir`] and [`super::chiplet_air::ChipletLookupAir`]). +pub(crate) const MIDEN_COLUMN_SHAPE: [usize; 7] = [ + MAIN_COLUMN_SHAPE[0], + MAIN_COLUMN_SHAPE[1], + MAIN_COLUMN_SHAPE[2], + MAIN_COLUMN_SHAPE[3], + CHIPLET_COLUMN_SHAPE[0], + CHIPLET_COLUMN_SHAPE[1], + CHIPLET_COLUMN_SHAPE[2], +]; + +/// Number of committed final aux values published with a proof. +/// +/// Only col 0 is a real committed final; slot 1 is a placeholder forced to zero, kept for +/// forward-compatibility with the MASM recursive verifier (which absorbs 2 boundary +/// values). All paths that emit or consume the pair must preserve the zero in slot 1. +/// +/// TODO(#3032): reduce to 1 once trace splitting lands and each sub-trace has its own +/// accumulator. +pub const NUM_LOGUP_COMMITTED_FINALS: usize = 2; + +// BOUNDARY EMITTER +// ================================================================================================ + +/// Emits the three Miden-AIR boundary correction terms (`c_block_hash`, +/// `c_log_precompile`, `c_kernel_rom`) into any [`BoundaryBuilder`]. +/// +/// Single source of truth shared between: +/// - [`crate::ProcessorAir`]'s `LookupAir::eval_boundary` (consumed by the debug walker), and +/// - [`crate::ProcessorAir::reduced_aux_values`] (verifier scalar check; drives the emissions +/// through a reducer that sums `Σ multiplicity / encode(msg)`). +/// +/// See `program_hash_message`, `transcript_messages`, and `kernel_proc_message` in +/// `air/src/lib.rs` for the canonical formulas this mirrors. +pub(crate) fn emit_miden_boundary(boundary: &mut B) { + let pv = boundary.public_values(); + let program_hash: [B::F; 4] = [ + pv[PV_PROGRAM_HASH], + pv[PV_PROGRAM_HASH + 1], + pv[PV_PROGRAM_HASH + 2], + pv[PV_PROGRAM_HASH + 3], + ]; + let final_state: [B::F; 4] = [ + pv[PV_TRANSCRIPT_STATE], + pv[PV_TRANSCRIPT_STATE + 1], + pv[PV_TRANSCRIPT_STATE + 2], + pv[PV_TRANSCRIPT_STATE + 3], + ]; + let kernel_digests: Vec<[B::F; 4]> = boundary + .var_len_public_inputs() + .first() + .map(|felts| felts.chunks_exact(WORD_SIZE).map(|d| [d[0], d[1], d[2], d[3]]).collect()) + .unwrap_or_default(); + + // Block-hash seed: +1 / encode(BLOCK_HASH_TABLE, [ph, 0, 0, 0]). + boundary.add( + "block_hash_seed", + BlockHashMsg::Child { + parent: B::F::ZERO, + child_hash: program_hash, + }, + ); + + // Log-precompile transcript terminals: +1 / d_initial − 1 / d_final. + boundary.add("log_precompile_initial", LogCapacityMsg { capacity: [B::F::ZERO; 4] }); + boundary.remove("log_precompile_final", LogCapacityMsg { capacity: final_state }); + + // Kernel ROM init: +Σ 1 / d_kernel_proc_msg_i over VLPI[0]. + for digest in kernel_digests { + boundary.add("kernel_rom_init", KernelRomMsg::init(digest)); + } +} + +// TESTS +// ================================================================================================ + +#[cfg(all(test, feature = "std"))] +mod tests { + extern crate std; + + use std::{vec, vec::Vec}; + + use miden_core::{ + field::{PrimeCharacteristicRing, QuadFelt}, + utils::RowMajorMatrix, + }; + use miden_crypto::stark::air::LiftedAir; + + use super::NUM_LOGUP_COMMITTED_FINALS; + use crate::{ + Felt, NUM_PUBLIC_VALUES, ProcessorAir, + constraints::lookup::{BusId, MIDEN_MAX_MESSAGE_WIDTH}, + lookup::{ + Challenges, + debug::{ValidateLayout, ValidateLookupAir, check_trace_balance}, + }, + trace::{AUX_TRACE_RAND_CHALLENGES, AUX_TRACE_WIDTH, TRACE_WIDTH}, + }; + + fn num_periodic() -> usize { + LiftedAir::::periodic_columns(&ProcessorAir).len() + } + + fn validate_layout() -> ValidateLayout { + ValidateLayout { + trace_width: TRACE_WIDTH, + num_public_values: NUM_PUBLIC_VALUES, + num_periodic_columns: num_periodic(), + permutation_width: AUX_TRACE_WIDTH, + num_permutation_challenges: AUX_TRACE_RAND_CHALLENGES, + num_permutation_values: NUM_LOGUP_COMMITTED_FINALS, + } + } + + /// One self-check that covers num_columns consistency, per-group / per-column + /// declared-vs-observed degree, cached-encoding canonical/encoded equivalence, + /// and simple-group scope (no `insert_encoded` outside cached-encoding groups). + #[test] + fn processor_air_lookup_validates() { + ValidateLookupAir::validate(&ProcessorAir, validate_layout()) + .unwrap_or_else(|err| panic!("ProcessorAir LookupAir validation failed: {err}")); + } + + /// Smoke test: the trace-balance checker runs to completion on a tiny zero-valued trace + /// against `ProcessorAir` without panicking. A zero-valued trace is not a valid program + /// execution so the report is expected to contain unmatched entries; this test only + /// asserts that the checker produces a report (instead of crashing). + #[test] + fn trace_balance_runs_on_zero_trace() { + const NUM_ROWS: usize = 4; + let data = vec![Felt::ZERO; TRACE_WIDTH * NUM_ROWS]; + let main_trace = RowMajorMatrix::new(data, TRACE_WIDTH); + let periodic: Vec> = + (0..num_periodic()).map(|_| vec![Felt::ZERO; NUM_ROWS]).collect(); + let publics: Vec = vec![Felt::ZERO; NUM_PUBLIC_VALUES]; + let challenges = Challenges::::new( + QuadFelt::ONE, + QuadFelt::ONE, + MIDEN_MAX_MESSAGE_WIDTH, + BusId::COUNT, + ); + + let _ = + check_trace_balance(&ProcessorAir, &main_trace, &periodic, &publics, &[], &challenges); + } +} diff --git a/air/src/constraints/lookup/mod.rs b/air/src/constraints/lookup/mod.rs new file mode 100644 index 0000000000..3f21328ae3 --- /dev/null +++ b/air/src/constraints/lookup/mod.rs @@ -0,0 +1,25 @@ +//! Miden-side wiring for the LogUp lookup-argument module. +//! +//! Holds the Miden-specific pieces: the [`MainLookupAir`](main_air::MainLookupAir) and +//! [`ChipletLookupAir`](chiplet_air::ChipletLookupAir) sub-AIRs, the seven bus emitters +//! (plus the [`lookup_op_flags`](buses::lookup_op_flags) helper) in [`buses`], the +//! shared [`emit_miden_boundary`](miden_air::emit_miden_boundary) function, the +//! [`MIDEN_COLUMN_SHAPE`](miden_air::MIDEN_COLUMN_SHAPE) and +//! [`NUM_LOGUP_COMMITTED_FINALS`](miden_air::NUM_LOGUP_COMMITTED_FINALS) constants, and the +//! Miden-side extension-trait impls pinning the generic +//! [`ConstraintLookupBuilder`](crate::lookup::ConstraintLookupBuilder) / +//! [`ProverLookupBuilder`](crate::lookup::ProverLookupBuilder) adapters to the Miden +//! `LookupBuilder` trait. +//! +//! The `LookupAir` and `AuxBuilder` trait impls themselves live on +//! [`crate::ProcessorAir`]; the field-polymorphic core (traits, adapters, accumulators, +//! debug walkers) lives in [`crate::lookup`]. + +pub(crate) mod buses; +pub mod chiplet_air; +mod extension_impls; +pub mod main_air; +pub mod messages; +pub mod miden_air; + +pub use messages::{BusId, MIDEN_MAX_MESSAGE_WIDTH}; diff --git a/air/src/constraints/mod.rs b/air/src/constraints/mod.rs index 5e34cd4327..1b5d40dd6a 100644 --- a/air/src/constraints/mod.rs +++ b/air/src/constraints/mod.rs @@ -1,41 +1,31 @@ -// `AB::Var: Copy` but clippy flags `.clone()` on it -#![allow(clippy::clone_on_copy)] - //! Miden VM Constraints //! //! This module contains the constraint functions for the Miden VM processor. //! //! ## Organization //! -//! Constraints are separated into two categories: -//! -//! ### Main Trace Constraints -//! - system: clock, ctx, fn_hash transitions -//! - range: range checker V column transitions -//! - stack: general stack constraints -//! -//! ### Bus Constraints (Auxiliary Trace) -//! - range::bus -//! -//! Bus constraints access the auxiliary trace via `builder.permutation()` and use -//! random challenges from `builder.permutation_randomness()` for multiset/LogUp verification. -//! -//! Additional components (decoder, chiplets) are introduced in later constraint chunks. +//! - **Main trace constraints** are evaluated by [`enforce_main`] and cover system / range / stack +//! / decoder / chiplets transitions. +//! - **LogUp lookup-argument constraints** are evaluated separately through the closure-based +//! `LookupAir` impl on [`crate::ProcessorAir`], wired in from `ProcessorAir::eval` via +//! [`crate::lookup::ConstraintLookupBuilder`]. -use miden_crypto::stark::air::{ExtensionBuilder, LiftedAirBuilder, WindowAccess}; +use chiplets::selectors::ChipletSelectors; -use crate::{Felt, MainTraceRow, trace::Challenges}; +use crate::{MainCols, MidenAirBuilder}; -pub mod bus; pub mod chiplets; +pub mod columns; +pub mod constants; pub mod decoder; pub mod ext_field; -mod op_flags; +pub mod lookup; +pub(crate) mod op_flags; pub mod public_inputs; pub mod range; pub mod stack; pub mod system; -pub mod tagging; +pub mod utils; // ENTRY POINTS // ================================================================================================ @@ -43,128 +33,16 @@ pub mod tagging; /// Enforces all main trace constraints. pub fn enforce_main( builder: &mut AB, - local: &MainTraceRow, - next: &MainTraceRow, + local: &MainCols, + next: &MainCols, + selectors: &ChipletSelectors, + op_flags: &op_flags::OpFlags, ) where - AB: LiftedAirBuilder, + AB: MidenAirBuilder, { - system::enforce_main(builder, local, next); + system::enforce_main(builder, local, next, op_flags); range::enforce_main(builder, local, next); - - let op_flags = op_flags::OpFlags::new(op_flags::ExprDecoderAccess::<_, AB::Expr>::new(local)); - stack::enforce_main(builder, local, next, &op_flags); - decoder::enforce_main(builder, local, next, &op_flags); - chiplets::enforce_main(builder, local, next); -} - -/// Enforces all auxiliary (bus) constraints: boundary + transition. -/// -/// Bus soundness relies on three mechanisms: -/// 1. **Boundary** -- aux columns start at identity (1 or 0) -/// 2. **Transition** -- row-to-row update rules determine all subsequent values -/// 3. **`reduced_aux_values`** -- final values satisfy bus identities -pub fn enforce_bus( - builder: &mut AB, - local: &MainTraceRow, - next: &MainTraceRow, -) where - AB: LiftedAirBuilder, -{ - let r = builder.permutation_randomness(); - let challenges = Challenges::::new(r[0].into(), r[1].into()); - let op_flags = op_flags::OpFlags::new(op_flags::ExprDecoderAccess::<_, AB::Expr>::new(local)); - - enforce_bus_boundary(builder); - - range::bus::enforce_bus(builder, local); - stack::bus::enforce_bus(builder, local, next, &op_flags, &challenges); - decoder::bus::enforce_bus(builder, local, next, &op_flags, &challenges); - chiplets::bus::enforce_bus(builder, local, next, &op_flags, &challenges); -} - -/// Enforces boundary constraints on all auxiliary columns. -/// -/// **First row:** running-product columns start at 1, LogUp sums start at 0. -/// -/// **Last row:** each aux column must equal its committed final value (from -/// `permutation_values`). This binds the aux trace polynomial to the values checked -/// by `reduced_aux_values`, preventing a malicious prover from committing arbitrary -/// finals that satisfy the bus identity without matching the actual trace. -fn enforce_bus_boundary(builder: &mut AB) -where - AB: LiftedAirBuilder, -{ - // First row: running products = 1, LogUp sums = 0. - enforce_bus_first_row(builder); - - // Last row: bind aux trace to committed finals checked by `reduced_aux_values`. - enforce_bus_last_row(builder); -} - -fn enforce_bus_first_row(builder: &mut AB) -where - AB: LiftedAirBuilder, -{ - use bus::indices::*; - use tagging::{TaggingAirBuilderExt, ids::TAG_BUS_BOUNDARY_BASE}; - - const N: usize = 8; - let ids: [usize; N] = core::array::from_fn(|i| TAG_BUS_BOUNDARY_BASE + i); - - let aux = builder.permutation(); - let aux_local = aux.current_slice(); - - let p1 = aux_local[P1_BLOCK_STACK]; - let p2 = aux_local[P2_BLOCK_HASH]; - let p3 = aux_local[P3_OP_GROUP]; - let s_aux = aux_local[P1_STACK]; - let b_hk = aux_local[B_HASH_KERNEL]; - let b_ch = aux_local[B_CHIPLETS]; - let b_rng = aux_local[B_RANGE]; - let v_wir = aux_local[V_WIRING]; - - builder.tagged_list(ids, "bus.boundary.first_row", |builder| { - let mut first = builder.when_first_row(); - first.assert_one_ext(p1); - first.assert_one_ext(p2); - first.assert_one_ext(p3); - first.assert_one_ext(s_aux); - first.assert_one_ext(b_hk); - first.assert_one_ext(b_ch); - first.assert_zero_ext(b_rng); - first.assert_zero_ext(v_wir); - }); -} - -fn enforce_bus_last_row(builder: &mut AB) -where - AB: LiftedAirBuilder, -{ - use tagging::{ - TaggingAirBuilderExt, - ids::{TAG_BUS_BOUNDARY_BASE, TAG_BUS_BOUNDARY_FIRST_ROW_COUNT}, - }; - - use crate::trace::AUX_TRACE_WIDTH; - - const N: usize = AUX_TRACE_WIDTH; - let ids: [usize; N] = - core::array::from_fn(|i| TAG_BUS_BOUNDARY_BASE + TAG_BUS_BOUNDARY_FIRST_ROW_COUNT + i); - - let cols: [AB::VarEF; N] = { - let aux = builder.permutation(); - let s = aux.current_slice(); - core::array::from_fn(|i| s[i]) - }; - let finals: [AB::ExprEF; N] = { - let f = builder.permutation_values(); - core::array::from_fn(|i| f[i].clone().into()) - }; - - builder.tagged_list(ids, "bus.boundary.last_row", |builder| { - let mut last = builder.when_last_row(); - for (col, expected) in cols.into_iter().zip(finals) { - last.assert_eq_ext(col, expected); - } - }); + stack::enforce_main(builder, local, next, op_flags); + decoder::enforce_main(builder, local, next, op_flags); + chiplets::enforce_main(builder, local, next, selectors); } diff --git a/air/src/constraints/op_flags/mod.rs b/air/src/constraints/op_flags/mod.rs index 27757b6d04..5a4a494864 100644 --- a/air/src/constraints/op_flags/mod.rs +++ b/air/src/constraints/op_flags/mod.rs @@ -4,13 +4,18 @@ //! throughout stack constraints to gate constraint enforcement based on which operation //! is currently being executed. //! -//! ## Operation Degree Categories +//! ## Opcode Bit Layout //! -//! Operations are grouped by their flag computation degree: -//! - **Degree 7**: 64 operations (opcodes 0-63) - use all 7 op bits -//! - **Degree 6**: 8 operations (opcodes 64-79) - u32 operations -//! - **Degree 5**: 16 operations (opcodes 80-95) - use op_bit_extra[0] -//! - **Degree 4**: 8 operations (opcodes 96-127) - use op_bit_extra[1] +//! Each opcode is 7 bits `[b0, b1, b2, b3, b4, b5, b6]` (b0 = LSB): +//! +//! ```text +//! b6 b5 b4 | Degree | Opcodes | Description +//! ---------+--------+----------+--------------------------- +//! 0 * * | 7 | 0 - 63 | All 7 bits discriminate +//! 1 0 0 | 6 | 64 - 79 | u32 ops (b0 unused) +//! 1 0 1 | 5 | 80 - 95 | Uses extra[0] column +//! 1 1 * | 4 | 96 - 127 | Uses extra[1] column +//! ``` //! //! ## Composite Flags //! @@ -19,16 +24,16 @@ //! - `left_shift_at(i)`: stack shifts left at position i //! - `right_shift_at(i)`: stack shifts right at position i -use core::marker::PhantomData; +use core::array; -use miden_core::{field::PrimeCharacteristicRing, operations::opcodes}; +use miden_core::{ + field::{Algebra, PrimeCharacteristicRing}, + operations::opcodes, +}; +use crate::constraints::{decoder::columns::DecoderCols, stack::columns::StackCols}; #[cfg(test)] -use crate::trace::decoder::NUM_OP_BITS; -use crate::trace::{ - decoder::{IS_LOOP_FLAG_COL_IDX, OP_BITS_EXTRA_COLS_RANGE, OP_BITS_RANGE}, - stack::{B0_COL_IDX, H0_COL_IDX}, -}; +use crate::trace::decoder::{NUM_OP_BITS, OP_BITS_RANGE}; // CONSTANTS // ================================================================================================ @@ -70,10 +75,13 @@ const DEGREE_5_OPCODE_ENDS: usize = DEGREE_5_OPCODE_STARTS + 15; const DEGREE_4_OPCODE_STARTS: usize = DEGREE_5_OPCODE_ENDS + 1; /// Opcode at which degree 4 operations end. -#[allow(dead_code)] +#[cfg(test)] const DEGREE_4_OPCODE_ENDS: usize = DEGREE_4_OPCODE_STARTS + 31; -// INTERNAL HELPERS +/// Op bit selectors: `bits[k][0]` = 1 - b_k (negation), `bits[k][1]` = b_k (value). +type OpBits = [[E; 2]; 7]; + +// OP FLAGS // ================================================================================================ /// Operation flags for all stack operations. @@ -85,7 +93,6 @@ const DEGREE_4_OPCODE_ENDS: usize = DEGREE_4_OPCODE_STARTS + 31; /// This struct is parameterized by the expression type `E` which allows it to work /// with both concrete field elements (for testing) and symbolic expressions (for /// constraint generation). -#[allow(dead_code)] pub struct OpFlags { degree7_op_flags: [E; NUM_DEGREE_7_OPS], degree6_op_flags: [E; NUM_DEGREE_6_OPS], @@ -99,128 +106,640 @@ pub struct OpFlags { right_shift: E, control_flow: E, overflow: E, - u32_rc_op: E, + + // Next-row control flow flags (degree 4) + end_next: E, + repeat_next: E, + respan_next: E, + halt_next: E, } -/// Helper trait for accessing decoder columns from a trace row. -pub trait DecoderAccess { - /// Returns the value of op_bit[index] from the decoder. - fn op_bit(&self, index: usize) -> E; +impl OpFlags +where + E: PrimeCharacteristicRing, +{ + /// Creates a new OpFlags instance by computing all flags from the decoder columns. + /// + /// Builds flags for the current row from `decoder`/`stack`, and also computes + /// degree-4 next-row control flow flags (END, REPEAT, RESPAN, HALT) from + /// `decoder_next`, so that callers never need to construct a second `OpFlags`. + /// + /// The computation uses intermediate values to minimize multiplications: + /// - Degree 7 flags: computed hierarchically from op bits + /// - Degree 6 flags: u32 operations, share common prefix `100` + /// - Degree 5 flags: use op_bit_extra[0] for degree reduction + /// - Degree 4 flags: use op_bit_extra[1] for degree reduction + pub fn new( + decoder: &DecoderCols, + stack: &StackCols, + decoder_next: &DecoderCols, + ) -> Self + where + V: Copy, + E: Algebra, + { + // Op bit selectors: bits[k][v] returns bit k with value v (0=negated, 1=value). + let bits: OpBits = array::from_fn(|k| { + let val = decoder.op_bits[k]; + [E::ONE - val, val.into()] + }); + // --- Precomputed multi-bit selector products --- + // Each array is built iteratively: prev[i>>1] * bits[next_bit][i&1]. + // MSB expanded first so index = MSB*2^(n-1) + ... + LSB. + + // b32: index = b3*2 + b2. Shared by degree-6, degree-5, and degree-7. + let b32: [E; 4] = array::from_fn(|i| bits[3][i >> 1].clone() * bits[2][i & 1].clone()); + // b321: index = b3*4 + b2*2 + b1. Used by degree-6 and degree-7 (with nb6 prefix). + let b321: [E; 8] = array::from_fn(|i| b32[i >> 1].clone() * bits[1][i & 1].clone()); + // b3210: index = b3*8 + b2*4 + b1*2 + b0. Used by degree-5. + let b3210: [E; 16] = array::from_fn(|i| b321[i >> 1].clone() * bits[0][i & 1].clone()); + // b432: index = b4*4 + b3*2 + b2. Used by degree-4. Reuses b32. + let b432: [E; 8] = array::from_fn(|i| bits[4][i >> 2].clone() * b32[i & 3].clone()); + // b654: index = b5*2 + b4 (b6 always negated). Used by degree-7. + let b654: [E; 4] = array::from_fn(|i| { + bits[5][i >> 1].clone() * bits[4][i & 1].clone() * bits[6][0].clone() + }); + // b654321: all bits except b0. index = b5*16 + b4*8 + b3*4 + b2*2 + b1. Reuses b321. + let b654321: [E; 32] = array::from_fn(|i| b654[i >> 3].clone() * b321[i & 7].clone()); + + // --- Degree-7 flags (opcodes 0-63) --- + // 64 flags, one per opcode. Each is a degree-7 product of all 7 bit selectors. + // b654321 holds the pre-b0 intermediates (degree 6) that pair adjacent opcodes + // differing only in the LSB (e.g., MOVUP2 and MOVDN2). + let pre_b0 = PreB0Flags { + movup_or_movdn: [ + b654321[opcodes::MOVUP2 as usize >> 1].clone(), // MOVUP2 | MOVDN2 + b654321[opcodes::MOVUP3 as usize >> 1].clone(), // MOVUP3 | MOVDN3 + b654321[opcodes::MOVUP4 as usize >> 1].clone(), // MOVUP4 | MOVDN4 + b654321[opcodes::MOVUP5 as usize >> 1].clone(), // MOVUP5 | MOVDN5 + b654321[opcodes::MOVUP6 as usize >> 1].clone(), // MOVUP6 | MOVDN6 + b654321[opcodes::MOVUP7 as usize >> 1].clone(), // MOVUP7 | MOVDN7 + b654321[opcodes::MOVUP8 as usize >> 1].clone(), // MOVUP8 | MOVDN8 + ], + swapw2_or_swapw3: b654321[opcodes::SWAPW2 as usize >> 1].clone(), + advpopw_or_expacc: b654321[opcodes::ADVPOPW as usize >> 1].clone(), + }; + let degree7_op_flags: [E; NUM_DEGREE_7_OPS] = + array::from_fn(|i| b654321[i >> 1].clone() * bits[0][i & 1].clone()); + + // --- Degree-6 flags (opcodes 64-79, u32 operations) --- + // Prefix `100` (b6=1, b5=0, b4=0), discriminated by [b1, b2, b3]. + // Index = b3*4 + b2*2 + b1: + // - 0: U32ADD - 1: U32SUB + // - 2: U32MUL - 3: U32DIV + // - 4: U32SPLIT - 5: U32ASSERT2 + // - 6: U32ADD3 - 7: U32MADD + let degree6_prefix = bits[6][1].clone() * bits[5][0].clone() * bits[4][0].clone(); + let degree6_op_flags: [E; NUM_DEGREE_6_OPS] = + array::from_fn(|i| degree6_prefix.clone() * b321[i].clone()); + + // --- Degree-5 flags (opcodes 80-95) --- + // Uses extra[0] = b6*(1-b5)*b4 (degree 3), discriminated by [b0, b1, b2, b3]. + // Index = b3*8 + b2*4 + b1*2 + b0: + // - 0: HPERM - 1: MPVERIFY + // - 2: PIPE - 3: MSTREAM + // - 4: SPLIT - 5: LOOP + // - 6: SPAN - 7: JOIN + // - 8: DYN - 9: HORNERBASE + // - 10: HORNEREXT - 11: PUSH + // - 12: DYNCALL - 13: EVALCIRCUIT + // - 14: LOGPRECOMPILE - 15: (unused) + let degree5_extra: E = decoder.extra[0].into(); + let degree5_op_flags: [E; NUM_DEGREE_5_OPS] = + array::from_fn(|i| degree5_extra.clone() * b3210[i].clone()); + + // --- Degree-4 flags (opcodes 96-127) --- + // Uses extra[1] = b6*b5 (degree 2), discriminated by [b2, b3, b4]. + // Index = b4*4 + b3*2 + b2: + // - 0: MRUPDATE - 1: CRYPTOSTREAM + // - 2: SYSCALL - 3: CALL + // - 4: END - 5: REPEAT + // - 6: RESPAN - 7: HALT + let degree4_extra = decoder.extra[1]; + let degree4_op_flags: [E; NUM_DEGREE_4_OPS] = + array::from_fn(|i| b432[i].clone() * degree4_extra); + + // --- Composite flags --- + let composite = Self::compute_composite_flags::( + &bits, + °ree7_op_flags, + pre_b0, + °ree6_op_flags, + °ree5_op_flags, + °ree4_op_flags, + decoder, + stack, + ); + + // --- Next-row control flow flags (degree 4) --- + // Detect END, REPEAT, RESPAN, HALT on the *next* row. + // Prefix = extra[1]' * b4' = b6'*b5'*b4'. + // - END = 0b0111_0000 → prefix * (1-b3') * (1-b2') + // - REPEAT = 0b0111_0100 → prefix * (1-b3') * b2' + // - RESPAN = 0b0111_1000 → prefix * b3' * (1-b2') + // - HALT = 0b0111_1100 → prefix * b3' * b2' + let (end_next, repeat_next, respan_next, halt_next) = { + let prefix: E = decoder_next.extra[1].into(); + let prefix = prefix * decoder_next.op_bits[4]; + // b32_next[i] = b3'[i>>1] * b2'[i&1], same pattern as b32 above. + let b32_next: [E; 4] = { + let b3 = decoder_next.op_bits[3]; + let b2 = decoder_next.op_bits[2]; + let bits_next: [[E; 2]; 2] = [[E::ONE - b2, b2.into()], [E::ONE - b3, b3.into()]]; + array::from_fn(|i| bits_next[1][i >> 1].clone() * bits_next[0][i & 1].clone()) + }; + ( + prefix.clone() * b32_next[0].clone(), // END: (1-b3') * (1-b2') + prefix.clone() * b32_next[1].clone(), // REPEAT: (1-b3') * b2' + prefix.clone() * b32_next[2].clone(), // RESPAN: b3' * (1-b2') + prefix * b32_next[3].clone(), // HALT: b3' * b2' + ) + }; - /// Returns the value of op_bit_extra[index] from the decoder. - fn op_bit_extra(&self, index: usize) -> E; + Self { + degree7_op_flags, + degree6_op_flags, + degree5_op_flags, + degree4_op_flags, + no_shift_flags: composite.no_shift, + left_shift_flags: composite.left_shift, + right_shift_flags: composite.right_shift, + left_shift: composite.left_shift_scalar, + right_shift: composite.right_shift_scalar, + control_flow: composite.control_flow, + overflow: composite.overflow, + end_next, + repeat_next, + respan_next, + halt_next, + } + } - /// Returns the h0 helper register (overflow indicator). - fn overflow_register(&self) -> E; + // COMPOSITE FLAGS + // ============================================================================================ - /// Returns the stack depth (b0 column). - fn stack_depth(&self) -> E; + /// Computes composite stack-shift flags, control flow flag, and overflow flag. + /// + /// Each `no_shift[d]` / `left_shift[d]` / `right_shift[d]` is the sum of all + /// operation flags whose stack impact matches that shift at depth `d`. These are + /// built incrementally: each depth adds or removes operations relative to the + /// previous depth. + #[allow(clippy::too_many_arguments)] + fn compute_composite_flags( + bits: &OpBits, + deg7: &[E; NUM_DEGREE_7_OPS], + pre_b0: PreB0Flags, + deg6: &[E; NUM_DEGREE_6_OPS], + deg5: &[E; NUM_DEGREE_5_OPS], + deg4: &[E; NUM_DEGREE_4_OPS], + decoder: &DecoderCols, + stack: &StackCols, + ) -> CompositeFlags + where + V: Copy, + E: Algebra, + { + let PreB0Flags { + movup_or_movdn, + swapw2_or_swapw3, + advpopw_or_expacc, + } = pre_b0; + + // --- Op flag accessors --- + let op7 = |op: u8| deg7[op as usize].clone(); + let op6 = |op: u8| deg6[get_op_index(op)].clone(); + let op5 = |op: u8| deg5[get_op_index(op)].clone(); + let op4 = |op: u8| deg4[get_op_index(op)].clone(); + + // --- Shared bit-prefix selectors --- + + // prefix_01: (1-b6)*b5 — degree 2, shared by prefix_010 and prefix_011 + let prefix_01 = bits[6][0].clone() * bits[5][1].clone(); + + // prefix_100: b6*(1-b5)*(1-b4) — degree 3, all u32 operations (opcodes 64-79) + let prefix_100 = bits[6][1].clone() * bits[5][0].clone() * bits[4][0].clone(); + + // --- END operation with loop flag --- + let is_loop_end = decoder.end_block_flags().is_loop; + let end_loop_flag = op4(opcodes::END) * is_loop_end; + + // ── No-shift flags ────────────────────────────────────────── + // no_shift[d] = sum of op flags whose stack position d is unchanged. + // Built incrementally via accumulate_depth_deltas. + + let no_shift_depth0 = E::sum_array::<10>(&[ + // +NOOP — no-op + op7(opcodes::NOOP), + // +U32ASSERT2 — checks s0,s1 are u32, no change + op6(opcodes::U32ASSERT2), + // +MPVERIFY — verifies Merkle path in place + op5(opcodes::MPVERIFY), + // +SPAN — control flow: begins basic block + op5(opcodes::SPAN), + // +JOIN — control flow: begins join block + op5(opcodes::JOIN), + // +EMIT — emits event, no stack change + op7(opcodes::EMIT), + // +RESPAN — control flow: next batch in basic block + op4(opcodes::RESPAN), + // +HALT — control flow: ends program + op4(opcodes::HALT), + // +CALL — control flow: enters procedure + op4(opcodes::CALL), + // +END*(1-loop) — no-shift only when NOT ending a loop body + op4(opcodes::END) * (E::ONE - is_loop_end), + ]); + + // +opcodes[0..8] –NOOP — unary ops that modify only s0 (EQZ, NEG, INV, INCR, NOT, MLOAD) + let no_shift_depth1 = deg7[0..8].iter().cloned().sum::() - op7(opcodes::NOOP); + + // +U32ADD +U32SUB +U32MUL +U32DIV — consume s0,s1, produce 2 results + let u32_arith_group = prefix_100.clone() * bits[3][0].clone(); + + let no_shift_depth4 = E::sum_array::<5>(&[ + // +MOVUP3|MOVDN3 — permute s0..s3 + movup_or_movdn[1].clone(), + // +ADVPOPW|EXPACC — overwrite s0..s3 in place + advpopw_or_expacc, + // +SWAPW2|SWAPW3 — swap s0..s3 with s8+ (leaves at depth 8) + swapw2_or_swapw3.clone(), + // +EXT2MUL — ext field multiply on s0..s3 + op7(opcodes::EXT2MUL), + // +MRUPDATE — Merkle root update on s0..s3 + op4(opcodes::MRUPDATE), + ]); + + // SWAPW2/SWAPW3 depth lifecycle: + // Op Swaps No-shift depths + // SWAPW2 s[0..4] ↔ s[8..12] 0-7, 12-15 + // SWAPW3 s[0..4] ↔ s[12..16] 0-7, 8-11 + // Combined pair: enters at 4, leaves at 8, re-enters at 12 (minus SWAPW3) + + let no_shift_depth8 + // +MOVUP7|MOVDN7 — permute s0..s7 + = movup_or_movdn[5].clone() + // +SWAPW — swap s0..s3 with s4..s7, only affects depths 0-7 + + op7(opcodes::SWAPW) + // –SWAPW2|SWAPW3 — target range s8+ now affected at this depth + - swapw2_or_swapw3.clone(); + + let no_shift_depth12 + // +SWAPW2|SWAPW3 — pair re-enters (both leave depths 12+ untouched) + = swapw2_or_swapw3 + // +HPERM — Poseidon2 permutation on s0..s11 + + op5(opcodes::HPERM) + // –SWAPW3 — SWAPW3 swaps s0..s3 with s12..s15, so s12+ still changes + - op7(opcodes::SWAPW3); + + let no_shift = accumulate_depth_deltas([ + // d=0 + no_shift_depth0, + // d=1 + no_shift_depth1, + // +SWAP — swap s0,s1 + // +u32_arith_group — U32ADD..U32DIV: consume s0,s1, produce 2 results + op7(opcodes::SWAP) + u32_arith_group, + // +MOVUP2|MOVDN2 — permute s0..s2 + movup_or_movdn[0].clone(), + // d=4 + no_shift_depth4, + // +MOVUP4|MOVDN4 — permute s0..s4 + movup_or_movdn[2].clone(), + // +MOVUP5|MOVDN5 — permute s0..s5 + movup_or_movdn[3].clone(), + // +MOVUP6|MOVDN6 — permute s0..s6 + movup_or_movdn[4].clone(), + // d=8 + no_shift_depth8, + // +MOVUP8|MOVDN8 — permute s0..s8 + movup_or_movdn[6].clone(), + // d=10 (unchanged) + E::ZERO, + // d=11 (unchanged) + E::ZERO, + // d=12 + no_shift_depth12, + // d=13 (unchanged) + E::ZERO, + // d=14 (unchanged) + E::ZERO, + // d=15 (unchanged) + E::ZERO, + ]); + + // ── Left-shift flags ──────────────────────────────────────── + // left_shift[d] = sum of op flags causing a left shift at depth d. + // Built incrementally via accumulate_depth_deltas. + + // All MOVUP/MOVDN pairs share bits [1..6] and differ only in b0: + // b0 = 0 → MOVUP{w}, b0 = 1 → MOVDN{w} (for all widths 2..8) + let all_mov_pairs = E::sum_array::<7>(&movup_or_movdn); + let all_movdn = all_mov_pairs.clone() * bits[0][1].clone(); + + let left_shift_depth1 = E::sum_array::<11>(&[ + // +ASSERT — consumes s0 (must be 1) + op7(opcodes::ASSERT), + // +MOVDN{2..8} — move s0 down, shifts left above + all_movdn, + // +DROP — discards s0 + op7(opcodes::DROP), + // +MSTORE — pops address s0, stores s1 to memory + op7(opcodes::MSTORE), + // +MSTOREW — pops address s0, stores word to memory + op7(opcodes::MSTOREW), + // +(opcode 47) — unused opcode slot + deg7[47].clone(), + // +SPLIT — control flow: pops condition from s0 + op5(opcodes::SPLIT), + // +LOOP — control flow: pops condition from s0 + op5(opcodes::LOOP), + // +END*loop — END when ending a loop: pops the loop flag + end_loop_flag.clone(), + // +DYN — control flow: consumes s0..s3 (target hash) + op5(opcodes::DYN), + // +DYNCALL — control flow: consumes s0..s3 (target hash) + op5(opcodes::DYNCALL), + ]); + + // +opcodes[32..40] –ASSERT — binary ops (EQ, ADD, MUL, AND, OR, U32AND, U32XOR) + // that consume s0,s1 and produce 1 result; ASSERT already counted at depth 1 + let left_shift_depth2 = deg7[32..40].iter().cloned().sum::() - op7(opcodes::ASSERT); + + let left_shift_depth3 + // +CSWAP — pops condition s0, conditionally swaps s1,s2; net -1 at depth 3 + = op7(opcodes::CSWAP) + // +U32ADD3 — pops s0,s1,s2, pushes 2 results; net -1 at depth 3 + + op6(opcodes::U32ADD3) + // +U32MADD — pops s0,s1,s2, pushes s0*s1+s2 as 2 results; net -1 at depth 3 + + op6(opcodes::U32MADD) + // –MOVDN2 — only shifts left at depths 1..2 + - op7(opcodes::MOVDN2); + + let left_shift = accumulate_depth_deltas([ + // d=0 (left shift undefined at depth 0) + E::ZERO, + // d=1 + left_shift_depth1, + // d=2 + left_shift_depth2, + // d=3 + left_shift_depth3, + // –MOVDN3 — only shifts left at depths 1..3 + -op7(opcodes::MOVDN3), + // +MLOADW — pops address, loads 4 values; net -1 at depth 5 + // –MOVDN4 — only shifts left at depths 1..4 + op7(opcodes::MLOADW) - op7(opcodes::MOVDN4), + // –MOVDN5 — only shifts left at depths 1..5 + -op7(opcodes::MOVDN5), + // –MOVDN6 — only shifts left at depths 1..6 + -op7(opcodes::MOVDN6), + // –MOVDN7 — only shifts left at depths 1..7 + -op7(opcodes::MOVDN7), + // +CSWAPW — pops condition, swaps words s1..s4 with s5..s8; net -1 from depth 9 + // –MOVDN8 — only shifts left at depths 1..8 + op7(opcodes::CSWAPW) - op7(opcodes::MOVDN8), + // d=10 (unchanged) + E::ZERO, + // d=11 (unchanged) + E::ZERO, + // d=12 (unchanged) + E::ZERO, + // d=13 (unchanged) + E::ZERO, + // d=14 (unchanged) + E::ZERO, + // d=15 (unchanged) + E::ZERO, + ]); + + // ── Right-shift flags ─────────────────────────────────────── + // right_shift[d] = sum of op flags causing a right shift at depth d. + // Built incrementally via accumulate_depth_deltas. + + let all_movup = all_mov_pairs * bits[0][0].clone(); + let right_shift_depth0 + // +deg7[48..64] — PAD, DUP0..DUP15, ADVPOP, SDEPTH, CLK: push one element + = deg7[48..64].iter().cloned().sum::() + // +PUSH — push immediate value + + op5(opcodes::PUSH) + // +MOVUP{2..8} — move element from below to top, shifting s0..s{w-1} right + + all_movup; + + let right_shift = accumulate_depth_deltas([ + // d=0 + right_shift_depth0, + // +U32SPLIT — pops one u32, pushes high and low halves; net +1 from depth 1 + op6(opcodes::U32SPLIT), + // –MOVUP2 — only shifts right at depths 0..1 + -op7(opcodes::MOVUP2), + // –MOVUP3 — only shifts right at depths 0..2 + -op7(opcodes::MOVUP3), + // –MOVUP4 — only shifts right at depths 0..3 + -op7(opcodes::MOVUP4), + // –MOVUP5 — only shifts right at depths 0..4 + -op7(opcodes::MOVUP5), + // –MOVUP6 — only shifts right at depths 0..5 + -op7(opcodes::MOVUP6), + // –MOVUP7 — only shifts right at depths 0..6 + -op7(opcodes::MOVUP7), + // –MOVUP8 — only shifts right at depths 0..7 + -op7(opcodes::MOVUP8), + // d=9 (unchanged) + E::ZERO, + // d=10 (unchanged) + E::ZERO, + // d=11 (unchanged) + E::ZERO, + // d=12 (unchanged) + E::ZERO, + // d=13 (unchanged) + E::ZERO, + // d=14 (unchanged) + E::ZERO, + // d=15 (unchanged) + E::ZERO, + ]); + + // ── Scalar shift flags ────────────────────────────────────── + // These are NOT the same expressions as right_shift[15] / left_shift[15]. + // They use low-degree bit prefixes that are algebraically equivalent on + // valid traces (exactly one opcode active), but produce lower-degree + // expressions for use in constraints that multiply these with other terms. + + // right_shift_scalar (degree 6): + // Uses prefix_011 (degree 3) instead of summing all 16 push-like degree-7 flags. + let prefix_011 = prefix_01.clone() * bits[4][1].clone(); + let right_shift_scalar + // +prefix_011 — PAD, DUP0..DUP15, ADVPOP, SDEPTH, CLK (opcodes 48-63) + = prefix_011 + // +PUSH — push immediate value + + op5(opcodes::PUSH) + // +U32SPLIT — pops one u32, pushes high and low halves + + op6(opcodes::U32SPLIT); + + // left_shift_scalar (degree 5): + // Uses prefix_010 (degree 3) instead of summing all left-shifting degree-7 flags. + // DYNCALL is intentionally excluded — it left-shifts the stack but uses + // decoder hasher state (h5) for overflow constraints, not the generic path. + let prefix_010 = prefix_01 * bits[4][0].clone(); + let u32_add3_madd_group = prefix_100 * bits[3][1].clone() * bits[2][1].clone(); + let left_shift_scalar = E::sum_array::<7>(&[ + // +prefix_010 — ASSERT, EQ, ADD, MUL, AND, OR, U32AND, U32XOR, DROP, + // CSWAP, CSWAPW, MLOADW, MSTORE, MSTOREW, (op46), (op47) + prefix_010, + // +u32_add3_madd_group — U32ADD3, U32MADD: consume 3, produce 2 + u32_add3_madd_group, + // +SPLIT — control flow: pops condition + op5(opcodes::SPLIT), + // +LOOP — control flow: pops condition + op5(opcodes::LOOP), + // +REPEAT — control flow: pops condition for next iteration + op4(opcodes::REPEAT), + // +END*loop — END when ending a loop: pops loop flag + end_loop_flag, + // +DYN — control flow: consumes target hash + op5(opcodes::DYN), + ]); + + // --- Control flow flag --- + // + // Control flow operations are the only operations that can execute when outside a basic + // block (i.e., when in_span = 0). This is enforced by the decoder constraint: + // (1 - in_span) * (1 - control_flow) = 0 + // + // Control flow operations (must include ALL of these): + // - Block starters: SPAN, JOIN, SPLIT, LOOP + // - Block transitions: END, REPEAT, RESPAN, HALT + // - Dynamic execution: DYN, DYNCALL + // - Procedure calls: CALL, SYSCALL + // + // IMPORTANT: If a new control flow operation is added, it MUST be included here, + // otherwise the decoder constraint will fail when executing that operation. + let control_flow = E::sum_array::<6>(&[ + // +SPAN, JOIN, SPLIT, LOOP — block starters + bits[3][0].clone() * bits[2][1].clone() * decoder.extra[0], + // +END, REPEAT, RESPAN, HALT — block transitions + bits[4][1].clone() * decoder.extra[1], + // +DYNCALL — dynamic execution + op5(opcodes::DYNCALL), + // +DYN — dynamic execution + op5(opcodes::DYN), + // +SYSCALL — procedure call + op4(opcodes::SYSCALL), + // +CALL — procedure call + op4(opcodes::CALL), + ]); - /// Returns the is_loop flag from the decoder. - fn is_loop_end(&self) -> E; -} + // Flag if overflow table contains values + let overflow: E = stack.b0.into(); + let overflow = (overflow - E::from_u64(16)) * stack.h0; -/// Implement DecoderAccess for MainTraceRow references. -impl DecoderAccess for &crate::MainTraceRow -where - T: Clone, -{ - #[inline] - fn op_bit(&self, index: usize) -> T { - self.decoder[OP_BITS_RANGE.start + index].clone() + CompositeFlags { + no_shift, + left_shift, + right_shift, + left_shift_scalar, + right_shift_scalar, + control_flow, + overflow, + } } - #[inline] - fn op_bit_extra(&self, index: usize) -> T { - self.decoder[OP_BITS_EXTRA_COLS_RANGE.start + index].clone() - } + // ------ Composite Flags --------------------------------------------------------------------- - #[inline] - fn overflow_register(&self) -> T { - self.stack[H0_COL_IDX].clone() + /// Returns the flag for when the stack item at the specified depth remains unchanged. + #[inline(always)] + pub fn no_shift_at(&self, index: usize) -> E { + self.no_shift_flags[index].clone() } - #[inline] - fn stack_depth(&self) -> T { - self.stack[B0_COL_IDX].clone() + /// Returns the flag for when the stack item at the specified depth shifts left. + /// Left shift is not defined on position 0, so returns default for index 0. + #[inline(always)] + pub fn left_shift_at(&self, index: usize) -> E { + self.left_shift_flags[index].clone() } - #[inline] - fn is_loop_end(&self) -> T { - self.decoder[IS_LOOP_FLAG_COL_IDX].clone() + /// Returns the flag for when the stack item at the specified depth shifts right. + #[inline(always)] + pub fn right_shift_at(&self, index: usize) -> E { + self.right_shift_flags[index].clone() } -} -/// Wrapper that converts trace row variables to expressions during decoder access. -/// -/// This is used when building constraints to convert `AB::Var` to `AB::Expr` so that -/// `OpFlags` can be created for use in constraint expressions. -pub struct ExprDecoderAccess<'a, V, E> { - row: &'a crate::MainTraceRow, - _phantom: PhantomData, -} - -impl<'a, V, E> ExprDecoderAccess<'a, V, E> { - /// Creates a new expression decoder access wrapper. - pub fn new(row: &'a crate::MainTraceRow) -> Self { - Self { row, _phantom: PhantomData } + /// Returns the scalar flag when the stack operation shifts the stack to the right. + /// + /// This is NOT the same expression as `right_shift_at(15)`. It uses low-degree + /// bit prefixes (degree 6) that are algebraically equivalent on valid traces, + /// producing a lower-degree expression for use in constraints that multiply + /// this flag with other terms. + #[inline(always)] + pub fn right_shift(&self) -> E { + self.right_shift.clone() } -} -impl<'a, V, E> DecoderAccess for ExprDecoderAccess<'a, V, E> -where - V: Clone + Into, -{ - #[inline] - fn op_bit(&self, index: usize) -> E { - self.row.decoder[OP_BITS_RANGE.start + index].clone().into() + /// Returns the scalar flag when the stack operation shifts the stack to the left. + /// + /// This is NOT the same expression as `left_shift_at(15)`. It uses low-degree + /// bit prefixes (degree 5) that are algebraically equivalent on valid traces. + /// + /// Excludes `DYNCALL` — it left-shifts the stack but is handled via the + /// per-position `left_shift_at` flags. The aggregate `left_shift` flag only + /// gates generic helper/overflow constraints, which don't apply to `DYNCALL` + /// because those helper columns are reused for the context switch and the + /// overflow pointer is stored in decoder hasher state (h5). + #[inline(always)] + pub fn left_shift(&self) -> E { + self.left_shift.clone() } - #[inline] - fn op_bit_extra(&self, index: usize) -> E { - self.row.decoder[OP_BITS_EXTRA_COLS_RANGE.start + index].clone().into() + /// Returns the flag when the current operation is a control flow operation. + /// + /// Control flow operations are the only operations allowed to execute when outside a basic + /// block (i.e., when in_span = 0). This includes: + /// - Block starters: SPAN, JOIN, SPLIT, LOOP + /// - Block transitions: END, REPEAT, RESPAN, HALT + /// - Dynamic execution: DYN, DYNCALL + /// - Procedure calls: CALL, SYSCALL + /// + /// Used by the decoder constraint: `(1 - in_span) * (1 - control_flow) = 0` + /// + /// Degree: 3 + #[inline(always)] + pub fn control_flow(&self) -> E { + self.control_flow.clone() } - #[inline] - fn overflow_register(&self) -> E { - self.row.stack[H0_COL_IDX].clone().into() + /// Returns the flag indicating whether the overflow stack contains values. + /// Degree: 2 + #[inline(always)] + pub fn overflow(&self) -> E { + self.overflow.clone() } - #[inline] - fn stack_depth(&self) -> E { - self.row.stack[B0_COL_IDX].clone().into() - } + // ------ Next-row flags ------------------------------------------------------------------- - #[inline] - fn is_loop_end(&self) -> E { - self.row.decoder[IS_LOOP_FLAG_COL_IDX].clone().into() + /// Returns the flag for END on the next row. Degree: 4 + #[inline(always)] + pub fn end_next(&self) -> E { + self.end_next.clone() } -} - -/// Helper function to compute binary NOT: 1 - x -#[inline] -fn binary_not(x: E) -> E -where - E: Clone + core::ops::Sub + PrimeCharacteristicRing, -{ - E::ONE - x -} -#[derive(Clone)] -struct Op { - bit: E, - not: E, -} + /// Returns the flag for REPEAT on the next row. Degree: 4 + #[inline(always)] + pub fn repeat_next(&self) -> E { + self.repeat_next.clone() + } -impl Op { - #[inline] - fn is(&self) -> E { - self.bit.clone() + /// Returns the flag for RESPAN on the next row. Degree: 4 + #[inline(always)] + pub fn respan_next(&self) -> E { + self.respan_next.clone() } - #[inline] - fn not(&self) -> E { - self.not.clone() + /// Returns the flag for HALT on the next row. Degree: 4 + #[inline(always)] + pub fn halt_next(&self) -> E { + self.halt_next.clone() } } @@ -236,397 +755,7 @@ macro_rules! op_flag_getters { }; } -#[allow(dead_code)] -impl OpFlags -where - E: Clone - + Default - + core::ops::Add - + core::ops::Sub - + core::ops::Mul - + PrimeCharacteristicRing, -{ - /// Creates a new OpFlags instance by computing all flags from the decoder columns. - /// - /// The computation uses intermediate values to minimize multiplications: - /// - Degree 7 flags: computed hierarchically from op bits - /// - Degree 6 flags: u32 operations, share common prefix `100` - /// - Degree 5 flags: use op_bit_extra[0] for degree reduction - /// - Degree 4 flags: use op_bit_extra[1] for degree reduction - pub fn new>(frame: D) -> Self { - // Initialize arrays with default values - let mut degree7_op_flags: [E; NUM_DEGREE_7_OPS] = core::array::from_fn(|_| E::default()); - let mut degree6_op_flags: [E; NUM_DEGREE_6_OPS] = core::array::from_fn(|_| E::default()); - let mut degree5_op_flags: [E; NUM_DEGREE_5_OPS] = core::array::from_fn(|_| E::default()); - let mut degree4_op_flags: [E; NUM_DEGREE_4_OPS] = core::array::from_fn(|_| E::default()); - let mut no_shift_flags: [E; NUM_STACK_IMPACT_FLAGS] = - core::array::from_fn(|_| E::default()); - let mut left_shift_flags: [E; NUM_STACK_IMPACT_FLAGS] = - core::array::from_fn(|_| E::default()); - let mut right_shift_flags: [E; NUM_STACK_IMPACT_FLAGS] = - core::array::from_fn(|_| E::default()); - - // Get op bits and their binary negations. - let op: [Op; 7] = core::array::from_fn(|i| { - let bit = frame.op_bit(i); - let not = binary_not(bit.clone()); - Op { bit, not } - }); - - // --- Low-degree prefix selectors for composite flags --- - // These produce degree-5 left_shift and right_shift composite flags. - // per spec: https://0xmiden.github.io/miden-vm/design/stack/op_constraints.html#shift-left-flag - - // Prefix `010` selector: (1-b6)*b5*(1-b4) - degree 3 - // Covers all degree-7 operations with this prefix (left shift ops) - let prefix_010 = op[6].not() * op[5].is() * op[4].not(); - - // Prefix `011` selector: (1-b6)*b5*b4 - degree 3 - // Covers all degree-7 operations with this prefix (right shift ops) - let prefix_011 = op[6].not() * op[5].is() * op[4].is(); - - // Prefix `10011` selector: b6*(1-b5)*(1-b4)*b3*b2 - degree 5 - // Covers U32ADD3 and U32MADD (both cause left shift by 2) - let add3_madd_prefix = op[6].is() * op[5].not() * op[4].not() * op[3].is() * op[2].is(); - - // --- Computation of degree 7 operation flags --- - - // Intermediate values computed from most significant bits - degree7_op_flags[0] = op[5].not() * op[4].not(); - degree7_op_flags[16] = op[5].not() * op[4].is(); - degree7_op_flags[32] = op[5].is() * op[4].not(); - // Prefix `11` in bits [5..4] (binary 110000 = 48). - degree7_op_flags[0b110000] = op[5].is() * op[4].is(); - - // Flag of prefix `100` - all degree 6 u32 operations - let f100 = degree7_op_flags[0].clone() * op[6].is(); - // Flag of prefix `1000` - u32 arithmetic operations - let f1000 = f100.clone() * op[3].not(); - - let not_6_not_3 = op[6].not() * op[3].not(); - let not_6_yes_3 = op[6].not() * op[3].is(); - - // Add fourth most significant bit along with most significant bit - for i in (0..64).step_by(16) { - let base = degree7_op_flags[i].clone(); - degree7_op_flags[i + 8] = base.clone() * not_6_yes_3.clone(); - degree7_op_flags[i] = base * not_6_not_3.clone(); - } - - // Flag of prefix `011` - degree 7 right shift operations - let f011 = degree7_op_flags[48].clone() + degree7_op_flags[56].clone(); - // Flag of prefix `010` - degree 7 left shift operations (reserved for future use) - let _f010 = degree7_op_flags[32].clone() + degree7_op_flags[40].clone(); - // Flag of prefix `0000` - no shift from position 1 onwards - let f0000 = degree7_op_flags[0].clone(); - // Flag of prefix `0100` - left shift from position 2 onwards - let f0100 = degree7_op_flags[32].clone(); - - // Add fifth most significant bit - for i in (0..64).step_by(8) { - let base = degree7_op_flags[i].clone(); - degree7_op_flags[i + 4] = base.clone() * op[2].is(); - degree7_op_flags[i] = base * op[2].not(); - } - - // Add sixth most significant bit - for i in (0..64).step_by(4) { - let base = degree7_op_flags[i].clone(); - degree7_op_flags[i + 2] = base.clone() * op[1].is(); - degree7_op_flags[i] = base * op[1].not(); - } - - // Cache flags for mov{up/dn}{2-8}, swapw{2-3} operations - let mov2_flag = degree7_op_flags[10].clone(); - let mov3_flag = degree7_op_flags[12].clone(); - let mov4_flag = degree7_op_flags[16].clone(); - let mov5_flag = degree7_op_flags[18].clone(); - let mov6_flag = degree7_op_flags[20].clone(); - let mov7_flag = degree7_op_flags[22].clone(); - let mov8_flag = degree7_op_flags[26].clone(); - let swapwx_flag = degree7_op_flags[28].clone(); - let adv_popw_expacc = degree7_op_flags[14].clone(); - - // Add least significant bit - for i in (0..64).step_by(2) { - let base = degree7_op_flags[i].clone(); - degree7_op_flags[i + 1] = base.clone() * op[0].is(); - degree7_op_flags[i] = base * op[0].not(); - } - - let ext2mul_flag = degree7_op_flags[25].clone(); - - // Flag when items from first position onwards are copied over (excludes NOOP) - let no_change_1_flag = f0000.clone() - degree7_op_flags[0].clone(); - // Flag when items from second position onwards shift left (excludes ASSERT) - let left_change_1_flag = f0100 - degree7_op_flags[32].clone(); - - // --- Computation of degree 6 operation flags --- - - // Degree 6 flag prefix is `100` - let degree_6_flag = op[6].is() * op[5].not() * op[4].not(); - - // Degree 6 flags do not use the first bit (op_bits[0]) - let not_2_not_3 = op[2].not() * op[3].not(); - let yes_2_not_3 = op[2].is() * op[3].not(); - let not_2_yes_3 = op[2].not() * op[3].is(); - let yes_2_yes_3 = op[2].is() * op[3].is(); - - degree6_op_flags[0] = op[1].not() * not_2_not_3.clone(); // U32ADD - degree6_op_flags[1] = op[1].is() * not_2_not_3.clone(); // U32SUB - degree6_op_flags[2] = op[1].not() * yes_2_not_3.clone(); // U32MUL - degree6_op_flags[3] = op[1].is() * yes_2_not_3.clone(); // U32DIV - degree6_op_flags[4] = op[1].not() * not_2_yes_3.clone(); // U32SPLIT - degree6_op_flags[5] = op[1].is() * not_2_yes_3.clone(); // U32ASSERT2 - degree6_op_flags[6] = op[1].not() * yes_2_yes_3.clone(); // U32ADD3 - degree6_op_flags[7] = op[1].is() * yes_2_yes_3.clone(); // U32MADD - - // Multiply by degree 6 flag - for flag in degree6_op_flags.iter_mut() { - *flag = flag.clone() * degree_6_flag.clone(); - } - - // --- Computation of degree 5 operation flags --- - - // Degree 5 flag uses the first degree reduction column - let degree_5_flag = frame.op_bit_extra(0); - - let not_0_not_1 = op[0].not() * op[1].not(); - let yes_0_not_1 = op[0].is() * op[1].not(); - let not_0_yes_1 = op[0].not() * op[1].is(); - let yes_0_yes_1 = op[0].is() * op[1].is(); - - degree5_op_flags[0] = not_0_not_1.clone() * op[2].not(); // HPERM - degree5_op_flags[1] = yes_0_not_1.clone() * op[2].not(); // MPVERIFY - degree5_op_flags[2] = not_0_yes_1.clone() * op[2].not(); // PIPE - degree5_op_flags[3] = yes_0_yes_1.clone() * op[2].not(); // MSTREAM - degree5_op_flags[4] = not_0_not_1.clone() * op[2].is(); // SPLIT - degree5_op_flags[5] = yes_0_not_1.clone() * op[2].is(); // LOOP - degree5_op_flags[6] = not_0_yes_1.clone() * op[2].is(); // SPAN - degree5_op_flags[7] = yes_0_yes_1.clone() * op[2].is(); // JOIN - - // Second half shares same lower 3 bits - for i in 0..8 { - degree5_op_flags[i + 8] = degree5_op_flags[i].clone(); - } - - // Update with op_bit[3] and degree 5 flag - let deg_5_not_3 = op[3].not() * degree_5_flag.clone(); - for flag in degree5_op_flags.iter_mut().take(8) { - *flag = flag.clone() * deg_5_not_3.clone(); - } - let deg_5_yes_3 = op[3].is() * degree_5_flag.clone(); - for flag in degree5_op_flags.iter_mut().skip(8) { - *flag = flag.clone() * deg_5_yes_3.clone(); - } - - // --- Computation of degree 4 operation flags --- - - // Degree 4 flag uses the second degree reduction column - let degree_4_flag = frame.op_bit_extra(1); - - // Degree 4 flags do not use the first two bits - degree4_op_flags[0] = not_2_not_3.clone(); // MRUPDATE - degree4_op_flags[1] = yes_2_not_3; // (unused) - degree4_op_flags[2] = not_2_yes_3; // SYSCALL - degree4_op_flags[3] = yes_2_yes_3; // CALL - - // Second half shares same lower 4 bits - for i in 0..4 { - degree4_op_flags[i + 4] = degree4_op_flags[i].clone(); - } - - // Update with op_bit[4] and degree 4 flag - let deg_4_not_4 = op[4].not() * degree_4_flag.clone(); - for flag in degree4_op_flags.iter_mut().take(4) { - *flag = flag.clone() * deg_4_not_4.clone(); - } - let deg_4_yes_4 = op[4].is() * degree_4_flag.clone(); - for flag in degree4_op_flags.iter_mut().skip(4) { - *flag = flag.clone() * deg_4_yes_4.clone(); - } - - // --- No shift composite flags computation --- - - // Flag for END operation causing stack to shift left (depends on whether in loop) - let shift_left_on_end = degree4_op_flags[4].clone() * frame.is_loop_end(); - - no_shift_flags[0] = degree7_op_flags[0].clone() // NOOP - + degree6_op_flags[5].clone() // U32ASSERT2 - + degree5_op_flags[1].clone() // MPVERIFY - + degree5_op_flags[6].clone() // SPAN - + degree5_op_flags[7].clone() // JOIN - + degree7_op_flags[31].clone() // EMIT - + degree4_op_flags[6].clone() // RESPAN - + degree4_op_flags[7].clone() // HALT - + degree4_op_flags[3].clone() // CALL - + degree4_op_flags[4].clone() * binary_not(frame.is_loop_end()); // END (non-loop) - - no_shift_flags[1] = no_shift_flags[0].clone() + no_change_1_flag; - no_shift_flags[2] = no_shift_flags[1].clone() - + degree7_op_flags[8].clone() // SWAP - + f1000.clone(); // u32 arithmetic - no_shift_flags[3] = no_shift_flags[2].clone() + mov2_flag.clone(); - no_shift_flags[4] = no_shift_flags[3].clone() - + mov3_flag.clone() - + adv_popw_expacc.clone() - + swapwx_flag.clone() - + ext2mul_flag.clone() - + degree4_op_flags[0].clone(); // MRUPDATE - - no_shift_flags[5] = no_shift_flags[4].clone() + mov4_flag.clone(); - no_shift_flags[6] = no_shift_flags[5].clone() + mov5_flag.clone(); - no_shift_flags[7] = no_shift_flags[6].clone() + mov6_flag.clone(); - no_shift_flags[8] = - no_shift_flags[7].clone() + mov7_flag.clone() + degree7_op_flags[24].clone() - - degree7_op_flags[28].clone(); - - no_shift_flags[9] = no_shift_flags[8].clone() + mov8_flag.clone(); - no_shift_flags[10] = no_shift_flags[9].clone(); - no_shift_flags[11] = no_shift_flags[9].clone(); - // SWAPW3; SWAPW2; HPERM - no_shift_flags[12] = no_shift_flags[9].clone() - degree7_op_flags[29].clone() - + degree7_op_flags[28].clone() - + degree5_op_flags[0].clone(); - no_shift_flags[13] = no_shift_flags[12].clone(); - no_shift_flags[14] = no_shift_flags[12].clone(); - no_shift_flags[15] = no_shift_flags[12].clone(); - - // --- Left shift composite flags computation --- - - let movdnn_flag = degree7_op_flags[11].clone() - + degree7_op_flags[13].clone() - + degree7_op_flags[17].clone() - + degree7_op_flags[19].clone() - + degree7_op_flags[21].clone() - + degree7_op_flags[23].clone() - + degree7_op_flags[27].clone(); - - let split_loop_flag = degree5_op_flags[4].clone() + degree5_op_flags[5].clone(); - let add3_madd_flag = degree6_op_flags[6].clone() + degree6_op_flags[7].clone(); - - left_shift_flags[1] = degree7_op_flags[32].clone() - + movdnn_flag.clone() - + degree7_op_flags[41].clone() - + degree7_op_flags[45].clone() - + degree7_op_flags[47].clone() - + degree7_op_flags[46].clone() - + split_loop_flag.clone() - + shift_left_on_end.clone() - + degree5_op_flags[8].clone() // DYN - + degree5_op_flags[12].clone(); // DYNCALL - - left_shift_flags[2] = left_shift_flags[1].clone() + left_change_1_flag; - left_shift_flags[3] = - left_shift_flags[2].clone() + add3_madd_flag.clone() + degree7_op_flags[42].clone() - - degree7_op_flags[11].clone(); - left_shift_flags[4] = left_shift_flags[3].clone() - degree7_op_flags[13].clone(); - left_shift_flags[5] = left_shift_flags[4].clone() + degree7_op_flags[44].clone() - - degree7_op_flags[17].clone(); - left_shift_flags[6] = left_shift_flags[5].clone() - degree7_op_flags[19].clone(); - left_shift_flags[7] = left_shift_flags[6].clone() - degree7_op_flags[21].clone(); - left_shift_flags[8] = left_shift_flags[7].clone() - degree7_op_flags[23].clone(); - left_shift_flags[9] = left_shift_flags[8].clone() + degree7_op_flags[43].clone() - - degree7_op_flags[27].clone(); - left_shift_flags[10] = left_shift_flags[9].clone(); - left_shift_flags[11] = left_shift_flags[9].clone(); - left_shift_flags[12] = left_shift_flags[9].clone(); - left_shift_flags[13] = left_shift_flags[9].clone(); - left_shift_flags[14] = left_shift_flags[9].clone(); - left_shift_flags[15] = left_shift_flags[9].clone(); - - // --- Right shift composite flags computation --- - - let movupn_flag = degree7_op_flags[10].clone() - + degree7_op_flags[12].clone() - + degree7_op_flags[16].clone() - + degree7_op_flags[18].clone() - + degree7_op_flags[20].clone() - + degree7_op_flags[22].clone() - + degree7_op_flags[26].clone(); - - right_shift_flags[0] = f011.clone() - + degree5_op_flags[11].clone() // PUSH - + movupn_flag.clone(); - - right_shift_flags[1] = right_shift_flags[0].clone() + degree6_op_flags[4].clone(); // U32SPLIT - - right_shift_flags[2] = right_shift_flags[1].clone() - degree7_op_flags[10].clone(); - right_shift_flags[3] = right_shift_flags[2].clone() - degree7_op_flags[12].clone(); - right_shift_flags[4] = right_shift_flags[3].clone() - degree7_op_flags[16].clone(); - right_shift_flags[5] = right_shift_flags[4].clone() - degree7_op_flags[18].clone(); - right_shift_flags[6] = right_shift_flags[5].clone() - degree7_op_flags[20].clone(); - right_shift_flags[7] = right_shift_flags[6].clone() - degree7_op_flags[22].clone(); - right_shift_flags[8] = right_shift_flags[7].clone() - degree7_op_flags[26].clone(); - right_shift_flags[9] = right_shift_flags[8].clone(); - right_shift_flags[10] = right_shift_flags[8].clone(); - right_shift_flags[11] = right_shift_flags[8].clone(); - right_shift_flags[12] = right_shift_flags[8].clone(); - right_shift_flags[13] = right_shift_flags[8].clone(); - right_shift_flags[14] = right_shift_flags[8].clone(); - right_shift_flags[15] = right_shift_flags[8].clone(); - - // --- Other composite flags --- - - // Flag if stack shifted right (degree 6, dominated by U32SPLIT) - // Uses prefix_011 (degree 3) instead of f011 (degree 4) for lower base degree - let right_shift = prefix_011.clone() - + degree5_op_flags[11].clone() // PUSH - + degree6_op_flags[4].clone(); // U32SPLIT - - // Flag if stack shifted left (degree 5). - // Uses low-degree prefixes to keep left_shift at degree 5 (avoids degree growth). - // Note: DYNCALL is intentionally excluded; see stack overflow depth constraints. - let left_shift = prefix_010.clone() - + add3_madd_prefix.clone() - + split_loop_flag - + degree4_op_flags[5].clone() // REPEAT - + shift_left_on_end - + degree5_op_flags[8].clone(); // DYN - - // Flag if current operation is a control flow operation. - // - // Control flow operations are the only operations that can execute when outside a basic - // block (i.e., when in_span = 0). This is enforced by the decoder constraint: - // (1 - in_span) * (1 - control_flow) = 0 - // - // Control flow operations (must include ALL of these): - // - Block starters: SPAN, JOIN, SPLIT, LOOP - // - Block transitions: END, REPEAT, RESPAN, HALT - // - Dynamic execution: DYN, DYNCALL - // - Procedure calls: CALL, SYSCALL - // - // IMPORTANT: If a new control flow operation is added, it MUST be included here, - // otherwise the decoder constraint will fail when executing that operation. - let control_flow = degree_5_flag * op[3].not() * op[2].is() // SPAN, JOIN, SPLIT, LOOP - + degree_4_flag * op[4].is() // END, REPEAT, RESPAN, HALT - + degree5_op_flags[8].clone() // DYN - + degree5_op_flags[12].clone() // DYNCALL - + degree4_op_flags[2].clone() // SYSCALL - + degree4_op_flags[3].clone(); // CALL - - // Flag if current operation is a degree 6 u32 operation - let u32_rc_op = f100; - - // Flag if overflow table contains values - let overflow = (frame.stack_depth() - E::from_u64(16)) * frame.overflow_register(); - - Self { - degree7_op_flags, - degree6_op_flags, - degree5_op_flags, - degree4_op_flags, - no_shift_flags, - left_shift_flags, - right_shift_flags, - left_shift, - right_shift, - control_flow, - overflow, - u32_rc_op, - } - } - +impl OpFlags { // STATE ACCESSORS // ============================================================================================ @@ -634,7 +763,7 @@ where op_flag_getters!(degree7_op_flags, /// Operation Flag of NOOP operation. - #[allow(dead_code)] + #[expect(dead_code)] noop => opcodes::NOOP, /// Operation Flag of EQZ operation. eqz => opcodes::EQZ, @@ -647,6 +776,7 @@ where /// Operation Flag of NOT operation. not => opcodes::NOT, /// Operation Flag of MLOAD operation. + #[expect(dead_code)] mload => opcodes::MLOAD, /// Operation Flag of SWAP operation. swap => opcodes::SWAP, @@ -664,7 +794,7 @@ where /// Operation Flag of MOVDN3 operation. movdn3 => opcodes::MOVDN3, /// Operation Flag of ADVPOPW operation. - #[allow(dead_code)] + #[expect(dead_code)] advpopw => opcodes::ADVPOPW, /// Operation Flag of EXPACC operation. expacc => opcodes::EXPACC, @@ -711,21 +841,28 @@ where /// Operation Flag of OR operation. or => opcodes::OR, /// Operation Flag of U32AND operation. + #[expect(dead_code)] u32and => opcodes::U32AND, /// Operation Flag of U32XOR operation. + #[expect(dead_code)] u32xor => opcodes::U32XOR, + /// Operation Flag of FRIE2F4 operation. + frie2f4 => opcodes::FRIE2F4, /// Operation Flag of DROP operation. - #[allow(dead_code)] + #[expect(dead_code)] drop => opcodes::DROP, /// Operation Flag of CSWAP operation. cswap => opcodes::CSWAP, /// Operation Flag of CSWAPW operation. cswapw => opcodes::CSWAPW, /// Operation Flag of MLOADW operation. + #[expect(dead_code)] mloadw => opcodes::MLOADW, /// Operation Flag of MSTORE operation. + #[expect(dead_code)] mstore => opcodes::MSTORE, /// Operation Flag of MSTOREW operation. + #[expect(dead_code)] mstorew => opcodes::MSTOREW, /// Operation Flag of PAD operation. pad => opcodes::PAD, @@ -754,7 +891,7 @@ where /// Operation Flag of DUP15 operation. dup15 => opcodes::DUP15, /// Operation Flag of ADVPOP operation. - #[allow(dead_code)] + #[expect(dead_code)] advpop => opcodes::ADVPOP, /// Operation Flag of SDEPTH operation. sdepth => opcodes::SDEPTH, @@ -787,8 +924,10 @@ where op_flag_getters!(degree5_op_flags, /// Operation Flag of HPERM operation. + #[expect(dead_code)] hperm => opcodes::HPERM, /// Operation Flag of MPVERIFY operation. + #[expect(dead_code)] mpverify => opcodes::MPVERIFY, /// Operation Flag of SPLIT operation. split => opcodes::SPLIT, @@ -797,6 +936,7 @@ where /// Operation Flag of SPAN operation. span => opcodes::SPAN, /// Operation Flag of JOIN operation. + #[expect(dead_code)] join => opcodes::JOIN, /// Operation Flag of PUSH operation. push => opcodes::PUSH, @@ -805,16 +945,20 @@ where /// Operation Flag of DYNCALL operation. dyncall => opcodes::DYNCALL, /// Operation Flag of EVALCIRCUIT operation. + #[expect(dead_code)] evalcircuit => opcodes::EVALCIRCUIT, /// Operation Flag of LOG_PRECOMPILE operation. + #[expect(dead_code)] log_precompile => opcodes::LOGPRECOMPILE, /// Operation Flag of HORNERBASE operation. hornerbase => opcodes::HORNERBASE, /// Operation Flag of HORNEREXT operation. hornerext => opcodes::HORNEREXT, /// Operation Flag of MSTREAM operation. + #[expect(dead_code)] mstream => opcodes::MSTREAM, /// Operation Flag of PIPE operation. + #[expect(dead_code)] pipe => opcodes::PIPE, ); @@ -822,6 +966,7 @@ where op_flag_getters!(degree4_op_flags, /// Operation Flag of MRUPDATE operation. + #[expect(dead_code)] mrupdate => opcodes::MRUPDATE, /// Operation Flag of CALL operation. call => opcodes::CALL, @@ -838,110 +983,35 @@ where /// Operation Flag of CRYPTOSTREAM operation. cryptostream => opcodes::CRYPTOSTREAM, ); - - // ------ Composite Flags --------------------------------------------------------------------- - - /// Returns the flag for when the stack item at the specified depth remains unchanged. - #[inline(always)] - pub fn no_shift_at(&self, index: usize) -> E { - self.no_shift_flags[index].clone() - } - - /// Returns the flag for when the stack item at the specified depth shifts left. - /// Left shift is not defined on position 0, so returns default for index 0. - #[inline(always)] - pub fn left_shift_at(&self, index: usize) -> E { - self.left_shift_flags[index].clone() - } - - /// Returns the flag for when the stack item at the specified depth shifts right. - #[inline(always)] - pub fn right_shift_at(&self, index: usize) -> E { - self.right_shift_flags[index].clone() - } - - /// Returns the flag when the stack operation shifts the stack to the right. - /// Degree: 6 - #[inline(always)] - pub fn right_shift(&self) -> E { - self.right_shift.clone() - } - - /// Returns the flag when the stack operation shifts the stack to the left. - /// - /// Note: `DYNCALL` still shifts the stack, but it is handled via the per-position - /// `left_shift_at` flags. The aggregate `left_shift` flag only gates the generic - /// helper/overflow constraints, which do not apply to `DYNCALL` because those - /// helper columns are reused for the context switch and the overflow pointer is - /// stored in decoder hasher state (h5), not in the usual helper/stack columns. - /// Degree: 5 - #[inline(always)] - pub fn left_shift(&self) -> E { - self.left_shift.clone() - } - - /// Returns the flag when the current operation is a control flow operation. - /// - /// Control flow operations are the only operations allowed to execute when outside a basic - /// block (i.e., when in_span = 0). This includes: - /// - Block starters: SPAN, JOIN, SPLIT, LOOP - /// - Block transitions: END, REPEAT, RESPAN, HALT - /// - Dynamic execution: DYN, DYNCALL - /// - Procedure calls: CALL, SYSCALL - /// - /// Used by the decoder constraint: `(1 - in_span) * (1 - control_flow) = 0` - /// - /// Degree: 3 - #[inline(always)] - pub fn control_flow(&self) -> E { - self.control_flow.clone() - } - - /// Returns the flag when the current operation is a u32 operation requiring range checks. - #[inline(always)] - #[allow(dead_code)] - pub fn u32_rc_op(&self) -> E { - self.u32_rc_op.clone() - } - - /// Returns the flag indicating whether the overflow stack contains values. - /// Degree: 2 - #[inline(always)] - pub fn overflow(&self) -> E { - self.overflow.clone() - } - - // TEST ACCESSORS - // ============================================================================================ - - /// Returns reference to degree 7 operation flags array (for testing). - #[cfg(test)] - pub fn degree7_op_flags(&self) -> &[E; NUM_DEGREE_7_OPS] { - &self.degree7_op_flags - } - - /// Returns reference to degree 6 operation flags array (for testing). - #[cfg(test)] - pub fn degree6_op_flags(&self) -> &[E; NUM_DEGREE_6_OPS] { - &self.degree6_op_flags - } - - /// Returns reference to degree 5 operation flags array (for testing). - #[cfg(test)] - pub fn degree5_op_flags(&self) -> &[E; NUM_DEGREE_5_OPS] { - &self.degree5_op_flags - } - - /// Returns reference to degree 4 operation flags array (for testing). - #[cfg(test)] - pub fn degree4_op_flags(&self) -> &[E; NUM_DEGREE_4_OPS] { - &self.degree4_op_flags - } } // INTERNAL HELPERS // ================================================================================================ +/// Pre-b0 intermediate flags captured before the final bit split. +/// +/// These are degree-6 products (all bits except b0) that pair adjacent opcodes +/// sharing all bits except the LSB. Used by composite shift flag computation. +struct PreB0Flags { + /// MOVUP{2..8} | MOVDN{2..8} paired flags, indexed 0..7 for widths 2..8. + movup_or_movdn: [E; 7], + /// SWAPW2 | SWAPW3 paired flag. + swapw2_or_swapw3: E, + /// ADVPOPW | EXPACC paired flag. + advpopw_or_expacc: E, +} + +/// Composite flag results: shift arrays, scalar flags, and control flow. +struct CompositeFlags { + no_shift: [E; NUM_STACK_IMPACT_FLAGS], + left_shift: [E; NUM_STACK_IMPACT_FLAGS], + right_shift: [E; NUM_STACK_IMPACT_FLAGS], + left_shift_scalar: E, + right_shift_scalar: E, + control_flow: E, + overflow: E, +} + /// Maps opcode of an operation to the index in its respective degree flag array. pub const fn get_op_index(opcode: u8) -> usize { let opcode = opcode as usize; @@ -961,6 +1031,18 @@ pub const fn get_op_index(opcode: u8) -> usize { } } +/// Prefix-sums an array of per-depth deltas in place. +/// +/// `result[d] = deltas[0] + deltas[1] + ... + deltas[d]` +fn accumulate_depth_deltas( + mut deltas: [E; N], +) -> [E; N] { + for i in 1..N { + deltas[i] = deltas[i - 1].clone() + deltas[i].clone(); + } + deltas +} + // TEST HELPERS // ================================================================================================ @@ -971,45 +1053,29 @@ pub const fn get_op_index(opcode: u8) -> usize { /// - Op bits extra columns are computed for degree reduction /// - All other columns are zero #[cfg(test)] -pub fn generate_test_row(opcode: usize) -> crate::MainTraceRow { - use miden_core::{ONE, ZERO}; +pub fn generate_test_row(opcode: usize) -> crate::MainCols { + use miden_core::{Felt, ZERO}; - use crate::trace::{ - CHIPLETS_WIDTH, DECODER_TRACE_WIDTH, RANGE_CHECK_TRACE_WIDTH, STACK_TRACE_WIDTH, - decoder::OP_BITS_EXTRA_COLS_RANGE, - }; + use crate::trace::{TRACE_WIDTH, decoder::OP_BITS_EXTRA_COLS_RANGE}; - // Get op bits for this opcode let op_bits = get_op_bits(opcode); - // Initialize decoder array with zeros - let mut decoder = [ZERO; DECODER_TRACE_WIDTH]; - - // Set op bits (indices 1-7 in decoder, after addr column at index 0) + // Build a flat zeroed row, then set the decoder op bits via the col map. + let mut row = [ZERO; TRACE_WIDTH]; for (i, &bit) in op_bits.iter().enumerate() { - decoder[OP_BITS_RANGE.start + i] = bit; + row[OP_BITS_RANGE.start + crate::trace::DECODER_TRACE_OFFSET + i] = bit; } - // Compute and set op bits extra columns for degree reduction + // Compute and set op bits extra columns for degree reduction. let bit_6 = op_bits[6]; let bit_5 = op_bits[5]; let bit_4 = op_bits[4]; + row[OP_BITS_EXTRA_COLS_RANGE.start + crate::trace::DECODER_TRACE_OFFSET] = + bit_6 * (Felt::ONE - bit_5) * bit_4; + row[OP_BITS_EXTRA_COLS_RANGE.start + 1 + crate::trace::DECODER_TRACE_OFFSET] = bit_6 * bit_5; - // op_bit_extra[0] = bit_6 * (1 - bit_5) * bit_4 (degree 5 flag) - decoder[OP_BITS_EXTRA_COLS_RANGE.start] = bit_6 * (ONE - bit_5) * bit_4; - - // op_bit_extra[1] = bit_6 * bit_5 (degree 4 flag) - decoder[OP_BITS_EXTRA_COLS_RANGE.start + 1] = bit_6 * bit_5; - - crate::MainTraceRow { - clk: ZERO, - ctx: ZERO, - fn_hash: [ZERO; 4], - decoder, - stack: [ZERO; STACK_TRACE_WIDTH], - range: [ZERO; RANGE_CHECK_TRACE_WIDTH], - chiplets: [ZERO; CHIPLETS_WIDTH], - } + // Safety: MainCols is #[repr(C)] with the same layout as [Felt; TRACE_WIDTH]. + unsafe { core::mem::transmute::<[Felt; TRACE_WIDTH], crate::MainCols>(row) } } /// Returns a 7-bit array representation of an opcode. @@ -1021,7 +1087,7 @@ pub fn get_op_bits(opcode: usize) -> [miden_core::Felt; NUM_OP_BITS] { let mut bit_array = [ZERO; NUM_OP_BITS]; for bit in bit_array.iter_mut() { - *bit = Felt::new((opcode_copy & 1) as u64); + *bit = Felt::new_unchecked((opcode_copy & 1) as u64); opcode_copy >>= 1; } diff --git a/air/src/constraints/op_flags/tests.rs b/air/src/constraints/op_flags/tests.rs index 9261f244b3..70a95a35b2 100644 --- a/air/src/constraints/op_flags/tests.rs +++ b/air/src/constraints/op_flags/tests.rs @@ -14,15 +14,14 @@ use super::{ NUM_DEGREE_4_OPS, NUM_DEGREE_5_OPS, NUM_DEGREE_6_OPS, NUM_DEGREE_7_OPS, OpFlags, generate_test_row, get_op_bits, get_op_index, }; -use crate::trace::decoder::IS_LOOP_FLAG_COL_IDX; - // HELPER // ================================================================================================ /// Creates OpFlags from an opcode using a generated test row. fn op_flags_for_opcode(opcode: usize) -> OpFlags { let row = generate_test_row(opcode); - OpFlags::new(&row) + let row_next = generate_test_row(0); // next row defaults to NOOP + OpFlags::new(&row.decoder, &row.stack, &row_next.decoder) } fn naive_flag(bits: &[Felt; 7], opcode: u8) -> Felt { @@ -186,35 +185,23 @@ fn degree_7_op_flags() { let expected_idx = get_op_index(opcode as u8); // Check degree 7 flags: exactly one should be ONE - for (i, &flag) in op_flags.degree7_op_flags().iter().enumerate() { + for (i, &flag) in op_flags.degree7_op_flags.iter().enumerate() { if i == expected_idx { - assert_eq!(flag, ONE, "Degree 7 flag {} should be ONE for opcode {}", i, opcode); + assert_eq!(flag, ONE, "Degree 7 flag {i} should be ONE for opcode {opcode}"); } else { - assert_eq!(flag, ZERO, "Degree 7 flag {} should be ZERO for opcode {}", i, opcode); + assert_eq!(flag, ZERO, "Degree 7 flag {i} should be ZERO for opcode {opcode}"); } } // All other degree flags should be ZERO - for (i, &flag) in op_flags.degree6_op_flags().iter().enumerate() { - assert_eq!( - flag, ZERO, - "Degree 6 flag {} should be ZERO for degree 7 opcode {}", - i, opcode - ); + for (i, &flag) in op_flags.degree6_op_flags.iter().enumerate() { + assert_eq!(flag, ZERO, "Degree 6 flag {i} should be ZERO for degree 7 opcode {opcode}"); } - for (i, &flag) in op_flags.degree5_op_flags().iter().enumerate() { - assert_eq!( - flag, ZERO, - "Degree 5 flag {} should be ZERO for degree 7 opcode {}", - i, opcode - ); + for (i, &flag) in op_flags.degree5_op_flags.iter().enumerate() { + assert_eq!(flag, ZERO, "Degree 5 flag {i} should be ZERO for degree 7 opcode {opcode}"); } - for (i, &flag) in op_flags.degree4_op_flags().iter().enumerate() { - assert_eq!( - flag, ZERO, - "Degree 4 flag {} should be ZERO for degree 7 opcode {}", - i, opcode - ); + for (i, &flag) in op_flags.degree4_op_flags.iter().enumerate() { + assert_eq!(flag, ZERO, "Degree 4 flag {i} should be ZERO for degree 7 opcode {opcode}"); } } } @@ -232,35 +219,23 @@ fn degree_6_op_flags() { let expected_idx = get_op_index(opcode as u8); // Check degree 6 flags - for (i, &flag) in op_flags.degree6_op_flags().iter().enumerate() { + for (i, &flag) in op_flags.degree6_op_flags.iter().enumerate() { if i == expected_idx { - assert_eq!(flag, ONE, "Degree 6 flag {} should be ONE for opcode {}", i, opcode); + assert_eq!(flag, ONE, "Degree 6 flag {i} should be ONE for opcode {opcode}"); } else { - assert_eq!(flag, ZERO, "Degree 6 flag {} should be ZERO for opcode {}", i, opcode); + assert_eq!(flag, ZERO, "Degree 6 flag {i} should be ZERO for opcode {opcode}"); } } // All other degree flags should be ZERO - for (i, &flag) in op_flags.degree7_op_flags().iter().enumerate() { - assert_eq!( - flag, ZERO, - "Degree 7 flag {} should be ZERO for degree 6 opcode {}", - i, opcode - ); + for (i, &flag) in op_flags.degree7_op_flags.iter().enumerate() { + assert_eq!(flag, ZERO, "Degree 7 flag {i} should be ZERO for degree 6 opcode {opcode}"); } - for (i, &flag) in op_flags.degree5_op_flags().iter().enumerate() { - assert_eq!( - flag, ZERO, - "Degree 5 flag {} should be ZERO for degree 6 opcode {}", - i, opcode - ); + for (i, &flag) in op_flags.degree5_op_flags.iter().enumerate() { + assert_eq!(flag, ZERO, "Degree 5 flag {i} should be ZERO for degree 6 opcode {opcode}"); } - for (i, &flag) in op_flags.degree4_op_flags().iter().enumerate() { - assert_eq!( - flag, ZERO, - "Degree 4 flag {} should be ZERO for degree 6 opcode {}", - i, opcode - ); + for (i, &flag) in op_flags.degree4_op_flags.iter().enumerate() { + assert_eq!(flag, ZERO, "Degree 4 flag {i} should be ZERO for degree 6 opcode {opcode}"); } } } @@ -277,35 +252,23 @@ fn degree_5_op_flags() { let expected_idx = get_op_index(opcode as u8); // Check degree 5 flags - for (i, &flag) in op_flags.degree5_op_flags().iter().enumerate() { + for (i, &flag) in op_flags.degree5_op_flags.iter().enumerate() { if i == expected_idx { - assert_eq!(flag, ONE, "Degree 5 flag {} should be ONE for opcode {}", i, opcode); + assert_eq!(flag, ONE, "Degree 5 flag {i} should be ONE for opcode {opcode}"); } else { - assert_eq!(flag, ZERO, "Degree 5 flag {} should be ZERO for opcode {}", i, opcode); + assert_eq!(flag, ZERO, "Degree 5 flag {i} should be ZERO for opcode {opcode}"); } } // All other degree flags should be ZERO - for (i, &flag) in op_flags.degree7_op_flags().iter().enumerate() { - assert_eq!( - flag, ZERO, - "Degree 7 flag {} should be ZERO for degree 5 opcode {}", - i, opcode - ); + for (i, &flag) in op_flags.degree7_op_flags.iter().enumerate() { + assert_eq!(flag, ZERO, "Degree 7 flag {i} should be ZERO for degree 5 opcode {opcode}"); } - for (i, &flag) in op_flags.degree6_op_flags().iter().enumerate() { - assert_eq!( - flag, ZERO, - "Degree 6 flag {} should be ZERO for degree 5 opcode {}", - i, opcode - ); + for (i, &flag) in op_flags.degree6_op_flags.iter().enumerate() { + assert_eq!(flag, ZERO, "Degree 6 flag {i} should be ZERO for degree 5 opcode {opcode}"); } - for (i, &flag) in op_flags.degree4_op_flags().iter().enumerate() { - assert_eq!( - flag, ZERO, - "Degree 4 flag {} should be ZERO for degree 5 opcode {}", - i, opcode - ); + for (i, &flag) in op_flags.degree4_op_flags.iter().enumerate() { + assert_eq!(flag, ZERO, "Degree 4 flag {i} should be ZERO for degree 5 opcode {opcode}"); } } } @@ -321,17 +284,17 @@ fn optimized_flags_match_naive() { let (deg7, deg6, deg5, deg4) = naive_op_flags(bits); let op_flags = op_flags_for_opcode(opcode); - for (i, &flag) in op_flags.degree7_op_flags().iter().enumerate() { - assert_eq!(flag, deg7[i], "degree7 flag mismatch at index {}", i); + for (i, &flag) in op_flags.degree7_op_flags.iter().enumerate() { + assert_eq!(flag, deg7[i], "degree7 flag mismatch at index {i}"); } - for (i, &flag) in op_flags.degree6_op_flags().iter().enumerate() { - assert_eq!(flag, deg6[i], "degree6 flag mismatch at index {}", i); + for (i, &flag) in op_flags.degree6_op_flags.iter().enumerate() { + assert_eq!(flag, deg6[i], "degree6 flag mismatch at index {i}"); } - for (i, &flag) in op_flags.degree5_op_flags().iter().enumerate() { - assert_eq!(flag, deg5[i], "degree5 flag mismatch at index {}", i); + for (i, &flag) in op_flags.degree5_op_flags.iter().enumerate() { + assert_eq!(flag, deg5[i], "degree5 flag mismatch at index {i}"); } - for (i, &flag) in op_flags.degree4_op_flags().iter().enumerate() { - assert_eq!(flag, deg4[i], "degree4 flag mismatch at index {}", i); + for (i, &flag) in op_flags.degree4_op_flags.iter().enumerate() { + assert_eq!(flag, deg4[i], "degree4 flag mismatch at index {i}"); } let (left_shift_flag, right_shift_flag, control_flow) = @@ -356,35 +319,23 @@ fn degree_4_op_flags() { let expected_idx = get_op_index(opcode as u8); // Check degree 4 flags - for (i, &flag) in op_flags.degree4_op_flags().iter().enumerate() { + for (i, &flag) in op_flags.degree4_op_flags.iter().enumerate() { if i == expected_idx { - assert_eq!(flag, ONE, "Degree 4 flag {} should be ONE for opcode {}", i, opcode); + assert_eq!(flag, ONE, "Degree 4 flag {i} should be ONE for opcode {opcode}"); } else { - assert_eq!(flag, ZERO, "Degree 4 flag {} should be ZERO for opcode {}", i, opcode); + assert_eq!(flag, ZERO, "Degree 4 flag {i} should be ZERO for opcode {opcode}"); } } // All other degree flags should be ZERO - for (i, &flag) in op_flags.degree7_op_flags().iter().enumerate() { - assert_eq!( - flag, ZERO, - "Degree 7 flag {} should be ZERO for degree 4 opcode {}", - i, opcode - ); + for (i, &flag) in op_flags.degree7_op_flags.iter().enumerate() { + assert_eq!(flag, ZERO, "Degree 7 flag {i} should be ZERO for degree 4 opcode {opcode}"); } - for (i, &flag) in op_flags.degree6_op_flags().iter().enumerate() { - assert_eq!( - flag, ZERO, - "Degree 6 flag {} should be ZERO for degree 4 opcode {}", - i, opcode - ); + for (i, &flag) in op_flags.degree6_op_flags.iter().enumerate() { + assert_eq!(flag, ZERO, "Degree 6 flag {i} should be ZERO for degree 4 opcode {opcode}"); } - for (i, &flag) in op_flags.degree5_op_flags().iter().enumerate() { - assert_eq!( - flag, ZERO, - "Degree 5 flag {} should be ZERO for degree 4 opcode {}", - i, opcode - ); + for (i, &flag) in op_flags.degree5_op_flags.iter().enumerate() { + assert_eq!(flag, ZERO, "Degree 5 flag {i} should be ZERO for degree 4 opcode {opcode}"); } } } @@ -407,9 +358,7 @@ fn composite_no_shift_flags() { assert_eq!( op_flags.no_shift_at(i), ONE, - "no_shift_at({}) should be ONE for opcode {:?}", - i, - opcode + "no_shift_at({i}) should be ONE for opcode {opcode:?}" ); } @@ -427,7 +376,7 @@ fn composite_incr_flags() { // Position 0 changes, positions 1-15 don't assert_eq!(op_flags.no_shift_at(0), ZERO); for i in 1..16 { - assert_eq!(op_flags.no_shift_at(i), ONE, "no_shift_at({}) should be ONE for INCR", i); + assert_eq!(op_flags.no_shift_at(i), ONE, "no_shift_at({i}) should be ONE for INCR"); } assert_eq!(op_flags.right_shift(), ZERO); @@ -442,7 +391,7 @@ fn composite_swap_flags() { assert_eq!(op_flags.no_shift_at(0), ZERO); assert_eq!(op_flags.no_shift_at(1), ZERO); for i in 2..16 { - assert_eq!(op_flags.no_shift_at(i), ONE, "no_shift_at({}) should be ONE for SWAP", i); + assert_eq!(op_flags.no_shift_at(i), ONE, "no_shift_at({i}) should be ONE for SWAP"); } assert_eq!(op_flags.right_shift(), ZERO); @@ -455,10 +404,10 @@ fn composite_hperm_flags() { let op_flags = op_flags_for_opcode(opcodes::HPERM.into()); for i in 0..12 { - assert_eq!(op_flags.no_shift_at(i), ZERO, "no_shift_at({}) should be ZERO for HPERM", i); + assert_eq!(op_flags.no_shift_at(i), ZERO, "no_shift_at({i}) should be ZERO for HPERM"); } for i in 12..16 { - assert_eq!(op_flags.no_shift_at(i), ONE, "no_shift_at({}) should be ONE for HPERM", i); + assert_eq!(op_flags.no_shift_at(i), ONE, "no_shift_at({i}) should be ONE for HPERM"); } assert_eq!(op_flags.right_shift(), ZERO); @@ -473,7 +422,7 @@ fn composite_loop_left_shift() { assert_eq!(op_flags.left_shift_at(0), ZERO); // LOOP shifts the stack left for i in 1..16 { - assert_eq!(op_flags.left_shift_at(i), ONE, "left_shift_at({}) should be ONE for LOOP", i); + assert_eq!(op_flags.left_shift_at(i), ONE, "left_shift_at({i}) should be ONE for LOOP"); } for i in 0..16 { assert_eq!(op_flags.no_shift_at(i), ZERO); @@ -493,7 +442,7 @@ fn composite_and_left_shift() { assert_eq!(op_flags.left_shift_at(0), ZERO); assert_eq!(op_flags.left_shift_at(1), ZERO); for i in 2..16 { - assert_eq!(op_flags.left_shift_at(i), ONE, "left_shift_at({}) should be ONE for AND", i); + assert_eq!(op_flags.left_shift_at(i), ONE, "left_shift_at({i}) should be ONE for AND"); } assert_eq!(op_flags.left_shift(), ONE); @@ -507,7 +456,7 @@ fn composite_dup1_right_shift() { // DUP1 shifts the entire stack right for i in 0..=15 { - assert_eq!(op_flags.right_shift_at(i), ONE, "right_shift_at({}) should be ONE for DUP1", i); + assert_eq!(op_flags.right_shift_at(i), ONE, "right_shift_at({i}) should be ONE for DUP1"); } for i in 0..16 { assert_eq!(op_flags.no_shift_at(i), ZERO); @@ -524,7 +473,7 @@ fn composite_push_right_shift() { // PUSH shifts the entire stack right for i in 0..=15 { - assert_eq!(op_flags.right_shift_at(i), ONE, "right_shift_at({}) should be ONE for PUSH", i); + assert_eq!(op_flags.right_shift_at(i), ONE, "right_shift_at({i}) should be ONE for PUSH"); } assert_eq!(op_flags.right_shift(), ONE); @@ -541,8 +490,7 @@ fn composite_end_flags() { assert_eq!( op_flags.no_shift_at(i), ONE, - "no_shift_at({}) should be ONE for END (no loop)", - i + "no_shift_at({i}) should be ONE for END (no loop)" ); } assert_eq!(op_flags.left_shift(), ZERO); @@ -550,23 +498,22 @@ fn composite_end_flags() { // END with loop flag: left shift (need to modify the row) let mut row = generate_test_row(opcodes::END.into()); - row.decoder[IS_LOOP_FLAG_COL_IDX] = ONE; - let op_flags_loop = OpFlags::new(&row); + row.decoder.hasher_state[5] = ONE; // is_loop flag + let row_next = generate_test_row(0); + let op_flags_loop: OpFlags = OpFlags::new(&row.decoder, &row.stack, &row_next.decoder); for i in 0..16 { assert_eq!( op_flags_loop.no_shift_at(i), ZERO, - "no_shift_at({}) should be ZERO for END (with loop)", - i + "no_shift_at({i}) should be ZERO for END (with loop)" ); } for i in 1..16 { assert_eq!( op_flags_loop.left_shift_at(i), ONE, - "left_shift_at({}) should be ONE for END (with loop)", - i + "left_shift_at({i}) should be ONE for END (with loop)" ); } assert_eq!(op_flags_loop.left_shift(), ONE); @@ -580,10 +527,10 @@ fn composite_swapw2_flags() { // Positions 4-7 and 12-15 should be no_shift (words that stay in place) for i in [0, 1, 2, 3, 8, 9, 10, 11] { - assert_eq!(op_flags.no_shift_at(i), ZERO, "no_shift_at({}) should be ZERO for SWAPW2", i); + assert_eq!(op_flags.no_shift_at(i), ZERO, "no_shift_at({i}) should be ZERO for SWAPW2"); } for i in [4, 5, 6, 7, 12, 13, 14, 15] { - assert_eq!(op_flags.no_shift_at(i), ONE, "no_shift_at({}) should be ONE for SWAPW2", i); + assert_eq!(op_flags.no_shift_at(i), ONE, "no_shift_at({i}) should be ONE for SWAPW2"); } assert_eq!(op_flags.right_shift(), ZERO); @@ -625,7 +572,7 @@ fn control_flow_flag() { for op in non_cf_ops { let op_flags = op_flags_for_opcode(op.op_code().into()); - assert_eq!(op_flags.control_flow(), ZERO, "control_flow should be ZERO for {:?}", op); + assert_eq!(op_flags.control_flow(), ZERO, "control_flow should be ZERO for {op:?}"); } } @@ -651,36 +598,3 @@ proptest! { } } } - -/// Tests u32_rc_op flag for u32 operations. -#[test] -fn u32_rc_op_flag() { - // U32 operations that require range checks (degree 6) - let u32_ops = [ - Operation::U32add, - Operation::U32sub, - Operation::U32mul, - Operation::U32div, - Operation::U32split, - Operation::U32assert2(ZERO), - Operation::U32add3, - Operation::U32madd, - ]; - - for op in u32_ops { - let op_flags = op_flags_for_opcode(op.op_code().into()); - assert_eq!(op_flags.u32_rc_op(), ONE, "u32_rc_op should be ONE for {:?}", op); - } - - // Non-u32 operations - let non_u32_ops = [ - Operation::Add, - Operation::Mul, - Operation::And, // Bitwise AND is degree 7, not u32 - ]; - - for op in non_u32_ops { - let op_flags = op_flags_for_opcode(op.op_code().into()); - assert_eq!(op_flags.u32_rc_op(), ZERO, "u32_rc_op should be ZERO for {:?}", op); - } -} diff --git a/air/src/constraints/public_inputs.rs b/air/src/constraints/public_inputs.rs index 47f21c9beb..ebc2ffc2c8 100644 --- a/air/src/constraints/public_inputs.rs +++ b/air/src/constraints/public_inputs.rs @@ -4,12 +4,9 @@ //! - First row: stack[0..16] == stack_inputs[0..16] //! - Last row: stack[0..16] == stack_outputs[0..16] -use miden_crypto::stark::air::{AirBuilder, LiftedAirBuilder}; +use miden_crypto::stark::air::AirBuilder; -use crate::{ - MainTraceRow, - constraints::tagging::{TaggingAirBuilderExt, ids::TAG_PUBLIC_INPUTS_BASE}, -}; +use crate::{MainCols, MidenAirBuilder}; // CONSTANTS // ================================================================================================ @@ -20,12 +17,6 @@ const STACK_DEPTH: usize = 16; /// (stack_inputs + stack_outputs + pc_transcript_state). const TAIL_LEN: usize = STACK_DEPTH + STACK_DEPTH + 4; -// TAGGING CONSTANTS -// ================================================================================================ - -const STACK_INPUT_NAMESPACE: &str = "public_inputs.stack_input"; -const STACK_OUTPUT_NAMESPACE: &str = "public_inputs.stack_output"; - // ENTRY POINTS // ================================================================================================ @@ -33,9 +24,9 @@ const STACK_OUTPUT_NAMESPACE: &str = "public_inputs.stack_output"; /// /// - First row: `stack[i] == stack_inputs[i]` for i in 0..16 /// - Last row: `stack[i] == stack_outputs[i]` for i in 0..16 -pub fn enforce_main(builder: &mut AB, local: &MainTraceRow) +pub fn enforce_main(builder: &mut AB, local: &MainCols) where - AB: LiftedAirBuilder, + AB: MidenAirBuilder, { // Copy public values into local arrays to release the immutable borrow on builder. let pv = builder.public_values(); @@ -46,27 +37,20 @@ where core::array::from_fn(|i| pv[n - TAIL_LEN + STACK_DEPTH + i]); // First row: stack[i] == stack_inputs[i] - let input_ids: [usize; STACK_DEPTH] = core::array::from_fn(|i| TAG_PUBLIC_INPUTS_BASE + i); - builder.tagged_list(input_ids, STACK_INPUT_NAMESPACE, |builder| { - builder - .when_first_row() - .assert_zeros(core::array::from_fn::<_, STACK_DEPTH, _>(|i| { - let stack_i: AB::Expr = local.stack[i].clone().into(); - let pv_i: AB::Expr = si[i].into(); - stack_i - pv_i - })); - }); + { + let builder = &mut builder.when_first_row(); + #[allow(clippy::needless_range_loop)] + for i in 0..STACK_DEPTH { + builder.assert_eq(local.stack.get(i), si[i]); + } + } // Last row: stack[i] == stack_outputs[i] - let output_ids: [usize; STACK_DEPTH] = - core::array::from_fn(|i| TAG_PUBLIC_INPUTS_BASE + STACK_DEPTH + i); - builder.tagged_list(output_ids, STACK_OUTPUT_NAMESPACE, |builder| { - builder - .when_last_row() - .assert_zeros(core::array::from_fn::<_, STACK_DEPTH, _>(|i| { - let stack_i: AB::Expr = local.stack[i].clone().into(); - let pv_i: AB::Expr = so[i].into(); - stack_i - pv_i - })); - }); + { + let builder = &mut builder.when_last_row(); + #[allow(clippy::needless_range_loop)] + for i in 0..STACK_DEPTH { + builder.assert_eq(local.stack.get(i), so[i]); + } + } } diff --git a/air/src/constraints/range/bus.rs b/air/src/constraints/range/bus.rs deleted file mode 100644 index 07f4e6dcb6..0000000000 --- a/air/src/constraints/range/bus.rs +++ /dev/null @@ -1,144 +0,0 @@ -//! Range checker bus constraint. -//! -//! This module enforces the LogUp protocol for the range checker bus (b_range). -//! The range checker validates that values are within [0, 2^16) by tracking requests -//! from stack and memory components against the range table responses. -//! -//! ## LogUp Protocol -//! -//! The bus accumulator b_range uses the LogUp protocol: -//! - Boundary: b_range[0] = 0 and b_range[last] = 0 (enforced by the wrapper AIR) -//! - Transition: b_range' = b_range + responses - requests -//! -//! Where requests come from stack (4 lookups) and memory (2 lookups), and -//! responses come from the range table (V column with multiplicity). - -use miden_core::field::PrimeCharacteristicRing; -use miden_crypto::stark::air::{ExtensionBuilder, LiftedAirBuilder, WindowAccess}; - -use crate::{ - MainTraceRow, - constraints::tagging::{TaggingAirBuilderExt, ids::TAG_RANGE_BUS_BASE}, - trace::{ - CHIPLET_S0_COL_IDX, CHIPLET_S1_COL_IDX, CHIPLET_S2_COL_IDX, CHIPLETS_OFFSET, - RANGE_CHECK_TRACE_OFFSET, chiplets, decoder, range, - }, -}; - -// CONSTANTS -// ================================================================================================ - -// --- SLICE-RELATIVE INDICES --------------------------------------------------------------------- -const STACK_LOOKUP_BASE: usize = decoder::USER_OP_HELPERS_OFFSET; -const OP_BIT_4_COL_IDX: usize = decoder::OP_BITS_RANGE.start + 4; -const OP_BIT_5_COL_IDX: usize = decoder::OP_BITS_RANGE.start + 5; -const OP_BIT_6_COL_IDX: usize = decoder::OP_BITS_RANGE.start + 6; -const CHIPLET_S0_IDX: usize = CHIPLET_S0_COL_IDX - CHIPLETS_OFFSET; -const CHIPLET_S1_IDX: usize = CHIPLET_S1_COL_IDX - CHIPLETS_OFFSET; -const CHIPLET_S2_IDX: usize = CHIPLET_S2_COL_IDX - CHIPLETS_OFFSET; -const MEMORY_D0_IDX: usize = chiplets::MEMORY_D0_COL_IDX - CHIPLETS_OFFSET; -const MEMORY_D1_IDX: usize = chiplets::MEMORY_D1_COL_IDX - CHIPLETS_OFFSET; -const RANGE_M_COL_IDX: usize = range::M_COL_IDX - RANGE_CHECK_TRACE_OFFSET; -const RANGE_V_COL_IDX: usize = range::V_COL_IDX - RANGE_CHECK_TRACE_OFFSET; - -// TAGGING CONSTANTS -// ================================================================================================ - -const RANGE_BUS_NAME: &str = "range.bus.transition"; - -// ENTRY POINTS -// ================================================================================================ - -/// Enforces the range checker bus constraint for LogUp checks. -/// -/// This constraint tracks range check requests from other components (stack and memory) -/// using the LogUp protocol. The bus accumulator b_range must start and end at 0, -/// and transition according to the LogUp update rule. -/// -/// ## Constraint Degree -/// -/// This is a degree-9 constraint. -/// -/// ## Lookups -/// -/// - Stack lookups (4): decoder helper columns (USER_OP_HELPERS_OFFSET..+4) -/// - Memory lookups (2): memory delta limbs (MEMORY_D0, MEMORY_D1) -/// - Range response: range V column with multiplicity range M column -pub fn enforce_bus(builder: &mut AB, local: &MainTraceRow) -where - AB: LiftedAirBuilder, -{ - // In Miden VM, auxiliary trace is always present - - // Extract values needed for constraints - let aux = builder.permutation(); - let aux_local = aux.current_slice(); - let aux_next = aux.next_slice(); - let b_local = aux_local[range::B_RANGE_COL_IDX]; - let b_next = aux_next[range::B_RANGE_COL_IDX]; - - let challenges = builder.permutation_randomness(); - let alpha = challenges[0]; - - // Denominators for LogUp - // Memory lookups: mv0 = alpha + chiplets[MEMORY_D0], mv1 = alpha + chiplets[MEMORY_D1] - let mv0: AB::ExprEF = alpha.into() + local.chiplets[MEMORY_D0_IDX].clone().into(); - let mv1: AB::ExprEF = alpha.into() + local.chiplets[MEMORY_D1_IDX].clone().into(); - - // Stack lookups: sv0-sv3 = alpha + decoder helper columns - let sv0: AB::ExprEF = alpha.into() + local.decoder[STACK_LOOKUP_BASE].clone().into(); - let sv1: AB::ExprEF = alpha.into() + local.decoder[STACK_LOOKUP_BASE + 1].clone().into(); - let sv2: AB::ExprEF = alpha.into() + local.decoder[STACK_LOOKUP_BASE + 2].clone().into(); - let sv3: AB::ExprEF = alpha.into() + local.decoder[STACK_LOOKUP_BASE + 3].clone().into(); - - // Range check value: alpha + range V column - let range_check: AB::ExprEF = alpha.into() + local.range[RANGE_V_COL_IDX].clone().into(); - - // Combined lookup denominators - let memory_lookups = mv0.clone() * mv1.clone(); - let stack_lookups = sv0.clone() * sv1.clone() * sv2.clone() * sv3.clone(); - let lookups = range_check.clone() * stack_lookups.clone() * memory_lookups.clone(); - - // Flags for conditional inclusion - // u32_rc_op = op_bit[6] * (1 - op_bit[5]) * (1 - op_bit[4]) - let not_4: AB::Expr = AB::Expr::ONE - local.decoder[OP_BIT_4_COL_IDX].clone().into(); - let not_5: AB::Expr = AB::Expr::ONE - local.decoder[OP_BIT_5_COL_IDX].clone().into(); - let u32_rc_op: AB::Expr = local.decoder[OP_BIT_6_COL_IDX].clone().into() * not_5 * not_4; - let sflag_rc_mem = range_check.clone() * memory_lookups.clone() * u32_rc_op; - - // chiplets_memory_flag = s0 * s1 * (1 - s2) - let s_0: AB::Expr = local.chiplets[CHIPLET_S0_IDX].clone().into(); - let s_1: AB::Expr = local.chiplets[CHIPLET_S1_IDX].clone().into(); - let s_2: AB::Expr = local.chiplets[CHIPLET_S2_IDX].clone().into(); - let chiplets_memory_flag: AB::Expr = s_0 * s_1 * (AB::Expr::ONE - s_2); - let mflag_rc_stack = range_check * stack_lookups.clone() * chiplets_memory_flag; - - // LogUp transition constraint terms - let b_next_term = b_next.into() * lookups.clone(); - let b_term = b_local.into() * lookups; - let rc_term = stack_lookups * memory_lookups * local.range[RANGE_M_COL_IDX].clone().into(); - - // Stack lookup removal terms - let s0_term = sflag_rc_mem.clone() * sv1.clone() * sv2.clone() * sv3.clone(); - let s1_term = sflag_rc_mem.clone() * sv0.clone() * sv2.clone() * sv3.clone(); - let s2_term = sflag_rc_mem.clone() * sv0.clone() * sv1.clone() * sv3; - let s3_term = sflag_rc_mem * sv0 * sv1 * sv2; - - // Memory lookup removal terms - let m0_term: AB::ExprEF = mflag_rc_stack.clone() * mv1; - let m1_term = mflag_rc_stack * mv0; - - // Main constraint: b_next * lookups = b * lookups + rc_term - s0_term - s1_term - s2_term - - // s3_term - m0_term - m1_term - builder.tagged(TAG_RANGE_BUS_BASE, RANGE_BUS_NAME, |builder| { - builder.when_transition().assert_zero_ext( - b_next_term - b_term - rc_term - + s0_term - + s1_term - + s2_term - + s3_term - + m0_term - + m1_term, - ); - }); -} diff --git a/air/src/constraints/range/columns.rs b/air/src/constraints/range/columns.rs new file mode 100644 index 0000000000..57b6116194 --- /dev/null +++ b/air/src/constraints/range/columns.rs @@ -0,0 +1,8 @@ +/// Range check columns in the main execution trace (2 columns). +#[repr(C)] +pub struct RangeCols { + /// Multiplicity: how many times this value is range-checked. + pub multiplicity: T, + /// The value being range-checked. + pub value: T, +} diff --git a/air/src/constraints/range/mod.rs b/air/src/constraints/range/mod.rs index 3d8a684455..696ecc02dc 100644 --- a/air/src/constraints/range/mod.rs +++ b/air/src/constraints/range/mod.rs @@ -6,109 +6,45 @@ //! //! Bus constraints for the range checker are in `bus`. -use miden_core::field::PrimeCharacteristicRing; -use miden_crypto::stark::air::{AirBuilder, LiftedAirBuilder}; +pub mod columns; -use crate::{ - MainTraceRow, - constraints::tagging::{ - TaggingAirBuilderExt, - ids::{TAG_RANGE_MAIN_BASE, TAG_RANGE_MAIN_COUNT}, - }, - trace::{RANGE_CHECK_TRACE_OFFSET, range}, -}; +use miden_crypto::stark::air::AirBuilder; -pub mod bus; - -// CONSTANTS -// ================================================================================================ - -// --- SLICE-RELATIVE INDICES --------------------------------------------------------------------- -const RANGE_V_COL_IDX: usize = range::V_COL_IDX - RANGE_CHECK_TRACE_OFFSET; - -// TAGGING CONSTANTS -// ================================================================================================ - -const RANGE_MAIN_NAMES: [&str; TAG_RANGE_MAIN_COUNT] = - ["range.main.v.first_row", "range.main.v.last_row", "range.main.v.transition"]; +use crate::{MainCols, MidenAirBuilder, constraints::constants::*}; // ENTRY POINTS // ================================================================================================ /// Enforces range checker main-trace constraints. -pub fn enforce_main( - builder: &mut AB, - local: &MainTraceRow, - next: &MainTraceRow, -) where - AB: LiftedAirBuilder, -{ - enforce_range_boundary_constraints(builder, local); - enforce_range_transition_constraint(builder, local, next); -} - -/// Enforces boundary constraints for the range checker. -/// -/// - First row: V[0] = 0 (range checker starts at 0) -/// - Last row: V[last] = 65535 (range checker ends at 2^16 - 1) -pub fn enforce_range_boundary_constraints(builder: &mut AB, local: &MainTraceRow) +pub fn enforce_main(builder: &mut AB, local: &MainCols, next: &MainCols) where - AB: LiftedAirBuilder, -{ - let v = local.range[RANGE_V_COL_IDX].clone(); - - // First row: V[0] = 0 - builder.tagged(TAG_RANGE_MAIN_BASE, RANGE_MAIN_NAMES[0], |builder| { - builder.when_first_row().assert_zero(v.clone()); - }); - - // Last row: V[last] = 65535 (2^16 - 1) - let sixty_five_k = AB::Expr::from_u32(65535); - builder.tagged(TAG_RANGE_MAIN_BASE + 1, RANGE_MAIN_NAMES[1], |builder| { - builder.when_last_row().assert_eq(v, sixty_five_k); - }); -} - -/// Enforces the transition constraint for the range checker V column. -/// -/// The V column must change by one of: {0, 1, 3, 9, 27, 81, 243, 729, 2187} -/// - 0 allows V to stay constant during padding rows -/// - Others are powers of 3: {3^0, 3^1, 3^2, 3^3, 3^4, 3^5, 3^6, 3^7} -/// -/// This is a degree-9 constraint. -pub fn enforce_range_transition_constraint( - builder: &mut AB, - local: &MainTraceRow, - next: &MainTraceRow, -) where - AB: LiftedAirBuilder, + AB: MidenAirBuilder, { - let v = local.range[RANGE_V_COL_IDX].clone(); - let v_next = next.range[RANGE_V_COL_IDX].clone(); - let change_v = v_next - v; - - // Powers of 3: {1, 3, 9, 27, 81, 243, 729, 2187} - let one_expr = AB::Expr::ONE; - let three = AB::Expr::from_u16(3); - let nine = AB::Expr::from_u16(9); - let twenty_seven = AB::Expr::from_u16(27); - let eighty_one = AB::Expr::from_u16(81); - let two_forty_three = AB::Expr::from_u16(243); - let seven_twenty_nine = AB::Expr::from_u16(729); - let two_one_eight_seven = AB::Expr::from_u16(2187); - - // Note: Extra factor of change_v allows V to stay constant (change_v = 0) during padding - builder.tagged(TAG_RANGE_MAIN_BASE + 2, RANGE_MAIN_NAMES[2], |builder| { + let v = local.range.value; + let v_next = next.range.value; + + // Range checker boundaries: V[0] = 0, V[last] = 2^16 - 1 + { + builder.when_first_row().assert_zero(v); + builder.when_last_row().assert_eq(v, TWO_POW_16_MINUS_1); + } + + // Transition constraint for the V column (degree 9). + // V must change by one of: {0, 1, 3, 9, 27, 81, 243, 729, 2187} + // - 0 allows V to stay constant during padding rows + // - Others are powers of 3: {3^0, 3^1, 3^2, 3^3, 3^4, 3^5, 3^6, 3^7} + { + let change_v = v_next - v; builder.when_transition().assert_zero( change_v.clone() - * (change_v.clone() - one_expr) - * (change_v.clone() - three) - * (change_v.clone() - nine) - * (change_v.clone() - twenty_seven) - * (change_v.clone() - eighty_one) - * (change_v.clone() - two_forty_three) - * (change_v.clone() - seven_twenty_nine) - * (change_v - two_one_eight_seven), + * (change_v.clone() - F_1) + * (change_v.clone() - F_3) + * (change_v.clone() - F_9) + * (change_v.clone() - F_27) + * (change_v.clone() - F_81) + * (change_v.clone() - F_243) + * (change_v.clone() - F_729) + * (change_v - F_2187), ); - }); + } } diff --git a/air/src/constraints/stack/bus.rs b/air/src/constraints/stack/bus.rs deleted file mode 100644 index f22d8ddb44..0000000000 --- a/air/src/constraints/stack/bus.rs +++ /dev/null @@ -1,148 +0,0 @@ -//! Stack overflow table bus constraint. -//! -//! This module enforces the running product constraint for the stack overflow table (p1). -//! The stack overflow table tracks values that overflow from the 16-element operand stack. -//! -//! The bus accumulator p1 uses a multiset check: -//! - Boundary: p1[0] = 1 and p1[last] = 1 (enforced by the wrapper AIR) -//! - Transition: p1' * requests = p1 * responses -//! -//! Where: -//! - Responses (adding rows): When right_shift, a row is added with (clk, s15, b1) -//! - Requests (removing rows): When (left_shift OR dyncall) AND non_empty_overflow, a row is -//! removed with (b1, s15', b1') or (b1, s15', hasher_state[5]) for dyncall -//! -//! ## Row Encoding -//! -//! Each row in the overflow table is encoded as: -//! `alpha + beta^0 * clk + beta^1 * val + beta^2 * prev` - -use miden_core::field::PrimeCharacteristicRing; -use miden_crypto::stark::air::{ExtensionBuilder, LiftedAirBuilder, WindowAccess}; - -use crate::{ - MainTraceRow, - constraints::{ - bus::indices::P1_STACK, - op_flags::OpFlags, - tagging::{TaggingAirBuilderExt, ids::TAG_STACK_OVERFLOW_BUS_BASE}, - }, - trace::{ - Challenges, - decoder::HASHER_STATE_RANGE, - stack::{B0_COL_IDX, B1_COL_IDX, H0_COL_IDX}, - }, -}; - -/// Tag ID and namespace for the stack overflow bus transition constraint. -const STACK_OVERFLOW_BUS_ID: usize = TAG_STACK_OVERFLOW_BUS_BASE; -const STACK_OVERFLOW_BUS_NAME: &str = "stack.overflow.bus.transition"; - -// ENTRY POINTS -// ================================================================================================ - -/// Enforces the stack overflow table bus constraint. -/// -/// This constraint tracks overflow table operations using a running product: -/// - Adding rows when right_shift (element pushed off stack position 15) -/// - Removing rows when (left_shift OR dyncall) AND overflow is non-empty -pub fn enforce_bus( - builder: &mut AB, - local: &MainTraceRow, - next: &MainTraceRow, - op_flags: &OpFlags, - challenges: &Challenges, -) where - AB: LiftedAirBuilder, -{ - // Auxiliary trace must be present. - - // Extract auxiliary trace values. - let (p1_local, p1_next) = { - let aux = builder.permutation(); - let aux_local = aux.current_slice(); - let aux_next = aux.next_slice(); - (aux_local[P1_STACK], aux_next[P1_STACK]) - }; - - let one_ef = AB::ExprEF::ONE; - - // ============================================================================================ - // TRANSITION CONSTRAINT - // ============================================================================================ - - // ------------------------------------------------------------------------- - // Stack and bookkeeping column values - // ------------------------------------------------------------------------- - - // Current row values - let clk: AB::Expr = local.clk.clone().into(); - let s15: AB::Expr = local.stack[15].clone().into(); - let b0: AB::Expr = local.stack[B0_COL_IDX].clone().into(); - let b1: AB::Expr = local.stack[B1_COL_IDX].clone().into(); - let h0: AB::Expr = local.stack[H0_COL_IDX].clone().into(); - - // Next row values (needed for removal) - let s15_next: AB::Expr = next.stack[15].clone().into(); - let b1_next: AB::Expr = next.stack[B1_COL_IDX].clone().into(); - - // Hasher state element 5, used by DYNCALL to store the new overflow table pointer. - let hasher_state_5: AB::Expr = local.decoder[HASHER_STATE_RANGE.start + 5].clone().into(); - - // ------------------------------------------------------------------------- - // Overflow condition: (b0 - 16) * h0 = 1 when overflow is non-empty - // ------------------------------------------------------------------------- - - let sixteen = AB::Expr::from_u16(16); - let is_non_empty_overflow: AB::Expr = (b0 - sixteen) * h0; - - // ------------------------------------------------------------------------- - // Operation flags - // ------------------------------------------------------------------------- - - let right_shift = op_flags.right_shift(); - let left_shift = op_flags.left_shift(); - let dyncall = op_flags.dyncall(); - - // ------------------------------------------------------------------------- - // Row value encoding: alpha + beta^0 * clk + beta^1 * val + beta^2 * prev - // ------------------------------------------------------------------------- - - // Response row value (adding to table during right_shift): - let response_row = challenges.encode([clk.clone(), s15.clone(), b1.clone()]); - - // Request row value for left_shift (removing from table): - let request_row_left = challenges.encode([b1.clone(), s15_next.clone(), b1_next.clone()]); - - // Request row value for dyncall (removing from table): - let request_row_dyncall = - challenges.encode([b1.clone(), s15_next.clone(), hasher_state_5.clone()]); - - // ------------------------------------------------------------------------- - // Compute response and request terms - // ------------------------------------------------------------------------- - - // Response: right_shift * response_row + (1 - right_shift) - let response: AB::ExprEF = response_row * right_shift.clone() + (one_ef.clone() - right_shift); - - // Request flags - let left_flag: AB::Expr = left_shift * is_non_empty_overflow.clone(); - let dyncall_flag: AB::Expr = dyncall * is_non_empty_overflow; - let request_flag_sum: AB::Expr = left_flag.clone() + dyncall_flag.clone(); - - // Request: left_flag * left_value + dyncall_flag * dyncall_value + (1 - sum(flags)) - let request: AB::ExprEF = request_row_left * left_flag.clone() - + request_row_dyncall * dyncall_flag.clone() - + (one_ef.clone() - request_flag_sum); - - // ------------------------------------------------------------------------- - // Main running product constraint - // ------------------------------------------------------------------------- - - let lhs = p1_next.into() * request; - let rhs = p1_local.into() * response; - - builder.tagged(STACK_OVERFLOW_BUS_ID, STACK_OVERFLOW_BUS_NAME, |builder| { - builder.when_transition().assert_zero_ext(lhs - rhs); - }); -} diff --git a/air/src/constraints/stack/columns.rs b/air/src/constraints/stack/columns.rs new file mode 100644 index 0000000000..2a9678541d --- /dev/null +++ b/air/src/constraints/stack/columns.rs @@ -0,0 +1,28 @@ +use miden_core::program::MIN_STACK_DEPTH; + +/// Stack columns in the main execution trace (19 columns). +#[repr(C)] +pub struct StackCols { + /// Top 16 stack elements s0-s15. + pub(crate) top: [T; MIN_STACK_DEPTH], + /// Stack depth. + pub b0: T, + /// Overflow table parent address. + pub b1: T, + /// Helper: 1/(b0 - 16) when b0 != 16, else 0. + pub h0: T, +} + +impl StackCols { + /// Returns the stack element at position `idx` (0 = top of stack). + pub fn get(&self, idx: usize) -> T { + self.top[idx] + } +} + +impl StackCols { + /// Returns a slice of stack elements for the given range. + pub fn elements(&self, range: impl core::slice::SliceIndex<[T], Output = [T]>) -> &[T] { + &self.top[range] + } +} diff --git a/air/src/constraints/stack/crypto.rs b/air/src/constraints/stack/crypto.rs new file mode 100644 index 0000000000..56c59c21ec --- /dev/null +++ b/air/src/constraints/stack/crypto.rs @@ -0,0 +1,466 @@ +//! Crypto operation constraints. +//! +//! This module enforces the non-bus stack constraints for four crypto-related operations: +//! +//! - **CRYPTOSTREAM**: Encrypts memory words via XOR (i.e. addition in the prime field) with the +//! Poseidon2 sponge rate. Constraints here enforce pointer advancement and state stability; the +//! actual memory I/O and XOR happen via the chiplet bus (constrained elsewhere). +//! +//! - **HORNERBASE**: Evaluates a polynomial with base-field coefficients at an extension-field +//! point, processing 8 coefficients per row via Horner's method. Used during STARK verification +//! for polynomial commitment checks. +//! +//! - **HORNEREXT**: Same as HORNERBASE but for polynomials with extension-field coefficients, +//! processing 4 coefficient pairs per row. +//! +//! - **FRIE2F4**: Performs FRI layer folding, combining 4 extension-field query evaluations into 1, +//! and verifying the previous layer's folding was correct. + +use miden_core::{Felt, field::PrimeCharacteristicRing}; +use miden_crypto::stark::air::AirBuilder; + +use crate::{ + MainCols, MidenAirBuilder, + constraints::{ + constants::{F_3, F_4, F_8}, + ext_field::{QuadFeltAirBuilder, QuadFeltExpr}, + op_flags::OpFlags, + }, +}; + +// Fourth root of unity inverses (for FRI ext2fold4). +// tau = g^((p-1)/4) where p is the Goldilocks prime. +const TAU_INV: Felt = Felt::new_unchecked(18446462594437873665); +const TAU2_INV: Felt = Felt::new_unchecked(18446744069414584320); +const TAU3_INV: Felt = Felt::new_unchecked(281474976710656); + +// ENTRY POINTS +// ================================================================================================ + +/// Enforces crypto operation constraints. +pub fn enforce_main( + builder: &mut AB, + local: &MainCols, + next: &MainCols, + op_flags: &OpFlags, +) where + AB: MidenAirBuilder, +{ + enforce_cryptostream_constraints(builder, local, next, op_flags); + enforce_hornerbase_constraints(builder, local, next, op_flags); + enforce_hornerext_constraints(builder, local, next, op_flags); + enforce_frie2f4_constraints(builder, local, next, op_flags); +} + +// CONSTRAINT HELPERS +// ================================================================================================ + +/// CRYPTOSTREAM: encrypts two memory words via XOR with the Poseidon2 sponge rate. +/// +/// The top 8 stack elements (rate/ciphertext) are updated by the chiplet bus, not +/// constrained here. These constraints enforce only: +/// - Capacity elements (s[8..12]) are preserved. +/// - Source and destination pointers (s[12], s[13]) advance by 8 (two words). +/// - Padding elements (s[14..16]) are preserved. +/// +/// Stack layout: +/// s[0..8] rate / ciphertext (updated via bus, unconstrained here) +/// s[8..12] capacity (preserved) +/// s[12] source pointer (incremented by 8) +/// s[13] destination pointer (incremented by 8) +/// s[14..16] padding (preserved) +fn enforce_cryptostream_constraints( + builder: &mut AB, + local: &MainCols, + next: &MainCols, + op_flags: &OpFlags, +) where + AB: MidenAirBuilder, +{ + let gate = builder.is_transition() * op_flags.cryptostream(); + let builder = &mut builder.when(gate); + + let s = &local.stack.top; + let s_next = &next.stack.top; + + // Capacity preserved. + builder.assert_eq(s_next[8], s[8]); + builder.assert_eq(s_next[9], s[9]); + builder.assert_eq(s_next[10], s[10]); + builder.assert_eq(s_next[11], s[11]); + + // Pointers advance by 8 (one memory word = 4 elements, two words per step). + builder.assert_eq(s_next[12], s[12].into() + F_8); + builder.assert_eq(s_next[13], s[13].into() + F_8); + + // Padding preserved. + builder.assert_eq(s_next[14], s[14]); + builder.assert_eq(s_next[15], s[15]); +} + +/// HORNERBASE: degree-7 polynomial evaluation over the quadratic extension field. +/// +/// Evaluates 8 base-field coefficients at an extension-field point α using Horner's +/// method, split into three stages for constraint degree reduction. The coefficients +/// are at s[0..8] with c0 being the highest-degree term (α⁷) and c7 the constant term. +/// +/// The prover supplies α and intermediate results (tmp0, tmp1) via helper registers. +/// Constraining the polynomial relations on these values forces correctness — no +/// separate validation of the helpers is needed. +/// +/// Stack layout: +/// s[0..8] c0..c7 base-field coefficients (c0 = α⁷ term, c7 = constant) +/// s[8..13] (unused) not affected by this operation +/// s[13] alpha_ptr memory address of α +/// s[14..16] (acc₀, acc₁) accumulator (quadratic extension element) +/// +/// Helper registers: +/// h[0..2] (α₀, α₁) evaluation point (read from alpha_ptr) +/// h[4..6] (tmp0₀, tmp0₁) first intermediate result +/// h[2..4] (tmp1₀, tmp1₁) second intermediate result +/// +/// Horner steps (expanded form; equivalent to (acc·α + c0)·α + c1, etc.): +/// tmp0 = acc · α² + (c0·α + c1) +/// tmp1 = tmp0 · α³ + (c2·α² + c3·α + c4) +/// acc' = tmp1 · α³ + (c5·α² + c6·α + c7) +fn enforce_hornerbase_constraints( + builder: &mut AB, + local: &MainCols, + next: &MainCols, + op_flags: &OpFlags, +) where + AB: MidenAirBuilder, +{ + let horner_builder = &mut builder.when(op_flags.hornerbase()); + + let s = &local.stack.top; + let s_next = &next.stack.top; + let helpers = local.decoder.user_op_helpers(); + + // Stack registers preserved during transition. + { + let builder = &mut horner_builder.when_transition(); + for i in 0..14 { + builder.assert_eq(s_next[i], s[i]); + } + } + + // Extension element alpha and its powers. + let alpha: QuadFeltExpr = QuadFeltExpr::new(helpers[0], helpers[1]); + let alpha_sq = alpha.clone().square(); + let alpha_cubed = alpha_sq.clone() * alpha.clone(); + + // Nondeterministic intermediates from decoder helpers. + let tmp0 = QuadFeltExpr::new(helpers[4], helpers[5]); + let tmp1 = QuadFeltExpr::new(helpers[2], helpers[3]); + + // Accumulator. + let acc = QuadFeltExpr::new(s[14], s[15]); + let acc_next = QuadFeltExpr::new(s_next[14], s_next[15]); + + // Base-field coefficient accessor. + let c = |i: usize| -> AB::Expr { s[i].into() }; + + // tmp0 = acc · α² + (c0·α + c1) + let tmp0_expected = acc * alpha_sq.clone() + alpha.clone() * c(0) + c(1); + // tmp1 = tmp0 · α³ + (c2·α² + c3·α + c4) + let tmp1_expected = + tmp0.clone() * alpha_cubed.clone() + alpha_sq.clone() * c(2) + alpha.clone() * c(3) + c(4); + // acc' = tmp1 · α³ + (c5·α² + c6·α + c7) + let acc_expected = tmp1.clone() * alpha_cubed + alpha_sq * c(5) + alpha * c(6) + c(7); + + // Intermediate temporaries match expected polynomial evaluations. + horner_builder.assert_eq_quad(tmp0, tmp0_expected); + horner_builder.assert_eq_quad(tmp1, tmp1_expected); + // Accumulator updated to next Horner step during transition. + horner_builder.when_transition().assert_eq_quad(acc_next, acc_expected); +} + +/// HORNEREXT: degree-3 polynomial evaluation over the quadratic extension field. +/// +/// Same Horner structure as HORNERBASE but with extension-field coefficients: each +/// coefficient is a quadratic extension element (a pair of base-field elements on +/// the stack). Processes 4 extension coefficients per row instead of 8 base ones, +/// so only α² is needed (not α³). +/// +/// Stack layout: +/// s[0..2] (c₀,₀, c₀,₁) highest-degree coefficient (α³ term) +/// s[2..4] (c₁,₀, c₁,₁) α² term +/// s[4..6] (c₂,₀, c₂,₁) α¹ term +/// s[6..8] (c₃,₀, c₃,₁) constant term +/// s[8..13] (unused) not affected by this operation +/// s[13] alpha_ptr memory address of α (word: [α₀, α₁, k0, k1]) +/// s[14..16] (acc₀, acc₁) accumulator (quadratic extension element) +/// +/// Helper registers: +/// h[0..2] (α₀, α₁) evaluation point +/// h[2..4] k0, k1 padding from the α memory word (unused by constraints) +/// h[4..6] (tmp₀, tmp₁) intermediate result +/// +/// Horner steps: +/// tmp = acc · α² + (c0·α + c1) +/// acc' = tmp · α² + (c2·α + c3) +fn enforce_hornerext_constraints( + builder: &mut AB, + local: &MainCols, + next: &MainCols, + op_flags: &OpFlags, +) where + AB: MidenAirBuilder, +{ + let horner_builder = &mut builder.when(op_flags.hornerext()); + + let s = &local.stack.top; + let s_next = &next.stack.top; + let helpers = local.decoder.user_op_helpers(); + + // Stack registers preserved during transition. + { + let builder = &mut horner_builder.when_transition(); + for i in 0..14 { + builder.assert_eq(s_next[i], s[i]); + } + } + + // Extension element alpha and its square. + let alpha: QuadFeltExpr = QuadFeltExpr::new(helpers[0], helpers[1]); + let alpha_sq = alpha.clone().square(); + + // Nondeterministic intermediate from decoder helpers. + let tmp = QuadFeltExpr::new(helpers[4], helpers[5]); + + // Accumulator. + let acc = QuadFeltExpr::new(s[14], s[15]); + let acc_next = QuadFeltExpr::new(s_next[14], s_next[15]); + + // Extension-field coefficient pairs from the stack. + let c0 = QuadFeltExpr::new(s[0], s[1]); + let c1 = QuadFeltExpr::new(s[2], s[3]); + let c2 = QuadFeltExpr::new(s[4], s[5]); + let c3 = QuadFeltExpr::new(s[6], s[7]); + + // tmp = acc · α² + (c0·α + c1) + let tmp_expected = acc * alpha_sq.clone() + alpha.clone() * c0 + c1; + // acc' = tmp · α² + (c2·α + c3) + let acc_expected = tmp.clone() * alpha_sq + alpha * c2 + c3; + + // Intermediate temporary matches expected polynomial evaluation. + horner_builder.assert_eq_quad(tmp, tmp_expected); + // Accumulator updated to next Horner step during transition. + horner_builder.when_transition().assert_eq_quad(acc_next, acc_expected); +} + +/// FRIE2F4: FRI layer folding — folds 4 extension-field query evaluations into 1. +/// +/// During FRI (Fast Reed-Solomon IOP) verification, the verifier reduces polynomial +/// degree by folding evaluations at related domain points. This operation folds 4 +/// query evaluations from a source domain of size 4N into 1 evaluation in the folded +/// domain of size N, using the verifier's random challenge α. +/// +/// The fold4 algorithm applies fold2 three times: +/// fold_mid0 = fold2(q0, q2, eval_point) — first conjugate pair +/// fold_mid1 = fold2(q1, q3, eval_point · τ⁻¹) — second pair (coset-shifted) +/// fold_result = fold2(fold_mid0, fold_mid1, eval_point_sq) +/// +/// where eval_point = α / domain_point, and domain_point = poe · tau_factor. +/// +/// The operation also verifies that the previous layer's folding was correct +/// (prev_eval must match the query value selected by the domain segment) and +/// advances state for the next layer (poe → poe⁴, layer pointer += 8). +/// +/// ## Register map +/// +/// Input stack (current row): +/// s[0..2] (q₀,₀, q₀,₁) query eval 0 ─┐ 4 extension-field evaluations +/// s[2..4] (q₂,₀, q₂,₁) query eval 2 │ (bit-reversed stack order; +/// s[4..6] (q₁,₀, q₁,₁) query eval 1 │ see "Bit-reversal" below) +/// s[6..8] (q₃,₀, q₃,₁) query eval 3 ─┘ +/// s[8] folded_pos query position in the folded domain +/// s[9] tree_index bit-reversed index: tree_index = 4·folded_pos + segment +/// s[10] poe power of initial domain generator +/// s[11..13] prev_eval previous layer's folded value (for consistency check) +/// s[13..15] (α₀, α₁) verifier challenge for this FRI layer +/// s[15] layer_ptr memory address of current FRI layer data +/// +/// Output stack (next row — first 10 positions are degree-reduction intermediates): +/// s'[0..2] fold_mid0 first fold2 intermediate result +/// s'[2..4] fold_mid1 second fold2 intermediate result +/// s'[4..8] seg_flag[0..3] domain segment flags (one-hot) +/// s'[8] poe_sq poe² +/// s'[9] tau_factor τ^(-segment) for this coset +/// s'[10] layer_ptr + 8 advanced layer pointer +/// s'[11] poe_fourth poe⁴ (for next FRI layer) +/// s'[12] folded_pos copied from input +/// s'[13..15] fold_result final fold4 output +/// +/// Helper registers (nondeterministic, provided by prover): +/// h[0..2] eval_point folding parameter = α / domain_point +/// h[2..4] eval_point_sq eval_point² (for the final fold2 round) +/// h[4] domain_point x = poe · tau_factor +/// h[5] domain_point_inv 1/x +/// +/// ## Bit-reversal +/// +/// Query values are stored on the stack in bit-reversed order (matching NTT +/// evaluation layout). The constraint names use natural order for fold4: +/// +/// stack position: [0,1] [2,3] [4,5] [6,7] +/// bit-reversed: qv0 qv1 qv2 qv3 +/// natural (fold4): q0 q2 q1 q3 +/// +/// fold4 pairs conjugate points: (q0, q2) and (q1, q3). +fn enforce_frie2f4_constraints( + builder: &mut AB, + local: &MainCols, + next: &MainCols, + op_flags: &OpFlags, +) where + AB: MidenAirBuilder, +{ + let builder = &mut builder.when(op_flags.frie2f4()); + + let s = &local.stack.top; + let s_next = &next.stack.top; + let helpers = local.decoder.user_op_helpers(); + + // ========================================================================== + // Inputs (current row) + // ========================================================================== + // Query values in natural order for fold4 (see "Bit-reversal" in docstring). + let q0 = QuadFeltExpr::new(s[0], s[1]); + let q2 = QuadFeltExpr::new(s[2], s[3]); + let q1 = QuadFeltExpr::new(s[4], s[5]); + let q3 = QuadFeltExpr::new(s[6], s[7]); + + let folded_pos = s[8]; + let tree_index = s[9]; + let poe = s[10]; + let prev_eval = QuadFeltExpr::new(s[11], s[12]); + let alpha = QuadFeltExpr::new(s[13], s[14]); + let layer_ptr = s[15]; + + // ========================================================================== + // Phase 1: Domain segment identification + // ========================================================================== + // Determine which coset of the 4-element multiplicative subgroup this query + // belongs to. The segment flags are one-hot: exactly one is 1. From them we + // derive the segment index (for position decomposition) and the tau factor + // (the twiddle factor τ^(-segment) for computing the domain point). + + let seg_flag_0 = s_next[4]; + let seg_flag_1 = s_next[5]; + let seg_flag_2 = s_next[6]; + let seg_flag_3 = s_next[7]; + + // Segment flags must be binary and exactly one must be active. + builder.assert_bools([seg_flag_0, seg_flag_1, seg_flag_2, seg_flag_3]); + builder.assert_one(seg_flag_0 + seg_flag_1 + seg_flag_2 + seg_flag_3); + + // The tree_index encodes both the folded position and the domain segment: + // tree_index = 4 · folded_pos + segment_index + // Bit-reversal mapping from flags to segment index: + // flag0 → 0, flag1 → 2, flag2 → 1, flag3 → 3 + // so segment_index = 2·flag1 + flag2 + 3·flag3. + let folded_pos_next = s_next[12]; + let segment_index = seg_flag_1.into().double() + seg_flag_2 + seg_flag_3 * F_3; + builder.assert_eq(tree_index, folded_pos_next * F_4 + segment_index); + + // Each segment corresponds to a power of τ⁻¹ (the inverse 4th root of unity). + // The one-hot flags select the appropriate power. + let tau_factor = s_next[9]; + let expected_tau = + seg_flag_0 + seg_flag_1 * TAU_INV + seg_flag_2 * TAU2_INV + seg_flag_3 * TAU3_INV; + builder.assert_eq(tau_factor, expected_tau); + + // ========================================================================== + // Phase 2: Folding parameters + // ========================================================================== + // Compute the domain point and evaluation parameters needed for fold2. + // + // The domain point is x = poe · tau_factor, the evaluation point in the source + // domain. The fold2 function needs eval_point = α/x and eval_point_sq = (α/x)². + // + // The prover supplies these nondeterministically via helper registers. + // Constraining the relations here forces the prover to provide correct values. + + // domain_point = poe · tau_factor, with a verified inverse. + let domain_point = helpers[4]; + let domain_point_inv = helpers[5]; + builder.assert_eq(domain_point, poe * tau_factor); + builder.assert_one(domain_point * domain_point_inv); + + // eval_point = α / domain_point = α · domain_point_inv (in Fp2). + let eval_point: QuadFeltExpr = QuadFeltExpr::new(helpers[0], helpers[1]); + builder.assert_eq_quad(eval_point.clone(), alpha * domain_point_inv.into()); + + // eval_point_sq = eval_point² (needed for the final fold2 round). + let eval_point_sq: QuadFeltExpr = QuadFeltExpr::new(helpers[2], helpers[3]); + builder.assert_eq_quad(eval_point_sq.clone(), eval_point.clone().square()); + + // ========================================================================== + // Phase 3: Fold4 — core FRI folding + // ========================================================================== + // fold2 recovers the degree-halved polynomial from evaluations at conjugate + // domain points. If f(z) = g(z²) + z·h(z²), then: + // f(x) + f(-x) = 2·g(x²) (even part) + // f(x) - f(-x) = 2x·h(x²) (odd part) + // Combining: fold2(f(x), f(-x), α/x) = g(x²) + (α/x)·h(x²) + // + // Formula: fold2(a, b, ep) = ((a + b) + (a - b) · ep) / 2 + // Constraint form: 2 · result = (a + b) + (a - b) · ep (avoids division). + + // Returns 2 · fold2(a, b, ep) as a constraint expression. + let fold2_doubled = |a: QuadFeltExpr, + b: QuadFeltExpr, + ep: QuadFeltExpr| + -> QuadFeltExpr { (a.clone() + b.clone()) + (a - b) * ep }; + + // Intermediate fold results stored in the next row for degree reduction. + let fold_mid0 = QuadFeltExpr::new(s_next[0], s_next[1]); + let fold_mid1 = QuadFeltExpr::new(s_next[2], s_next[3]); + let fold_result = QuadFeltExpr::new(s_next[13], s_next[14]); + + // Three fold2 applications compose into fold4: + // fold_mid0 = fold2(q0, q2, eval_point) + // fold_mid1 = fold2(q1, q3, eval_point · τ⁻¹) + // fold_result = fold2(fold_mid0, fold_mid1, eval_point_sq) + + builder.assert_eq_quad(fold_mid0.clone().double(), fold2_doubled(q0, q2, eval_point.clone())); + + // The second conjugate pair lives on a coset shifted by τ, so the evaluation + // parameter is adjusted by τ⁻¹ to account for the coset offset. + let eval_point_coset = eval_point * AB::Expr::from(TAU_INV); + builder.assert_eq_quad(fold_mid1.clone().double(), fold2_doubled(q1, q3, eval_point_coset)); + + builder + .assert_eq_quad(fold_result.double(), fold2_doubled(fold_mid0, fold_mid1, eval_point_sq)); + + // ========================================================================== + // Phase 4: Cross-layer consistency and state updates + // ========================================================================== + + // The folded output from the previous FRI layer (prev_eval) must equal the + // query value at the position indicated by the domain segment. This links + // adjacent FRI layers: layer k's fold_result appears as one of layer k+1's + // four query inputs. + // + // The segment flags select which query value to compare. Uses raw stack + // positions because the query QuadFeltExprs were consumed by fold2 above. + // Mapping: seg_flag_0 → s[0,1]=q0, seg_flag_1 → s[4,5]=q1, + // seg_flag_2 → s[2,3]=q2, seg_flag_3 → s[6,7]=q3. + let selected_re = s[0] * seg_flag_0 + s[4] * seg_flag_1 + s[2] * seg_flag_2 + s[6] * seg_flag_3; + let selected_im = s[1] * seg_flag_0 + s[5] * seg_flag_1 + s[3] * seg_flag_2 + s[7] * seg_flag_3; + builder.assert_eq_quad(prev_eval, QuadFeltExpr::new(selected_re, selected_im)); + + // Domain generator powers for the next layer: poe → poe² → poe⁴. + // Split into two squarings to keep constraint degree low. + let poe_sq = s_next[8]; + let poe_fourth = s_next[11]; + builder.assert_eq(poe_sq, poe * poe); + builder.assert_eq(poe_fourth, poe_sq * poe_sq); + + // Advance the layer pointer and preserve the folded position. + let layer_ptr_next = s_next[10]; + builder.assert_eq(layer_ptr_next, layer_ptr + F_8); + builder.assert_eq(folded_pos_next, folded_pos); +} diff --git a/air/src/constraints/stack/crypto/mod.rs b/air/src/constraints/stack/crypto/mod.rs deleted file mode 100644 index cf699d71dc..0000000000 --- a/air/src/constraints/stack/crypto/mod.rs +++ /dev/null @@ -1,339 +0,0 @@ -//! Crypto operation constraints. -//! -//! This module enforces crypto-related stack ops: -//! CRYPTOSTREAM, HORNERBASE, and HORNEREXT. - -use miden_core::field::PrimeCharacteristicRing; -use miden_crypto::stark::air::LiftedAirBuilder; - -use crate::{ - MainTraceRow, - constraints::{ - ext_field::QuadFeltExpr, - op_flags::OpFlags, - tagging::{ - TagGroup, TaggingAirBuilderExt, ids::TAG_STACK_CRYPTO_BASE, tagged_assert_zero, - tagged_assert_zero_integrity, - }, - }, - trace::decoder::USER_OP_HELPERS_OFFSET, -}; - -// CONSTANTS -// ================================================================================================ - -/// Number of crypto op constraints. -#[allow(dead_code)] -pub const NUM_CONSTRAINTS: usize = 46; - -/// Base tag ID for crypto op constraints. -const STACK_CRYPTO_BASE_ID: usize = TAG_STACK_CRYPTO_BASE; - -/// Tag namespaces for crypto op constraints. -const STACK_CRYPTO_NAMES: [&str; NUM_CONSTRAINTS] = [ - // CRYPTOSTREAM (8) - "stack.crypto.cryptostream", - "stack.crypto.cryptostream", - "stack.crypto.cryptostream", - "stack.crypto.cryptostream", - "stack.crypto.cryptostream", - "stack.crypto.cryptostream", - "stack.crypto.cryptostream", - "stack.crypto.cryptostream", - // HORNERBASE (20) - "stack.crypto.hornerbase", - "stack.crypto.hornerbase", - "stack.crypto.hornerbase", - "stack.crypto.hornerbase", - "stack.crypto.hornerbase", - "stack.crypto.hornerbase", - "stack.crypto.hornerbase", - "stack.crypto.hornerbase", - "stack.crypto.hornerbase", - "stack.crypto.hornerbase", - "stack.crypto.hornerbase", - "stack.crypto.hornerbase", - "stack.crypto.hornerbase", - "stack.crypto.hornerbase", - "stack.crypto.hornerbase", - "stack.crypto.hornerbase", - "stack.crypto.hornerbase", - "stack.crypto.hornerbase", - "stack.crypto.hornerbase", - "stack.crypto.hornerbase", - // HORNEREXT (18) - "stack.crypto.hornerext", - "stack.crypto.hornerext", - "stack.crypto.hornerext", - "stack.crypto.hornerext", - "stack.crypto.hornerext", - "stack.crypto.hornerext", - "stack.crypto.hornerext", - "stack.crypto.hornerext", - "stack.crypto.hornerext", - "stack.crypto.hornerext", - "stack.crypto.hornerext", - "stack.crypto.hornerext", - "stack.crypto.hornerext", - "stack.crypto.hornerext", - "stack.crypto.hornerext", - "stack.crypto.hornerext", - "stack.crypto.hornerext", - "stack.crypto.hornerext", -]; - -/// Tag metadata for this constraint group. -const STACK_CRYPTO_TAGS: TagGroup = TagGroup { - base: STACK_CRYPTO_BASE_ID, - names: &STACK_CRYPTO_NAMES, -}; - -// ENTRY POINTS -// ================================================================================================ - -/// Enforces crypto operation constraints. -pub fn enforce_main( - builder: &mut AB, - local: &MainTraceRow, - next: &MainTraceRow, - op_flags: &OpFlags, -) where - AB: LiftedAirBuilder, -{ - let mut idx = 0usize; - enforce_cryptostream_constraints(builder, local, next, op_flags, &mut idx); - enforce_hornerbase_constraints(builder, local, next, op_flags, &mut idx); - enforce_hornerext_constraints(builder, local, next, op_flags, &mut idx); -} - -// CONSTRAINT HELPERS -// ================================================================================================ - -fn enforce_cryptostream_constraints( - builder: &mut AB, - local: &MainTraceRow, - next: &MainTraceRow, - op_flags: &OpFlags, - idx: &mut usize, -) where - AB: LiftedAirBuilder, -{ - // CRYPTOSTREAM keeps the top of the stack stable except for the two counters - // that track the stream offset. Those counters advance by 8 (one word) per row. - // Everything is gated by the op flag, so the constraints are active only when - // CRYPTOSTREAM is executed. - let eight: AB::Expr = AB::Expr::from_u16(8); - let gate = op_flags.cryptostream(); - - assert_zero( - builder, - idx, - gate.clone() * (next.stack[8].clone().into() - local.stack[8].clone().into()), - ); - assert_zero( - builder, - idx, - gate.clone() * (next.stack[9].clone().into() - local.stack[9].clone().into()), - ); - assert_zero( - builder, - idx, - gate.clone() * (next.stack[10].clone().into() - local.stack[10].clone().into()), - ); - assert_zero( - builder, - idx, - gate.clone() * (next.stack[11].clone().into() - local.stack[11].clone().into()), - ); - assert_zero( - builder, - idx, - gate.clone() - * (next.stack[12].clone().into() - (local.stack[12].clone().into() + eight.clone())), - ); - assert_zero( - builder, - idx, - gate.clone() * (next.stack[13].clone().into() - (local.stack[13].clone().into() + eight)), - ); - assert_zero( - builder, - idx, - gate.clone() * (next.stack[14].clone().into() - local.stack[14].clone().into()), - ); - assert_zero( - builder, - idx, - gate * (next.stack[15].clone().into() - local.stack[15].clone().into()), - ); -} - -fn enforce_hornerbase_constraints( - builder: &mut AB, - local: &MainTraceRow, - next: &MainTraceRow, - op_flags: &OpFlags, - idx: &mut usize, -) where - AB: LiftedAirBuilder, -{ - // HORNERBASE evaluates a degree-7 polynomial over the quadratic extension. - // The accumulator lives in stack[14..16] and is updated using helper values - // supplied (nondeterministically) through the decoder helper registers. We - // enforce the algebraic relationships that must hold between the helpers, the - // coefficients on the stack, and the accumulator update. These constraints - // also implicitly bind the helper values to the required power relations. - let gate = op_flags.hornerbase(); - - // The lower 14 stack registers remain unchanged during HORNERBASE. - for i in 0..14 { - assert_zero( - builder, - idx, - gate.clone() * (next.stack[i].clone().into() - local.stack[i].clone().into()), - ); - } - - // Decoder helper columns contain alpha components and intermediate temporaries. - // We read them starting at USER_OP_HELPERS_OFFSET to avoid hardcoding column indices. - let base = USER_OP_HELPERS_OFFSET; - let a0: AB::Expr = local.decoder[base].clone().into(); - let a1: AB::Expr = local.decoder[base + 1].clone().into(); - let tmp1_0: AB::Expr = local.decoder[base + 2].clone().into(); - let tmp1_1: AB::Expr = local.decoder[base + 3].clone().into(); - let tmp0_0: AB::Expr = local.decoder[base + 4].clone().into(); - let tmp0_1: AB::Expr = local.decoder[base + 5].clone().into(); - - let acc0: AB::Expr = local.stack[14].clone().into(); - let acc1: AB::Expr = local.stack[15].clone().into(); - let acc0_next: AB::Expr = next.stack[14].clone().into(); - let acc1_next: AB::Expr = next.stack[15].clone().into(); - - // Coefficients are read from the bottom of the stack. - let c: [AB::Expr; 8] = core::array::from_fn(|i| local.stack[i].clone().into()); - - // Quadratic extension view (Fp2 with u^2 = 7): - // - alpha = (a0, a1), acc = (acc0, acc1) - // - tmp0 = (tmp0_0, tmp0_1), tmp1 = (tmp1_0, tmp1_1) - // - c[0..7] are base-field scalars - // - // Horner form: - // tmp0 = acc * alpha^2 + (c0 * alpha + c1) - // tmp1 = tmp0 * alpha^3 + (c2 * alpha^2 + c3 * alpha + c4) - // acc' = tmp1 * alpha^3 + (c5 * alpha^2 + c6 * alpha + c7) - let alpha: QuadFeltExpr = QuadFeltExpr::new(&a0, &a1); - let alpha2 = alpha.clone().square(); - let alpha3 = alpha2.clone() * alpha.clone(); - let acc: QuadFeltExpr = QuadFeltExpr::new(&acc0, &acc1); - let acc_alpha2: QuadFeltExpr = acc * alpha2.clone(); - let tmp0: QuadFeltExpr = QuadFeltExpr::new(&tmp0_0, &tmp0_1); - let tmp0_alpha3: QuadFeltExpr = tmp0.clone() * alpha3.clone(); - let tmp1: QuadFeltExpr = QuadFeltExpr::new(&tmp1_0, &tmp1_1); - - // tmp0 = acc * alpha^2 + (c0 * alpha + c1) - let tmp0_expected: QuadFeltExpr = - acc_alpha2 + alpha.clone() * c[0].clone() + c[1].clone(); - let [tmp0_exp_0, tmp0_exp_1] = tmp0_expected.into_parts(); - - // tmp1 = tmp0 * alpha^3 + (c2 * alpha^2 + c3 * alpha + c4) - let tmp1_expected: QuadFeltExpr = - tmp0_alpha3 + alpha2.clone() * c[2].clone() + alpha.clone() * c[3].clone() + c[4].clone(); - let [tmp1_exp_0, tmp1_exp_1] = tmp1_expected.into_parts(); - - // acc' = tmp1 * alpha^3 + (alpha^2 * c5 + alpha * c6 + c7) - let acc_expected: QuadFeltExpr = - tmp1 * alpha3 + alpha2.clone() * c[5].clone() + alpha.clone() * c[6].clone() + c[7].clone(); - let [acc_exp_0, acc_exp_1] = acc_expected.into_parts(); - - assert_zero_integrity(builder, idx, gate.clone() * (tmp0_0 - tmp0_exp_0)); - assert_zero_integrity(builder, idx, gate.clone() * (tmp0_1 - tmp0_exp_1)); - assert_zero_integrity(builder, idx, gate.clone() * (tmp1_0 - tmp1_exp_0)); - assert_zero_integrity(builder, idx, gate.clone() * (tmp1_1 - tmp1_exp_1)); - assert_zero(builder, idx, gate.clone() * (acc0_next - acc_exp_0)); - assert_zero(builder, idx, gate * (acc1_next - acc_exp_1)); -} - -fn enforce_hornerext_constraints( - builder: &mut AB, - local: &MainTraceRow, - next: &MainTraceRow, - op_flags: &OpFlags, - idx: &mut usize, -) where - AB: LiftedAirBuilder, -{ - // HORNEREXT evaluates a degree-3 polynomial over the quadratic extension with - // a smaller helper set. As with HORNERBASE, helper values are supplied via - // decoder columns, and the constraints below bind them to the required - // power relations and accumulator update. - let gate = op_flags.hornerext(); - - // The lower 14 stack registers are unchanged by HORNEREXT. - for i in 0..14 { - assert_zero( - builder, - idx, - gate.clone() * (next.stack[i].clone().into() - local.stack[i].clone().into()), - ); - } - - // Helper columns and accumulator values. - let base = USER_OP_HELPERS_OFFSET; - let a0: AB::Expr = local.decoder[base].clone().into(); - let a1: AB::Expr = local.decoder[base + 1].clone().into(); - let tmp0: AB::Expr = local.decoder[base + 4].clone().into(); - let tmp1: AB::Expr = local.decoder[base + 5].clone().into(); - - let acc0: AB::Expr = local.stack[14].clone().into(); - let acc1: AB::Expr = local.stack[15].clone().into(); - let acc0_next: AB::Expr = next.stack[14].clone().into(); - let acc1_next: AB::Expr = next.stack[15].clone().into(); - - // Coefficients live at the bottom of the stack. - let s: [AB::Expr; 8] = core::array::from_fn(|i| local.stack[i].clone().into()); - - // Quadratic extension view (Fp2 with u^2 = 7): - // - alpha = (a0, a1), acc = (acc0, acc1), tmp = (tmp0, tmp1) - // - extension coefficients use the stack pairs: c0 = (s0, s1), c1 = (s2, s3), c2 = (s4, s5), c3 - // = (s6, s7) - // - // Horner form: - // tmp = acc * alpha^2 + (c0 * alpha + c1) - // acc' = tmp * alpha^2 + (c2 * alpha + c3) - let alpha: QuadFeltExpr = QuadFeltExpr::new(&a0, &a1); - let alpha2 = alpha.clone().square(); - let acc: QuadFeltExpr = QuadFeltExpr::new(&acc0, &acc1); - let acc_alpha2: QuadFeltExpr = acc * alpha2.clone(); - let tmp: QuadFeltExpr = QuadFeltExpr::new(&tmp0, &tmp1); - let tmp_alpha2: QuadFeltExpr = tmp * alpha2; - - let c0 = QuadFeltExpr::new(&s[0], &s[1]); - let c1 = QuadFeltExpr::new(&s[2], &s[3]); - let c2 = QuadFeltExpr::new(&s[4], &s[5]); - let c3 = QuadFeltExpr::new(&s[6], &s[7]); - - // tmp = acc * alpha^2 + (c0 * alpha + c1) - let tmp_expected: QuadFeltExpr = acc_alpha2 + alpha.clone() * c0 + c1; - let [tmp_exp_0, tmp_exp_1] = tmp_expected.into_parts(); - - // acc' = tmp * alpha^2 + (c2 * alpha + c3) - let acc_expected: QuadFeltExpr = tmp_alpha2 + alpha * c2 + c3; - let [acc_exp_0, acc_exp_1] = acc_expected.into_parts(); - - assert_zero_integrity(builder, idx, gate.clone() * (tmp0 - tmp_exp_0)); - assert_zero_integrity(builder, idx, gate.clone() * (tmp1 - tmp_exp_1)); - assert_zero(builder, idx, gate.clone() * (acc0_next - acc_exp_0)); - assert_zero(builder, idx, gate * (acc1_next - acc_exp_1)); -} - -fn assert_zero(builder: &mut AB, idx: &mut usize, expr: AB::Expr) { - tagged_assert_zero(builder, &STACK_CRYPTO_TAGS, idx, expr); -} - -fn assert_zero_integrity( - builder: &mut AB, - idx: &mut usize, - expr: AB::Expr, -) { - tagged_assert_zero_integrity(builder, &STACK_CRYPTO_TAGS, idx, expr); -} diff --git a/air/src/constraints/stack/general.rs b/air/src/constraints/stack/general.rs new file mode 100644 index 0000000000..408f426b82 --- /dev/null +++ b/air/src/constraints/stack/general.rs @@ -0,0 +1,89 @@ +//! General stack transition constraints. +//! +//! This module contains the general constraints that enforce how stack items transition +//! based on the operation type (no shift, left shift, right shift). +//! +//! ## Stack Transition Model +//! +//! The stack has 16 visible positions (0-15). For each operation, stack items can: +//! - **Stay in place** (no shift): item stays at same position +//! - **Shift left**: item moves to position i from position i+1 +//! - **Shift right**: item moves to position i from position i-1 +//! +//! ## Constraints +//! +//! 1. **Position 0**: Can receive from position 0 (no shift) or position 1 (left shift). Right +//! shift doesn't apply - position 0 gets a new value pushed. +//! +//! 2. **Positions 1-14**: Can receive from position i (no shift), i+1 (left shift), or i-1 (right +//! shift). +//! +//! 3. **Position 15**: Can receive from position 15 (no shift) or position 14 (right shift). Left +//! shift at position 15 is handled by overflow constraints (zeroing). +//! +//! 4. **Top binary**: Enforced by the specific op constraints that require it. + +use miden_crypto::stark::air::AirBuilder; + +use crate::{MainCols, MidenAirBuilder, constraints::op_flags::OpFlags}; + +// ENTRY POINTS +// ================================================================================================ + +/// Enforces all general stack transition constraints. +/// +/// This includes: +/// - 16 constraints for stack item transitions at each position +pub fn enforce_main( + builder: &mut AB, + local: &MainCols, + next: &MainCols, + op_flags: &OpFlags, +) where + AB: MidenAirBuilder, +{ + // For each position i, the constraint ensures that the next value is consistent + // with the current value based on the shift flags: + // + // next[i] * flag_sum = no_shift[i] * current[i] + // + left_shift[i+1] * current[i+1] + // + right_shift[i-1] * current[i-1] + // + // where flag_sum is the sum of applicable flags for that position. + + // Position 0: no right shift (new value pushed instead) + // next[0] * flag_sum = no_shift[0] * current[0] + left_shift[1] * current[1] + { + let flag_sum = op_flags.no_shift_at(0) + op_flags.left_shift_at(1); + let expected = op_flags.no_shift_at(0) * local.stack.get(0).into() + + op_flags.left_shift_at(1) * local.stack.get(1).into(); + let actual = next.stack.get(0); + + builder.when_transition().assert_zero(actual * flag_sum - expected); + } + + // Positions 1-14: all three shift types possible. + for i in 1..15 { + let flag_sum = op_flags.no_shift_at(i) + + op_flags.left_shift_at(i + 1) + + op_flags.right_shift_at(i - 1); + + let expected = op_flags.no_shift_at(i) * local.stack.get(i).into() + + op_flags.left_shift_at(i + 1) * local.stack.get(i + 1).into() + + op_flags.right_shift_at(i - 1) * local.stack.get(i - 1).into(); + let actual = next.stack.get(i); + + builder.when_transition().assert_zero(actual * flag_sum - expected); + } + + // Position 15: no left shift (handled by overflow constraints) + // next[15] * flag_sum = no_shift[15] * current[15] + right_shift[14] * current[14] + { + let flag_sum = op_flags.no_shift_at(15) + op_flags.right_shift_at(14); + let expected = op_flags.no_shift_at(15) * local.stack.get(15).into() + + op_flags.right_shift_at(14) * local.stack.get(14).into(); + let actual = next.stack.get(15); + + builder.when_transition().assert_zero(actual * flag_sum - expected); + } +} diff --git a/air/src/constraints/stack/general/mod.rs b/air/src/constraints/stack/general/mod.rs deleted file mode 100644 index 28bc538f64..0000000000 --- a/air/src/constraints/stack/general/mod.rs +++ /dev/null @@ -1,133 +0,0 @@ -//! General stack transition constraints. -//! -//! This module contains the general constraints that enforce how stack items transition -//! based on the operation type (no shift, left shift, right shift). -//! -//! ## Stack Transition Model -//! -//! The stack has 16 visible positions (0-15). For each operation, stack items can: -//! - **Stay in place** (no shift): item stays at same position -//! - **Shift left**: item moves to position i from position i+1 -//! - **Shift right**: item moves to position i from position i-1 -//! -//! ## Constraints -//! -//! 1. **Position 0**: Can receive from position 0 (no shift) or position 1 (left shift). Right -//! shift doesn't apply - position 0 gets a new value pushed. -//! -//! 2. **Positions 1-14**: Can receive from position i (no shift), i+1 (left shift), or i-1 (right -//! shift). -//! -//! 3. **Position 15**: Can receive from position 15 (no shift) or position 14 (right shift). Left -//! shift at position 15 is handled by overflow constraints (zeroing). -//! -//! 4. **Top binary**: Enforced by the specific op constraints that require it. - -use miden_crypto::stark::air::{AirBuilder, LiftedAirBuilder}; - -use crate::{ - MainTraceRow, - constraints::{ - op_flags::OpFlags, - tagging::{ - TaggingAirBuilderExt, - ids::{TAG_STACK_GENERAL_BASE, TAG_STACK_GENERAL_COUNT}, - }, - }, -}; - -// CONSTANTS -// ================================================================================================ - -/// Number of general stack constraints. -/// 16 constraints for stack item transitions. -pub const NUM_CONSTRAINTS: usize = TAG_STACK_GENERAL_COUNT; - -/// Tag base ID for stack general constraints. -/// Tag namespaces for stack general constraints. -const STACK_GENERAL_NAMES: [&str; NUM_CONSTRAINTS] = [ - "stack.general.transition.0", - "stack.general.transition.1", - "stack.general.transition.2", - "stack.general.transition.3", - "stack.general.transition.4", - "stack.general.transition.5", - "stack.general.transition.6", - "stack.general.transition.7", - "stack.general.transition.8", - "stack.general.transition.9", - "stack.general.transition.10", - "stack.general.transition.11", - "stack.general.transition.12", - "stack.general.transition.13", - "stack.general.transition.14", - "stack.general.transition.15", -]; - -// ENTRY POINTS -// ================================================================================================ - -/// Enforces all general stack transition constraints. -/// -/// This includes: -/// - 16 constraints for stack item transitions at each position -pub fn enforce_main( - builder: &mut AB, - local: &MainTraceRow, - next: &MainTraceRow, - op_flags: &OpFlags, -) where - AB: LiftedAirBuilder, -{ - // For each position i, the constraint ensures that the next value is consistent - // with the current value based on the shift flags: - // - // next[i] * flag_sum = no_shift[i] * current[i] - // + left_shift[i+1] * current[i+1] - // + right_shift[i-1] * current[i-1] - // - // where flag_sum is the sum of applicable flags for that position. - - // Position 0: no right shift (new value pushed instead) - // next[0] * flag_sum = no_shift[0] * current[0] + left_shift[1] * current[1] - { - let flag_sum = op_flags.no_shift_at(0) + op_flags.left_shift_at(1); - let expected = op_flags.no_shift_at(0) * local.stack[0].clone().into() - + op_flags.left_shift_at(1) * local.stack[1].clone().into(); - let actual: AB::Expr = next.stack[0].clone().into(); - - builder.tagged(TAG_STACK_GENERAL_BASE, STACK_GENERAL_NAMES[0], |builder| { - builder.when_transition().assert_zero(actual * flag_sum - expected); - }); - } - - // Positions 1-14: all three shift types possible. - for (i, &namespace) in STACK_GENERAL_NAMES.iter().enumerate().take(15).skip(1) { - let flag_sum = op_flags.no_shift_at(i) - + op_flags.left_shift_at(i + 1) - + op_flags.right_shift_at(i - 1); - - let expected = op_flags.no_shift_at(i) * local.stack[i].clone().into() - + op_flags.left_shift_at(i + 1) * local.stack[i + 1].clone().into() - + op_flags.right_shift_at(i - 1) * local.stack[i - 1].clone().into(); - let actual: AB::Expr = next.stack[i].clone().into(); - - let id = TAG_STACK_GENERAL_BASE + i; - builder.tagged(id, namespace, |builder| { - builder.when_transition().assert_zero(actual * flag_sum - expected); - }); - } - - // Position 15: no left shift (handled by overflow constraints) - // next[15] * flag_sum = no_shift[15] * current[15] + right_shift[14] * current[14] - { - let flag_sum = op_flags.no_shift_at(15) + op_flags.right_shift_at(14); - let expected = op_flags.no_shift_at(15) * local.stack[15].clone().into() - + op_flags.right_shift_at(14) * local.stack[14].clone().into(); - let actual: AB::Expr = next.stack[15].clone().into(); - - builder.tagged(TAG_STACK_GENERAL_BASE + 15, STACK_GENERAL_NAMES[15], |builder| { - builder.when_transition().assert_zero(actual * flag_sum - expected); - }); - } -} diff --git a/air/src/constraints/stack/mod.rs b/air/src/constraints/stack/mod.rs index d4fde5aee5..1584330aea 100644 --- a/air/src/constraints/stack/mod.rs +++ b/air/src/constraints/stack/mod.rs @@ -3,16 +3,14 @@ //! This module exposes the general stack transition, stack ops, stack arith/u32, stack crypto, //! and stack overflow constraints. -pub mod bus; +pub mod columns; pub mod crypto; pub mod general; pub mod ops; pub mod overflow; pub mod stack_arith; -use miden_crypto::stark::air::LiftedAirBuilder; - -use crate::{MainTraceRow, constraints::op_flags::OpFlags}; +use crate::{MainCols, MidenAirBuilder, constraints::op_flags::OpFlags}; // ENTRY POINTS // ================================================================================================ @@ -20,11 +18,11 @@ use crate::{MainTraceRow, constraints::op_flags::OpFlags}; /// Enforces stack main-trace constraints for this group. pub fn enforce_main( builder: &mut AB, - local: &MainTraceRow, - next: &MainTraceRow, + local: &MainCols, + next: &MainCols, op_flags: &OpFlags, ) where - AB: LiftedAirBuilder, + AB: MidenAirBuilder, { general::enforce_main(builder, local, next, op_flags); overflow::enforce_main(builder, local, next, op_flags); diff --git a/air/src/constraints/stack/ops.rs b/air/src/constraints/stack/ops.rs new file mode 100644 index 0000000000..7db8ef8896 --- /dev/null +++ b/air/src/constraints/stack/ops.rs @@ -0,0 +1,266 @@ +//! Stack operation constraints. +//! +//! This module enforces ops that directly rewrite visible stack items: +//! PAD, DUP*, CLK, SWAP, MOVUP/MOVDN, SWAPW/SWAPDW, conditional swaps, and small +//! system/io stack ops (ASSERT, CALLER, SDEPTH). +//! +//! Stack shifting is enforced in the general stack constraints; here we only cover explicit +//! rewrites of stack positions for these op groups. + +use miden_crypto::stark::air::AirBuilder; + +use crate::{ + MainCols, MidenAirBuilder, + constraints::{op_flags::OpFlags, utils::BoolNot}, +}; + +// ENTRY POINT +// ================================================================================================ + +/// Enforces stack operation constraints for PAD/DUP/CLK/SWAP/MOV/SWAPW/CSWAP. +pub fn enforce_main( + builder: &mut AB, + local: &MainCols, + next: &MainCols, + op_flags: &OpFlags, +) where + AB: MidenAirBuilder, +{ + let s0 = local.stack.get(0); + let s1 = local.stack.get(1); + let s2 = local.stack.get(2); + let s3 = local.stack.get(3); + let s4 = local.stack.get(4); + let s5 = local.stack.get(5); + let s6 = local.stack.get(6); + let s7 = local.stack.get(7); + let s8 = local.stack.get(8); + let s9 = local.stack.get(9); + let s10 = local.stack.get(10); + let s11 = local.stack.get(11); + let s12 = local.stack.get(12); + let s13 = local.stack.get(13); + let s14 = local.stack.get(14); + let s15 = local.stack.get(15); + let stack_depth = local.stack.b0; + + let fn_hash_0 = local.system.fn_hash[0]; + let fn_hash_1 = local.system.fn_hash[1]; + let fn_hash_2 = local.system.fn_hash[2]; + let fn_hash_3 = local.system.fn_hash[3]; + + let s0_next = next.stack.get(0); + let s1_next = next.stack.get(1); + let s2_next = next.stack.get(2); + let s3_next = next.stack.get(3); + let s4_next = next.stack.get(4); + let s5_next = next.stack.get(5); + let s6_next = next.stack.get(6); + let s7_next = next.stack.get(7); + let s8_next = next.stack.get(8); + let s9_next = next.stack.get(9); + let s10_next = next.stack.get(10); + let s11_next = next.stack.get(11); + let s12_next = next.stack.get(12); + let s13_next = next.stack.get(13); + let s14_next = next.stack.get(14); + let s15_next = next.stack.get(15); + + let is_pad = op_flags.pad(); + let is_dup = op_flags.dup(); + let is_dup1 = op_flags.dup1(); + let is_dup2 = op_flags.dup2(); + let is_dup3 = op_flags.dup3(); + let is_dup4 = op_flags.dup4(); + let is_dup5 = op_flags.dup5(); + let is_dup6 = op_flags.dup6(); + let is_dup7 = op_flags.dup7(); + let is_dup9 = op_flags.dup9(); + let is_dup11 = op_flags.dup11(); + let is_dup13 = op_flags.dup13(); + let is_dup15 = op_flags.dup15(); + + let is_clk = op_flags.clk(); + + let is_swap = op_flags.swap(); + let is_movup2 = op_flags.movup2(); + let is_movup3 = op_flags.movup3(); + let is_movup4 = op_flags.movup4(); + let is_movup5 = op_flags.movup5(); + let is_movup6 = op_flags.movup6(); + let is_movup7 = op_flags.movup7(); + let is_movup8 = op_flags.movup8(); + + let is_movdn2 = op_flags.movdn2(); + let is_movdn3 = op_flags.movdn3(); + let is_movdn4 = op_flags.movdn4(); + let is_movdn5 = op_flags.movdn5(); + let is_movdn6 = op_flags.movdn6(); + let is_movdn7 = op_flags.movdn7(); + let is_movdn8 = op_flags.movdn8(); + + let is_swapw = op_flags.swapw(); + let is_swapw2 = op_flags.swapw2(); + let is_swapw3 = op_flags.swapw3(); + let is_swapdw = op_flags.swapdw(); + + let is_cswap = op_flags.cswap(); + let is_cswapw = op_flags.cswapw(); + let is_assert = op_flags.assert_op(); + let is_caller = op_flags.caller(); + let is_sdepth = op_flags.sdepth(); + + // All constraints are gated by op flags which vanish on the last row. + let builder = &mut builder.when_transition(); + + // PAD + builder.when(is_pad).assert_zero(s0_next); + + // DUP* + builder.when(is_dup).assert_eq(s0_next, s0); + builder.when(is_dup1).assert_eq(s0_next, s1); + builder.when(is_dup2).assert_eq(s0_next, s2); + builder.when(is_dup3).assert_eq(s0_next, s3); + builder.when(is_dup4).assert_eq(s0_next, s4); + builder.when(is_dup5).assert_eq(s0_next, s5); + builder.when(is_dup6).assert_eq(s0_next, s6); + builder.when(is_dup7).assert_eq(s0_next, s7); + builder.when(is_dup9).assert_eq(s0_next, s9); + builder.when(is_dup11).assert_eq(s0_next, s11); + builder.when(is_dup13).assert_eq(s0_next, s13); + builder.when(is_dup15).assert_eq(s0_next, s15); + + // CLK + let clk = local.system.clk; + builder.when(is_clk).assert_eq(s0_next, clk); + + // SWAP: exchange top two stack elements. + { + let builder = &mut builder.when(is_swap); + builder.assert_eq(s0_next, s1); + builder.assert_eq(s1_next, s0); + } + + // MOVUP + builder.when(is_movup2).assert_eq(s0_next, s2); + builder.when(is_movup3).assert_eq(s0_next, s3); + builder.when(is_movup4).assert_eq(s0_next, s4); + builder.when(is_movup5).assert_eq(s0_next, s5); + builder.when(is_movup6).assert_eq(s0_next, s6); + builder.when(is_movup7).assert_eq(s0_next, s7); + builder.when(is_movup8).assert_eq(s0_next, s8); + + // MOVDN + builder.when(is_movdn2).assert_eq(s2_next, s0); + builder.when(is_movdn3).assert_eq(s3_next, s0); + builder.when(is_movdn4).assert_eq(s4_next, s0); + builder.when(is_movdn5).assert_eq(s5_next, s0); + builder.when(is_movdn6).assert_eq(s6_next, s0); + builder.when(is_movdn7).assert_eq(s7_next, s0); + builder.when(is_movdn8).assert_eq(s8_next, s0); + + // SWAPW: exchange first and second words. + { + let builder = &mut builder.when(is_swapw); + builder.assert_eq(s0_next, s4); + builder.assert_eq(s1_next, s5); + builder.assert_eq(s2_next, s6); + builder.assert_eq(s3_next, s7); + builder.assert_eq(s4_next, s0); + builder.assert_eq(s5_next, s1); + builder.assert_eq(s6_next, s2); + builder.assert_eq(s7_next, s3); + } + + // SWAPW2: exchange first and third words. + { + let builder = &mut builder.when(is_swapw2); + builder.assert_eq(s0_next, s8); + builder.assert_eq(s1_next, s9); + builder.assert_eq(s2_next, s10); + builder.assert_eq(s3_next, s11); + builder.assert_eq(s8_next, s0); + builder.assert_eq(s9_next, s1); + builder.assert_eq(s10_next, s2); + builder.assert_eq(s11_next, s3); + } + + // SWAPW3: exchange first and fourth words. + { + let builder = &mut builder.when(is_swapw3); + builder.assert_eq(s0_next, s12); + builder.assert_eq(s1_next, s13); + builder.assert_eq(s2_next, s14); + builder.assert_eq(s3_next, s15); + builder.assert_eq(s12_next, s0); + builder.assert_eq(s13_next, s1); + builder.assert_eq(s14_next, s2); + builder.assert_eq(s15_next, s3); + } + + // SWAPDW: exchange first and second double-words. + { + let builder = &mut builder.when(is_swapdw); + builder.assert_eq(s0_next, s8); + builder.assert_eq(s1_next, s9); + builder.assert_eq(s2_next, s10); + builder.assert_eq(s3_next, s11); + builder.assert_eq(s4_next, s12); + builder.assert_eq(s5_next, s13); + builder.assert_eq(s6_next, s14); + builder.assert_eq(s7_next, s15); + builder.assert_eq(s8_next, s0); + builder.assert_eq(s9_next, s1); + builder.assert_eq(s10_next, s2); + builder.assert_eq(s11_next, s3); + builder.assert_eq(s12_next, s4); + builder.assert_eq(s13_next, s5); + builder.assert_eq(s14_next, s6); + builder.assert_eq(s15_next, s7); + } + + // CSWAP / CSWAPW: conditional swaps using s0 as the selector. + let cswap_c = s0; + let cswap_c_inv = cswap_c.into().not(); + + // Binary constraint for the cswap selector (must be 0 or 1). + builder.when(is_cswap.clone()).assert_bool(cswap_c); + + // Conditional swap equations for the top two stack items. + { + let builder = &mut builder.when(is_cswap); + builder.assert_eq(s0_next, cswap_c * s2.into() + cswap_c_inv.clone() * s1.into()); + builder.assert_eq(s1_next, cswap_c * s1.into() + cswap_c_inv.clone() * s2.into()); + } + + // Binary constraint for the cswapw selector (same selector as cswap). + builder.when(is_cswapw.clone()).assert_bool(cswap_c); + + // Conditional swap equations for the top two words. + { + let builder = &mut builder.when(is_cswapw); + builder.assert_eq(s0_next, cswap_c * s5.into() + cswap_c_inv.clone() * s1.into()); + builder.assert_eq(s1_next, cswap_c * s6.into() + cswap_c_inv.clone() * s2.into()); + builder.assert_eq(s2_next, cswap_c * s7.into() + cswap_c_inv.clone() * s3.into()); + builder.assert_eq(s3_next, cswap_c * s8.into() + cswap_c_inv.clone() * s4.into()); + builder.assert_eq(s4_next, cswap_c * s1.into() + cswap_c_inv.clone() * s5.into()); + builder.assert_eq(s5_next, cswap_c * s2.into() + cswap_c_inv.clone() * s6.into()); + builder.assert_eq(s6_next, cswap_c * s3.into() + cswap_c_inv.clone() * s7.into()); + builder.assert_eq(s7_next, cswap_c * s4.into() + cswap_c_inv * s8.into()); + } + + // ASSERT: top element must be 1 (shift handled by stack general). + builder.when(is_assert).assert_one(s0); + + // CALLER: load fn_hash into the top 4 stack elements. + { + let builder = &mut builder.when(is_caller); + builder.assert_eq(s0_next, fn_hash_0); + builder.assert_eq(s1_next, fn_hash_1); + builder.assert_eq(s2_next, fn_hash_2); + builder.assert_eq(s3_next, fn_hash_3); + } + + // SDEPTH: push current stack depth to the top. + builder.when(is_sdepth).assert_eq(s0_next, stack_depth); +} diff --git a/air/src/constraints/stack/ops/mod.rs b/air/src/constraints/stack/ops/mod.rs deleted file mode 100644 index c4564bd97a..0000000000 --- a/air/src/constraints/stack/ops/mod.rs +++ /dev/null @@ -1,478 +0,0 @@ -//! Stack operation constraints. -//! -//! This module enforces ops that directly rewrite visible stack items: -//! PAD, DUP*, CLK, SWAP, MOVUP/MOVDN, SWAPW/SWAPDW, conditional swaps, and small -//! system/io stack ops (ASSERT, CALLER, SDEPTH). -//! -//! Stack shifting is enforced in the general stack constraints; here we only cover explicit -//! rewrites of stack positions for these op groups. - -use miden_core::field::PrimeCharacteristicRing; -use miden_crypto::stark::air::LiftedAirBuilder; - -use crate::{ - MainTraceRow, - constraints::{ - op_flags::OpFlags, - tagging::{ - TagGroup, TaggingAirBuilderExt, ids::TAG_STACK_OPS_BASE, tagged_assert_zero, - tagged_assert_zero_integrity, tagged_assert_zeros, - }, - }, -}; - -// CONSTANTS -// ================================================================================================ - -/// Number of stack ops constraints. -pub const NUM_CONSTRAINTS: usize = 88; - -/// Base tag ID for stack ops constraints. -const STACK_OPS_BASE_ID: usize = TAG_STACK_OPS_BASE; - -/// Tag namespaces for stack ops constraints. -const STACK_OPS_NAMES: [&str; NUM_CONSTRAINTS] = [ - // PAD - "stack.ops.pad", - // DUP* - "stack.ops.dup", - "stack.ops.dup1", - "stack.ops.dup2", - "stack.ops.dup3", - "stack.ops.dup4", - "stack.ops.dup5", - "stack.ops.dup6", - "stack.ops.dup7", - "stack.ops.dup9", - "stack.ops.dup11", - "stack.ops.dup13", - "stack.ops.dup15", - // CLK - "stack.ops.clk", - // SWAP: exchange the top two stack items. - "stack.ops.swap", - "stack.ops.swap", - // MOVUP: move an item at depth N to the top. - "stack.ops.movup2", - "stack.ops.movup3", - "stack.ops.movup4", - "stack.ops.movup5", - "stack.ops.movup6", - "stack.ops.movup7", - "stack.ops.movup8", - // MOVDN: move the top item down to depth N. - "stack.ops.movdn2", - "stack.ops.movdn3", - "stack.ops.movdn4", - "stack.ops.movdn5", - "stack.ops.movdn6", - "stack.ops.movdn7", - "stack.ops.movdn8", - // SWAPW: swap word [0..3] with word [4..7]. - "stack.ops.swapw", - "stack.ops.swapw", - "stack.ops.swapw", - "stack.ops.swapw", - "stack.ops.swapw", - "stack.ops.swapw", - "stack.ops.swapw", - "stack.ops.swapw", - // SWAPW2: swap word [0..3] with word [8..11]. - "stack.ops.swapw2", - "stack.ops.swapw2", - "stack.ops.swapw2", - "stack.ops.swapw2", - "stack.ops.swapw2", - "stack.ops.swapw2", - "stack.ops.swapw2", - "stack.ops.swapw2", - // SWAPW3: swap word [0..3] with word [12..15]. - "stack.ops.swapw3", - "stack.ops.swapw3", - "stack.ops.swapw3", - "stack.ops.swapw3", - "stack.ops.swapw3", - "stack.ops.swapw3", - "stack.ops.swapw3", - "stack.ops.swapw3", - // SWAPDW: swap double-word [0..7] with [8..15]. - "stack.ops.swapdw", - "stack.ops.swapdw", - "stack.ops.swapdw", - "stack.ops.swapdw", - "stack.ops.swapdw", - "stack.ops.swapdw", - "stack.ops.swapdw", - "stack.ops.swapdw", - "stack.ops.swapdw", - "stack.ops.swapdw", - "stack.ops.swapdw", - "stack.ops.swapdw", - "stack.ops.swapdw", - "stack.ops.swapdw", - "stack.ops.swapdw", - "stack.ops.swapdw", - // CSWAP - "stack.ops.cswap", - "stack.ops.cswap", - "stack.ops.cswap", - // CSWAPW - "stack.ops.cswapw", - "stack.ops.cswapw", - "stack.ops.cswapw", - "stack.ops.cswapw", - "stack.ops.cswapw", - "stack.ops.cswapw", - "stack.ops.cswapw", - "stack.ops.cswapw", - "stack.ops.cswapw", - // ASSERT - "stack.system.assert", - // CALLER - "stack.system.caller", - "stack.system.caller", - "stack.system.caller", - "stack.system.caller", - // SDEPTH - "stack.io.sdepth", -]; - -/// Tag metadata for this constraint group. -const STACK_OPS_TAGS: TagGroup = TagGroup { - base: STACK_OPS_BASE_ID, - names: &STACK_OPS_NAMES, -}; - -// ENTRY POINT -// ================================================================================================ - -/// Enforces stack operation constraints for PAD/DUP/CLK/SWAP/MOV/SWAPW/CSWAP. -pub fn enforce_main( - builder: &mut AB, - local: &MainTraceRow, - next: &MainTraceRow, - op_flags: &OpFlags, -) where - AB: LiftedAirBuilder, -{ - let s0: AB::Expr = local.stack[0].clone().into(); - let s1: AB::Expr = local.stack[1].clone().into(); - let s2: AB::Expr = local.stack[2].clone().into(); - let s3: AB::Expr = local.stack[3].clone().into(); - let s4: AB::Expr = local.stack[4].clone().into(); - let s5: AB::Expr = local.stack[5].clone().into(); - let s6: AB::Expr = local.stack[6].clone().into(); - let s7: AB::Expr = local.stack[7].clone().into(); - let s8: AB::Expr = local.stack[8].clone().into(); - let s9: AB::Expr = local.stack[9].clone().into(); - let s10: AB::Expr = local.stack[10].clone().into(); - let s11: AB::Expr = local.stack[11].clone().into(); - let s12: AB::Expr = local.stack[12].clone().into(); - let s13: AB::Expr = local.stack[13].clone().into(); - let s14: AB::Expr = local.stack[14].clone().into(); - let s15: AB::Expr = local.stack[15].clone().into(); - let stack_depth: AB::Expr = local.stack[16].clone().into(); - - let fn_hash_0: AB::Expr = local.fn_hash[0].clone().into(); - let fn_hash_1: AB::Expr = local.fn_hash[1].clone().into(); - let fn_hash_2: AB::Expr = local.fn_hash[2].clone().into(); - let fn_hash_3: AB::Expr = local.fn_hash[3].clone().into(); - - let s0_next: AB::Expr = next.stack[0].clone().into(); - let s1_next: AB::Expr = next.stack[1].clone().into(); - let s2_next: AB::Expr = next.stack[2].clone().into(); - let s3_next: AB::Expr = next.stack[3].clone().into(); - let s4_next: AB::Expr = next.stack[4].clone().into(); - let s5_next: AB::Expr = next.stack[5].clone().into(); - let s6_next: AB::Expr = next.stack[6].clone().into(); - let s7_next: AB::Expr = next.stack[7].clone().into(); - let s8_next: AB::Expr = next.stack[8].clone().into(); - let s9_next: AB::Expr = next.stack[9].clone().into(); - let s10_next: AB::Expr = next.stack[10].clone().into(); - let s11_next: AB::Expr = next.stack[11].clone().into(); - let s12_next: AB::Expr = next.stack[12].clone().into(); - let s13_next: AB::Expr = next.stack[13].clone().into(); - let s14_next: AB::Expr = next.stack[14].clone().into(); - let s15_next: AB::Expr = next.stack[15].clone().into(); - - let is_pad = op_flags.pad(); - let is_dup = op_flags.dup(); - let is_dup1 = op_flags.dup1(); - let is_dup2 = op_flags.dup2(); - let is_dup3 = op_flags.dup3(); - let is_dup4 = op_flags.dup4(); - let is_dup5 = op_flags.dup5(); - let is_dup6 = op_flags.dup6(); - let is_dup7 = op_flags.dup7(); - let is_dup9 = op_flags.dup9(); - let is_dup11 = op_flags.dup11(); - let is_dup13 = op_flags.dup13(); - let is_dup15 = op_flags.dup15(); - - let is_clk = op_flags.clk(); - - let is_swap = op_flags.swap(); - let is_movup2 = op_flags.movup2(); - let is_movup3 = op_flags.movup3(); - let is_movup4 = op_flags.movup4(); - let is_movup5 = op_flags.movup5(); - let is_movup6 = op_flags.movup6(); - let is_movup7 = op_flags.movup7(); - let is_movup8 = op_flags.movup8(); - - let is_movdn2 = op_flags.movdn2(); - let is_movdn3 = op_flags.movdn3(); - let is_movdn4 = op_flags.movdn4(); - let is_movdn5 = op_flags.movdn5(); - let is_movdn6 = op_flags.movdn6(); - let is_movdn7 = op_flags.movdn7(); - let is_movdn8 = op_flags.movdn8(); - - let is_swapw = op_flags.swapw(); - let is_swapw2 = op_flags.swapw2(); - let is_swapw3 = op_flags.swapw3(); - let is_swapdw = op_flags.swapdw(); - - let is_cswap = op_flags.cswap(); - let is_cswapw = op_flags.cswapw(); - let is_assert = op_flags.assert_op(); - let is_caller = op_flags.caller(); - let is_sdepth = op_flags.sdepth(); - - let mut idx = 0usize; - - // PAD - assert_zero(builder, &mut idx, is_pad * s0_next.clone()); - - // DUP* - assert_zero(builder, &mut idx, is_dup * (s0_next.clone() - s0.clone())); - assert_zero(builder, &mut idx, is_dup1 * (s0_next.clone() - s1.clone())); - assert_zero(builder, &mut idx, is_dup2 * (s0_next.clone() - s2.clone())); - assert_zero(builder, &mut idx, is_dup3 * (s0_next.clone() - s3.clone())); - assert_zero(builder, &mut idx, is_dup4 * (s0_next.clone() - s4.clone())); - assert_zero(builder, &mut idx, is_dup5 * (s0_next.clone() - s5.clone())); - assert_zero(builder, &mut idx, is_dup6 * (s0_next.clone() - s6.clone())); - assert_zero(builder, &mut idx, is_dup7 * (s0_next.clone() - s7.clone())); - assert_zero(builder, &mut idx, is_dup9 * (s0_next.clone() - s9.clone())); - assert_zero(builder, &mut idx, is_dup11 * (s0_next.clone() - s11.clone())); - assert_zero(builder, &mut idx, is_dup13 * (s0_next.clone() - s13.clone())); - assert_zero(builder, &mut idx, is_dup15 * (s0_next.clone() - s15.clone())); - - // CLK - let clk: AB::Expr = local.clk.clone().into(); - assert_zero(builder, &mut idx, is_clk * (s0_next.clone() - clk)); - - // SWAP - assert_zeros( - builder, - &mut idx, - "stack.ops.swap", - [ - is_swap.clone() * (s0_next.clone() - s1.clone()), - is_swap * (s1_next.clone() - s0.clone()), - ], - ); - - // MOVUP - assert_zero(builder, &mut idx, is_movup2 * (s0_next.clone() - s2.clone())); - assert_zero(builder, &mut idx, is_movup3 * (s0_next.clone() - s3.clone())); - assert_zero(builder, &mut idx, is_movup4 * (s0_next.clone() - s4.clone())); - assert_zero(builder, &mut idx, is_movup5 * (s0_next.clone() - s5.clone())); - assert_zero(builder, &mut idx, is_movup6 * (s0_next.clone() - s6.clone())); - assert_zero(builder, &mut idx, is_movup7 * (s0_next.clone() - s7.clone())); - assert_zero(builder, &mut idx, is_movup8 * (s0_next.clone() - s8.clone())); - - // MOVDN - assert_zero(builder, &mut idx, is_movdn2 * (s2_next.clone() - s0.clone())); - assert_zero(builder, &mut idx, is_movdn3 * (s3_next.clone() - s0.clone())); - assert_zero(builder, &mut idx, is_movdn4 * (s4_next.clone() - s0.clone())); - assert_zero(builder, &mut idx, is_movdn5 * (s5_next.clone() - s0.clone())); - assert_zero(builder, &mut idx, is_movdn6 * (s6_next.clone() - s0.clone())); - assert_zero(builder, &mut idx, is_movdn7 * (s7_next.clone() - s0.clone())); - assert_zero(builder, &mut idx, is_movdn8 * (s8_next.clone() - s0.clone())); - - // SWAPW - assert_zeros( - builder, - &mut idx, - "stack.ops.swapw", - [ - is_swapw.clone() * (s0_next.clone() - s4.clone()), - is_swapw.clone() * (s1_next.clone() - s5.clone()), - is_swapw.clone() * (s2_next.clone() - s6.clone()), - is_swapw.clone() * (s3_next.clone() - s7.clone()), - is_swapw.clone() * (s4_next.clone() - s0.clone()), - is_swapw.clone() * (s5_next.clone() - s1.clone()), - is_swapw.clone() * (s6_next.clone() - s2.clone()), - is_swapw * (s7_next.clone() - s3.clone()), - ], - ); - - // SWAPW2 - assert_zeros( - builder, - &mut idx, - "stack.ops.swapw2", - [ - is_swapw2.clone() * (s0_next.clone() - s8.clone()), - is_swapw2.clone() * (s1_next.clone() - s9.clone()), - is_swapw2.clone() * (s2_next.clone() - s10.clone()), - is_swapw2.clone() * (s3_next.clone() - s11.clone()), - is_swapw2.clone() * (s8_next.clone() - s0.clone()), - is_swapw2.clone() * (s9_next.clone() - s1.clone()), - is_swapw2.clone() * (s10_next.clone() - s2.clone()), - is_swapw2 * (s11_next.clone() - s3.clone()), - ], - ); - - // SWAPW3 - assert_zeros( - builder, - &mut idx, - "stack.ops.swapw3", - [ - is_swapw3.clone() * (s0_next.clone() - s12.clone()), - is_swapw3.clone() * (s1_next.clone() - s13.clone()), - is_swapw3.clone() * (s2_next.clone() - s14.clone()), - is_swapw3.clone() * (s3_next.clone() - s15.clone()), - is_swapw3.clone() * (s12_next.clone() - s0.clone()), - is_swapw3.clone() * (s13_next.clone() - s1.clone()), - is_swapw3.clone() * (s14_next.clone() - s2.clone()), - is_swapw3 * (s15_next.clone() - s3.clone()), - ], - ); - - // SWAPDW - assert_zeros( - builder, - &mut idx, - "stack.ops.swapdw", - [ - is_swapdw.clone() * (s0_next.clone() - s8.clone()), - is_swapdw.clone() * (s1_next.clone() - s9.clone()), - is_swapdw.clone() * (s2_next.clone() - s10.clone()), - is_swapdw.clone() * (s3_next.clone() - s11.clone()), - is_swapdw.clone() * (s4_next.clone() - s12.clone()), - is_swapdw.clone() * (s5_next.clone() - s13.clone()), - is_swapdw.clone() * (s6_next.clone() - s14.clone()), - is_swapdw.clone() * (s7_next.clone() - s15.clone()), - is_swapdw.clone() * (s8_next.clone() - s0.clone()), - is_swapdw.clone() * (s9_next.clone() - s1.clone()), - is_swapdw.clone() * (s10_next.clone() - s2.clone()), - is_swapdw.clone() * (s11_next.clone() - s3.clone()), - is_swapdw.clone() * (s12_next.clone() - s4.clone()), - is_swapdw.clone() * (s13_next.clone() - s5.clone()), - is_swapdw.clone() * (s14_next.clone() - s6.clone()), - is_swapdw * (s15_next.clone() - s7.clone()), - ], - ); - - // CSWAP / CSWAPW: conditional swaps using s0 as the selector. - let cswap_c = s0.clone(); - let cswap_c_inv = AB::Expr::ONE - cswap_c.clone(); - - // Binary constraint for the cswap selector (must be 0 or 1). - assert_zero_integrity( - builder, - &mut idx, - is_cswap.clone() * (cswap_c.clone() * (cswap_c.clone() - AB::Expr::ONE)), - ); - - // Conditional swap equations for the top two stack items. - assert_zeros( - builder, - &mut idx, - "stack.ops.cswap", - [ - is_cswap.clone() - * (s0_next.clone() - - (cswap_c.clone() * s2.clone() + cswap_c_inv.clone() * s1.clone())), - is_cswap - * (s1_next.clone() - - (cswap_c.clone() * s1.clone() + cswap_c_inv.clone() * s2.clone())), - ], - ); - - // Binary constraint for the cswapw selector (same selector as cswap). - assert_zero_integrity( - builder, - &mut idx, - is_cswapw.clone() * (cswap_c.clone() * (cswap_c.clone() - AB::Expr::ONE)), - ); - - // Conditional swap equations for the top two words. - assert_zeros( - builder, - &mut idx, - "stack.ops.cswapw", - [ - is_cswapw.clone() - * (s0_next.clone() - - (cswap_c.clone() * s5.clone() + cswap_c_inv.clone() * s1.clone())), - is_cswapw.clone() - * (s1_next.clone() - - (cswap_c.clone() * s6.clone() + cswap_c_inv.clone() * s2.clone())), - is_cswapw.clone() - * (s2_next.clone() - - (cswap_c.clone() * s7.clone() + cswap_c_inv.clone() * s3.clone())), - is_cswapw.clone() - * (s3_next.clone() - - (cswap_c.clone() * s8.clone() + cswap_c_inv.clone() * s4.clone())), - is_cswapw.clone() - * (s4_next.clone() - - (cswap_c.clone() * s1.clone() + cswap_c_inv.clone() * s5.clone())), - is_cswapw.clone() - * (s5_next.clone() - - (cswap_c.clone() * s2.clone() + cswap_c_inv.clone() * s6.clone())), - is_cswapw.clone() - * (s6_next.clone() - - (cswap_c.clone() * s3.clone() + cswap_c_inv.clone() * s7.clone())), - is_cswapw - * (s7_next.clone() - - (cswap_c.clone() * s4.clone() + cswap_c_inv.clone() * s8.clone())), - ], - ); - - // ASSERT: top element must be 1 (shift handled by stack general). - assert_zero_integrity(builder, &mut idx, is_assert * (s0 - AB::Expr::ONE)); - - // CALLER: load fn_hash into the top 4 stack elements. - assert_zeros( - builder, - &mut idx, - "stack.system.caller", - [ - is_caller.clone() * (s0_next.clone() - fn_hash_0), - is_caller.clone() * (s1_next.clone() - fn_hash_1), - is_caller.clone() * (s2_next.clone() - fn_hash_2), - is_caller * (s3_next.clone() - fn_hash_3), - ], - ); - - // SDEPTH: push current stack depth to the top. - assert_zero(builder, &mut idx, is_sdepth * (s0_next - stack_depth)); -} - -// CONSTRAINT HELPERS -// ================================================================================================ - -fn assert_zero_integrity( - builder: &mut AB, - idx: &mut usize, - expr: AB::Expr, -) { - tagged_assert_zero_integrity(builder, &STACK_OPS_TAGS, idx, expr); -} - -fn assert_zero(builder: &mut AB, idx: &mut usize, expr: AB::Expr) { - tagged_assert_zero(builder, &STACK_OPS_TAGS, idx, expr); -} - -fn assert_zeros( - builder: &mut AB, - idx: &mut usize, - namespace: &'static str, - exprs: [AB::Expr; N], -) { - tagged_assert_zeros(builder, &STACK_OPS_TAGS, idx, namespace, exprs); -} diff --git a/air/src/constraints/stack/overflow/mod.rs b/air/src/constraints/stack/overflow.rs similarity index 53% rename from air/src/constraints/stack/overflow/mod.rs rename to air/src/constraints/stack/overflow.rs index b523fd28cb..b40f2db638 100644 --- a/air/src/constraints/stack/overflow/mod.rs +++ b/air/src/constraints/stack/overflow.rs @@ -27,41 +27,13 @@ //! - On left shift with depth = 16: stack[15]' = 0 (no item to restore) use miden_core::field::PrimeCharacteristicRing; -use miden_crypto::stark::air::{AirBuilder, LiftedAirBuilder}; +use miden_crypto::stark::air::AirBuilder; use crate::{ - MainTraceRow, - constraints::{ - op_flags::OpFlags, - tagging::{ - TaggingAirBuilderExt, - ids::{TAG_STACK_OVERFLOW_BASE, TAG_STACK_OVERFLOW_COUNT}, - }, - }, - trace::{ - decoder::{IS_CALL_FLAG_COL_IDX, IS_SYSCALL_FLAG_COL_IDX}, - stack::{B0_COL_IDX, B1_COL_IDX}, - }, + MainCols, MidenAirBuilder, + constraints::{constants::*, op_flags::OpFlags, utils::BoolNot}, }; -// CONSTANTS -// ================================================================================================ - -/// Base tag ID for stack overflow constraints. -const STACK_OVERFLOW_BASE_ID: usize = TAG_STACK_OVERFLOW_BASE; - -/// Tag namespaces for stack overflow constraints (boundary + transition). -const STACK_OVERFLOW_NAMES: [&str; TAG_STACK_OVERFLOW_COUNT] = [ - "stack.overflow.depth.first_row", - "stack.overflow.depth.last_row", - "stack.overflow.addr.first_row", - "stack.overflow.addr.last_row", - "stack.overflow.depth.transition", - "stack.overflow.flag.transition", - "stack.overflow.addr.transition", - "stack.overflow.zero_insert.transition", -]; - // ENTRY POINTS // ================================================================================================ @@ -74,39 +46,28 @@ const STACK_OVERFLOW_NAMES: [&str; TAG_STACK_OVERFLOW_COUNT] = [ /// 4. Last stack item is zeroed on left shift when depth = 16 pub fn enforce_main( builder: &mut AB, - local: &MainTraceRow, - next: &MainTraceRow, + local: &MainCols, + next: &MainCols, op_flags: &OpFlags, ) where - AB: LiftedAirBuilder, + AB: MidenAirBuilder, { // Boundary constraints: stack depth and overflow pointer must start/end clean. - let sixteen: AB::Expr = AB::Expr::from_u16(16); - let zero: AB::Expr = AB::Expr::ZERO; - builder.tagged(STACK_OVERFLOW_BASE_ID, STACK_OVERFLOW_NAMES[0], |builder| { - builder - .when_first_row() - .assert_zero(local.stack[B0_COL_IDX].clone().into() - sixteen.clone()); - }); - builder.tagged(STACK_OVERFLOW_BASE_ID + 1, STACK_OVERFLOW_NAMES[1], |builder| { - builder - .when_last_row() - .assert_zero(local.stack[B0_COL_IDX].clone().into() - sixteen); - }); - builder.tagged(STACK_OVERFLOW_BASE_ID + 2, STACK_OVERFLOW_NAMES[2], |builder| { - builder - .when_first_row() - .assert_zero(local.stack[B1_COL_IDX].clone().into() - zero.clone()); - }); - builder.tagged(STACK_OVERFLOW_BASE_ID + 3, STACK_OVERFLOW_NAMES[3], |builder| { - builder - .when_last_row() - .assert_zero(local.stack[B1_COL_IDX].clone().into() - zero); - }); + builder.when_first_row().assert_eq(local.stack.b0, F_16); + builder.when_last_row().assert_eq(local.stack.b0, F_16); + builder.when_first_row().assert_zero(local.stack.b1); + builder.when_last_row().assert_zero(local.stack.b1); // Transition constraints: depth bookkeeping, overflow flag, and pointer updates. enforce_stack_depth_constraints(builder, local, next, op_flags); - enforce_overflow_flag_constraints(builder, local, op_flags); + + // Overflow flag: (1 - overflow) * (depth - 16) = 0 + // When depth > 16, overflow must be 1; when depth = 16, satisfied for any h0. + { + let depth = local.stack.b0; + builder.when(op_flags.overflow().not()).assert_eq(depth, F_16); + } + enforce_overflow_index_constraints(builder, local, next, op_flags); } @@ -124,21 +85,21 @@ pub fn enforce_main( /// The END operation exiting a CALL/SYSCALL block is handled separately via multiset constraints. fn enforce_stack_depth_constraints( builder: &mut AB, - local: &MainTraceRow, - next: &MainTraceRow, + local: &MainCols, + next: &MainCols, op_flags: &OpFlags, ) where - AB: LiftedAirBuilder, + AB: MidenAirBuilder, { - let depth: AB::Expr = local.stack[B0_COL_IDX].clone().into(); - let depth_next: AB::Expr = next.stack[B0_COL_IDX].clone().into(); + let depth = local.stack.b0; + let depth_next = next.stack.b0; // Flag for CALL, DYNCALL, or SYSCALL operations let call_or_dyncall_or_syscall = op_flags.call() + op_flags.dyncall() + op_flags.syscall(); // Flag for END operation that ends a CALL/DYNCALL or SYSCALL block - let is_call_or_dyncall_end: AB::Expr = local.decoder[IS_CALL_FLAG_COL_IDX].clone().into(); - let is_syscall_end: AB::Expr = local.decoder[IS_SYSCALL_FLAG_COL_IDX].clone().into(); + let is_call_or_dyncall_end = local.decoder.hasher_state[6]; + let is_syscall_end = local.decoder.hasher_state[7]; let call_or_dyncall_or_syscall_end = op_flags.end() * (is_call_or_dyncall_end + is_syscall_end); // Invariants relied on here: @@ -164,7 +125,7 @@ fn enforce_stack_depth_constraints( // - We still need to suppress the raw (b0' - b0) term on END-of-call rows, hence the mask. let normal_mask = AB::Expr::ONE - call_or_dyncall_or_syscall.clone() - call_or_dyncall_or_syscall_end; - let depth_delta_part = (depth_next.clone() - depth.clone()) * normal_mask; + let depth_delta_part = (depth_next.into() - depth.into()) * normal_mask; // Left shift with non-empty overflow: when f_shl=1 and f_ov=1, depth must decrement by 1. // This contributes +1 to the LHS, enforcing b0' = b0 - 1. @@ -175,41 +136,12 @@ fn enforce_stack_depth_constraints( let right_shift_part = op_flags.right_shift(); // CALL/SYSCALL/DYNCALL: depth resets to 16 when entering a new context. - let call_part = call_or_dyncall_or_syscall * (depth_next - AB::Expr::from_u16(16)); + let call_part = call_or_dyncall_or_syscall * (depth_next.into() - F_16); // Combined constraint: normal depth update + shift effects + call reset = 0. - builder.tagged(STACK_OVERFLOW_BASE_ID + 4, STACK_OVERFLOW_NAMES[4], |builder| { - builder - .when_transition() - .assert_zero(depth_delta_part + left_shift_part - right_shift_part + call_part); - }); -} - -/// Enforces overflow flag constraints. -/// -/// The overflow flag h0 must satisfy: -/// - (1 - overflow) * (b0 - 16) = 0 -/// -/// This ensures: -/// - When b0 = 16 (no overflow): the constraint is satisfied for any h0 -/// - When b0 > 16 (overflow): h0 must be set such that overflow = (b0 - 16) * h0 = 1 -fn enforce_overflow_flag_constraints( - builder: &mut AB, - local: &MainTraceRow, - op_flags: &OpFlags, -) where - AB: LiftedAirBuilder, -{ - let depth: AB::Expr = local.stack[B0_COL_IDX].clone().into(); - - // (1 - overflow) * (depth - 16) = 0 - // When depth > 16, overflow must be 1 (meaning h0 = 1/(depth - 16)) - // When depth = 16, this constraint is satisfied regardless of overflow - let constraint = (AB::Expr::ONE - op_flags.overflow()) * (depth - AB::Expr::from_u16(16)); - - builder.tagged(STACK_OVERFLOW_BASE_ID + 5, STACK_OVERFLOW_NAMES[5], |builder| { - builder.assert_zero(constraint); - }); + builder + .when_transition() + .assert_zero(depth_delta_part + left_shift_part - right_shift_part + call_part); } /// Enforces overflow bookkeeping index constraints. @@ -219,26 +151,26 @@ fn enforce_overflow_flag_constraints( /// 2. On left shift with depth = 16: stack[15]' = 0 (no item to restore from overflow) fn enforce_overflow_index_constraints( builder: &mut AB, - local: &MainTraceRow, - next: &MainTraceRow, + local: &MainCols, + next: &MainCols, op_flags: &OpFlags, ) where - AB: LiftedAirBuilder, + AB: MidenAirBuilder, { - let overflow_addr_next: AB::Expr = next.stack[B1_COL_IDX].clone().into(); - let clk: AB::Expr = local.clk.clone().into(); - let last_stack_item_next: AB::Expr = next.stack[15].clone().into(); + let overflow_addr_next = next.stack.b1; + let clk = local.system.clk; + let last_stack_item_next = next.stack.get(15); // On right shift, the overflow address should be set to current clk - let right_shift_constraint = (overflow_addr_next - clk) * op_flags.right_shift(); - builder.tagged(STACK_OVERFLOW_BASE_ID + 6, STACK_OVERFLOW_NAMES[6], |builder| { - builder.when_transition().assert_zero(right_shift_constraint); - }); + builder + .when_transition() + .when(op_flags.right_shift()) + .assert_eq(overflow_addr_next, clk); // On left shift when depth = 16 (no overflow), last stack item should be zero - let left_shift_constraint = - (AB::Expr::ONE - op_flags.overflow()) * op_flags.left_shift() * last_stack_item_next; - builder.tagged(STACK_OVERFLOW_BASE_ID + 7, STACK_OVERFLOW_NAMES[7], |builder| { - builder.when_transition().assert_zero(left_shift_constraint); - }); + builder + .when_transition() + .when(op_flags.overflow().not()) + .when(op_flags.left_shift()) + .assert_zero(last_stack_item_next); } diff --git a/air/src/constraints/stack/stack_arith/mod.rs b/air/src/constraints/stack/stack_arith/mod.rs index daef674461..d3b9ff65f6 100644 --- a/air/src/constraints/stack/stack_arith/mod.rs +++ b/air/src/constraints/stack/stack_arith/mod.rs @@ -4,94 +4,15 @@ //! (ADD/NEG/MUL/INV/INCR/NOT/AND/OR/EQ/EQZ/EXPACC/EXT2MUL) and u32 arithmetic ops //! (U32SPLIT/U32ADD/U32ADD3/U32SUB/U32MUL/U32MADD/U32DIV/U32ASSERT2). +#[cfg(test)] +mod tests; + use miden_core::field::PrimeCharacteristicRing; -use miden_crypto::stark::air::LiftedAirBuilder; +use miden_crypto::stark::air::AirBuilder; use crate::{ - MainTraceRow, - constraints::{ - op_flags::OpFlags, - tagging::{ - TagGroup, TaggingAirBuilderExt, ids::TAG_STACK_ARITH_BASE, tagged_assert_zero, - tagged_assert_zero_integrity, - }, - }, - trace::decoder::USER_OP_HELPERS_OFFSET, -}; - -// CONSTANTS -// ================================================================================================ - -/// Number of stack arith/u32 constraints. -#[allow(dead_code)] -pub const NUM_CONSTRAINTS: usize = 42; - -/// Base tag ID for stack arith/u32 constraints. -const STACK_ARITH_BASE_ID: usize = TAG_STACK_ARITH_BASE; - -/// Tag namespaces for stack arith/u32 constraints. -const STACK_ARITH_NAMES: [&str; NUM_CONSTRAINTS] = [ - // ADD/NEG/MUL/INV/INCR - "stack.arith.add", - "stack.arith.neg", - "stack.arith.mul", - "stack.arith.inv", - "stack.arith.incr", - // NOT - "stack.arith.not", - "stack.arith.not", - // AND - "stack.arith.and", - "stack.arith.and", - "stack.arith.and", - // OR - "stack.arith.or", - "stack.arith.or", - "stack.arith.or", - // EQ - "stack.arith.eq", - "stack.arith.eq", - // EQZ - "stack.arith.eqz", - "stack.arith.eqz", - // EXPACC - "stack.arith.expacc", - "stack.arith.expacc", - "stack.arith.expacc", - "stack.arith.expacc", - "stack.arith.expacc", - // EXT2MUL - "stack.arith.ext2mul", - "stack.arith.ext2mul", - "stack.arith.ext2mul", - "stack.arith.ext2mul", - // U32 shared/output - "stack.arith.u32.shared", - "stack.arith.u32.output", - "stack.arith.u32.output", - // U32SPLIT/U32ADD/U32ADD3 - "stack.arith.u32.split", - "stack.arith.u32.add", - "stack.arith.u32.add3", - // U32SUB - "stack.arith.u32.sub", - "stack.arith.u32.sub", - "stack.arith.u32.sub", - // U32MUL/U32MADD - "stack.arith.u32.mul", - "stack.arith.u32.madd", - // U32DIV - "stack.arith.u32.div", - "stack.arith.u32.div", - "stack.arith.u32.div", - // U32ASSERT2 - "stack.arith.u32.assert2", - "stack.arith.u32.assert2", -]; - -const STACK_ARITH_TAGS: TagGroup = TagGroup { - base: STACK_ARITH_BASE_ID, - names: &STACK_ARITH_NAMES, + MainCols, MidenAirBuilder, + constraints::{constants::*, op_flags::OpFlags}, }; // ENTRY POINTS @@ -100,35 +21,32 @@ const STACK_ARITH_TAGS: TagGroup = TagGroup { /// Enforces stack arith/u32 constraints. pub fn enforce_main( builder: &mut AB, - local: &MainTraceRow, - next: &MainTraceRow, + local: &MainCols, + next: &MainCols, op_flags: &OpFlags, ) where - AB: LiftedAirBuilder, + AB: MidenAirBuilder, { - let mut idx = 0usize; + let s0: AB::Expr = local.stack.get(0).into(); + let s1: AB::Expr = local.stack.get(1).into(); + let s2: AB::Expr = local.stack.get(2).into(); + let s3: AB::Expr = local.stack.get(3).into(); - let s0: AB::Expr = local.stack[0].clone().into(); - let s1: AB::Expr = local.stack[1].clone().into(); - let s2: AB::Expr = local.stack[2].clone().into(); - let s3: AB::Expr = local.stack[3].clone().into(); + let s0_next: AB::Expr = next.stack.get(0).into(); + let s1_next: AB::Expr = next.stack.get(1).into(); + let s2_next: AB::Expr = next.stack.get(2).into(); + let s3_next: AB::Expr = next.stack.get(3).into(); - let s0_next: AB::Expr = next.stack[0].clone().into(); - let s1_next: AB::Expr = next.stack[1].clone().into(); - let s2_next: AB::Expr = next.stack[2].clone().into(); - let s3_next: AB::Expr = next.stack[3].clone().into(); - - // Decoder helper columns: h0..h5 are stored starting at USER_OP_HELPERS_OFFSET. - // These helpers are op-specific and are validated by the constraints below. + // Decoder helper columns: hasher_state[2..8] are user-op helpers. // - h0 is used as an inverse witness (EQ/EQZ) or exp_val (EXPACC). // - h1..h4 hold u32 limbs / range-check witnesses for u32 ops. // - h5 is currently unused in this module. - let base = USER_OP_HELPERS_OFFSET; - let uop_h0: AB::Expr = local.decoder[base].clone().into(); - let uop_h1: AB::Expr = local.decoder[base + 1].clone().into(); - let uop_h2: AB::Expr = local.decoder[base + 2].clone().into(); - let uop_h3: AB::Expr = local.decoder[base + 3].clone().into(); - let uop_h4: AB::Expr = local.decoder[base + 4].clone().into(); + let [uop_h0, uop_h1, uop_h2, uop_h3, uop_h4, _] = local.decoder.user_op_helpers(); + let uop_h0: AB::Expr = uop_h0.into(); + let uop_h1: AB::Expr = uop_h1.into(); + let uop_h2: AB::Expr = uop_h2.into(); + let uop_h3: AB::Expr = uop_h3.into(); + let uop_h4: AB::Expr = uop_h4.into(); // Field ops. let is_add = op_flags.add(); @@ -157,63 +75,74 @@ pub fn enforce_main( // ------------------------------------------------------------------------- // Field ops // ------------------------------------------------------------------------- - assert_zero(builder, &mut idx, is_add * (s0_next.clone() - (s0.clone() + s1.clone()))); - assert_zero(builder, &mut idx, is_neg * (s0_next.clone() + s0.clone())); - assert_zero(builder, &mut idx, is_mul * (s0_next.clone() - s0.clone() * s1.clone())); - assert_zero(builder, &mut idx, is_inv * (s0_next.clone() * s0.clone() - AB::Expr::ONE)); - assert_zero(builder, &mut idx, is_incr * (s0_next.clone() - s0.clone() - AB::Expr::ONE)); - - assert_zero_integrity( - builder, - &mut idx, - is_not.clone() * (s0.clone() * (s0.clone() - AB::Expr::ONE)), - ); - assert_zero(builder, &mut idx, is_not * (s0.clone() + s0_next.clone() - AB::Expr::ONE)); - assert_zero_integrity( - builder, - &mut idx, - is_and.clone() * (s0.clone() * (s0.clone() - AB::Expr::ONE)), - ); - assert_zero_integrity( - builder, - &mut idx, - is_and.clone() * (s1.clone() * (s1.clone() - AB::Expr::ONE)), - ); - assert_zero(builder, &mut idx, is_and * (s0_next.clone() - s0.clone() * s1.clone())); - - assert_zero_integrity( - builder, - &mut idx, - is_or.clone() * (s0.clone() * (s0.clone() - AB::Expr::ONE)), - ); - assert_zero_integrity( - builder, - &mut idx, - is_or.clone() * (s1.clone() * (s1.clone() - AB::Expr::ONE)), - ); - assert_zero( - builder, - &mut idx, - is_or * (s0_next.clone() - (s0.clone() + s1.clone() - s0.clone() * s1.clone())), - ); + // ADD: s0' = s0 + s1 + builder + .when_transition() + .when(is_add) + .assert_eq(s0_next.clone(), s0.clone() + s1.clone()); + + // NEG: s0' = -s0 + builder.when_transition().when(is_neg).assert_zero(s0_next.clone() + s0.clone()); + + // MUL: s0' = s0 * s1 + builder + .when_transition() + .when(is_mul) + .assert_eq(s0_next.clone(), s0.clone() * s1.clone()); + + // INV: s0' * s0 = 1 + builder.when_transition().when(is_inv).assert_one(s0_next.clone() * s0.clone()); + + // INCR: s0' = s0 + 1 + builder + .when_transition() + .when(is_incr) + .assert_eq(s0_next.clone(), s0.clone() + F_1); + + // NOT: s0 is boolean, s0 + s0' = 1. + { + let builder = &mut builder.when(is_not); + builder.assert_bool(s0.clone()); + builder.when_transition().assert_eq(s0.clone() + s0_next.clone(), F_1); + } + + // AND: s0, s1 are boolean, s0' = s0 * s1. + { + let builder = &mut builder.when(is_and); + builder.assert_bool(s0.clone()); + builder.assert_bool(s1.clone()); + builder.when_transition().assert_eq(s0_next.clone(), s0.clone() * s1.clone()); + } + + // OR: s0, s1 are boolean, s0' = s0 + s1 - s0 * s1. + { + let builder = &mut builder.when(is_or); + builder.assert_bool(s0.clone()); + builder.assert_bool(s1.clone()); + builder + .when_transition() + .assert_eq(s0_next.clone(), s0.clone() + s1.clone() - s0.clone() * s1.clone()); + } // EQ: if s0 != s1, h0 acts as 1/(s0 - s1) and forces s0' = 0; if equal, s0' = 1. - let eq_diff = s0.clone() - s1.clone(); - assert_zero(builder, &mut idx, is_eq.clone() * (eq_diff.clone() * s0_next.clone())); - assert_zero( - builder, - &mut idx, - is_eq * (s0_next.clone() - (AB::Expr::ONE - eq_diff * uop_h0.clone())), - ); + // eq_diff * s0_next and the inverse witness constraint are intrinsic (conditional inverse). + let eq_diff: AB::Expr = s0.clone() - s1.clone(); + { + let gate = builder.is_transition() * is_eq; + let builder = &mut builder.when(gate); + builder.assert_zero(eq_diff.clone() * s0_next.clone()); + builder.assert_eq(s0_next.clone(), AB::Expr::ONE - eq_diff * uop_h0.clone()); + } // EQZ: if s0 != 0, h0 acts as 1/s0 and forces s0' = 0; if zero, s0' = 1. - assert_zero(builder, &mut idx, is_eqz.clone() * (s0.clone() * s0_next.clone())); - assert_zero( - builder, - &mut idx, - is_eqz * (s0_next.clone() - (AB::Expr::ONE - s0.clone() * uop_h0.clone())), - ); + // s0 * s0_next and the inverse witness constraint are intrinsic (conditional inverse). + { + let gate = builder.is_transition() * is_eqz; + let builder = &mut builder.when(gate); + builder.assert_zero(s0.clone() * s0_next.clone()); + builder.assert_eq(s0_next.clone(), AB::Expr::ONE - s0.clone() * uop_h0.clone()); + } // EXPACC: exp_next = exp^2, exp_val = 1 + (exp - 1) * exp_bit, acc_next = acc * exp_val. let exp = s1.clone(); @@ -224,150 +153,105 @@ pub fn enforce_main( let exp_b = s3.clone(); let exp_b_next = s3_next.clone(); let exp_val = uop_h0.clone(); - let two: AB::Expr = AB::Expr::from_u16(2); - - assert_zero(builder, &mut idx, is_expacc.clone() * (exp_next - exp.clone() * exp.clone())); - assert_zero( - builder, - &mut idx, - is_expacc.clone() - * (exp_val.clone() - AB::Expr::ONE - (exp - AB::Expr::ONE) * exp_bit.clone()), - ); - assert_zero(builder, &mut idx, is_expacc.clone() * (acc_next - acc * exp_val)); - assert_zero( - builder, - &mut idx, - is_expacc.clone() * (exp_b - exp_b_next * two - exp_bit.clone()), - ); - assert_zero(builder, &mut idx, is_expacc * (exp_bit.clone() * (exp_bit - AB::Expr::ONE))); + // EXPACC transition: squaring, exp_val witness, accumulation, bit decomposition, and boolean + // check. + { + let gate = builder.is_transition() * is_expacc; + let builder = &mut builder.when(gate); + builder.assert_eq(exp_next, exp.clone() * exp.clone()); + builder.assert_eq(exp_val.clone(), (exp - F_1) * exp_bit.clone() + F_1); + builder.assert_eq(acc_next, acc * exp_val); + builder.assert_eq(exp_b, exp_b_next * F_2 + exp_bit.clone()); + builder.assert_bool(exp_bit); + } + // EXT2MUL let ext_b0 = s0.clone(); let ext_b1 = s1.clone(); let ext_a0 = s2.clone(); - let ext_a1 = s3.clone(); + let ext_a1 = s3; let ext_d0 = s0_next.clone(); let ext_d1 = s1_next.clone(); - let ext_c0 = s2_next.clone(); - let ext_c1 = s3_next.clone(); + let ext_c0 = s2_next; + let ext_c1 = s3_next; let ext_a0_b0 = ext_a0.clone() * ext_b0.clone(); let ext_a1_b1 = ext_a1.clone() * ext_b1.clone(); - let seven: AB::Expr = AB::Expr::from_u16(7); - assert_zero(builder, &mut idx, is_ext2mul.clone() * (ext_d0 - ext_b0.clone())); - assert_zero(builder, &mut idx, is_ext2mul.clone() * (ext_d1 - ext_b1.clone())); - assert_zero( - builder, - &mut idx, - is_ext2mul.clone() * (ext_c0 - (ext_a0_b0.clone() + seven.clone() * ext_a1_b1.clone())), - ); - assert_zero( - builder, - &mut idx, - is_ext2mul * (ext_c1 - ((ext_a0 + ext_a1) * (ext_b0 + ext_b1) - ext_a0_b0 - ext_a1_b1)), - ); + // EXT2MUL transition: quadratic extension multiplication producing (c0, c1) from (a, b). + { + let gate = builder.is_transition() * is_ext2mul; + let builder = &mut builder.when(gate); + builder.assert_eq(ext_d0, ext_b0.clone()); + builder.assert_eq(ext_d1, ext_b1.clone()); + builder.assert_eq(ext_c0, ext_a0_b0.clone() + ext_a1_b1.clone() * F_7); + builder.assert_eq(ext_c1, (ext_a0 + ext_a1) * (ext_b0 + ext_b1) - ext_a0_b0 - ext_a1_b1); + } // ------------------------------------------------------------------------- // U32 ops // ------------------------------------------------------------------------- - let two_pow_16: AB::Expr = AB::Expr::from_u64(1u64 << 16); - let two_pow_32: AB::Expr = AB::Expr::from_u64(1u64 << 32); - let two_pow_48: AB::Expr = AB::Expr::from_u64(1u64 << 48); - let two_pow_32_minus_one: AB::Expr = AB::Expr::from_u64((1u64 << 32) - 1); - // U32 limbs: v_lo = h1*2^16 + h0, v_hi = h3*2^16 + h2. - let u32_v_lo = uop_h1.clone() * two_pow_16.clone() + uop_h0.clone(); - let u32_v_hi = uop_h3.clone() * two_pow_16 + uop_h2.clone(); - let u32_v48 = uop_h2.clone() * two_pow_32.clone() + u32_v_lo.clone(); - let u32_v64 = uop_h3.clone() * two_pow_48 + u32_v48.clone(); + let u32_v_lo = uop_h1 * TWO_POW_16 + uop_h0; + let u32_v_hi = uop_h3.clone() * TWO_POW_16 + uop_h2.clone(); + let u32_v48 = uop_h2 * TWO_POW_32 + u32_v_lo.clone(); + let u32_v64 = uop_h3.clone() * TWO_POW_48 + u32_v48.clone(); // Element validity check for u32split/u32mul/u32madd. + // u32_v_hi_comp * u32_v_lo is intrinsic (symmetry test: setting either factor to 0 hides a + // case). let u32_split_mul_madd = is_u32split.clone() + is_u32mul.clone() + is_u32madd.clone(); - let u32_v_hi_comp = AB::Expr::ONE - uop_h4.clone() * (two_pow_32_minus_one - u32_v_hi.clone()); - assert_zero_integrity( - builder, - &mut idx, - u32_split_mul_madd * (u32_v_hi_comp * u32_v_lo.clone()), - ); + let u32_v_hi_comp = + AB::Expr::ONE - uop_h4 * (AB::Expr::from(TWO_POW_32_MINUS_1) - u32_v_hi.clone()); + builder.when(u32_split_mul_madd).assert_zero(u32_v_hi_comp * u32_v_lo.clone()); + // U32 ops with two outputs: s0' = v_lo, s1' = v_hi. let u32_two_outputs = is_u32split.clone() + is_u32add.clone() + is_u32add3.clone() + is_u32mul.clone() + is_u32madd.clone(); - assert_zero( - builder, - &mut idx, - u32_two_outputs.clone() * (s0_next.clone() - u32_v_lo.clone()), - ); - assert_zero(builder, &mut idx, u32_two_outputs * (s1_next.clone() - u32_v_hi.clone())); - - assert_zero_integrity(builder, &mut idx, is_u32split * (s0.clone() - u32_v64.clone())); - assert_zero_integrity( - builder, - &mut idx, - is_u32add * (s0.clone() + s1.clone() - u32_v48.clone()), - ); - assert_zero_integrity( - builder, - &mut idx, - is_u32add3 * (s0.clone() + s1.clone() + s2.clone() - u32_v48.clone()), - ); - - assert_zero( - builder, - &mut idx, - is_u32sub.clone() - * (s1.clone() - (s0.clone() + s1_next.clone() - s0_next.clone() * two_pow_32.clone())), - ); - assert_zero( - builder, - &mut idx, - is_u32sub.clone() * (s0_next.clone() * (s0_next.clone() - AB::Expr::ONE)), - ); - assert_zero(builder, &mut idx, is_u32sub * (s1_next.clone() - u32_v_lo.clone())); - - assert_zero_integrity( - builder, - &mut idx, - is_u32mul * (s0.clone() * s1.clone() - u32_v64.clone()), - ); - assert_zero_integrity( - builder, - &mut idx, - is_u32madd * (s0.clone() * s1.clone() + s2 - u32_v64.clone()), - ); - - assert_zero( - builder, - &mut idx, - is_u32div.clone() * (s1.clone() - (s0.clone() * s1_next.clone() + s0_next.clone())), - ); - assert_zero( - builder, - &mut idx, - is_u32div.clone() * (s1.clone() - s1_next.clone() - u32_v_lo.clone()), - ); - assert_zero( - builder, - &mut idx, - is_u32div * (s0.clone() - s0_next.clone() - (u32_v_hi.clone() + AB::Expr::ONE)), - ); - - assert_zero(builder, &mut idx, is_u32assert2.clone() * (s0_next - u32_v_hi.clone())); - assert_zero(builder, &mut idx, is_u32assert2 * (s1_next - u32_v_lo)); -} - -// CONSTRAINT HELPERS -// ================================================================================================ - -fn assert_zero(builder: &mut AB, idx: &mut usize, expr: AB::Expr) { - tagged_assert_zero(builder, &STACK_ARITH_TAGS, idx, expr); -} - -fn assert_zero_integrity( - builder: &mut AB, - idx: &mut usize, - expr: AB::Expr, -) { - tagged_assert_zero_integrity(builder, &STACK_ARITH_TAGS, idx, expr); + { + let gate = builder.is_transition() * u32_two_outputs; + let builder = &mut builder.when(gate); + builder.assert_eq(s0_next.clone(), u32_v_lo.clone()); + builder.assert_eq(s1_next.clone(), u32_v_hi.clone()); + } + + builder.when(is_u32split).assert_eq(s0.clone(), u32_v64.clone()); + builder + .when(is_u32add.clone()) + .assert_eq(s0.clone() + s1.clone(), u32_v48.clone()); + builder + .when(is_u32add3.clone()) + .assert_eq(s0.clone() + s1.clone() + s2.clone(), u32_v48); + builder.when(is_u32add + is_u32add3).assert_zero(uop_h3); + + // U32SUB: s1 = s0 + s1' - s0' * 2^32, s0' is boolean (borrow), s1' = v_lo. + { + let gate = builder.is_transition() * is_u32sub; + let builder = &mut builder.when(gate); + builder.assert_eq(s1.clone(), s0.clone() + s1_next.clone() - s0_next.clone() * TWO_POW_32); + builder.assert_bool(s0_next.clone()); + builder.assert_eq(s1_next.clone(), u32_v_lo.clone()); + } + + builder.when(is_u32mul).assert_eq(s0.clone() * s1.clone(), u32_v64.clone()); + builder.when(is_u32madd).assert_eq(s0.clone() * s1.clone() + s2, u32_v64); + + // U32DIV: s1 = s0 * s1' + s0', range checks on remainder and quotient bounds. + { + let gate = builder.is_transition() * is_u32div; + let builder = &mut builder.when(gate); + builder.assert_eq(s1.clone(), s0.clone() * s1_next.clone() + s0_next.clone()); + builder.assert_eq(s1 - s1_next.clone(), u32_v_lo.clone()); + builder.assert_eq(s0 - s0_next.clone(), u32_v_hi.clone() + F_1); + } + + // U32ASSERT2: verifies both stack elements are valid u32 values. + { + let gate = builder.is_transition() * is_u32assert2; + let builder = &mut builder.when(gate); + builder.assert_eq(s0_next, u32_v_hi); + builder.assert_eq(s1_next, u32_v_lo); + } } diff --git a/air/src/constraints/stack/stack_arith/tests.rs b/air/src/constraints/stack/stack_arith/tests.rs new file mode 100644 index 0000000000..0334eea524 --- /dev/null +++ b/air/src/constraints/stack/stack_arith/tests.rs @@ -0,0 +1,331 @@ +use alloc::vec::Vec; + +use miden_core::{ + Felt, + field::{Field, PrimeCharacteristicRing, PrimeField64, QuadFelt}, + operations::opcodes, +}; +use miden_crypto::stark::{ + air::{AirBuilder, EmptyWindow, ExtensionBuilder, PeriodicAirBuilder, PermutationAirBuilder}, + matrix::RowMajorMatrix, +}; + +use super::enforce_main; +use crate::{ + MainCols, + constraints::op_flags::{OpFlags, generate_test_row}, + trace::{AUX_TRACE_RAND_CHALLENGES, AUX_TRACE_WIDTH, TRACE_WIDTH}, +}; + +struct ConstraintEvalBuilder { + main: RowMajorMatrix, + aux: RowMajorMatrix, + randomness: Vec, + permutation_values: Vec, + periodic_values: Vec, + evaluations: Vec, +} + +impl ConstraintEvalBuilder { + fn new() -> Self { + Self { + main: RowMajorMatrix::new(vec![Felt::ZERO; TRACE_WIDTH * 2], TRACE_WIDTH), + aux: RowMajorMatrix::new(vec![QuadFelt::ZERO; AUX_TRACE_WIDTH * 2], AUX_TRACE_WIDTH), + randomness: vec![QuadFelt::ZERO; AUX_TRACE_RAND_CHALLENGES], + permutation_values: vec![QuadFelt::ZERO; AUX_TRACE_WIDTH], + periodic_values: Vec::new(), + evaluations: Vec::new(), + } + } +} + +impl AirBuilder for ConstraintEvalBuilder { + type F = Felt; + type Expr = Felt; + type Var = Felt; + type PreprocessedWindow = EmptyWindow; + type MainWindow = RowMajorMatrix; + type PublicVar = Felt; + + fn main(&self) -> Self::MainWindow { + self.main.clone() + } + + fn preprocessed(&self) -> &Self::PreprocessedWindow { + EmptyWindow::empty_ref() + } + + fn is_first_row(&self) -> Self::Expr { + Felt::ZERO + } + + fn is_last_row(&self) -> Self::Expr { + Felt::ZERO + } + + fn is_transition_window(&self, size: usize) -> Self::Expr { + assert_eq!(size, 2, "stack_arith only uses 2-row transition constraints"); + Felt::ONE + } + + fn assert_zero>(&mut self, x: I) { + self.evaluations.push(QuadFelt::from(x.into())); + } + + fn public_values(&self) -> &[Self::PublicVar] { + &[] + } +} + +impl ExtensionBuilder for ConstraintEvalBuilder { + type EF = QuadFelt; + type ExprEF = QuadFelt; + type VarEF = QuadFelt; + + fn assert_zero_ext(&mut self, x: I) + where + I: Into, + { + self.evaluations.push(x.into()); + } +} + +impl PermutationAirBuilder for ConstraintEvalBuilder { + type MP = RowMajorMatrix; + type RandomVar = QuadFelt; + type PermutationVar = QuadFelt; + + fn permutation(&self) -> Self::MP { + self.aux.clone() + } + + fn permutation_randomness(&self) -> &[Self::RandomVar] { + &self.randomness + } + + fn permutation_values(&self) -> &[Self::PermutationVar] { + &self.permutation_values + } +} + +impl PeriodicAirBuilder for ConstraintEvalBuilder { + type PeriodicVar = Felt; + + fn periodic_values(&self) -> &[Self::PeriodicVar] { + &self.periodic_values + } +} + +/// Sets the u32 helper registers (hasher_state[2..7]) in the decoder. +fn set_u32_helpers(row: &mut MainCols, lo: u32, hi: u32) { + row.decoder.hasher_state[2] = Felt::new_unchecked(lo as u64 & 0xffff); + row.decoder.hasher_state[3] = Felt::new_unchecked((lo as u64) >> 16); + row.decoder.hasher_state[4] = Felt::new_unchecked(hi as u64 & 0xffff); + row.decoder.hasher_state[5] = Felt::new_unchecked((hi as u64) >> 16); + row.decoder.hasher_state[6] = Felt::ZERO; +} + +fn eval_stack_arith(local: &MainCols, next: &MainCols) -> Vec { + let mut builder = ConstraintEvalBuilder::new(); + let op_flags = OpFlags::new(&local.decoder, &local.stack, &next.decoder); + enforce_main(&mut builder, local, next, &op_flags); + builder.evaluations +} + +fn assert_constraints_accept(local: &MainCols, next: &MainCols, message: &str) { + let evaluations = eval_stack_arith(local, next); + assert!(evaluations.iter().all(|value| *value == QuadFelt::ZERO), "{message}"); +} + +fn assert_constraints_reject(local: &MainCols, next: &MainCols, message: &str) { + let evaluations = eval_stack_arith(local, next); + assert!(evaluations.iter().any(|value| *value != QuadFelt::ZERO), "{message}"); +} + +#[test] +fn stack_arith_u32add_constraints_allow_non_u32_operands() { + let non_u32 = Felt::new_unchecked(Felt::ORDER_U64 - 1); + assert!(non_u32.as_canonical_u64() > u32::MAX as u64); + + let mut local = generate_test_row(opcodes::U32ADD as usize); + local.stack.top[0] = non_u32; + local.stack.top[1] = Felt::ONE; + set_u32_helpers(&mut local, 0, 0); + + let next = generate_test_row(0); + + let op_flags: OpFlags = OpFlags::new(&local.decoder, &local.stack, &next.decoder); + assert_eq!(op_flags.u32add(), Felt::ONE); + assert_eq!(op_flags.u32sub(), Felt::ZERO); + + assert_constraints_accept( + &local, + &next, + "expected U32ADD constraints to accept a non-u32 operand with forged u32 outputs", + ); +} + +#[test] +fn stack_arith_u32add_constraints_reject_forged_high_carry_limb() { + let mut local = generate_test_row(opcodes::U32ADD as usize); + local.stack.top[0] = Felt::ZERO; + local.stack.top[1] = Felt::ZERO; + set_u32_helpers(&mut local, 0, 1 << 16); + + let mut next = generate_test_row(0); + next.stack.top[0] = Felt::ZERO; + next.stack.top[1] = Felt::new_unchecked(1 << 16); + + let op_flags: OpFlags = OpFlags::new(&local.decoder, &local.stack, &next.decoder); + assert_eq!(op_flags.u32add(), Felt::ONE); + + assert_constraints_reject( + &local, + &next, + "expected U32ADD constraints to reject carry values with a nonzero high limb", + ); +} + +#[test] +fn stack_arith_u32add3_constraints_reject_forged_high_carry_limb() { + let mut local = generate_test_row(opcodes::U32ADD3 as usize); + local.stack.top[0] = Felt::ZERO; + local.stack.top[1] = Felt::ZERO; + local.stack.top[2] = Felt::ZERO; + set_u32_helpers(&mut local, 0, 1 << 16); + + let mut next = generate_test_row(0); + next.stack.top[0] = Felt::ZERO; + next.stack.top[1] = Felt::new_unchecked(1 << 16); + + let op_flags: OpFlags = OpFlags::new(&local.decoder, &local.stack, &next.decoder); + assert_eq!(op_flags.u32add3(), Felt::ONE); + + assert_constraints_reject( + &local, + &next, + "expected U32ADD3 constraints to reject carry values with a nonzero high limb", + ); +} + +#[test] +fn stack_arith_u64_overflowing_add_rejects_forged_low_limb_carry() { + let mut add_local = generate_test_row(opcodes::U32ADD as usize); + add_local.stack.top[0] = Felt::ZERO; + add_local.stack.top[1] = Felt::ZERO; + set_u32_helpers(&mut add_local, 0, 1 << 16); + + let mut add_next = generate_test_row(opcodes::U32ADD3 as usize); + add_next.stack.top[0] = Felt::ZERO; + add_next.stack.top[1] = Felt::new_unchecked(1 << 16); + add_next.stack.top[2] = Felt::ZERO; + add_next.stack.top[3] = Felt::ZERO; + + let mut add3_local = generate_test_row(opcodes::U32ADD3 as usize); + add3_local.stack.top[0] = Felt::new_unchecked(1 << 16); + add3_local.stack.top[1] = Felt::ZERO; + add3_local.stack.top[2] = Felt::ZERO; + add3_local.stack.top[3] = Felt::ZERO; + set_u32_helpers(&mut add3_local, 1 << 16, 0); + + let mut add3_next = generate_test_row(0); + add3_next.stack.top[0] = Felt::new_unchecked(1 << 16); + add3_next.stack.top[1] = Felt::ZERO; + + assert_constraints_reject( + &add_local, + &add_next, + "expected the forged low-limb carry in u64::overflowing_add to be rejected at U32ADD", + ); + assert_constraints_accept( + &add3_local, + &add3_next, + "expected U32ADD3 to accept honest propagation of a 65536 carry once it is on the stack", + ); +} + +#[test] +fn stack_arith_u32sub_constraints_allow_non_u32_operands() { + let non_u32 = Felt::new_unchecked(Felt::ORDER_U64 - 1); + let diff = ((1u64 << 32) - 12_290) as u32; + assert!(non_u32.as_canonical_u64() > u32::MAX as u64); + + let mut local = generate_test_row(opcodes::U32SUB as usize); + local.stack.top[0] = Felt::new_unchecked(12_289); + local.stack.top[1] = non_u32; + set_u32_helpers(&mut local, diff, 0); + + let mut next = generate_test_row(0); + next.stack.top[0] = Felt::ONE; + next.stack.top[1] = Felt::new_unchecked(diff as u64); + + let op_flags: OpFlags = OpFlags::new(&local.decoder, &local.stack, &next.decoder); + assert_eq!(op_flags.u32sub(), Felt::ONE); + assert_eq!(op_flags.u32add(), Felt::ZERO); + + assert_constraints_accept( + &local, + &next, + "expected U32SUB constraints to accept a non-u32 operand with forged u32 outputs", + ); +} + +#[test] +fn stack_arith_u32mul_constraints_allow_non_u32_sha256_rotr_operand() { + let non_u32 = Felt::new_unchecked((u32::MAX as u64) + 2); + let rotr_7_multiplier = Felt::new_unchecked(1 << 25); + let product = non_u32.as_canonical_u64() * rotr_7_multiplier.as_canonical_u64(); + let lo = product as u32; + let hi = (product >> 32) as u32; + + assert!(non_u32.as_canonical_u64() > u32::MAX as u64); + + let mut local = generate_test_row(opcodes::U32MUL as usize); + local.stack.top[0] = rotr_7_multiplier; + local.stack.top[1] = non_u32; + set_u32_helpers(&mut local, lo, hi); + local.decoder.hasher_state[6] = Felt::new_unchecked(u32::MAX as u64 - hi as u64).inverse(); + + let mut next = generate_test_row(0); + next.stack.top[0] = Felt::new_unchecked(lo as u64); + next.stack.top[1] = Felt::new_unchecked(hi as u64); + + let op_flags: OpFlags = OpFlags::new(&local.decoder, &local.stack, &next.decoder); + assert_eq!(op_flags.u32mul(), Felt::ONE); + + assert_constraints_accept( + &local, + &next, + "expected U32MUL constraints to accept a non-u32 operand with forged rotr outputs", + ); +} + +#[test] +fn stack_arith_u32div_constraints_allow_non_u32_sha256_shr_operand() { + let non_u32 = Felt::new_unchecked((u32::MAX as u64) + 2); + let divisor = Felt::new_unchecked(8); + let quotient = Felt::new_unchecked(non_u32.as_canonical_u64() / divisor.as_canonical_u64()); + let remainder = Felt::new_unchecked(non_u32.as_canonical_u64() % divisor.as_canonical_u64()); + let lo = (non_u32.as_canonical_u64() - quotient.as_canonical_u64()) as u32; + let hi = (divisor.as_canonical_u64() - remainder.as_canonical_u64() - 1) as u32; + + assert!(non_u32.as_canonical_u64() > u32::MAX as u64); + + let mut local = generate_test_row(opcodes::U32DIV as usize); + local.stack.top[0] = divisor; + local.stack.top[1] = non_u32; + set_u32_helpers(&mut local, lo, hi); + + let mut next = generate_test_row(0); + next.stack.top[0] = remainder; + next.stack.top[1] = quotient; + + let op_flags: OpFlags = OpFlags::new(&local.decoder, &local.stack, &next.decoder); + assert_eq!(op_flags.u32div(), Felt::ONE); + + assert_constraints_accept( + &local, + &next, + "expected U32DIV constraints to accept a non-u32 operand with forged shr outputs", + ); +} diff --git a/air/src/constraints/system/columns.rs b/air/src/constraints/system/columns.rs new file mode 100644 index 0000000000..29a3a6f143 --- /dev/null +++ b/air/src/constraints/system/columns.rs @@ -0,0 +1,15 @@ +use miden_core::WORD_SIZE; + +/// System columns in the main execution trace (6 columns). +/// +/// These columns track global execution state: clock cycle, execution context, and +/// the function hash (digest) of the currently executing function. +#[repr(C)] +pub struct SystemCols { + /// Clock cycle counter. + pub clk: T, + /// Context identifier. + pub ctx: T, + /// Function hash (digest) of the currently executing function. + pub fn_hash: [T; WORD_SIZE], +} diff --git a/air/src/constraints/system/mod.rs b/air/src/constraints/system/mod.rs index 9fc00baf1d..a1536fd9be 100644 --- a/air/src/constraints/system/mod.rs +++ b/air/src/constraints/system/mod.rs @@ -29,147 +29,73 @@ //! Note: END operation's restoration is handled by the block stack table (bus-based), //! not by these constraints. These constraints only handle the non-END cases. -use miden_core::field::PrimeCharacteristicRing; -use miden_crypto::stark::air::{AirBuilder, LiftedAirBuilder}; +pub mod columns; + +use miden_crypto::stark::air::AirBuilder; use crate::{ - MainTraceRow, - constraints::{ - op_flags::{ExprDecoderAccess, OpFlags}, - tagging::{ - TaggingAirBuilderExt, - ids::{ - TAG_SYSTEM_CLK_BASE, TAG_SYSTEM_CLK_COUNT, TAG_SYSTEM_CTX_BASE, - TAG_SYSTEM_CTX_COUNT, TAG_SYSTEM_FN_HASH_BASE, - }, - }, - }, - trace::decoder::HASHER_STATE_OFFSET, + MainCols, MidenAirBuilder, + constraints::{constants::F_1, op_flags::OpFlags, utils::BoolNot}, }; -// TAGGING CONSTANTS -// ================================================================================================ - -const SYSTEM_CLK_NAMES: [&str; TAG_SYSTEM_CLK_COUNT] = - ["system.clk.first_row", "system.clk.transition"]; - -const SYSTEM_CTX_NAMES: [&str; TAG_SYSTEM_CTX_COUNT] = - ["system.ctx.call_dyncall", "system.ctx.syscall", "system.ctx.default"]; - -const SYSTEM_FN_HASH_LOAD_NAMESPACE: &str = "system.fn_hash.load"; -const SYSTEM_FN_HASH_PRESERVE_NAMESPACE: &str = "system.fn_hash.preserve"; - // ENTRY POINTS // ================================================================================================ /// Enforces system constraints. pub fn enforce_main( builder: &mut AB, - local: &MainTraceRow, - next: &MainTraceRow, + local: &MainCols, + next: &MainCols, + op_flags: &OpFlags, ) where - AB: LiftedAirBuilder, + AB: MidenAirBuilder, { - enforce_clock_constraint(builder, local, next); - enforce_ctx_constraints(builder, local, next); - enforce_fn_hash_constraints(builder, local, next); -} - -// CONSTRAINT HELPERS -// ================================================================================================ - -/// Enforces the clock constraint: clk' = clk + 1. -pub(crate) fn enforce_clock_constraint( - builder: &mut AB, - local: &MainTraceRow, - next: &MainTraceRow, -) where - AB: LiftedAirBuilder, -{ - builder.tagged(TAG_SYSTEM_CLK_BASE, SYSTEM_CLK_NAMES[0], |builder| { - builder.when_first_row().assert_zero(local.clk.clone()); - }); - - builder.tagged(TAG_SYSTEM_CLK_BASE + 1, SYSTEM_CLK_NAMES[1], |builder| { - builder - .when_transition() - .assert_eq(next.clk.clone(), local.clk.clone() + AB::Expr::ONE); - }); -} - -/// Enforces execution context transition constraints. -pub(crate) fn enforce_ctx_constraints( - builder: &mut AB, - local: &MainTraceRow, - next: &MainTraceRow, -) where - AB: LiftedAirBuilder, -{ - let ctx: AB::Expr = local.ctx.clone().into(); - let ctx_next: AB::Expr = next.ctx.clone().into(); - let clk: AB::Expr = local.clk.clone().into(); - - let op_flags = OpFlags::new(ExprDecoderAccess::new(local)); + // Clock: starts at 0, increments by 1 + { + builder.when_first_row().assert_zero(local.system.clk); + builder.when_transition().assert_eq(next.system.clk, local.system.clk + F_1); + } let f_call = op_flags.call(); let f_syscall = op_flags.syscall(); let f_dyncall = op_flags.dyncall(); let f_end = op_flags.end(); - let call_dyncall_flag = f_call.clone() + f_dyncall.clone(); - let expected_new_ctx = clk + AB::Expr::ONE; - builder.tagged(TAG_SYSTEM_CTX_BASE, SYSTEM_CTX_NAMES[0], |builder| { - builder - .when_transition() - .assert_zero(call_dyncall_flag * (ctx_next.clone() - expected_new_ctx)); - }); - - builder.tagged(TAG_SYSTEM_CTX_BASE + 1, SYSTEM_CTX_NAMES[1], |builder| { - builder.when_transition().assert_zero(f_syscall.clone() * ctx_next.clone()); - }); - - let change_ctx_flag = f_call + f_syscall + f_dyncall + f_end; - let default_flag = AB::Expr::ONE - change_ctx_flag; - builder.tagged(TAG_SYSTEM_CTX_BASE + 2, SYSTEM_CTX_NAMES[2], |builder| { - builder.when_transition().assert_zero(default_flag * (ctx_next - ctx)); - }); -} - -/// Enforces function hash transition constraints. -pub(crate) fn enforce_fn_hash_constraints( - builder: &mut AB, - local: &MainTraceRow, - next: &MainTraceRow, -) where - AB: LiftedAirBuilder, -{ - let op_flags = OpFlags::new(ExprDecoderAccess::new(local)); - let f_call = op_flags.call(); - let f_dyncall = op_flags.dyncall(); - let f_end = op_flags.end(); - - let f_load = f_call.clone() + f_dyncall.clone(); - let f_preserve = AB::Expr::ONE - (f_load.clone() + f_end); - - let load_ids: [usize; 4] = core::array::from_fn(|i| TAG_SYSTEM_FN_HASH_BASE + i); - builder.tagged_list(load_ids, SYSTEM_FN_HASH_LOAD_NAMESPACE, |builder| { - builder.when_transition().when(f_load.clone()).assert_zeros( - core::array::from_fn::<_, 4, _>(|i| { - let fn_hash_i_next: AB::Expr = next.fn_hash[i].clone().into(); - let decoder_h_i: AB::Expr = local.decoder[HASHER_STATE_OFFSET + i].clone().into(); - fn_hash_i_next - decoder_h_i - }), - ); - }); - - let preserve_ids: [usize; 4] = core::array::from_fn(|i| TAG_SYSTEM_FN_HASH_BASE + 4 + i); - builder.tagged_list(preserve_ids, SYSTEM_FN_HASH_PRESERVE_NAMESPACE, |builder| { - builder - .when_transition() - .when(f_preserve.clone()) - .assert_zeros(core::array::from_fn::<_, 4, _>(|i| { - let fn_hash_i: AB::Expr = local.fn_hash[i].clone().into(); - let fn_hash_i_next: AB::Expr = next.fn_hash[i].clone().into(); - fn_hash_i_next - fn_hash_i - })); - }); + // Execution context transition constraints (see module doc for transition table) + { + let ctx = local.system.ctx; + let ctx_next = next.system.ctx; + let clk = local.system.clk; + + let call_dyncall_flag = f_call.clone() + f_dyncall.clone(); + let change_ctx_flag = + f_call.clone() + f_syscall.clone() + f_dyncall.clone() + f_end.clone(); + let default_flag = change_ctx_flag.not(); + + let builder = &mut builder.when_transition(); + builder.when(call_dyncall_flag).assert_eq(ctx_next, clk + F_1); + builder.when(f_syscall).assert_zero(ctx_next); + builder.when(default_flag).assert_eq(ctx_next, ctx); + } + + // Function hash transition constraints (see module doc for transition table) + { + let f_load = f_call + f_dyncall; + let f_preserve = (f_load.clone() + f_end).not(); + + let builder = &mut builder.when_transition(); + + { + let builder = &mut builder.when(f_load); + for i in 0..4 { + builder.assert_eq(next.system.fn_hash[i], local.decoder.hasher_state[i]); + } + } + + { + let builder = &mut builder.when(f_preserve); + for i in 0..4 { + builder.assert_eq(next.system.fn_hash[i], local.system.fn_hash[i]); + } + } + } } diff --git a/air/src/constraints/tagging/enabled.rs b/air/src/constraints/tagging/enabled.rs deleted file mode 100644 index 975ea83359..0000000000 --- a/air/src/constraints/tagging/enabled.rs +++ /dev/null @@ -1,45 +0,0 @@ -//! Constraint tagging helpers for stable numeric IDs. -//! -//! This module is compiled in tests or when the `testing` feature is enabled, with `std` available. -//! Non-testing or no-std builds use a no-op stub. This keeps call sites clean and avoids `std` -//! machinery in production. - -use miden_crypto::stark::air::LiftedAirBuilder; - -/// Extension methods for tagging constraints. -/// -/// These helpers wrap blocks that should emit a fixed number of assertions. Each assertion -/// consumes one ID from the active tagged block, and the block panics if the count mismatches. -pub trait TaggingAirBuilderExt: LiftedAirBuilder { - /// Tag exactly one asserted constraint. - /// - /// Panics if the wrapped block emits zero or multiple assertions when tagging is enabled. - fn tagged( - &mut self, - id: usize, - namespace: &'static str, - f: impl FnOnce(&mut Self) -> R, - ) -> R { - if !super::state::is_enabled() { - return f(self); - } - super::state::with_tag(vec![id], namespace, || f(self)) - } - - /// Tag a list of asserted constraints (e.g., `assert_zeros` or per-iteration loops). - /// - /// Panics if the wrapped block does not emit exactly `N` assertions when tagging is enabled. - fn tagged_list( - &mut self, - ids: [usize; N], - namespace: &'static str, - f: impl FnOnce(&mut Self) -> R, - ) -> R { - if !super::state::is_enabled() { - return f(self); - } - super::state::with_tag(ids.to_vec(), namespace, || f(self)) - } -} - -impl TaggingAirBuilderExt for T {} diff --git a/air/src/constraints/tagging/fallback.rs b/air/src/constraints/tagging/fallback.rs deleted file mode 100644 index 40c93de45f..0000000000 --- a/air/src/constraints/tagging/fallback.rs +++ /dev/null @@ -1,28 +0,0 @@ -//! No-op tagging helpers for non-testing or no-std builds. - -use miden_crypto::stark::air::LiftedAirBuilder; -/// No-op tagging extension for non-testing builds. -/// -/// The methods call the provided closure directly so they have no runtime overhead beyond -/// the call itself (which the optimizer should inline away). -pub trait TaggingAirBuilderExt: LiftedAirBuilder { - fn tagged( - &mut self, - _id: usize, - _namespace: &'static str, - f: impl FnOnce(&mut Self) -> R, - ) -> R { - f(self) - } - - fn tagged_list( - &mut self, - _ids: [usize; N], - _namespace: &'static str, - f: impl FnOnce(&mut Self) -> R, - ) -> R { - f(self) - } -} - -impl TaggingAirBuilderExt for T {} diff --git a/air/src/constraints/tagging/fixtures.rs b/air/src/constraints/tagging/fixtures.rs deleted file mode 100644 index 84ad557964..0000000000 --- a/air/src/constraints/tagging/fixtures.rs +++ /dev/null @@ -1,2369 +0,0 @@ -//! Test fixtures for constraint tagging. - -use alloc::vec::Vec; - -use miden_core::{Felt, field::QuadFelt}; - -use super::ood_eval::EvalRecord; - -/// Seed used for OOD evaluation fixtures. -pub const OOD_SEED: u64 = 0xc0ffee; - -/// Expected OOD evaluations for the current group. -/// -/// These values are captured from the Rust constraints with seed 0xC0FFEE. -pub fn current_group_expected() -> Vec { - vec![ - EvalRecord { - id: 0, - namespace: "system.clk.first_row", - value: QuadFelt::new([Felt::new(1065013626484053923), Felt::new(0)]), - }, - EvalRecord { - id: 1, - namespace: "system.clk.transition", - value: QuadFelt::new([Felt::new(5561241394822338942), Felt::new(0)]), - }, - EvalRecord { - id: 2, - namespace: "system.ctx.call_dyncall", - value: QuadFelt::new([Felt::new(8631524473419082362), Felt::new(0)]), - }, - EvalRecord { - id: 3, - namespace: "system.ctx.syscall", - value: QuadFelt::new([Felt::new(3242942367983627164), Felt::new(0)]), - }, - EvalRecord { - id: 4, - namespace: "system.ctx.default", - value: QuadFelt::new([Felt::new(2699910395066589652), Felt::new(0)]), - }, - EvalRecord { - id: 5, - namespace: "system.fn_hash.load", - value: QuadFelt::new([Felt::new(5171717963692258605), Felt::new(0)]), - }, - EvalRecord { - id: 6, - namespace: "system.fn_hash.load", - value: QuadFelt::new([Felt::new(8961147296413400172), Felt::new(0)]), - }, - EvalRecord { - id: 7, - namespace: "system.fn_hash.load", - value: QuadFelt::new([Felt::new(11894020196642675053), Felt::new(0)]), - }, - EvalRecord { - id: 8, - namespace: "system.fn_hash.load", - value: QuadFelt::new([Felt::new(16889079421217525114), Felt::new(0)]), - }, - EvalRecord { - id: 9, - namespace: "system.fn_hash.preserve", - value: QuadFelt::new([Felt::new(11909329801663906014), Felt::new(0)]), - }, - EvalRecord { - id: 10, - namespace: "system.fn_hash.preserve", - value: QuadFelt::new([Felt::new(6717961555159342431), Felt::new(0)]), - }, - EvalRecord { - id: 11, - namespace: "system.fn_hash.preserve", - value: QuadFelt::new([Felt::new(3950851291570048124), Felt::new(0)]), - }, - EvalRecord { - id: 12, - namespace: "system.fn_hash.preserve", - value: QuadFelt::new([Felt::new(11146653144264413142), Felt::new(0)]), - }, - EvalRecord { - id: 13, - namespace: "range.main.v.first_row", - value: QuadFelt::new([Felt::new(1112338059331632069), Felt::new(0)]), - }, - EvalRecord { - id: 14, - namespace: "range.main.v.last_row", - value: QuadFelt::new([Felt::new(13352757668188868927), Felt::new(0)]), - }, - EvalRecord { - id: 15, - namespace: "range.main.v.transition", - value: QuadFelt::new([Felt::new(12797082443503681195), Felt::new(0)]), - }, - EvalRecord { - id: 16, - namespace: "stack.general.transition.0", - value: QuadFelt::new([Felt::new(2617308096902219240), Felt::new(0)]), - }, - EvalRecord { - id: 17, - namespace: "stack.general.transition.1", - value: QuadFelt::new([Felt::new(4439102810547612775), Felt::new(0)]), - }, - EvalRecord { - id: 18, - namespace: "stack.general.transition.2", - value: QuadFelt::new([Felt::new(15221140463513662734), Felt::new(0)]), - }, - EvalRecord { - id: 19, - namespace: "stack.general.transition.3", - value: QuadFelt::new([Felt::new(4910128267170087966), Felt::new(0)]), - }, - EvalRecord { - id: 20, - namespace: "stack.general.transition.4", - value: QuadFelt::new([Felt::new(8221884229886405628), Felt::new(0)]), - }, - EvalRecord { - id: 21, - namespace: "stack.general.transition.5", - value: QuadFelt::new([Felt::new(87491100192562680), Felt::new(0)]), - }, - EvalRecord { - id: 22, - namespace: "stack.general.transition.6", - value: QuadFelt::new([Felt::new(11411892308848385202), Felt::new(0)]), - }, - EvalRecord { - id: 23, - namespace: "stack.general.transition.7", - value: QuadFelt::new([Felt::new(2425094460891103256), Felt::new(0)]), - }, - EvalRecord { - id: 24, - namespace: "stack.general.transition.8", - value: QuadFelt::new([Felt::new(2767534397043537043), Felt::new(0)]), - }, - EvalRecord { - id: 25, - namespace: "stack.general.transition.9", - value: QuadFelt::new([Felt::new(11686523590994044007), Felt::new(0)]), - }, - EvalRecord { - id: 26, - namespace: "stack.general.transition.10", - value: QuadFelt::new([Felt::new(15000969044032170777), Felt::new(0)]), - }, - EvalRecord { - id: 27, - namespace: "stack.general.transition.11", - value: QuadFelt::new([Felt::new(17422355615541008592), Felt::new(0)]), - }, - EvalRecord { - id: 28, - namespace: "stack.general.transition.12", - value: QuadFelt::new([Felt::new(2555448945580115158), Felt::new(0)]), - }, - EvalRecord { - id: 29, - namespace: "stack.general.transition.13", - value: QuadFelt::new([Felt::new(8864896307613509), Felt::new(0)]), - }, - EvalRecord { - id: 30, - namespace: "stack.general.transition.14", - value: QuadFelt::new([Felt::new(3997062422665481459), Felt::new(0)]), - }, - EvalRecord { - id: 31, - namespace: "stack.general.transition.15", - value: QuadFelt::new([Felt::new(6149720027324442163), Felt::new(0)]), - }, - EvalRecord { - id: 32, - namespace: "stack.overflow.depth.first_row", - value: QuadFelt::new([Felt::new(1820735510664294085), Felt::new(0)]), - }, - EvalRecord { - id: 33, - namespace: "stack.overflow.depth.last_row", - value: QuadFelt::new([Felt::new(12520055704510454391), Felt::new(0)]), - }, - EvalRecord { - id: 34, - namespace: "stack.overflow.addr.first_row", - value: QuadFelt::new([Felt::new(9235172344178625178), Felt::new(0)]), - }, - EvalRecord { - id: 35, - namespace: "stack.overflow.addr.last_row", - value: QuadFelt::new([Felt::new(6001883085148683205), Felt::new(0)]), - }, - EvalRecord { - id: 36, - namespace: "stack.overflow.depth.transition", - value: QuadFelt::new([Felt::new(6706883717633639596), Felt::new(0)]), - }, - EvalRecord { - id: 37, - namespace: "stack.overflow.flag.transition", - value: QuadFelt::new([Felt::new(5309566436521762910), Felt::new(0)]), - }, - EvalRecord { - id: 38, - namespace: "stack.overflow.addr.transition", - value: QuadFelt::new([Felt::new(13739720401332236216), Felt::new(0)]), - }, - EvalRecord { - id: 39, - namespace: "stack.overflow.zero_insert.transition", - value: QuadFelt::new([Felt::new(15830245309845547857), Felt::new(0)]), - }, - EvalRecord { - id: 40, - namespace: "stack.ops.pad", - value: QuadFelt::new([Felt::new(13331629930659656176), Felt::new(0)]), - }, - EvalRecord { - id: 41, - namespace: "stack.ops.dup", - value: QuadFelt::new([Felt::new(756650319667756050), Felt::new(0)]), - }, - EvalRecord { - id: 42, - namespace: "stack.ops.dup1", - value: QuadFelt::new([Felt::new(8866275161884692697), Felt::new(0)]), - }, - EvalRecord { - id: 43, - namespace: "stack.ops.dup2", - value: QuadFelt::new([Felt::new(3836534398031583164), Felt::new(0)]), - }, - EvalRecord { - id: 44, - namespace: "stack.ops.dup3", - value: QuadFelt::new([Felt::new(14027345575708861734), Felt::new(0)]), - }, - EvalRecord { - id: 45, - namespace: "stack.ops.dup4", - value: QuadFelt::new([Felt::new(6758311777121484896), Felt::new(0)]), - }, - EvalRecord { - id: 46, - namespace: "stack.ops.dup5", - value: QuadFelt::new([Felt::new(3070735592903657788), Felt::new(0)]), - }, - EvalRecord { - id: 47, - namespace: "stack.ops.dup6", - value: QuadFelt::new([Felt::new(7754656097784875208), Felt::new(0)]), - }, - EvalRecord { - id: 48, - namespace: "stack.ops.dup7", - value: QuadFelt::new([Felt::new(6720121361576140513), Felt::new(0)]), - }, - EvalRecord { - id: 49, - namespace: "stack.ops.dup9", - value: QuadFelt::new([Felt::new(17539764796672551158), Felt::new(0)]), - }, - EvalRecord { - id: 50, - namespace: "stack.ops.dup11", - value: QuadFelt::new([Felt::new(10804911883091000860), Felt::new(0)]), - }, - EvalRecord { - id: 51, - namespace: "stack.ops.dup13", - value: QuadFelt::new([Felt::new(9611708950007293491), Felt::new(0)]), - }, - EvalRecord { - id: 52, - namespace: "stack.ops.dup15", - value: QuadFelt::new([Felt::new(8853070398648442411), Felt::new(0)]), - }, - EvalRecord { - id: 53, - namespace: "stack.ops.clk", - value: QuadFelt::new([Felt::new(9109734313690111543), Felt::new(0)]), - }, - EvalRecord { - id: 54, - namespace: "stack.ops.swap", - value: QuadFelt::new([Felt::new(3018402783504114630), Felt::new(0)]), - }, - EvalRecord { - id: 55, - namespace: "stack.ops.swap", - value: QuadFelt::new([Felt::new(17272825861332302734), Felt::new(0)]), - }, - EvalRecord { - id: 56, - namespace: "stack.ops.movup2", - value: QuadFelt::new([Felt::new(6365383181668196029), Felt::new(0)]), - }, - EvalRecord { - id: 57, - namespace: "stack.ops.movup3", - value: QuadFelt::new([Felt::new(11479712264864576587), Felt::new(0)]), - }, - EvalRecord { - id: 58, - namespace: "stack.ops.movup4", - value: QuadFelt::new([Felt::new(12050324136647260589), Felt::new(0)]), - }, - EvalRecord { - id: 59, - namespace: "stack.ops.movup5", - value: QuadFelt::new([Felt::new(4842889514271599822), Felt::new(0)]), - }, - EvalRecord { - id: 60, - namespace: "stack.ops.movup6", - value: QuadFelt::new([Felt::new(7388624400246275858), Felt::new(0)]), - }, - EvalRecord { - id: 61, - namespace: "stack.ops.movup7", - value: QuadFelt::new([Felt::new(10382124953564405655), Felt::new(0)]), - }, - EvalRecord { - id: 62, - namespace: "stack.ops.movup8", - value: QuadFelt::new([Felt::new(14668661130070444298), Felt::new(0)]), - }, - EvalRecord { - id: 63, - namespace: "stack.ops.movdn2", - value: QuadFelt::new([Felt::new(7617911967740804399), Felt::new(0)]), - }, - EvalRecord { - id: 64, - namespace: "stack.ops.movdn3", - value: QuadFelt::new([Felt::new(10587498815844952065), Felt::new(0)]), - }, - EvalRecord { - id: 65, - namespace: "stack.ops.movdn4", - value: QuadFelt::new([Felt::new(6234074065813353677), Felt::new(0)]), - }, - EvalRecord { - id: 66, - namespace: "stack.ops.movdn5", - value: QuadFelt::new([Felt::new(8228745571736556881), Felt::new(0)]), - }, - EvalRecord { - id: 67, - namespace: "stack.ops.movdn6", - value: QuadFelt::new([Felt::new(1255130201489737978), Felt::new(0)]), - }, - EvalRecord { - id: 68, - namespace: "stack.ops.movdn7", - value: QuadFelt::new([Felt::new(4861541115171604729), Felt::new(0)]), - }, - EvalRecord { - id: 69, - namespace: "stack.ops.movdn8", - value: QuadFelt::new([Felt::new(7218300239612772413), Felt::new(0)]), - }, - EvalRecord { - id: 70, - namespace: "stack.ops.swapw", - value: QuadFelt::new([Felt::new(1397391365707566947), Felt::new(0)]), - }, - EvalRecord { - id: 71, - namespace: "stack.ops.swapw", - value: QuadFelt::new([Felt::new(15192275354424729852), Felt::new(0)]), - }, - EvalRecord { - id: 72, - namespace: "stack.ops.swapw", - value: QuadFelt::new([Felt::new(8991791753517007572), Felt::new(0)]), - }, - EvalRecord { - id: 73, - namespace: "stack.ops.swapw", - value: QuadFelt::new([Felt::new(6845904526592099338), Felt::new(0)]), - }, - EvalRecord { - id: 74, - namespace: "stack.ops.swapw", - value: QuadFelt::new([Felt::new(14405008868848810993), Felt::new(0)]), - }, - EvalRecord { - id: 75, - namespace: "stack.ops.swapw", - value: QuadFelt::new([Felt::new(14818059880037013402), Felt::new(0)]), - }, - EvalRecord { - id: 76, - namespace: "stack.ops.swapw", - value: QuadFelt::new([Felt::new(12858781526955010288), Felt::new(0)]), - }, - EvalRecord { - id: 77, - namespace: "stack.ops.swapw", - value: QuadFelt::new([Felt::new(4346525868099676574), Felt::new(0)]), - }, - EvalRecord { - id: 78, - namespace: "stack.ops.swapw2", - value: QuadFelt::new([Felt::new(12020803221700843056), Felt::new(0)]), - }, - EvalRecord { - id: 79, - namespace: "stack.ops.swapw2", - value: QuadFelt::new([Felt::new(5905514554571101818), Felt::new(0)]), - }, - EvalRecord { - id: 80, - namespace: "stack.ops.swapw2", - value: QuadFelt::new([Felt::new(13967530246007855218), Felt::new(0)]), - }, - EvalRecord { - id: 81, - namespace: "stack.ops.swapw2", - value: QuadFelt::new([Felt::new(1745280905200466463), Felt::new(0)]), - }, - EvalRecord { - id: 82, - namespace: "stack.ops.swapw2", - value: QuadFelt::new([Felt::new(8273384627661819419), Felt::new(0)]), - }, - EvalRecord { - id: 83, - namespace: "stack.ops.swapw2", - value: QuadFelt::new([Felt::new(17907212562142949954), Felt::new(0)]), - }, - EvalRecord { - id: 84, - namespace: "stack.ops.swapw2", - value: QuadFelt::new([Felt::new(10641837676859047674), Felt::new(0)]), - }, - EvalRecord { - id: 85, - namespace: "stack.ops.swapw2", - value: QuadFelt::new([Felt::new(5696399439164028901), Felt::new(0)]), - }, - EvalRecord { - id: 86, - namespace: "stack.ops.swapw3", - value: QuadFelt::new([Felt::new(261758456050090541), Felt::new(0)]), - }, - EvalRecord { - id: 87, - namespace: "stack.ops.swapw3", - value: QuadFelt::new([Felt::new(13783565204182644984), Felt::new(0)]), - }, - EvalRecord { - id: 88, - namespace: "stack.ops.swapw3", - value: QuadFelt::new([Felt::new(8373199292442046895), Felt::new(0)]), - }, - EvalRecord { - id: 89, - namespace: "stack.ops.swapw3", - value: QuadFelt::new([Felt::new(17987956356814792948), Felt::new(0)]), - }, - EvalRecord { - id: 90, - namespace: "stack.ops.swapw3", - value: QuadFelt::new([Felt::new(15863165148623313437), Felt::new(0)]), - }, - EvalRecord { - id: 91, - namespace: "stack.ops.swapw3", - value: QuadFelt::new([Felt::new(15873554387396407564), Felt::new(0)]), - }, - EvalRecord { - id: 92, - namespace: "stack.ops.swapw3", - value: QuadFelt::new([Felt::new(13572800254923888612), Felt::new(0)]), - }, - EvalRecord { - id: 93, - namespace: "stack.ops.swapw3", - value: QuadFelt::new([Felt::new(37494485778659889), Felt::new(0)]), - }, - EvalRecord { - id: 94, - namespace: "stack.ops.swapdw", - value: QuadFelt::new([Felt::new(5468305410596890575), Felt::new(0)]), - }, - EvalRecord { - id: 95, - namespace: "stack.ops.swapdw", - value: QuadFelt::new([Felt::new(8148573700621797018), Felt::new(0)]), - }, - EvalRecord { - id: 96, - namespace: "stack.ops.swapdw", - value: QuadFelt::new([Felt::new(174223531403505930), Felt::new(0)]), - }, - EvalRecord { - id: 97, - namespace: "stack.ops.swapdw", - value: QuadFelt::new([Felt::new(7472429897136677074), Felt::new(0)]), - }, - EvalRecord { - id: 98, - namespace: "stack.ops.swapdw", - value: QuadFelt::new([Felt::new(9085995615849733227), Felt::new(0)]), - }, - EvalRecord { - id: 99, - namespace: "stack.ops.swapdw", - value: QuadFelt::new([Felt::new(17751305329307070351), Felt::new(0)]), - }, - EvalRecord { - id: 100, - namespace: "stack.ops.swapdw", - value: QuadFelt::new([Felt::new(12464875440922891257), Felt::new(0)]), - }, - EvalRecord { - id: 101, - namespace: "stack.ops.swapdw", - value: QuadFelt::new([Felt::new(7381981033510767101), Felt::new(0)]), - }, - EvalRecord { - id: 102, - namespace: "stack.ops.swapdw", - value: QuadFelt::new([Felt::new(14206386269299463916), Felt::new(0)]), - }, - EvalRecord { - id: 103, - namespace: "stack.ops.swapdw", - value: QuadFelt::new([Felt::new(5165712881513112310), Felt::new(0)]), - }, - EvalRecord { - id: 104, - namespace: "stack.ops.swapdw", - value: QuadFelt::new([Felt::new(9505024677507267655), Felt::new(0)]), - }, - EvalRecord { - id: 105, - namespace: "stack.ops.swapdw", - value: QuadFelt::new([Felt::new(7199235098885318815), Felt::new(0)]), - }, - EvalRecord { - id: 106, - namespace: "stack.ops.swapdw", - value: QuadFelt::new([Felt::new(14863071265127885763), Felt::new(0)]), - }, - EvalRecord { - id: 107, - namespace: "stack.ops.swapdw", - value: QuadFelt::new([Felt::new(7964997496183729586), Felt::new(0)]), - }, - EvalRecord { - id: 108, - namespace: "stack.ops.swapdw", - value: QuadFelt::new([Felt::new(17447611484236572336), Felt::new(0)]), - }, - EvalRecord { - id: 109, - namespace: "stack.ops.swapdw", - value: QuadFelt::new([Felt::new(7663698430658282360), Felt::new(0)]), - }, - EvalRecord { - id: 110, - namespace: "stack.ops.cswap", - value: QuadFelt::new([Felt::new(7787471015064615045), Felt::new(0)]), - }, - EvalRecord { - id: 111, - namespace: "stack.ops.cswap", - value: QuadFelt::new([Felt::new(18107469477286194402), Felt::new(0)]), - }, - EvalRecord { - id: 112, - namespace: "stack.ops.cswap", - value: QuadFelt::new([Felt::new(8228755909294702214), Felt::new(0)]), - }, - EvalRecord { - id: 113, - namespace: "stack.ops.cswapw", - value: QuadFelt::new([Felt::new(4517595434872149482), Felt::new(0)]), - }, - EvalRecord { - id: 114, - namespace: "stack.ops.cswapw", - value: QuadFelt::new([Felt::new(7382517392819628451), Felt::new(0)]), - }, - EvalRecord { - id: 115, - namespace: "stack.ops.cswapw", - value: QuadFelt::new([Felt::new(4827417633003237585), Felt::new(0)]), - }, - EvalRecord { - id: 116, - namespace: "stack.ops.cswapw", - value: QuadFelt::new([Felt::new(17779390882653606052), Felt::new(0)]), - }, - EvalRecord { - id: 117, - namespace: "stack.ops.cswapw", - value: QuadFelt::new([Felt::new(16587491652407655425), Felt::new(0)]), - }, - EvalRecord { - id: 118, - namespace: "stack.ops.cswapw", - value: QuadFelt::new([Felt::new(6936098212561125534), Felt::new(0)]), - }, - EvalRecord { - id: 119, - namespace: "stack.ops.cswapw", - value: QuadFelt::new([Felt::new(5094958697700743127), Felt::new(0)]), - }, - EvalRecord { - id: 120, - namespace: "stack.ops.cswapw", - value: QuadFelt::new([Felt::new(189412762651021203), Felt::new(0)]), - }, - EvalRecord { - id: 121, - namespace: "stack.ops.cswapw", - value: QuadFelt::new([Felt::new(8308993958309806023), Felt::new(0)]), - }, - EvalRecord { - id: 122, - namespace: "stack.system.assert", - value: QuadFelt::new([Felt::new(8348363779099446030), Felt::new(0)]), - }, - EvalRecord { - id: 123, - namespace: "stack.system.caller", - value: QuadFelt::new([Felt::new(16674981897661760210), Felt::new(0)]), - }, - EvalRecord { - id: 124, - namespace: "stack.system.caller", - value: QuadFelt::new([Felt::new(14361028107722480662), Felt::new(0)]), - }, - EvalRecord { - id: 125, - namespace: "stack.system.caller", - value: QuadFelt::new([Felt::new(9738252875195915138), Felt::new(0)]), - }, - EvalRecord { - id: 126, - namespace: "stack.system.caller", - value: QuadFelt::new([Felt::new(15161342143096572193), Felt::new(0)]), - }, - EvalRecord { - id: 127, - namespace: "stack.io.sdepth", - value: QuadFelt::new([Felt::new(9690568048381717864), Felt::new(0)]), - }, - EvalRecord { - id: 128, - namespace: "stack.crypto.cryptostream", - value: QuadFelt::new([Felt::new(12685385640397555155), Felt::new(0)]), - }, - EvalRecord { - id: 129, - namespace: "stack.crypto.cryptostream", - value: QuadFelt::new([Felt::new(17365149299857381549), Felt::new(0)]), - }, - EvalRecord { - id: 130, - namespace: "stack.crypto.cryptostream", - value: QuadFelt::new([Felt::new(7455833729327549495), Felt::new(0)]), - }, - EvalRecord { - id: 131, - namespace: "stack.crypto.cryptostream", - value: QuadFelt::new([Felt::new(15687115573708323478), Felt::new(0)]), - }, - EvalRecord { - id: 132, - namespace: "stack.crypto.cryptostream", - value: QuadFelt::new([Felt::new(7143356749732107964), Felt::new(0)]), - }, - EvalRecord { - id: 133, - namespace: "stack.crypto.cryptostream", - value: QuadFelt::new([Felt::new(16804762938330714938), Felt::new(0)]), - }, - EvalRecord { - id: 134, - namespace: "stack.crypto.cryptostream", - value: QuadFelt::new([Felt::new(11562801811268566657), Felt::new(0)]), - }, - EvalRecord { - id: 135, - namespace: "stack.crypto.cryptostream", - value: QuadFelt::new([Felt::new(6374246579471617400), Felt::new(0)]), - }, - EvalRecord { - id: 136, - namespace: "stack.crypto.hornerbase", - value: QuadFelt::new([Felt::new(6682735393816016083), Felt::new(0)]), - }, - EvalRecord { - id: 137, - namespace: "stack.crypto.hornerbase", - value: QuadFelt::new([Felt::new(15946014808270501272), Felt::new(0)]), - }, - EvalRecord { - id: 138, - namespace: "stack.crypto.hornerbase", - value: QuadFelt::new([Felt::new(15603944589931385962), Felt::new(0)]), - }, - EvalRecord { - id: 139, - namespace: "stack.crypto.hornerbase", - value: QuadFelt::new([Felt::new(9275882712531701258), Felt::new(0)]), - }, - EvalRecord { - id: 140, - namespace: "stack.crypto.hornerbase", - value: QuadFelt::new([Felt::new(2477075229563534723), Felt::new(0)]), - }, - EvalRecord { - id: 141, - namespace: "stack.crypto.hornerbase", - value: QuadFelt::new([Felt::new(5290505604769958968), Felt::new(0)]), - }, - EvalRecord { - id: 142, - namespace: "stack.crypto.hornerbase", - value: QuadFelt::new([Felt::new(2851265439044985455), Felt::new(0)]), - }, - EvalRecord { - id: 143, - namespace: "stack.crypto.hornerbase", - value: QuadFelt::new([Felt::new(18383212236849004064), Felt::new(0)]), - }, - EvalRecord { - id: 144, - namespace: "stack.crypto.hornerbase", - value: QuadFelt::new([Felt::new(1727422736811819477), Felt::new(0)]), - }, - EvalRecord { - id: 145, - namespace: "stack.crypto.hornerbase", - value: QuadFelt::new([Felt::new(8661298711862814846), Felt::new(0)]), - }, - EvalRecord { - id: 146, - namespace: "stack.crypto.hornerbase", - value: QuadFelt::new([Felt::new(4909615103768362856), Felt::new(0)]), - }, - EvalRecord { - id: 147, - namespace: "stack.crypto.hornerbase", - value: QuadFelt::new([Felt::new(6313538606129191078), Felt::new(0)]), - }, - EvalRecord { - id: 148, - namespace: "stack.crypto.hornerbase", - value: QuadFelt::new([Felt::new(16477933543947236322), Felt::new(0)]), - }, - EvalRecord { - id: 149, - namespace: "stack.crypto.hornerbase", - value: QuadFelt::new([Felt::new(8923348207341089911), Felt::new(0)]), - }, - EvalRecord { - id: 150, - namespace: "stack.crypto.hornerbase", - value: QuadFelt::new([Felt::new(8415559196869506674), Felt::new(0)]), - }, - EvalRecord { - id: 151, - namespace: "stack.crypto.hornerbase", - value: QuadFelt::new([Felt::new(12374820114184953398), Felt::new(0)]), - }, - EvalRecord { - id: 152, - namespace: "stack.crypto.hornerbase", - value: QuadFelt::new([Felt::new(2975290982061044481), Felt::new(0)]), - }, - EvalRecord { - id: 153, - namespace: "stack.crypto.hornerbase", - value: QuadFelt::new([Felt::new(13487726821146861348), Felt::new(0)]), - }, - EvalRecord { - id: 154, - namespace: "stack.crypto.hornerbase", - value: QuadFelt::new([Felt::new(9982904041042376807), Felt::new(0)]), - }, - EvalRecord { - id: 155, - namespace: "stack.crypto.hornerbase", - value: QuadFelt::new([Felt::new(5949627607219451329), Felt::new(0)]), - }, - EvalRecord { - id: 156, - namespace: "stack.crypto.hornerext", - value: QuadFelt::new([Felt::new(4258650708569289369), Felt::new(0)]), - }, - EvalRecord { - id: 157, - namespace: "stack.crypto.hornerext", - value: QuadFelt::new([Felt::new(10623987720748853996), Felt::new(0)]), - }, - EvalRecord { - id: 158, - namespace: "stack.crypto.hornerext", - value: QuadFelt::new([Felt::new(7214338718283715042), Felt::new(0)]), - }, - EvalRecord { - id: 159, - namespace: "stack.crypto.hornerext", - value: QuadFelt::new([Felt::new(11353293984106841353), Felt::new(0)]), - }, - EvalRecord { - id: 160, - namespace: "stack.crypto.hornerext", - value: QuadFelt::new([Felt::new(13021994910061529075), Felt::new(0)]), - }, - EvalRecord { - id: 161, - namespace: "stack.crypto.hornerext", - value: QuadFelt::new([Felt::new(16890098475354732519), Felt::new(0)]), - }, - EvalRecord { - id: 162, - namespace: "stack.crypto.hornerext", - value: QuadFelt::new([Felt::new(17909680271515252883), Felt::new(0)]), - }, - EvalRecord { - id: 163, - namespace: "stack.crypto.hornerext", - value: QuadFelt::new([Felt::new(17436574006020893038), Felt::new(0)]), - }, - EvalRecord { - id: 164, - namespace: "stack.crypto.hornerext", - value: QuadFelt::new([Felt::new(11510839286135128168), Felt::new(0)]), - }, - EvalRecord { - id: 165, - namespace: "stack.crypto.hornerext", - value: QuadFelt::new([Felt::new(5781748113887851533), Felt::new(0)]), - }, - EvalRecord { - id: 166, - namespace: "stack.crypto.hornerext", - value: QuadFelt::new([Felt::new(14599010851776253883), Felt::new(0)]), - }, - EvalRecord { - id: 167, - namespace: "stack.crypto.hornerext", - value: QuadFelt::new([Felt::new(9495625123030210045), Felt::new(0)]), - }, - EvalRecord { - id: 168, - namespace: "stack.crypto.hornerext", - value: QuadFelt::new([Felt::new(7672904073310511358), Felt::new(0)]), - }, - EvalRecord { - id: 169, - namespace: "stack.crypto.hornerext", - value: QuadFelt::new([Felt::new(775511618954631186), Felt::new(0)]), - }, - EvalRecord { - id: 170, - namespace: "stack.crypto.hornerext", - value: QuadFelt::new([Felt::new(1082901338727409004), Felt::new(0)]), - }, - EvalRecord { - id: 171, - namespace: "stack.crypto.hornerext", - value: QuadFelt::new([Felt::new(13302599741550075590), Felt::new(0)]), - }, - EvalRecord { - id: 172, - namespace: "stack.crypto.hornerext", - value: QuadFelt::new([Felt::new(4231043957658294146), Felt::new(0)]), - }, - EvalRecord { - id: 173, - namespace: "stack.crypto.hornerext", - value: QuadFelt::new([Felt::new(16476104241930761470), Felt::new(0)]), - }, - EvalRecord { - id: 174, - namespace: "stack.arith.add", - value: QuadFelt::new([Felt::new(12162183238628940886), Felt::new(0)]), - }, - EvalRecord { - id: 175, - namespace: "stack.arith.neg", - value: QuadFelt::new([Felt::new(5581128975715924145), Felt::new(0)]), - }, - EvalRecord { - id: 176, - namespace: "stack.arith.mul", - value: QuadFelt::new([Felt::new(8554389406737436796), Felt::new(0)]), - }, - EvalRecord { - id: 177, - namespace: "stack.arith.inv", - value: QuadFelt::new([Felt::new(5063887741998958642), Felt::new(0)]), - }, - EvalRecord { - id: 178, - namespace: "stack.arith.incr", - value: QuadFelt::new([Felt::new(4639763508506743987), Felt::new(0)]), - }, - EvalRecord { - id: 179, - namespace: "stack.arith.not", - value: QuadFelt::new([Felt::new(4035466692403055130), Felt::new(0)]), - }, - EvalRecord { - id: 180, - namespace: "stack.arith.not", - value: QuadFelt::new([Felt::new(13177116281714227608), Felt::new(0)]), - }, - EvalRecord { - id: 181, - namespace: "stack.arith.and", - value: QuadFelt::new([Felt::new(3385806455961392573), Felt::new(0)]), - }, - EvalRecord { - id: 182, - namespace: "stack.arith.and", - value: QuadFelt::new([Felt::new(10970170501742489729), Felt::new(0)]), - }, - EvalRecord { - id: 183, - namespace: "stack.arith.and", - value: QuadFelt::new([Felt::new(2412459788431241921), Felt::new(0)]), - }, - EvalRecord { - id: 184, - namespace: "stack.arith.or", - value: QuadFelt::new([Felt::new(3841745486638047933), Felt::new(0)]), - }, - EvalRecord { - id: 185, - namespace: "stack.arith.or", - value: QuadFelt::new([Felt::new(3504719246524046533), Felt::new(0)]), - }, - EvalRecord { - id: 186, - namespace: "stack.arith.or", - value: QuadFelt::new([Felt::new(8108995209839065445), Felt::new(0)]), - }, - EvalRecord { - id: 187, - namespace: "stack.arith.eq", - value: QuadFelt::new([Felt::new(14385477599012828093), Felt::new(0)]), - }, - EvalRecord { - id: 188, - namespace: "stack.arith.eq", - value: QuadFelt::new([Felt::new(17777414138310332081), Felt::new(0)]), - }, - EvalRecord { - id: 189, - namespace: "stack.arith.eqz", - value: QuadFelt::new([Felt::new(1585550152724577414), Felt::new(0)]), - }, - EvalRecord { - id: 190, - namespace: "stack.arith.eqz", - value: QuadFelt::new([Felt::new(8914500005861323211), Felt::new(0)]), - }, - EvalRecord { - id: 191, - namespace: "stack.arith.expacc", - value: QuadFelt::new([Felt::new(10821948734140194924), Felt::new(0)]), - }, - EvalRecord { - id: 192, - namespace: "stack.arith.expacc", - value: QuadFelt::new([Felt::new(18138155306684050585), Felt::new(0)]), - }, - EvalRecord { - id: 193, - namespace: "stack.arith.expacc", - value: QuadFelt::new([Felt::new(11221181362690184920), Felt::new(0)]), - }, - EvalRecord { - id: 194, - namespace: "stack.arith.expacc", - value: QuadFelt::new([Felt::new(9522158304362954603), Felt::new(0)]), - }, - EvalRecord { - id: 195, - namespace: "stack.arith.expacc", - value: QuadFelt::new([Felt::new(13901486800460794091), Felt::new(0)]), - }, - EvalRecord { - id: 196, - namespace: "stack.arith.ext2mul", - value: QuadFelt::new([Felt::new(7911065669822474568), Felt::new(0)]), - }, - EvalRecord { - id: 197, - namespace: "stack.arith.ext2mul", - value: QuadFelt::new([Felt::new(3598619357058098113), Felt::new(0)]), - }, - EvalRecord { - id: 198, - namespace: "stack.arith.ext2mul", - value: QuadFelt::new([Felt::new(996509971607279275), Felt::new(0)]), - }, - EvalRecord { - id: 199, - namespace: "stack.arith.ext2mul", - value: QuadFelt::new([Felt::new(13600174711341153155), Felt::new(0)]), - }, - EvalRecord { - id: 200, - namespace: "stack.arith.u32.shared", - value: QuadFelt::new([Felt::new(1597821177308476955), Felt::new(0)]), - }, - EvalRecord { - id: 201, - namespace: "stack.arith.u32.output", - value: QuadFelt::new([Felt::new(13697666666561534208), Felt::new(0)]), - }, - EvalRecord { - id: 202, - namespace: "stack.arith.u32.output", - value: QuadFelt::new([Felt::new(18192033048549134928), Felt::new(0)]), - }, - EvalRecord { - id: 203, - namespace: "stack.arith.u32.split", - value: QuadFelt::new([Felt::new(15868014234137212529), Felt::new(0)]), - }, - EvalRecord { - id: 204, - namespace: "stack.arith.u32.add", - value: QuadFelt::new([Felt::new(3877846355380377379), Felt::new(0)]), - }, - EvalRecord { - id: 205, - namespace: "stack.arith.u32.add3", - value: QuadFelt::new([Felt::new(14996475617734368887), Felt::new(0)]), - }, - EvalRecord { - id: 206, - namespace: "stack.arith.u32.sub", - value: QuadFelt::new([Felt::new(3623920048867462270), Felt::new(0)]), - }, - EvalRecord { - id: 207, - namespace: "stack.arith.u32.sub", - value: QuadFelt::new([Felt::new(5319755831391255333), Felt::new(0)]), - }, - EvalRecord { - id: 208, - namespace: "stack.arith.u32.sub", - value: QuadFelt::new([Felt::new(15655064156696355905), Felt::new(0)]), - }, - EvalRecord { - id: 209, - namespace: "stack.arith.u32.mul", - value: QuadFelt::new([Felt::new(10932857720351146657), Felt::new(0)]), - }, - EvalRecord { - id: 210, - namespace: "stack.arith.u32.madd", - value: QuadFelt::new([Felt::new(5677672016010321812), Felt::new(0)]), - }, - EvalRecord { - id: 211, - namespace: "stack.arith.u32.div", - value: QuadFelt::new([Felt::new(40380517428295215), Felt::new(0)]), - }, - EvalRecord { - id: 212, - namespace: "stack.arith.u32.div", - value: QuadFelt::new([Felt::new(15350419499859122435), Felt::new(0)]), - }, - EvalRecord { - id: 213, - namespace: "stack.arith.u32.div", - value: QuadFelt::new([Felt::new(14341334560480736404), Felt::new(0)]), - }, - EvalRecord { - id: 214, - namespace: "stack.arith.u32.assert2", - value: QuadFelt::new([Felt::new(6089961092604608348), Felt::new(0)]), - }, - EvalRecord { - id: 215, - namespace: "stack.arith.u32.assert2", - value: QuadFelt::new([Felt::new(3427128116590576361), Felt::new(0)]), - }, - EvalRecord { - id: 216, - namespace: "decoder.in_span.first_row", - value: QuadFelt::new([Felt::new(14927496178105230921), Felt::new(0)]), - }, - EvalRecord { - id: 217, - namespace: "decoder.in_span.binary", - value: QuadFelt::new([Felt::new(14486244054610710736), Felt::new(0)]), - }, - EvalRecord { - id: 218, - namespace: "decoder.in_span.span", - value: QuadFelt::new([Felt::new(466300909996410452), Felt::new(0)]), - }, - EvalRecord { - id: 219, - namespace: "decoder.in_span.respan", - value: QuadFelt::new([Felt::new(3338971954421326066), Felt::new(0)]), - }, - EvalRecord { - id: 220, - namespace: "decoder.op_bits.b0.binary", - value: QuadFelt::new([Felt::new(13628791071868321124), Felt::new(0)]), - }, - EvalRecord { - id: 221, - namespace: "decoder.op_bits.b1.binary", - value: QuadFelt::new([Felt::new(2117480814916000258), Felt::new(0)]), - }, - EvalRecord { - id: 222, - namespace: "decoder.op_bits.b2.binary", - value: QuadFelt::new([Felt::new(16926933246570374887), Felt::new(0)]), - }, - EvalRecord { - id: 223, - namespace: "decoder.op_bits.b3.binary", - value: QuadFelt::new([Felt::new(9176310969543325496), Felt::new(0)]), - }, - EvalRecord { - id: 224, - namespace: "decoder.op_bits.b4.binary", - value: QuadFelt::new([Felt::new(7537316481676351991), Felt::new(0)]), - }, - EvalRecord { - id: 225, - namespace: "decoder.op_bits.b5.binary", - value: QuadFelt::new([Felt::new(2144456409708417452), Felt::new(0)]), - }, - EvalRecord { - id: 226, - namespace: "decoder.op_bits.b6.binary", - value: QuadFelt::new([Felt::new(4533994350960751386), Felt::new(0)]), - }, - EvalRecord { - id: 227, - namespace: "decoder.extra.e0", - value: QuadFelt::new([Felt::new(8133745730975361882), Felt::new(0)]), - }, - EvalRecord { - id: 228, - namespace: "decoder.extra.e1", - value: QuadFelt::new([Felt::new(1382945310839592478), Felt::new(0)]), - }, - EvalRecord { - id: 229, - namespace: "decoder.op_bits.u32_prefix.b0", - value: QuadFelt::new([Felt::new(3295186688501169293), Felt::new(0)]), - }, - EvalRecord { - id: 230, - namespace: "decoder.op_bits.very_high.b0", - value: QuadFelt::new([Felt::new(1492924210658182178), Felt::new(0)]), - }, - EvalRecord { - id: 231, - namespace: "decoder.op_bits.very_high.b1", - value: QuadFelt::new([Felt::new(11514104647859742926), Felt::new(0)]), - }, - EvalRecord { - id: 232, - namespace: "decoder.batch_flags.c0.binary", - value: QuadFelt::new([Felt::new(5362129305222679805), Felt::new(0)]), - }, - EvalRecord { - id: 233, - namespace: "decoder.batch_flags.c1.binary", - value: QuadFelt::new([Felt::new(7857195453682114326), Felt::new(0)]), - }, - EvalRecord { - id: 234, - namespace: "decoder.batch_flags.c2.binary", - value: QuadFelt::new([Felt::new(7691051559149421836), Felt::new(0)]), - }, - EvalRecord { - id: 235, - namespace: "decoder.general.split_loop.s0.binary", - value: QuadFelt::new([Felt::new(14496120396244092127), Felt::new(0)]), - }, - EvalRecord { - id: 236, - namespace: "decoder.general.dyn.h4.zero", - value: QuadFelt::new([Felt::new(1277805081675897337), Felt::new(0)]), - }, - EvalRecord { - id: 237, - namespace: "decoder.general.dyn.h5.zero", - value: QuadFelt::new([Felt::new(4194588350245381799), Felt::new(0)]), - }, - EvalRecord { - id: 238, - namespace: "decoder.general.dyn.h6.zero", - value: QuadFelt::new([Felt::new(16022182314963541978), Felt::new(0)]), - }, - EvalRecord { - id: 239, - namespace: "decoder.general.dyn.h7.zero", - value: QuadFelt::new([Felt::new(8836314757936512908), Felt::new(0)]), - }, - EvalRecord { - id: 240, - namespace: "decoder.general.repeat.s0.one", - value: QuadFelt::new([Felt::new(12665553195229242113), Felt::new(0)]), - }, - EvalRecord { - id: 241, - namespace: "decoder.general.repeat.h4.one", - value: QuadFelt::new([Felt::new(7110671376227656729), Felt::new(0)]), - }, - EvalRecord { - id: 242, - namespace: "decoder.general.end.loop.s0.zero", - value: QuadFelt::new([Felt::new(17349561739015487668), Felt::new(0)]), - }, - EvalRecord { - id: 243, - namespace: "decoder.general.end_repeat.h0.carry", - value: QuadFelt::new([Felt::new(14675084366068366020), Felt::new(0)]), - }, - EvalRecord { - id: 244, - namespace: "decoder.general.end_repeat.h1.carry", - value: QuadFelt::new([Felt::new(7206936627190077403), Felt::new(0)]), - }, - EvalRecord { - id: 245, - namespace: "decoder.general.end_repeat.h2.carry", - value: QuadFelt::new([Felt::new(6718740807857903289), Felt::new(0)]), - }, - EvalRecord { - id: 246, - namespace: "decoder.general.end_repeat.h3.carry", - value: QuadFelt::new([Felt::new(17516850364483319430), Felt::new(0)]), - }, - EvalRecord { - id: 247, - namespace: "decoder.general.end_repeat.h4.carry", - value: QuadFelt::new([Felt::new(6539200550348860466), Felt::new(0)]), - }, - EvalRecord { - id: 248, - namespace: "decoder.general.halt.next", - value: QuadFelt::new([Felt::new(46417891308149319), Felt::new(0)]), - }, - EvalRecord { - id: 249, - namespace: "decoder.group_count.delta.binary", - value: QuadFelt::new([Felt::new(14515312709656548917), Felt::new(0)]), - }, - EvalRecord { - id: 250, - namespace: "decoder.group_count.decrement.h0_or_imm", - value: QuadFelt::new([Felt::new(13182337539042779943), Felt::new(0)]), - }, - EvalRecord { - id: 251, - namespace: "decoder.group_count.span_decrement", - value: QuadFelt::new([Felt::new(6058211846758132294), Felt::new(0)]), - }, - EvalRecord { - id: 252, - namespace: "decoder.group_count.end_or_respan.hold", - value: QuadFelt::new([Felt::new(11052268645110095431), Felt::new(0)]), - }, - EvalRecord { - id: 253, - namespace: "decoder.group_count.end.zero", - value: QuadFelt::new([Felt::new(8085923270334721350), Felt::new(0)]), - }, - EvalRecord { - id: 254, - namespace: "decoder.op_group.shift", - value: QuadFelt::new([Felt::new(1312737539633457020), Felt::new(0)]), - }, - EvalRecord { - id: 255, - namespace: "decoder.op_group.end_or_respan.h0.zero", - value: QuadFelt::new([Felt::new(12951763225475877068), Felt::new(0)]), - }, - EvalRecord { - id: 256, - namespace: "decoder.op_index.span_respan.reset", - value: QuadFelt::new([Felt::new(10573491584444022281), Felt::new(0)]), - }, - EvalRecord { - id: 257, - namespace: "decoder.op_index.new_group.reset", - value: QuadFelt::new([Felt::new(6175768744156945971), Felt::new(0)]), - }, - EvalRecord { - id: 258, - namespace: "decoder.op_index.increment", - value: QuadFelt::new([Felt::new(11099022161747498050), Felt::new(0)]), - }, - EvalRecord { - id: 259, - namespace: "decoder.op_index.range", - value: QuadFelt::new([Felt::new(10884671635123915786), Felt::new(0)]), - }, - EvalRecord { - id: 260, - namespace: "decoder.batch_flags.span_sum", - value: QuadFelt::new([Felt::new(3694838697400308733), Felt::new(0)]), - }, - EvalRecord { - id: 261, - namespace: "decoder.batch_flags.zero_when_not_span", - value: QuadFelt::new([Felt::new(3630764990867231714), Felt::new(0)]), - }, - EvalRecord { - id: 262, - namespace: "decoder.batch_flags.h4.zero", - value: QuadFelt::new([Felt::new(2244382601531916648), Felt::new(0)]), - }, - EvalRecord { - id: 263, - namespace: "decoder.batch_flags.h5.zero", - value: QuadFelt::new([Felt::new(15434877991581266285), Felt::new(0)]), - }, - EvalRecord { - id: 264, - namespace: "decoder.batch_flags.h6.zero", - value: QuadFelt::new([Felt::new(7419023179375721027), Felt::new(0)]), - }, - EvalRecord { - id: 265, - namespace: "decoder.batch_flags.h7.zero", - value: QuadFelt::new([Felt::new(7459745966287177285), Felt::new(0)]), - }, - EvalRecord { - id: 266, - namespace: "decoder.batch_flags.h2.zero", - value: QuadFelt::new([Felt::new(11698744832781440772), Felt::new(0)]), - }, - EvalRecord { - id: 267, - namespace: "decoder.batch_flags.h3.zero", - value: QuadFelt::new([Felt::new(8586259512688079232), Felt::new(0)]), - }, - EvalRecord { - id: 268, - namespace: "decoder.batch_flags.h1.zero", - value: QuadFelt::new([Felt::new(7969602088154595265), Felt::new(0)]), - }, - EvalRecord { - id: 269, - namespace: "decoder.addr.hold_in_span", - value: QuadFelt::new([Felt::new(5569758276797826136), Felt::new(0)]), - }, - EvalRecord { - id: 270, - namespace: "decoder.addr.respan.increment", - value: QuadFelt::new([Felt::new(7010123233147094271), Felt::new(0)]), - }, - EvalRecord { - id: 271, - namespace: "decoder.addr.halt.zero", - value: QuadFelt::new([Felt::new(571992094937652912), Felt::new(0)]), - }, - EvalRecord { - id: 272, - namespace: "decoder.control_flow.sp_complement", - value: QuadFelt::new([Felt::new(2368373158779190039), Felt::new(0)]), - }, - EvalRecord { - id: 273, - namespace: "chiplets.selectors.s0.binary", - value: QuadFelt::new([Felt::new(13339369523717109295), Felt::new(0)]), - }, - EvalRecord { - id: 274, - namespace: "chiplets.selectors.s1.binary", - value: QuadFelt::new([Felt::new(5399081030326323264), Felt::new(0)]), - }, - EvalRecord { - id: 275, - namespace: "chiplets.selectors.s2.binary", - value: QuadFelt::new([Felt::new(12423271937388024622), Felt::new(0)]), - }, - EvalRecord { - id: 276, - namespace: "chiplets.selectors.s3.binary", - value: QuadFelt::new([Felt::new(6104289749728022881), Felt::new(0)]), - }, - EvalRecord { - id: 277, - namespace: "chiplets.selectors.s4.binary", - value: QuadFelt::new([Felt::new(1241452016395320053), Felt::new(0)]), - }, - EvalRecord { - id: 278, - namespace: "chiplets.selectors.s0.stability", - value: QuadFelt::new([Felt::new(14729701512419667041), Felt::new(0)]), - }, - EvalRecord { - id: 279, - namespace: "chiplets.selectors.s1.stability", - value: QuadFelt::new([Felt::new(8909164618174988456), Felt::new(0)]), - }, - EvalRecord { - id: 280, - namespace: "chiplets.selectors.s2.stability", - value: QuadFelt::new([Felt::new(17247285692427399965), Felt::new(0)]), - }, - EvalRecord { - id: 281, - namespace: "chiplets.selectors.s3.stability", - value: QuadFelt::new([Felt::new(18202363660063267394), Felt::new(0)]), - }, - EvalRecord { - id: 282, - namespace: "chiplets.selectors.s4.stability", - value: QuadFelt::new([Felt::new(6610185862666795331), Felt::new(0)]), - }, - EvalRecord { - id: 283, - namespace: "chiplets.hasher.permutation.init", - value: QuadFelt::new([Felt::new(4099164774137728313), Felt::new(0)]), - }, - EvalRecord { - id: 284, - namespace: "chiplets.hasher.permutation.init", - value: QuadFelt::new([Felt::new(14454658395404025559), Felt::new(0)]), - }, - EvalRecord { - id: 285, - namespace: "chiplets.hasher.permutation.init", - value: QuadFelt::new([Felt::new(14045750606291612344), Felt::new(0)]), - }, - EvalRecord { - id: 286, - namespace: "chiplets.hasher.permutation.init", - value: QuadFelt::new([Felt::new(4962577616206122596), Felt::new(0)]), - }, - EvalRecord { - id: 287, - namespace: "chiplets.hasher.permutation.init", - value: QuadFelt::new([Felt::new(17693281290536116739), Felt::new(0)]), - }, - EvalRecord { - id: 288, - namespace: "chiplets.hasher.permutation.init", - value: QuadFelt::new([Felt::new(2566307954601069485), Felt::new(0)]), - }, - EvalRecord { - id: 289, - namespace: "chiplets.hasher.permutation.init", - value: QuadFelt::new([Felt::new(7014825251917345868), Felt::new(0)]), - }, - EvalRecord { - id: 290, - namespace: "chiplets.hasher.permutation.init", - value: QuadFelt::new([Felt::new(12643485402937350728), Felt::new(0)]), - }, - EvalRecord { - id: 291, - namespace: "chiplets.hasher.permutation.init", - value: QuadFelt::new([Felt::new(13773518984372045426), Felt::new(0)]), - }, - EvalRecord { - id: 292, - namespace: "chiplets.hasher.permutation.init", - value: QuadFelt::new([Felt::new(12725128195760136818), Felt::new(0)]), - }, - EvalRecord { - id: 293, - namespace: "chiplets.hasher.permutation.init", - value: QuadFelt::new([Felt::new(12789485480014529422), Felt::new(0)]), - }, - EvalRecord { - id: 294, - namespace: "chiplets.hasher.permutation.init", - value: QuadFelt::new([Felt::new(2064555680622899263), Felt::new(0)]), - }, - EvalRecord { - id: 295, - namespace: "chiplets.hasher.permutation.external", - value: QuadFelt::new([Felt::new(14965667877036435255), Felt::new(0)]), - }, - EvalRecord { - id: 296, - namespace: "chiplets.hasher.permutation.external", - value: QuadFelt::new([Felt::new(8649163745447702544), Felt::new(0)]), - }, - EvalRecord { - id: 297, - namespace: "chiplets.hasher.permutation.external", - value: QuadFelt::new([Felt::new(1871614405591673138), Felt::new(0)]), - }, - EvalRecord { - id: 298, - namespace: "chiplets.hasher.permutation.external", - value: QuadFelt::new([Felt::new(3904379054162154278), Felt::new(0)]), - }, - EvalRecord { - id: 299, - namespace: "chiplets.hasher.permutation.external", - value: QuadFelt::new([Felt::new(14269032524621289009), Felt::new(0)]), - }, - EvalRecord { - id: 300, - namespace: "chiplets.hasher.permutation.external", - value: QuadFelt::new([Felt::new(819271014970897034), Felt::new(0)]), - }, - EvalRecord { - id: 301, - namespace: "chiplets.hasher.permutation.external", - value: QuadFelt::new([Felt::new(7445347300254257143), Felt::new(0)]), - }, - EvalRecord { - id: 302, - namespace: "chiplets.hasher.permutation.external", - value: QuadFelt::new([Felt::new(18264241495848405505), Felt::new(0)]), - }, - EvalRecord { - id: 303, - namespace: "chiplets.hasher.permutation.external", - value: QuadFelt::new([Felt::new(4022419953426403986), Felt::new(0)]), - }, - EvalRecord { - id: 304, - namespace: "chiplets.hasher.permutation.external", - value: QuadFelt::new([Felt::new(16556927457681327599), Felt::new(0)]), - }, - EvalRecord { - id: 305, - namespace: "chiplets.hasher.permutation.external", - value: QuadFelt::new([Felt::new(7630095839895141032), Felt::new(0)]), - }, - EvalRecord { - id: 306, - namespace: "chiplets.hasher.permutation.external", - value: QuadFelt::new([Felt::new(17073915086247210099), Felt::new(0)]), - }, - EvalRecord { - id: 307, - namespace: "chiplets.hasher.permutation.internal", - value: QuadFelt::new([Felt::new(12354414453280530108), Felt::new(0)]), - }, - EvalRecord { - id: 308, - namespace: "chiplets.hasher.permutation.internal", - value: QuadFelt::new([Felt::new(15162996181146864722), Felt::new(0)]), - }, - EvalRecord { - id: 309, - namespace: "chiplets.hasher.permutation.internal", - value: QuadFelt::new([Felt::new(3799802584325483032), Felt::new(0)]), - }, - EvalRecord { - id: 310, - namespace: "chiplets.hasher.permutation.internal", - value: QuadFelt::new([Felt::new(7503666179952416559), Felt::new(0)]), - }, - EvalRecord { - id: 311, - namespace: "chiplets.hasher.permutation.internal", - value: QuadFelt::new([Felt::new(5195105242383400264), Felt::new(0)]), - }, - EvalRecord { - id: 312, - namespace: "chiplets.hasher.permutation.internal", - value: QuadFelt::new([Felt::new(2672184473444251603), Felt::new(0)]), - }, - EvalRecord { - id: 313, - namespace: "chiplets.hasher.permutation.internal", - value: QuadFelt::new([Felt::new(1545887997090789749), Felt::new(0)]), - }, - EvalRecord { - id: 314, - namespace: "chiplets.hasher.permutation.internal", - value: QuadFelt::new([Felt::new(212978569305465235), Felt::new(0)]), - }, - EvalRecord { - id: 315, - namespace: "chiplets.hasher.permutation.internal", - value: QuadFelt::new([Felt::new(7828622218965306157), Felt::new(0)]), - }, - EvalRecord { - id: 316, - namespace: "chiplets.hasher.permutation.internal", - value: QuadFelt::new([Felt::new(15313472288808367905), Felt::new(0)]), - }, - EvalRecord { - id: 317, - namespace: "chiplets.hasher.permutation.internal", - value: QuadFelt::new([Felt::new(1544567903496578828), Felt::new(0)]), - }, - EvalRecord { - id: 318, - namespace: "chiplets.hasher.permutation.internal", - value: QuadFelt::new([Felt::new(6950222684787745222), Felt::new(0)]), - }, - EvalRecord { - id: 319, - namespace: "chiplets.hasher.selectors.binary", - value: QuadFelt::new([Felt::new(17059167507535516774), Felt::new(0)]), - }, - EvalRecord { - id: 320, - namespace: "chiplets.hasher.selectors.binary", - value: QuadFelt::new([Felt::new(2543200120204459519), Felt::new(0)]), - }, - EvalRecord { - id: 321, - namespace: "chiplets.hasher.selectors.binary", - value: QuadFelt::new([Felt::new(17534396985644786691), Felt::new(0)]), - }, - EvalRecord { - id: 322, - namespace: "chiplets.hasher.selectors.stability", - value: QuadFelt::new([Felt::new(6479352521221779748), Felt::new(0)]), - }, - EvalRecord { - id: 323, - namespace: "chiplets.hasher.selectors.stability", - value: QuadFelt::new([Felt::new(210512107158412246), Felt::new(0)]), - }, - EvalRecord { - id: 324, - namespace: "chiplets.hasher.selectors.continuation", - value: QuadFelt::new([Felt::new(15715623607701353500), Felt::new(0)]), - }, - EvalRecord { - id: 325, - namespace: "chiplets.hasher.selectors.invalid", - value: QuadFelt::new([Felt::new(13405975868755856198), Felt::new(0)]), - }, - EvalRecord { - id: 326, - namespace: "chiplets.hasher.abp.capacity", - value: QuadFelt::new([Felt::new(1899048554833837921), Felt::new(0)]), - }, - EvalRecord { - id: 327, - namespace: "chiplets.hasher.abp.capacity", - value: QuadFelt::new([Felt::new(12437244811220538952), Felt::new(0)]), - }, - EvalRecord { - id: 328, - namespace: "chiplets.hasher.abp.capacity", - value: QuadFelt::new([Felt::new(10139411892992277524), Felt::new(0)]), - }, - EvalRecord { - id: 329, - namespace: "chiplets.hasher.abp.capacity", - value: QuadFelt::new([Felt::new(15737189571305100043), Felt::new(0)]), - }, - EvalRecord { - id: 330, - namespace: "chiplets.hasher.output.index", - value: QuadFelt::new([Felt::new(16881983815653283540), Felt::new(0)]), - }, - EvalRecord { - id: 331, - namespace: "chiplets.hasher.merkle.index.binary", - value: QuadFelt::new([Felt::new(13143318647927561805), Felt::new(0)]), - }, - EvalRecord { - id: 332, - namespace: "chiplets.hasher.merkle.index.stability", - value: QuadFelt::new([Felt::new(13941205471766075471), Felt::new(0)]), - }, - EvalRecord { - id: 333, - namespace: "chiplets.hasher.merkle.capacity", - value: QuadFelt::new([Felt::new(5486621160745001548), Felt::new(0)]), - }, - EvalRecord { - id: 334, - namespace: "chiplets.hasher.merkle.capacity", - value: QuadFelt::new([Felt::new(15134096900702524735), Felt::new(0)]), - }, - EvalRecord { - id: 335, - namespace: "chiplets.hasher.merkle.capacity", - value: QuadFelt::new([Felt::new(17576701782509621064), Felt::new(0)]), - }, - EvalRecord { - id: 336, - namespace: "chiplets.hasher.merkle.capacity", - value: QuadFelt::new([Felt::new(14561117990313963177), Felt::new(0)]), - }, - EvalRecord { - id: 337, - namespace: "chiplets.hasher.merkle.digest.rate0", - value: QuadFelt::new([Felt::new(8725087617587926550), Felt::new(0)]), - }, - EvalRecord { - id: 338, - namespace: "chiplets.hasher.merkle.digest.rate0", - value: QuadFelt::new([Felt::new(12515088494833138961), Felt::new(0)]), - }, - EvalRecord { - id: 339, - namespace: "chiplets.hasher.merkle.digest.rate0", - value: QuadFelt::new([Felt::new(6965398204541535664), Felt::new(0)]), - }, - EvalRecord { - id: 340, - namespace: "chiplets.hasher.merkle.digest.rate0", - value: QuadFelt::new([Felt::new(11433229023120737569), Felt::new(0)]), - }, - EvalRecord { - id: 341, - namespace: "chiplets.hasher.merkle.digest.rate1", - value: QuadFelt::new([Felt::new(4884394573065500633), Felt::new(0)]), - }, - EvalRecord { - id: 342, - namespace: "chiplets.hasher.merkle.digest.rate1", - value: QuadFelt::new([Felt::new(16805257998005939804), Felt::new(0)]), - }, - EvalRecord { - id: 343, - namespace: "chiplets.hasher.merkle.digest.rate1", - value: QuadFelt::new([Felt::new(55029178798193706), Felt::new(0)]), - }, - EvalRecord { - id: 344, - namespace: "chiplets.hasher.merkle.digest.rate1", - value: QuadFelt::new([Felt::new(17219870521967201546), Felt::new(0)]), - }, - EvalRecord { - id: 345, - namespace: "chiplets.bitwise.op.binary", - value: QuadFelt::new([Felt::new(15474882094825938582), Felt::new(0)]), - }, - EvalRecord { - id: 346, - namespace: "chiplets.bitwise.op.stability", - value: QuadFelt::new([Felt::new(654157308496499224), Felt::new(0)]), - }, - EvalRecord { - id: 347, - namespace: "chiplets.bitwise.a_bits.binary", - value: QuadFelt::new([Felt::new(1034651076143976640), Felt::new(0)]), - }, - EvalRecord { - id: 348, - namespace: "chiplets.bitwise.a_bits.binary", - value: QuadFelt::new([Felt::new(4003142075320695647), Felt::new(0)]), - }, - EvalRecord { - id: 349, - namespace: "chiplets.bitwise.a_bits.binary", - value: QuadFelt::new([Felt::new(303909215511455897), Felt::new(0)]), - }, - EvalRecord { - id: 350, - namespace: "chiplets.bitwise.a_bits.binary", - value: QuadFelt::new([Felt::new(5362728732691526694), Felt::new(0)]), - }, - EvalRecord { - id: 351, - namespace: "chiplets.bitwise.b_bits.binary", - value: QuadFelt::new([Felt::new(11650758097842027858), Felt::new(0)]), - }, - EvalRecord { - id: 352, - namespace: "chiplets.bitwise.b_bits.binary", - value: QuadFelt::new([Felt::new(7007196355931725843), Felt::new(0)]), - }, - EvalRecord { - id: 353, - namespace: "chiplets.bitwise.b_bits.binary", - value: QuadFelt::new([Felt::new(11561896106611918266), Felt::new(0)]), - }, - EvalRecord { - id: 354, - namespace: "chiplets.bitwise.b_bits.binary", - value: QuadFelt::new([Felt::new(4060803575635852640), Felt::new(0)]), - }, - EvalRecord { - id: 355, - namespace: "chiplets.bitwise.first_row", - value: QuadFelt::new([Felt::new(14840226897639012209), Felt::new(0)]), - }, - EvalRecord { - id: 356, - namespace: "chiplets.bitwise.first_row", - value: QuadFelt::new([Felt::new(15513879563001185502), Felt::new(0)]), - }, - EvalRecord { - id: 357, - namespace: "chiplets.bitwise.first_row", - value: QuadFelt::new([Felt::new(5652235828559265944), Felt::new(0)]), - }, - EvalRecord { - id: 358, - namespace: "chiplets.bitwise.input.transition", - value: QuadFelt::new([Felt::new(12380774213272670463), Felt::new(0)]), - }, - EvalRecord { - id: 359, - namespace: "chiplets.bitwise.input.transition", - value: QuadFelt::new([Felt::new(7940993120185857575), Felt::new(0)]), - }, - EvalRecord { - id: 360, - namespace: "chiplets.bitwise.output.prev", - value: QuadFelt::new([Felt::new(7984380758996607942), Felt::new(0)]), - }, - EvalRecord { - id: 361, - namespace: "chiplets.bitwise.output.aggregate", - value: QuadFelt::new([Felt::new(11338003127856250266), Felt::new(0)]), - }, - EvalRecord { - id: 362, - namespace: "chiplets.memory.binary", - value: QuadFelt::new([Felt::new(6518050416979602887), Felt::new(0)]), - }, - EvalRecord { - id: 363, - namespace: "chiplets.memory.binary", - value: QuadFelt::new([Felt::new(5143376107998730535), Felt::new(0)]), - }, - EvalRecord { - id: 364, - namespace: "chiplets.memory.binary", - value: QuadFelt::new([Felt::new(1931814968789928617), Felt::new(0)]), - }, - EvalRecord { - id: 365, - namespace: "chiplets.memory.binary", - value: QuadFelt::new([Felt::new(15470079227779320896), Felt::new(0)]), - }, - EvalRecord { - id: 366, - namespace: "chiplets.memory.word_idx.zero", - value: QuadFelt::new([Felt::new(15459815149111314868), Felt::new(0)]), - }, - EvalRecord { - id: 367, - namespace: "chiplets.memory.word_idx.zero", - value: QuadFelt::new([Felt::new(15800347411094406640), Felt::new(0)]), - }, - EvalRecord { - id: 368, - namespace: "chiplets.memory.first_row.zero", - value: QuadFelt::new([Felt::new(16535341688150290637), Felt::new(0)]), - }, - EvalRecord { - id: 369, - namespace: "chiplets.memory.first_row.zero", - value: QuadFelt::new([Felt::new(10335801429662869046), Felt::new(0)]), - }, - EvalRecord { - id: 370, - namespace: "chiplets.memory.first_row.zero", - value: QuadFelt::new([Felt::new(17069212044771710732), Felt::new(0)]), - }, - EvalRecord { - id: 371, - namespace: "chiplets.memory.first_row.zero", - value: QuadFelt::new([Felt::new(2325691270454543127), Felt::new(0)]), - }, - EvalRecord { - id: 372, - namespace: "chiplets.memory.delta.inv", - value: QuadFelt::new([Felt::new(3175424288859001789), Felt::new(0)]), - }, - EvalRecord { - id: 373, - namespace: "chiplets.memory.delta.inv", - value: QuadFelt::new([Felt::new(2653406619128719065), Felt::new(0)]), - }, - EvalRecord { - id: 374, - namespace: "chiplets.memory.delta.inv", - value: QuadFelt::new([Felt::new(17858142172042463544), Felt::new(0)]), - }, - EvalRecord { - id: 375, - namespace: "chiplets.memory.delta.inv", - value: QuadFelt::new([Felt::new(6206863499132972446), Felt::new(0)]), - }, - EvalRecord { - id: 376, - namespace: "chiplets.memory.delta.transition", - value: QuadFelt::new([Felt::new(5078351230126014060), Felt::new(0)]), - }, - EvalRecord { - id: 377, - namespace: "chiplets.memory.scw.flag", - value: QuadFelt::new([Felt::new(18433800756547531428), Felt::new(0)]), - }, - EvalRecord { - id: 378, - namespace: "chiplets.memory.scw.reads", - value: QuadFelt::new([Felt::new(1473872865192822987), Felt::new(0)]), - }, - EvalRecord { - id: 379, - namespace: "chiplets.memory.value.consistency", - value: QuadFelt::new([Felt::new(11685142466069024125), Felt::new(0)]), - }, - EvalRecord { - id: 380, - namespace: "chiplets.memory.value.consistency", - value: QuadFelt::new([Felt::new(15197055428524072106), Felt::new(0)]), - }, - EvalRecord { - id: 381, - namespace: "chiplets.memory.value.consistency", - value: QuadFelt::new([Felt::new(14617718835619740558), Felt::new(0)]), - }, - EvalRecord { - id: 382, - namespace: "chiplets.memory.value.consistency", - value: QuadFelt::new([Felt::new(12293856690108503135), Felt::new(0)]), - }, - EvalRecord { - id: 383, - namespace: "chiplets.ace.selector.binary", - value: QuadFelt::new([Felt::new(2923257613600653893), Felt::new(0)]), - }, - EvalRecord { - id: 384, - namespace: "chiplets.ace.selector.binary", - value: QuadFelt::new([Felt::new(4182752542556273997), Felt::new(0)]), - }, - EvalRecord { - id: 385, - namespace: "chiplets.ace.section.flags", - value: QuadFelt::new([Felt::new(6988234832692930146), Felt::new(0)]), - }, - EvalRecord { - id: 386, - namespace: "chiplets.ace.section.flags", - value: QuadFelt::new([Felt::new(835405595669725766), Felt::new(0)]), - }, - EvalRecord { - id: 387, - namespace: "chiplets.ace.section.flags", - value: QuadFelt::new([Felt::new(17586531527103856415), Felt::new(0)]), - }, - EvalRecord { - id: 388, - namespace: "chiplets.ace.section.flags", - value: QuadFelt::new([Felt::new(17554338302334456122), Felt::new(0)]), - }, - EvalRecord { - id: 389, - namespace: "chiplets.ace.section.flags", - value: QuadFelt::new([Felt::new(7430977299237244825), Felt::new(0)]), - }, - EvalRecord { - id: 390, - namespace: "chiplets.ace.section.transition", - value: QuadFelt::new([Felt::new(9634147153406944231), Felt::new(0)]), - }, - EvalRecord { - id: 391, - namespace: "chiplets.ace.section.transition", - value: QuadFelt::new([Felt::new(3218972305890399047), Felt::new(0)]), - }, - EvalRecord { - id: 392, - namespace: "chiplets.ace.section.transition", - value: QuadFelt::new([Felt::new(13940329983080013930), Felt::new(0)]), - }, - EvalRecord { - id: 393, - namespace: "chiplets.ace.section.transition", - value: QuadFelt::new([Felt::new(10279516906957804027), Felt::new(0)]), - }, - EvalRecord { - id: 394, - namespace: "chiplets.ace.read.ids", - value: QuadFelt::new([Felt::new(12585176929173957399), Felt::new(0)]), - }, - EvalRecord { - id: 395, - namespace: "chiplets.ace.read.to_eval", - value: QuadFelt::new([Felt::new(30354383937781757), Felt::new(0)]), - }, - EvalRecord { - id: 396, - namespace: "chiplets.ace.eval.op", - value: QuadFelt::new([Felt::new(12481984196006840571), Felt::new(0)]), - }, - EvalRecord { - id: 397, - namespace: "chiplets.ace.eval.result", - value: QuadFelt::new([Felt::new(10009759308289170950), Felt::new(0)]), - }, - EvalRecord { - id: 398, - namespace: "chiplets.ace.eval.result", - value: QuadFelt::new([Felt::new(9663557940632289707), Felt::new(0)]), - }, - EvalRecord { - id: 399, - namespace: "chiplets.ace.final.zero", - value: QuadFelt::new([Felt::new(13957751954200526468), Felt::new(0)]), - }, - EvalRecord { - id: 400, - namespace: "chiplets.ace.final.zero", - value: QuadFelt::new([Felt::new(13589615335587828352), Felt::new(0)]), - }, - EvalRecord { - id: 401, - namespace: "chiplets.ace.final.zero", - value: QuadFelt::new([Felt::new(6818409555600730615), Felt::new(0)]), - }, - EvalRecord { - id: 402, - namespace: "chiplets.ace.first_row.start", - value: QuadFelt::new([Felt::new(613969461051885369), Felt::new(0)]), - }, - EvalRecord { - id: 403, - namespace: "chiplets.kernel_rom.sfirst.binary", - value: QuadFelt::new([Felt::new(9960038227923904827), Felt::new(0)]), - }, - EvalRecord { - id: 404, - namespace: "chiplets.kernel_rom.digest.contiguity", - value: QuadFelt::new([Felt::new(12113043600978981430), Felt::new(0)]), - }, - EvalRecord { - id: 405, - namespace: "chiplets.kernel_rom.digest.contiguity", - value: QuadFelt::new([Felt::new(15559322172686928295), Felt::new(0)]), - }, - EvalRecord { - id: 406, - namespace: "chiplets.kernel_rom.digest.contiguity", - value: QuadFelt::new([Felt::new(12593211604980696045), Felt::new(0)]), - }, - EvalRecord { - id: 407, - namespace: "chiplets.kernel_rom.digest.contiguity", - value: QuadFelt::new([Felt::new(4420066076215265302), Felt::new(0)]), - }, - EvalRecord { - id: 408, - namespace: "chiplets.kernel_rom.first_row.start", - value: QuadFelt::new([Felt::new(3652575802134874675), Felt::new(0)]), - }, - EvalRecord { - id: 409, - namespace: "bus.boundary.first_row", - value: QuadFelt::new([Felt::new(9595061266498737687), Felt::new(12539219129346040916)]), - }, - EvalRecord { - id: 410, - namespace: "bus.boundary.first_row", - value: QuadFelt::new([Felt::new(9906922257952985525), Felt::new(7135908125271346815)]), - }, - EvalRecord { - id: 411, - namespace: "bus.boundary.first_row", - value: QuadFelt::new([ - Felt::new(12010012593361720439), - Felt::new(12696089236309457996), - ]), - }, - EvalRecord { - id: 412, - namespace: "bus.boundary.first_row", - value: QuadFelt::new([Felt::new(15694046535368016026), Felt::new(2643587524945520847)]), - }, - EvalRecord { - id: 413, - namespace: "bus.boundary.first_row", - value: QuadFelt::new([ - Felt::new(14293326901983424168), - Felt::new(17664958916890505700), - ]), - }, - EvalRecord { - id: 414, - namespace: "bus.boundary.first_row", - value: QuadFelt::new([Felt::new(7543823668837069064), Felt::new(1474978857022258416)]), - }, - EvalRecord { - id: 415, - namespace: "bus.boundary.first_row", - value: QuadFelt::new([Felt::new(12608813705579209032), Felt::new(3989096837606726344)]), - }, - EvalRecord { - id: 416, - namespace: "bus.boundary.first_row", - value: QuadFelt::new([Felt::new(9950426725853620663), Felt::new(6907538708340539779)]), - }, - EvalRecord { - id: 417, - namespace: "bus.boundary.last_row", - value: QuadFelt::new([Felt::new(16755949710966147218), Felt::new(3829676215971849169)]), - }, - EvalRecord { - id: 418, - namespace: "bus.boundary.last_row", - value: QuadFelt::new([Felt::new(3258168421295425687), Felt::new(11322075087561196224)]), - }, - EvalRecord { - id: 419, - namespace: "bus.boundary.last_row", - value: QuadFelt::new([Felt::new(7867249080765390980), Felt::new(6932757161403890473)]), - }, - EvalRecord { - id: 420, - namespace: "bus.boundary.last_row", - value: QuadFelt::new([Felt::new(10129458707234267975), Felt::new(5812206347609968155)]), - }, - EvalRecord { - id: 421, - namespace: "bus.boundary.last_row", - value: QuadFelt::new([Felt::new(3253668216479680364), Felt::new(9725218274111543600)]), - }, - EvalRecord { - id: 422, - namespace: "bus.boundary.last_row", - value: QuadFelt::new([ - Felt::new(10901759410743368556), - Felt::new(10824838696757528120), - ]), - }, - EvalRecord { - id: 423, - namespace: "bus.boundary.last_row", - value: QuadFelt::new([ - Felt::new(11130917779834521749), - Felt::new(17051345074679664416), - ]), - }, - EvalRecord { - id: 424, - namespace: "bus.boundary.last_row", - value: QuadFelt::new([Felt::new(5654815015773734620), Felt::new(8487995846868635892)]), - }, - EvalRecord { - id: 425, - namespace: "range.bus.transition", - value: QuadFelt::new([ - Felt::new(10365289165200035540), - Felt::new(16469718665506609592), - ]), - }, - EvalRecord { - id: 426, - namespace: "stack.overflow.bus.transition", - value: QuadFelt::new([Felt::new(7384164985445418427), Felt::new(3858806565449404456)]), - }, - EvalRecord { - id: 427, - namespace: "decoder.bus.p1.transition", - value: QuadFelt::new([ - Felt::new(11611432650982424455), - Felt::new(10377793451000863001), - ]), - }, - EvalRecord { - id: 428, - namespace: "decoder.bus.p2.transition", - value: QuadFelt::new([ - Felt::new(15040597896341508305), - Felt::new(11465419388996005277), - ]), - }, - EvalRecord { - id: 429, - namespace: "decoder.bus.p3.transition", - value: QuadFelt::new([Felt::new(9395869302542898577), Felt::new(6472917827183803848)]), - }, - EvalRecord { - id: 430, - namespace: "chiplets.bus.hash_kernel.transition", - value: QuadFelt::new([Felt::new(4291070431816775519), Felt::new(7576850277917859979)]), - }, - EvalRecord { - id: 431, - namespace: "chiplets.bus.chiplets.transition", - value: QuadFelt::new([Felt::new(7990980974626587792), Felt::new(5675027937982935418)]), - }, - EvalRecord { - id: 432, - namespace: "chiplets.bus.wiring.transition", - value: QuadFelt::new([Felt::new(7613678356270986878), Felt::new(10445474671979834467)]), - }, - EvalRecord { - id: 433, - namespace: "public_inputs.stack_input", - value: QuadFelt::new([Felt::new(15272471560572797098), Felt::new(0)]), - }, - EvalRecord { - id: 434, - namespace: "public_inputs.stack_input", - value: QuadFelt::new([Felt::new(6210121216967517740), Felt::new(0)]), - }, - EvalRecord { - id: 435, - namespace: "public_inputs.stack_input", - value: QuadFelt::new([Felt::new(6183121070077706579), Felt::new(0)]), - }, - EvalRecord { - id: 436, - namespace: "public_inputs.stack_input", - value: QuadFelt::new([Felt::new(9532591940374591279), Felt::new(0)]), - }, - EvalRecord { - id: 437, - namespace: "public_inputs.stack_input", - value: QuadFelt::new([Felt::new(6543026845990824540), Felt::new(0)]), - }, - EvalRecord { - id: 438, - namespace: "public_inputs.stack_input", - value: QuadFelt::new([Felt::new(12968646586941648028), Felt::new(0)]), - }, - EvalRecord { - id: 439, - namespace: "public_inputs.stack_input", - value: QuadFelt::new([Felt::new(15417838146196464330), Felt::new(0)]), - }, - EvalRecord { - id: 440, - namespace: "public_inputs.stack_input", - value: QuadFelt::new([Felt::new(13833104913151358010), Felt::new(0)]), - }, - EvalRecord { - id: 441, - namespace: "public_inputs.stack_input", - value: QuadFelt::new([Felt::new(16618206067970158350), Felt::new(0)]), - }, - EvalRecord { - id: 442, - namespace: "public_inputs.stack_input", - value: QuadFelt::new([Felt::new(4151771141262045661), Felt::new(0)]), - }, - EvalRecord { - id: 443, - namespace: "public_inputs.stack_input", - value: QuadFelt::new([Felt::new(10573320072889417521), Felt::new(0)]), - }, - EvalRecord { - id: 444, - namespace: "public_inputs.stack_input", - value: QuadFelt::new([Felt::new(10186179372804063393), Felt::new(0)]), - }, - EvalRecord { - id: 445, - namespace: "public_inputs.stack_input", - value: QuadFelt::new([Felt::new(4590904619046098580), Felt::new(0)]), - }, - EvalRecord { - id: 446, - namespace: "public_inputs.stack_input", - value: QuadFelt::new([Felt::new(4720108777520454648), Felt::new(0)]), - }, - EvalRecord { - id: 447, - namespace: "public_inputs.stack_input", - value: QuadFelt::new([Felt::new(1104703905961606104), Felt::new(0)]), - }, - EvalRecord { - id: 448, - namespace: "public_inputs.stack_input", - value: QuadFelt::new([Felt::new(4555570289354185559), Felt::new(0)]), - }, - EvalRecord { - id: 449, - namespace: "public_inputs.stack_output", - value: QuadFelt::new([Felt::new(4934304800106382014), Felt::new(0)]), - }, - EvalRecord { - id: 450, - namespace: "public_inputs.stack_output", - value: QuadFelt::new([Felt::new(5378514856609319392), Felt::new(0)]), - }, - EvalRecord { - id: 451, - namespace: "public_inputs.stack_output", - value: QuadFelt::new([Felt::new(17190327489693035335), Felt::new(0)]), - }, - EvalRecord { - id: 452, - namespace: "public_inputs.stack_output", - value: QuadFelt::new([Felt::new(12600879734326452251), Felt::new(0)]), - }, - EvalRecord { - id: 453, - namespace: "public_inputs.stack_output", - value: QuadFelt::new([Felt::new(5557099402378706294), Felt::new(0)]), - }, - EvalRecord { - id: 454, - namespace: "public_inputs.stack_output", - value: QuadFelt::new([Felt::new(13124668006842155196), Felt::new(0)]), - }, - EvalRecord { - id: 455, - namespace: "public_inputs.stack_output", - value: QuadFelt::new([Felt::new(17115224159882577972), Felt::new(0)]), - }, - EvalRecord { - id: 456, - namespace: "public_inputs.stack_output", - value: QuadFelt::new([Felt::new(329687429495640731), Felt::new(0)]), - }, - EvalRecord { - id: 457, - namespace: "public_inputs.stack_output", - value: QuadFelt::new([Felt::new(17291436379366401128), Felt::new(0)]), - }, - EvalRecord { - id: 458, - namespace: "public_inputs.stack_output", - value: QuadFelt::new([Felt::new(6803320890344610422), Felt::new(0)]), - }, - EvalRecord { - id: 459, - namespace: "public_inputs.stack_output", - value: QuadFelt::new([Felt::new(11244089584150196777), Felt::new(0)]), - }, - EvalRecord { - id: 460, - namespace: "public_inputs.stack_output", - value: QuadFelt::new([Felt::new(4009248599872349722), Felt::new(0)]), - }, - EvalRecord { - id: 461, - namespace: "public_inputs.stack_output", - value: QuadFelt::new([Felt::new(16110944964025361102), Felt::new(0)]), - }, - EvalRecord { - id: 462, - namespace: "public_inputs.stack_output", - value: QuadFelt::new([Felt::new(15140047176671544897), Felt::new(0)]), - }, - EvalRecord { - id: 463, - namespace: "public_inputs.stack_output", - value: QuadFelt::new([Felt::new(16756664313597184040), Felt::new(0)]), - }, - EvalRecord { - id: 464, - namespace: "public_inputs.stack_output", - value: QuadFelt::new([Felt::new(2298685071572703448), Felt::new(0)]), - }, - ] -} - -/// Returns the active expected OOD evaluations for the current tagged group. -pub fn active_expected_ood_evals() -> Vec { - current_group_expected() -} diff --git a/air/src/constraints/tagging/ids.rs b/air/src/constraints/tagging/ids.rs deleted file mode 100644 index 4e72b15173..0000000000 --- a/air/src/constraints/tagging/ids.rs +++ /dev/null @@ -1,110 +0,0 @@ -//! Tag group base IDs and sizes. - -/// Base ID for the system constraint group. -pub const TAG_SYSTEM_BASE: usize = 0; -/// Number of system clock constraints. -pub const TAG_SYSTEM_CLK_COUNT: usize = 2; -/// Number of system context constraints. -pub const TAG_SYSTEM_CTX_COUNT: usize = 3; -/// Number of system function-hash constraints. -pub const TAG_SYSTEM_FN_HASH_COUNT: usize = 8; - -/// Base ID for the system clock constraints. -pub const TAG_SYSTEM_CLK_BASE: usize = TAG_SYSTEM_BASE; -/// Base ID for the system context constraints. -pub const TAG_SYSTEM_CTX_BASE: usize = TAG_SYSTEM_CLK_BASE + TAG_SYSTEM_CLK_COUNT; -/// Base ID for the system function-hash constraints. -pub const TAG_SYSTEM_FN_HASH_BASE: usize = TAG_SYSTEM_CTX_BASE + TAG_SYSTEM_CTX_COUNT; - -/// Total number of system constraints in this group. -pub const TAG_SYSTEM_COUNT: usize = - TAG_SYSTEM_CLK_COUNT + TAG_SYSTEM_CTX_COUNT + TAG_SYSTEM_FN_HASH_COUNT; - -/// Base ID for the range checker main constraint group. -pub const TAG_RANGE_MAIN_BASE: usize = TAG_SYSTEM_BASE + TAG_SYSTEM_COUNT; -/// Number of range checker main constraints in this group. -pub const TAG_RANGE_MAIN_COUNT: usize = 3; - -/// Base ID for the stack general constraint group. -pub const TAG_STACK_GENERAL_BASE: usize = TAG_RANGE_MAIN_BASE + TAG_RANGE_MAIN_COUNT; -/// Number of stack general constraints in this group. -pub const TAG_STACK_GENERAL_COUNT: usize = 16; - -/// Base ID for the stack overflow constraint group. -pub const TAG_STACK_OVERFLOW_BASE: usize = TAG_STACK_GENERAL_BASE + TAG_STACK_GENERAL_COUNT; -/// Number of stack overflow constraints in this group. -pub const TAG_STACK_OVERFLOW_COUNT: usize = 8; - -/// Base ID for the stack ops constraint group. -pub const TAG_STACK_OPS_BASE: usize = TAG_STACK_OVERFLOW_BASE + TAG_STACK_OVERFLOW_COUNT; -/// Number of stack ops constraints in this group. -pub const TAG_STACK_OPS_COUNT: usize = 88; - -/// Base ID for the stack crypto constraint group. -pub const TAG_STACK_CRYPTO_BASE: usize = TAG_STACK_OPS_BASE + TAG_STACK_OPS_COUNT; -/// Number of stack crypto constraints in this group. -pub const TAG_STACK_CRYPTO_COUNT: usize = 46; - -/// Base ID for the stack arith/u32 constraint group. -pub const TAG_STACK_ARITH_BASE: usize = TAG_STACK_CRYPTO_BASE + TAG_STACK_CRYPTO_COUNT; -/// Number of stack arith/u32 constraints in this group. -pub const TAG_STACK_ARITH_COUNT: usize = 42; - -/// Base ID for the decoder constraint group. -pub const TAG_DECODER_BASE: usize = TAG_STACK_ARITH_BASE + TAG_STACK_ARITH_COUNT; -/// Number of decoder constraints in this group. -pub const TAG_DECODER_COUNT: usize = 57; - -/// Base ID for the chiplets constraint group. -pub const TAG_CHIPLETS_BASE: usize = TAG_DECODER_BASE + TAG_DECODER_COUNT; -/// Number of chiplets constraints in this group. -pub const TAG_CHIPLETS_COUNT: usize = 136; - -/// Base ID for the bus boundary constraint group. -/// 8 first-row (aux columns pinned to identity) + 8 last-row (aux columns bound to finals) = 16. -pub const TAG_BUS_BOUNDARY_BASE: usize = TAG_CHIPLETS_BASE + TAG_CHIPLETS_COUNT; -pub const TAG_BUS_BOUNDARY_FIRST_ROW_COUNT: usize = 8; -pub const TAG_BUS_BOUNDARY_LAST_ROW_COUNT: usize = 8; -pub const TAG_BUS_BOUNDARY_COUNT: usize = - TAG_BUS_BOUNDARY_FIRST_ROW_COUNT + TAG_BUS_BOUNDARY_LAST_ROW_COUNT; - -/// Base ID for the range bus constraint. -pub const TAG_RANGE_BUS_BASE: usize = TAG_BUS_BOUNDARY_BASE + TAG_BUS_BOUNDARY_COUNT; -/// Number of range bus constraints in this group. -pub const TAG_RANGE_BUS_COUNT: usize = 1; - -/// Base ID for the stack overflow bus constraint group. -pub const TAG_STACK_OVERFLOW_BUS_BASE: usize = TAG_RANGE_BUS_BASE + TAG_RANGE_BUS_COUNT; -/// Number of stack overflow bus constraints in this group. -pub const TAG_STACK_OVERFLOW_BUS_COUNT: usize = 1; - -/// Base ID for the decoder bus constraint group. -pub const TAG_DECODER_BUS_BASE: usize = TAG_STACK_OVERFLOW_BUS_BASE + TAG_STACK_OVERFLOW_BUS_COUNT; -/// Number of decoder bus constraints in this group. -pub const TAG_DECODER_BUS_COUNT: usize = 3; - -/// Base ID for the hash-kernel bus constraint. -pub const TAG_HASH_KERNEL_BUS_BASE: usize = TAG_DECODER_BUS_BASE + TAG_DECODER_BUS_COUNT; -/// Number of hash-kernel bus constraints in this group. -pub const TAG_HASH_KERNEL_BUS_COUNT: usize = 1; - -/// Base ID for the chiplets bus constraint. -pub const TAG_CHIPLETS_BUS_BASE: usize = TAG_HASH_KERNEL_BUS_BASE + TAG_HASH_KERNEL_BUS_COUNT; -/// Number of chiplets bus constraints in this group. -pub const TAG_CHIPLETS_BUS_COUNT: usize = 1; - -/// Base ID for the wiring bus constraint. -pub const TAG_WIRING_BUS_BASE: usize = TAG_CHIPLETS_BUS_BASE + TAG_CHIPLETS_BUS_COUNT; -/// Number of wiring bus constraints in this group. -pub const TAG_WIRING_BUS_COUNT: usize = 1; - -/// Base ID for the public inputs boundary constraint group. -pub const TAG_PUBLIC_INPUTS_BASE: usize = TAG_WIRING_BUS_BASE + TAG_WIRING_BUS_COUNT; -/// Number of public input boundary constraints. -/// 16 stack input first-row + 16 stack output last-row = 32. -#[cfg(all(test, feature = "std"))] -pub const TAG_PUBLIC_INPUTS_COUNT: usize = 32; - -/// Total number of tagged constraints in the current group set. -#[cfg(all(test, feature = "std"))] -pub const TAG_TOTAL_COUNT: usize = TAG_PUBLIC_INPUTS_BASE + TAG_PUBLIC_INPUTS_COUNT; diff --git a/air/src/constraints/tagging/mod.rs b/air/src/constraints/tagging/mod.rs deleted file mode 100644 index b1f55e70e5..0000000000 --- a/air/src/constraints/tagging/mod.rs +++ /dev/null @@ -1,112 +0,0 @@ -//! Constraint tagging helpers for stable numeric IDs. -//! -//! This module dispatches to the full tagging implementation in test/`testing` builds -//! and a no-op fallback in production/no-std builds. - -use miden_crypto::stark::air::{AirBuilder, ExtensionBuilder}; - -pub mod ids; - -#[cfg(all(any(test, feature = "testing"), feature = "std"))] -mod enabled; -#[cfg(not(all(any(test, feature = "testing"), feature = "std")))] -mod fallback; - -#[cfg(all(test, feature = "std"))] -mod fixtures; -#[cfg(all(test, feature = "std"))] -mod ood_eval; -#[cfg(all(any(test, feature = "testing"), feature = "std"))] -mod state; - -#[cfg(all(any(test, feature = "testing"), feature = "std"))] -pub use enabled::*; -#[cfg(not(all(any(test, feature = "testing"), feature = "std")))] -pub use fallback::*; - -/// Tag metadata for a constraint group (base ID + ordered names). -#[derive(Clone, Copy)] -pub struct TagGroup { - pub base: usize, - pub names: &'static [&'static str], -} - -/// Tag and assert a single constraint, advancing the per-group index. -pub fn tagged_assert_zero( - builder: &mut AB, - group: &TagGroup, - idx: &mut usize, - expr: AB::Expr, -) { - debug_assert!(*idx < group.names.len(), "tag index out of bounds"); - let id = group.base + *idx; - let name = group.names[*idx]; - builder.tagged(id, name, |builder| { - builder.when_transition().assert_zero(expr); - }); - *idx += 1; -} - -/// Tag and assert a single integrity constraint, advancing the per-group index. -pub fn tagged_assert_zero_integrity( - builder: &mut AB, - group: &TagGroup, - idx: &mut usize, - expr: AB::Expr, -) { - debug_assert!(*idx < group.names.len(), "tag index out of bounds"); - let id = group.base + *idx; - let name = group.names[*idx]; - builder.tagged(id, name, |builder| { - builder.assert_zero(expr); - }); - *idx += 1; -} - -/// Tag and assert a fixed list of constraints, advancing the per-group index. -pub fn tagged_assert_zeros( - builder: &mut AB, - group: &TagGroup, - idx: &mut usize, - namespace: &'static str, - exprs: [AB::Expr; N], -) { - debug_assert!(*idx + N <= group.names.len(), "tag index out of bounds"); - let ids: [usize; N] = core::array::from_fn(|i| group.base + *idx + i); - builder.tagged_list(ids, namespace, |builder| { - builder.when_transition().assert_zeros(exprs); - }); - *idx += N; -} - -/// Tag and assert a fixed list of integrity constraints, advancing the per-group index. -pub fn tagged_assert_zeros_integrity( - builder: &mut AB, - group: &TagGroup, - idx: &mut usize, - namespace: &'static str, - exprs: [AB::Expr; N], -) { - debug_assert!(*idx + N <= group.names.len(), "tag index out of bounds"); - let ids: [usize; N] = core::array::from_fn(|i| group.base + *idx + i); - builder.tagged_list(ids, namespace, |builder| { - builder.assert_zeros(exprs); - }); - *idx += N; -} - -/// Tag and assert a single extension-field constraint, advancing the per-group index. -pub fn tagged_assert_zero_ext( - builder: &mut AB, - group: &TagGroup, - idx: &mut usize, - expr: AB::ExprEF, -) { - debug_assert!(*idx < group.names.len(), "tag index out of bounds"); - let id = group.base + *idx; - let name = group.names[*idx]; - builder.tagged(id, name, |builder| { - builder.when_transition().assert_zero_ext(expr); - }); - *idx += 1; -} diff --git a/air/src/constraints/tagging/ood_eval.rs b/air/src/constraints/tagging/ood_eval.rs deleted file mode 100644 index d325539bdf..0000000000 --- a/air/src/constraints/tagging/ood_eval.rs +++ /dev/null @@ -1,289 +0,0 @@ -//! OOD evaluation helper for tagged constraint parity tests. - -use alloc::vec::Vec; - -use miden_core::{Felt, field::QuadFelt}; -use miden_crypto::stark::{ - air::{AirBuilder, EmptyWindow, ExtensionBuilder, PeriodicAirBuilder, PermutationAirBuilder}, - matrix::RowMajorMatrix, -}; - -use super::state; -use crate::constraints::{chiplets::bitwise, tagging::ids::TAG_TOTAL_COUNT}; - -/// Captured evaluation for a single tagged constraint. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct EvalRecord { - /// Stable numeric ID (zero-based). - pub id: usize, - /// Human-readable namespace for debugging. - pub namespace: &'static str, - /// Constraint evaluation in the quadratic extension field. - pub value: QuadFelt, -} - -/// AIR builder that evaluates each constraint at a random OOD point. -/// -/// All main/aux trace values, row flags, and challenges are pseudo-random but deterministic -/// for a given seed. Each constraint's evaluation is recorded in ID order. -pub struct OodEvalAirBuilder { - main: RowMajorMatrix, - permutation: RowMajorMatrix, - permutation_randomness: Vec, - permutation_values: Vec, - public_values: Vec, - periodic_values: Vec, - first_row: Felt, - last_row: Felt, - transition: Felt, - records: Vec, - used: Vec>, - prev_enabled: bool, -} - -impl OodEvalAirBuilder { - /// Build an OOD evaluator seeded with `seed`. - /// - /// The seed deterministically fills the trace matrices, row flags, and random challenges. - pub fn new(seed: u64) -> Self { - let prev_enabled = state::is_enabled(); - state::set_enabled(true); - - let mut rng = SeededRng::new(seed); - let main = RowMajorMatrix::new( - (0..crate::trace::TRACE_WIDTH * 2).map(|_| rng.next_felt()).collect(), - crate::trace::TRACE_WIDTH, - ); - let permutation = RowMajorMatrix::new( - (0..crate::trace::AUX_TRACE_WIDTH * 2).map(|_| rng.next_quad()).collect(), - crate::trace::AUX_TRACE_WIDTH, - ); - // Only store the actually used (alpha and beta), but consume MAX_MESSAGE_WIDTH - // from the RNG to keep the seed state stable and ensure that the fixtures - // remain unchanged. - let all_randomness: Vec = - (0..crate::trace::MAX_MESSAGE_WIDTH).map(|_| rng.next_quad()).collect(); - let permutation_randomness: Vec = - all_randomness[..crate::trace::AUX_TRACE_RAND_CHALLENGES].to_vec(); - let permutation_values: Vec = - (0..crate::trace::AUX_TRACE_WIDTH).map(|_| rng.next_quad()).collect(); - let first_row = rng.next_felt(); - let last_row = rng.next_felt(); - let transition = rng.next_felt(); - let periodic_values = (0..bitwise::NUM_PERIODIC_COLUMNS).map(|_| rng.next_felt()).collect(); - - // Generate enough random public values for the boundary constraints. - // Minimum tail: 36 elements (16 SI + 16 SO + 4 PC transcript state) + 4 program hash. - let public_values = (0..40).map(|_| rng.next_felt()).collect(); - - Self { - main, - permutation, - permutation_randomness, - permutation_values, - public_values, - periodic_values, - first_row, - last_row, - transition, - records: Vec::new(), - used: vec![None; TAG_TOTAL_COUNT], - prev_enabled, - } - } - - pub fn records(&self) -> &[EvalRecord] { - &self.records - } - - /// Panics if any expected ID was not recorded. - pub fn assert_complete(&self) { - let missing: Vec = self - .used - .iter() - .enumerate() - .filter_map(|(id, entry)| entry.is_none().then_some(id)) - .collect(); - - if !missing.is_empty() { - panic!("missing constraint ids: {missing:?}"); - } - } - - fn record(&mut self, id: usize, namespace: &'static str, value: QuadFelt) { - let expected = self.records.len(); - if id != expected { - panic!("constraint id {} out of order (expected {})", id, expected); - } - if id >= self.used.len() { - panic!("constraint id {} is out of range (max {})", id, self.used.len() - 1); - } - if let Some(prev) = self.used[id] { - panic!("constraint id {} already used (previous namespace: {})", id, prev); - } - self.used[id] = Some(namespace); - self.records.push(EvalRecord { id, namespace, value }); - } -} - -impl Drop for OodEvalAirBuilder { - fn drop(&mut self) { - state::set_enabled(self.prev_enabled); - } -} - -// --- Individual trait impls so the blanket LiftedAirBuilder applies --- - -impl AirBuilder for OodEvalAirBuilder { - type F = Felt; - type Expr = Felt; - type Var = Felt; - type PreprocessedWindow = EmptyWindow; - type MainWindow = RowMajorMatrix; - type PublicVar = Felt; - - fn main(&self) -> Self::MainWindow { - self.main.clone() - } - - fn preprocessed(&self) -> &Self::PreprocessedWindow { - EmptyWindow::empty_ref() - } - - fn is_first_row(&self) -> Self::Expr { - self.first_row - } - - fn is_last_row(&self) -> Self::Expr { - self.last_row - } - - fn is_transition_window(&self, size: usize) -> Self::Expr { - if size == 2 { - self.transition - } else { - panic!("OOD eval only supports a window size of 2"); - } - } - - fn assert_zero>(&mut self, x: I) { - let (id, namespace) = state::consume_tag(); - let value = QuadFelt::from(x.into()); - self.record(id, namespace, value); - } - - fn public_values(&self) -> &[Self::PublicVar] { - &self.public_values - } -} - -impl ExtensionBuilder for OodEvalAirBuilder { - type EF = QuadFelt; - type ExprEF = QuadFelt; - type VarEF = QuadFelt; - - fn assert_zero_ext(&mut self, x: I) - where - I: Into, - { - let (id, namespace) = state::consume_tag(); - let value = x.into(); - self.record(id, namespace, value); - } -} - -impl PermutationAirBuilder for OodEvalAirBuilder { - type MP = RowMajorMatrix; - type RandomVar = QuadFelt; - type PermutationVar = QuadFelt; - - fn permutation(&self) -> Self::MP { - self.permutation.clone() - } - - fn permutation_randomness(&self) -> &[Self::RandomVar] { - &self.permutation_randomness - } - - fn permutation_values(&self) -> &[Self::PermutationVar] { - &self.permutation_values - } -} - -impl PeriodicAirBuilder for OodEvalAirBuilder { - type PeriodicVar = Felt; - - fn periodic_values(&self) -> &[Self::PeriodicVar] { - &self.periodic_values - } -} - -/// Deterministic RNG based on a seed and counter. -struct SeededRng { - seed: u64, - counter: u64, -} - -impl SeededRng { - fn new(seed: u64) -> Self { - Self { seed, counter: 0 } - } - - fn next_felt(&mut self) -> Felt { - let bytes = self.next_seed_bytes(); - miden_crypto::rand::test_utils::prng_value::(bytes) - } - - fn next_quad(&mut self) -> QuadFelt { - QuadFelt::new([self.next_felt(), self.next_felt()]) - } - - fn next_seed_bytes(&mut self) -> [u8; 32] { - let counter = self.counter; - self.counter = self.counter.wrapping_add(1); - let mix = self.seed ^ counter; - let sum = self.seed.wrapping_add(counter); - let mut out = [0u8; 32]; - out[0..8].copy_from_slice(&self.seed.to_le_bytes()); - out[8..16].copy_from_slice(&counter.to_le_bytes()); - out[16..24].copy_from_slice(&mix.to_le_bytes()); - out[24..32].copy_from_slice(&sum.to_le_bytes()); - out - } -} - -#[cfg(test)] -mod tests { - use alloc::vec::Vec; - - use miden_core::{Felt, field::QuadFelt}; - - use super::{ - super::{ - fixtures::{OOD_SEED, active_expected_ood_evals}, - ids::TAG_TOTAL_COUNT, - }, - EvalRecord, OodEvalAirBuilder, - }; - use crate::{LiftedAir, ProcessorAir}; - - fn run_group_parity_test(expected: Vec) { - assert_eq!(expected.len(), TAG_TOTAL_COUNT); - let mut builder = OodEvalAirBuilder::new(OOD_SEED); - LiftedAir::::eval(&ProcessorAir, &mut builder); - builder.assert_complete(); - - let actual = builder.records(); - assert_eq!(actual.len(), expected.len()); - for (actual, expected) in actual.iter().zip(expected.iter()) { - assert_eq!(actual.id, expected.id); - assert_eq!(actual.namespace, expected.namespace); - assert_eq!(actual.value, expected.value); - } - } - - #[test] - fn test_miden_vm_ood_evals_match() { - run_group_parity_test(active_expected_ood_evals()); - } -} diff --git a/air/src/constraints/tagging/state.rs b/air/src/constraints/tagging/state.rs deleted file mode 100644 index dcde383102..0000000000 --- a/air/src/constraints/tagging/state.rs +++ /dev/null @@ -1,87 +0,0 @@ -//! Thread-local tagging state for enforcing tag ordering and counts. - -use alloc::vec::Vec; -use std::{ - cell::{Cell, RefCell}, - thread_local, -}; -/// Active tagged block metadata. -#[derive(Debug)] -struct TagContext { - namespace: &'static str, - ids: Vec, - next: usize, -} - -thread_local! { - static TAGGING_ENABLED: Cell = const { Cell::new(false) }; - static TAG_STACK: RefCell> = const { RefCell::new(Vec::new()) }; -} - -/// Returns `true` when tagging is enabled for the current thread. -pub fn is_enabled() -> bool { - TAGGING_ENABLED.with(|flag| flag.get()) -} - -/// Enables or disables tagging for the current thread. -#[cfg(test)] -pub fn set_enabled(enabled: bool) { - TAGGING_ENABLED.with(|flag| flag.set(enabled)); -} - -/// Run `f` under a tagged context with the provided IDs. -/// -/// This enforces: -/// - exactly one tagged context at a time (no nesting), -/// - at least one ID, -/// - and the number of emitted assertions matches the ID list length. -pub fn with_tag(ids: Vec, namespace: &'static str, f: impl FnOnce() -> R) -> R { - if ids.is_empty() { - panic!("tagged block '{namespace}' must include at least one id"); - } - TAG_STACK.with(|stack| { - let mut stack = stack.borrow_mut(); - if !stack.is_empty() { - panic!("nested tagged blocks are not allowed"); - } - stack.push(TagContext { namespace, ids, next: 0 }); - }); - - let result = f(); - - TAG_STACK.with(|stack| { - let mut stack = stack.borrow_mut(); - let ctx = stack.pop().expect("tag stack underflow"); - if ctx.next != ctx.ids.len() { - panic!( - "tagged block '{}' expected {} asserts, saw {}", - ctx.namespace, - ctx.ids.len(), - ctx.next - ); - } - }); - - result -} - -/// Consume the next tag ID for the current tagged context. -/// -/// Panics if called outside a tagged block or if the block emits too many assertions. -#[cfg(test)] -pub fn consume_tag() -> (usize, &'static str) { - TAG_STACK.with(|stack| { - let mut stack = stack.borrow_mut(); - let ctx = stack.last_mut().expect("assertion made without an active tagged block"); - if ctx.next >= ctx.ids.len() { - panic!( - "tagged block '{}' exceeded expected asserts ({})", - ctx.namespace, - ctx.ids.len() - ); - } - let id = ctx.ids[ctx.next]; - ctx.next += 1; - (id, ctx.namespace) - }) -} diff --git a/air/src/constraints/utils.rs b/air/src/constraints/utils.rs new file mode 100644 index 0000000000..2e4173a729 --- /dev/null +++ b/air/src/constraints/utils.rs @@ -0,0 +1,31 @@ +//! Utility extension traits for constraint code. + +use miden_core::field::PrimeCharacteristicRing; + +/// Extension trait adding `.not()` for boolean negation (`1 - self`). +pub trait BoolNot: PrimeCharacteristicRing { + fn not(&self) -> Self { + Self::ONE - self.clone() + } +} + +impl BoolNot for T {} + +/// Aggregate bits into a value (little-endian) using Horner's method: `sum(2^i * limbs[i])`. +/// +/// Evaluates as `((limbs[N-1]*2 + limbs[N-2])*2 + ...)*2 + limbs[0]`. +#[inline] +pub fn horner_eval_bits, E: PrimeCharacteristicRing>( + limbs: &[T; N], +) -> E { + const { + assert! { N >= 1}; + } + limbs + .iter() + .rev() + .cloned() + .map(Into::into) + .reduce(|acc, bit| acc.double() + bit) + .expect("non-empty array") +} diff --git a/air/src/lib.rs b/air/src/lib.rs index 32640228cd..8f2a9fec87 100644 --- a/air/src/lib.rs +++ b/air/src/lib.rs @@ -9,6 +9,8 @@ extern crate std; use alloc::vec::Vec; use core::borrow::Borrow; +#[cfg(feature = "arbitrary")] +use miden_core::program::Kernel; use miden_core::{ WORD_SIZE, Word, field::ExtensionField, @@ -18,12 +20,41 @@ use miden_core::{ use miden_crypto::stark::air::{ ReducedAuxValues, ReductionError, VarLenPublicInputs, WindowAccess, }; +#[cfg(feature = "arbitrary")] +use proptest::prelude::*; +pub mod ace; pub mod config; mod constraints; - +pub mod lookup; pub mod trace; -use trace::{AUX_TRACE_WIDTH, MainTraceRow, TRACE_WIDTH}; + +/// Miden VM-specific LogUp lookup argument: bus identifiers and bus message types. +/// +/// The `LookupAir` and `AuxBuilder` trait impls live directly on [`crate::ProcessorAir`]. +/// The generic LogUp framework this builds on lives in [`crate::lookup`] and is free of +/// Miden-specific types so it can be extracted into its own crate. +pub mod logup { + pub use crate::constraints::lookup::{ + BusId, MIDEN_MAX_MESSAGE_WIDTH, messages::*, miden_air::NUM_LOGUP_COMMITTED_FINALS, + }; +} + +use constraints::{ + columns::MainCols, + lookup::{ + chiplet_air::{ChipletLookupAir, ChipletLookupBuilder}, + main_air::{MainLookupAir, MainLookupBuilder}, + miden_air::{MIDEN_COLUMN_SHAPE, emit_miden_boundary}, + }, +}; +use logup::{BusId, MIDEN_MAX_MESSAGE_WIDTH, NUM_LOGUP_COMMITTED_FINALS}; +use lookup::{ + BoundaryBuilder, Challenges, ConstraintLookupBuilder, LookupAir, LookupMessage, + build_logup_aux_trace, +}; +use miden_core::utils::RowMajorMatrix; +use trace::TRACE_WIDTH; // RE-EXPORTS // ================================================================================================ @@ -35,19 +66,34 @@ mod export { }; pub use miden_crypto::stark::{ air::{ - AirBuilder, AirWitness, AuxBuilder, BaseAir, ExtensionBuilder, LiftedAir, - LiftedAirBuilder, PermutationAirBuilder, + AirBuilder, AuxBuilder, BaseAir, ExtensionBuilder, LiftedAir, LiftedAirBuilder, + PermutationAirBuilder, }, debug, }; + pub use miden_lifted_stark::AirWitness; } pub use export::*; +// MIDEN AIR BUILDER +// ================================================================================================ + +/// Convenience super-trait that pins `LiftedAirBuilder` to our field. +/// +/// All constraint functions in this crate should be generic over `AB: MidenAirBuilder` +/// instead of spelling out the full `LiftedAirBuilder` bound. +pub trait MidenAirBuilder: LiftedAirBuilder {} +impl> MidenAirBuilder for T {} + // PUBLIC INPUTS // ================================================================================================ -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq)] +#[cfg_attr( + all(feature = "arbitrary", test), + miden_test_serde_macros::serde_test(binary_serde(true), serde_test(false)) +)] pub struct PublicInputs { program_info: ProgramInfo, stack_inputs: StackInputs, @@ -127,6 +173,35 @@ impl PublicInputs { } } +#[cfg(feature = "arbitrary")] +impl Arbitrary for PublicInputs { + type Parameters = (); + type Strategy = BoxedStrategy; + + fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { + fn felt_strategy() -> impl Strategy { + any::().prop_map(Felt::from) + } + + fn word_strategy() -> impl Strategy { + any::<[u32; WORD_SIZE]>().prop_map(|values| Word::new(values.map(Felt::from))) + } + + let program_info = word_strategy() + .prop_map(|program_hash| ProgramInfo::new(program_hash, Kernel::default())); + let stack_inputs = proptest::collection::vec(felt_strategy(), 0..=MIN_STACK_DEPTH) + .prop_map(|values| StackInputs::new(&values).expect("generated stack inputs fit")); + let stack_outputs = proptest::collection::vec(felt_strategy(), 0..=MIN_STACK_DEPTH) + .prop_map(|values| StackOutputs::new(&values).expect("generated stack outputs fit")); + + (program_info, stack_inputs, stack_outputs, word_strategy()) + .prop_map(|(program_info, stack_inputs, stack_outputs, pc_transcript_state)| { + Self::new(program_info, stack_inputs, stack_outputs, pc_transcript_state) + }) + .boxed() + } +} + // SERIALIZATION // ================================================================================================ @@ -167,6 +242,9 @@ impl Deserializable for PublicInputs { /// [36..40] precompile transcript state pub const NUM_PUBLIC_VALUES: usize = WORD_SIZE + MIN_STACK_DEPTH + MIN_STACK_DEPTH + WORD_SIZE; +/// LogUp aux trace width: 4 main-trace columns + 3 chiplet-trace columns. +pub const LOGUP_AUX_TRACE_WIDTH: usize = 7; + // Public values layout offsets. const PV_PROGRAM_HASH: usize = 0; const PV_TRANSCRIPT_STATE: usize = NUM_PUBLIC_VALUES - WORD_SIZE; @@ -198,9 +276,7 @@ impl BaseAir for ProcessorAir { impl> LiftedAir for ProcessorAir { fn periodic_columns(&self) -> Vec> { - let mut cols = constraints::chiplets::hasher::periodic_columns(); - cols.extend(constraints::chiplets::bitwise::periodic_columns()); - cols + constraints::chiplets::columns::PeriodicCols::periodic_columns() } fn num_randomness(&self) -> usize { @@ -208,11 +284,14 @@ impl> LiftedAir for ProcessorAir { } fn aux_width(&self) -> usize { - AUX_TRACE_WIDTH + // 4 main-trace + 3 chiplet-trace = 7 LogUp columns. Matches + // `ProcessorAir::num_columns()` (LookupAir impl) and the per-row shape returned by + // `ProcessorAir::build_aux_trace` (AuxBuilder impl). + LOGUP_AUX_TRACE_WIDTH } fn num_aux_values(&self) -> usize { - AUX_TRACE_WIDTH + NUM_LOGUP_COMMITTED_FINALS } /// Returns the number of variable-length public input slices. @@ -235,17 +314,19 @@ impl> LiftedAir for ProcessorAir { where EF: ExtensionField, { - // Extract final aux column values. - let p1 = aux_values[trace::DECODER_AUX_TRACE_OFFSET]; - let p2 = aux_values[trace::DECODER_AUX_TRACE_OFFSET + 1]; - let p3 = aux_values[trace::DECODER_AUX_TRACE_OFFSET + 2]; - let s_aux = aux_values[trace::STACK_AUX_TRACE_OFFSET]; - let b_range = aux_values[trace::RANGE_CHECK_AUX_TRACE_OFFSET]; - let b_hash_kernel = aux_values[trace::HASH_KERNEL_VTABLE_AUX_TRACE_OFFSET]; - let b_chiplets = aux_values[trace::CHIPLETS_BUS_AUX_TRACE_OFFSET]; - let v_wiring = aux_values[trace::ACE_CHIPLET_WIRING_BUS_OFFSET]; - - // Parse fixed-length public values (see `NUM_PUBLIC_VALUES` for layout). + // LogUp boundary identity. The verifier checks `is_identity()` — i.e. + // `prod == ONE && sum == ZERO` — on the accumulated `ReducedAuxValues` + // across every AIR. There are no multiplicative bus checks under LogUp, so + // `prod = ONE`. The boundary equation lives in `sum`: + // + // sum = Σ aux_finals[col] + total_correction + // + // `total_correction` cancels the unmatched-fraction contributions from the + // three open buses (block hash, log precompile, kernel ROM init). Rather + // than spelling those out here, we drive the shared + // `emit_miden_boundary` emitter — the same source `LookupAir::eval_boundary` + // uses for the debug walker — through a reducer that accumulates + // `Σ multiplicity · encode(msg)⁻¹` into an `EF`. if public_values.len() != NUM_PUBLIC_VALUES { return Err(format!( "expected {} public values, got {}", @@ -254,84 +335,58 @@ impl> LiftedAir for ProcessorAir { ) .into()); } - let program_hash: Word = public_values[PV_PROGRAM_HASH..PV_PROGRAM_HASH + WORD_SIZE] - .try_into() - .map_err(|_| -> ReductionError { "invalid program hash slice".into() })?; - let pc_transcript_state: PrecompileTranscriptState = public_values - [PV_TRANSCRIPT_STATE..PV_TRANSCRIPT_STATE + WORD_SIZE] - .try_into() - .map_err(|_| -> ReductionError { "invalid transcript state slice".into() })?; - - // Precompute challenge powers once for all bus message encodings. - let challenges = trace::Challenges::::new(challenges[0], challenges[1]); - - // Compute expected bus messages from public inputs and derived challenges. - let ph_msg = program_hash_message(&challenges, &program_hash); - - let (default_transcript_msg, final_transcript_msg) = - transcript_messages(&challenges, pc_transcript_state); + if var_len_public_inputs.len() != 1 { + return Err(format!( + "expected 1 var-len public input slice, got {}", + var_len_public_inputs.len() + ) + .into()); + } + if !var_len_public_inputs[0].len().is_multiple_of(WORD_SIZE) { + return Err(format!( + "kernel digest felts length {} is not a multiple of {}", + var_len_public_inputs[0].len(), + WORD_SIZE + ) + .into()); + } - let kernel_reduced = kernel_reduced_from_var_len(&challenges, var_len_public_inputs)?; + let challenges = Challenges::::new( + challenges[0], + challenges[1], + MIDEN_MAX_MESSAGE_WIDTH, + BusId::COUNT, + ); + + let mut reducer = ReduceBoundaryBuilder { + challenges: &challenges, + public_values, + var_len_public_inputs, + sum: EF::ZERO, + error: None, + }; + emit_miden_boundary(&mut reducer); + let total_correction = reducer.finalize()?; + + // TODO(#3032): aux_values[1..] are the placeholder slots from + // NUM_LOGUP_COMMITTED_FINALS (see `constraints::lookup::miden_air`); enforce the + // zero invariant until trace splitting lands. The recursive verifier gets the + // matching `AuxBusBoundary(col) = 0` identity via `LogUpBoundaryConfig::zero_columns` + // (see `ace.rs`), so both paths reject a nonzero padding slot. + for unused_aux in aux_values.iter().skip(1) { + if !unused_aux.is_zero() { + return Err("padding aux value is non-zero".into()); + } + } + let aux_sum: EF = aux_values.iter().copied().sum(); - // Combine all multiset column finals with reduced variable length public-inputs. - // - // Running-product columns accumulate `responses / requests` at each row, so - // their final value is product(responses) / product(requests) over the entire trace. - // - // Columns whose requests and responses fully cancel end at 1: - // p1 (block stack table) -- every block pushed is later popped - // p3 (op group table) -- every op group pushed is later consumed - // s_aux (stack overflow) -- every overflow push has a matching pop - // - // Columns with public-input-dependent boundary terms end at non-unity values: - // - // p2 (block hash table): - // The root block's hash is removed from the table at END, but was never - // added (the root has no parent that would add it). This leaves one - // unmatched removal: p2_final = 1 / ph_msg. - // - // b_hash_kernel (chiplets virtual table: sibling table + transcript state): - // The log_precompile transcript tracking chain starts by removing - // default_transcript_msg (initial capacity state) and ends by inserting - // final_transcript_msg (final capacity state). On the other hand, sibling table - // entries cancel out. Net: b_hk_final = final_transcript_msg / default_transcript_msg. - // - // b_chiplets (chiplets bus): - // Each unique kernel procedure produces a KernelRomInitMessage response - // from the kernel ROM chiplet These init messages are matched by the verifier - // via public inputs. Net: b_ch_final = product(kernel_init_msgs) = kernel_reduced. - // - // Multiplying all finals with correction terms: - // prod = (p1 * p3 * s_aux) -- each is 1 - // * (p2 * ph_msg) -- (1/ph_msg) * ph_msg = 1 - // * (b_hk * default_msg / final_msg) -- cancels to 1 - // * (b_ch / kernel_reduced) -- cancels to 1 - // - // Rearranged: prod = all_finals * ph_msg * default_msg / (final_msg * kernel_reduced) (= 1) - let expected_denom = final_transcript_msg * kernel_reduced; - let expected_denom_inv = expected_denom - .try_inverse() - .ok_or_else(|| -> ReductionError { "zero denominator in reduced_aux_values".into() })?; - - let prod = p1 - * p2 - * p3 - * s_aux - * b_hash_kernel - * b_chiplets - * ph_msg - * default_transcript_msg - * expected_denom_inv; - - // LogUp: all columns should end at 0. - let sum = b_range + v_wiring; - - Ok(ReducedAuxValues { prod, sum }) + Ok(ReducedAuxValues { + prod: EF::ONE, + sum: aux_sum + total_correction, + }) } - fn eval>(&self, builder: &mut AB) { - use crate::constraints; - + fn eval(&self, builder: &mut AB) { let main = builder.main(); // Access the two rows: current (local) and next @@ -339,109 +394,158 @@ impl> LiftedAir for ProcessorAir { let next = main.next_slice(); // Use structured column access via MainTraceCols - let local: &MainTraceRow = (*local).borrow(); - let next: &MainTraceRow = (*next).borrow(); + let local: &MainCols = (*local).borrow(); + let next: &MainCols = (*next).borrow(); + + // Build chiplet selectors and op flags once, shared by main and bus constraints. + let selectors = + constraints::chiplets::selectors::build_chiplet_selectors(builder, local, next); + let op_flags = + constraints::op_flags::OpFlags::new(&local.decoder, &local.stack, &next.decoder); // Main trace constraints. - constraints::enforce_main(builder, local, next); + constraints::enforce_main(builder, local, next, &selectors, &op_flags); - // Auxiliary (bus) constraints. - constraints::enforce_bus(builder, local, next); + { + let mut lb = ConstraintLookupBuilder::new(builder, self); + >::eval(self, &mut lb); + } // Public inputs boundary constraints. constraints::public_inputs::enforce_main(builder, local); } + + fn log_quotient_degree(&self) -> usize + where + Self: Sized, + { + // override to avoid recomputing through the SymbolicAir + 3 + } } -// REDUCED AUX VALUES HELPERS -// ================================================================================================ +// --- LookupAir impl (7-column aggregator over main + chiplet sub-AIRs) --- -/// Builds the program-hash bus message for the block-hash table boundary term. -/// -/// Must match `BlockHashTableRow::from_end().collapse()` on the prover side for the -/// root block, which encodes `[parent_id=0, hash[0..4], is_first_child=0, is_loop_body=0]`. -fn program_hash_message>( - challenges: &trace::Challenges, - program_hash: &Word, -) -> EF { - challenges.encode([ - Felt::ZERO, // parent_id = 0 (root block) - program_hash[0], - program_hash[1], - program_hash[2], - program_hash[3], - Felt::ZERO, // is_first_child = false - Felt::ZERO, // is_loop_body = false - ]) +impl LookupAir for ProcessorAir +where + LB: MainLookupBuilder + ChipletLookupBuilder, +{ + fn num_columns(&self) -> usize { + MIDEN_COLUMN_SHAPE.len() + } + + fn column_shape(&self) -> &[usize] { + &MIDEN_COLUMN_SHAPE + } + + fn max_message_width(&self) -> usize { + // Width of the `beta_powers` table precomputed by `Challenges::new`, also equal + // to the exponent of `gamma = beta^MIDEN_MAX_MESSAGE_WIDTH` used in the per-bus + // prefix. Must match the MASM recursive verifier's Poseidon2 absorption loop. + // `HasherMsg::State` is the widest live payload at 15 slots (label@β⁰, addr@β¹, + // node_index@β², state[0..12]@β³..β¹⁴); the 16th slot is unused slack kept for + // MASM transcript alignment. + MIDEN_MAX_MESSAGE_WIDTH + } + + fn num_bus_ids(&self) -> usize { + BusId::COUNT + } + + fn eval(&self, builder: &mut LB) { + MainLookupAir.eval(builder); + ChipletLookupAir.eval(builder); + } + + fn eval_boundary(&self, boundary: &mut B) + where + B: BoundaryBuilder, + { + emit_miden_boundary(boundary); + } } -/// Returns the pair of (initial, final) log-precompile transcript messages for the -/// virtual-table bus boundary term. -/// -/// The initial message uses the default (zero) capacity state; the final message uses -/// the public-input transcript state. -fn transcript_messages>( - challenges: &trace::Challenges, - final_state: PrecompileTranscriptState, -) -> (EF, EF) { - let encode = |state: PrecompileTranscriptState| { - let cap: &[Felt] = state.as_ref(); - challenges.encode([ - Felt::from_u8(trace::LOG_PRECOMPILE_LABEL), - cap[0], - cap[1], - cap[2], - cap[3], - ]) - }; - (encode(PrecompileTranscriptState::default()), encode(final_state)) +// --- AuxBuilder impl (stateless LogUp aux-trace construction) --- + +impl AuxBuilder for ProcessorAir +where + EF: ExtensionField, +{ + fn build_aux_trace( + &self, + main: &RowMajorMatrix, + challenges: &[EF], + ) -> (RowMajorMatrix, Vec) { + let (aux_trace, mut committed) = build_logup_aux_trace(self, main, challenges); + // TODO(#3032): pad the placeholder slot — see `NUM_LOGUP_COMMITTED_FINALS`. Remove + // the pad once trace splitting lands. + debug_assert_eq!( + committed.len(), + 1, + "build_logup_aux_trace should return exactly one real committed final" + ); + committed.push(EF::ZERO); + (aux_trace, committed) + } } -/// Builds the kernel procedure init message for the kernel ROM bus. +// REDUCED-AUX BOUNDARY BUILDER +// ================================================================================================ + +/// `BoundaryBuilder` impl that reduces each emitted interaction to its LogUp +/// denominator contribution `multiplicity · encode(msg)⁻¹` and sums them into a +/// running `EF` accumulator. +/// +/// Lets `reduced_aux_values` reuse the structured boundary emissions from +/// [`emit_miden_boundary`] — the same source consumed by the debug walker — +/// instead of open-coding the three corrections a second time. /// -/// Must match `KernelRomInitMessage::value()` on the prover side, which encodes -/// `[KERNEL_PROC_INIT_LABEL, digest[0..4]]`. -fn kernel_proc_message>( - challenges: &trace::Challenges, - digest: &Word, -) -> EF { - challenges.encode([ - trace::chiplets::kernel_rom::KERNEL_PROC_INIT_LABEL, - digest[0], - digest[1], - digest[2], - digest[3], - ]) +/// Denominators are `α + Σ βⁱ · field_i` with random `α, β`; on any legitimate proof they +/// are non-zero with overwhelming probability. A malformed/adversarial proof can still +/// drive a denominator to zero, so the reducer captures the first failure and surfaces it +/// to `reduced_aux_values`, which bubbles a [`ReductionError`] to the verifier rather than +/// panicking. +struct ReduceBoundaryBuilder<'a, EF: ExtensionField> { + challenges: &'a Challenges, + public_values: &'a [Felt], + var_len_public_inputs: VarLenPublicInputs<'a, Felt>, + sum: EF, + error: Option, } -/// Reduces kernel procedure digests from var-len public inputs into a multiset product. -/// -/// Expects exactly one variable-length public input slice containing all kernel digests -/// as concatenated `Felt`s (i.e. `len % WORD_SIZE == 0`). -fn kernel_reduced_from_var_len>( - challenges: &trace::Challenges, - var_len_public_inputs: VarLenPublicInputs<'_, Felt>, -) -> Result { - if var_len_public_inputs.len() != 1 { - return Err(format!( - "expected 1 var-len public input slice, got {}", - var_len_public_inputs.len() - ) - .into()); +impl<'a, EF: ExtensionField> ReduceBoundaryBuilder<'a, EF> { + fn finalize(self) -> Result { + match self.error { + Some(err) => Err(err), + None => Ok(self.sum), + } } - let kernel_felts = var_len_public_inputs[0]; - if !kernel_felts.len().is_multiple_of(WORD_SIZE) { - return Err(format!( - "kernel digest felts length {} is not a multiple of {}", - kernel_felts.len(), - WORD_SIZE - ) - .into()); +} + +impl<'a, EF: ExtensionField> BoundaryBuilder for ReduceBoundaryBuilder<'a, EF> { + type F = Felt; + type EF = EF; + + fn public_values(&self) -> &[Felt] { + self.public_values + } + + fn var_len_public_inputs(&self) -> &[&[Felt]] { + self.var_len_public_inputs } - let mut acc = EF::ONE; - for digest in kernel_felts.chunks_exact(WORD_SIZE) { - let word: Word = [digest[0], digest[1], digest[2], digest[3]].into(); - acc *= kernel_proc_message(challenges, &word); + + fn insert(&mut self, _name: &'static str, multiplicity: Felt, msg: M) + where + M: LookupMessage, + { + if self.error.is_some() { + return; + } + match msg.encode(self.challenges).try_inverse() { + Some(inv) => self.sum += inv * multiplicity, + None => { + self.error = Some("LogUp boundary denominator was zero".into()); + }, + } } - Ok(acc) } diff --git a/air/src/lookup/aux_builder.rs b/air/src/lookup/aux_builder.rs new file mode 100644 index 0000000000..eae0ad5592 --- /dev/null +++ b/air/src/lookup/aux_builder.rs @@ -0,0 +1,734 @@ +//! Generic LogUp aux-trace construction. +//! +//! Prover collection writes `(multiplicity, encoded_denominator)` pairs into a +//! [`LookupFractions`] buffer (one flat `Vec<(F, EF)>` plus one flat `Vec` of per-row +//! per-column counts). The fused [`accumulate`] pass batch-inverts denominators and walks +//! rows in order with a running accumulator column, writing out the complete aux trace as a +//! [`RowMajorMatrix`]. [`accumulate_slow`] is the reference oracle that does the same +//! computation naively (one `try_inverse()` per fraction). +//! +//! [`build_logup_aux_trace`] sources challenges and periodic columns from the AIR, +//! runs [`build_lookup_fractions`] and [`accumulate`], and returns `(aux_trace, +//! acc_final)`. +//! +//! ## Aux trace shape +//! +//! [`accumulate`] returns a [`RowMajorMatrix`] with `num_rows + 1` rows: +//! +//! - row 0 is the all-`ZERO` initial accumulator +//! - row `r` (for `1..=num_rows`) holds the running sum **after** row `r − 1`'s fraction +//! contributions have been folded in +//! - row `num_rows` is therefore the global running sum across the entire trace +//! +//! The return value of [`build_logup_aux_trace`] splits that matrix in two: +//! +//! - `aux_trace` is the first `num_rows` rows of the accumulator — it starts at `ZERO` and ends at +//! the running sum **before** the last row's contribution. The last row's fraction contribution +//! does **not** appear in the aux trace. +//! - `committed_finals` is `[acc_final]`: the single accumulator terminal read out of row +//! `num_rows`. +//! +//! ## Fraction buffer layout +//! +//! - `fractions` holds every `(multiplicity, encoded_denominator)` pair every row pushes, in the +//! exact order the builder produces them. Across one row, column 0's fractions come first, then +//! column 1's, …, then column `num_cols - 1`'s. Across rows, row 0's block comes before row 1's. +//! - `counts` has exactly `num_rows * num_cols` entries, laid out row-major: `counts[r * num_cols + +//! c]` is the number of fractions row `r` pushed into column `c`. Equivalently, +//! `counts.chunks(num_cols).nth(r)` is row `r`'s per-column tally. +//! +//! Both vecs are sized up front from [`LookupAir::column_shape`] so the hot row loop can +//! push into `Vec::with_capacity`-backed storage without re-allocating. + +use alloc::{vec, vec::Vec}; + +use miden_core::{ + field::{ExtensionField, Field}, + utils::{Matrix, RowMajorMatrix}, +}; +use miden_crypto::stark::air::LiftedAir; + +use super::{Challenges, LookupAir, ProverLookupBuilder, prover::build_lookup_fractions}; + +/// Row-chunk granularity for the fused accumulator. Matches +/// [`crate::trace::main_trace::ROW_MAJOR_CHUNK_SIZE`] so we stay consistent with the +/// repo's row-major tuning: ~512 rows × avg shape ~3 ≈ 1.5 K fractions per chunk and +/// ~24 KiB of chunk-local scratch, comfortably L1-resident on any modern x86/arm core. +const ACCUMULATE_ROWS_PER_CHUNK: usize = 512; + +// TOP-LEVEL DRIVER +// ================================================================================================ + +/// Generic `AuxBuilder::build_aux_trace` body for any `LiftedAir + LookupAir` AIR. +/// +/// Sources `alpha`, `beta`, `max_message_width`, `num_bus_ids`, and periodic columns +/// from the AIR, runs collection + accumulation, and returns `(aux_trace, vec![acc_final])`. +/// +/// The challenges ordering (`challenges[0] = alpha`, `challenges[1] = beta`) mirrors the +/// constraint-path adapter's `ConstraintLookupBuilder::new` so prover- and constraint-path +/// challenges line up. +pub fn build_logup_aux_trace( + air: &A, + main: &RowMajorMatrix, + challenges: &[EF], +) -> (RowMajorMatrix, Vec) +where + F: Field, + EF: ExtensionField, + A: LiftedAir, + for<'a> A: LookupAir>, +{ + let _span = tracing::info_span!("build_aux_trace_logup").entered(); + + let alpha = challenges[0]; + let beta = challenges[1]; + let lookup_challenges = + Challenges::::new(alpha, beta, air.max_message_width(), air.num_bus_ids()); + let periodic = air.periodic_columns(); + + let fractions = build_lookup_fractions(air, main, &periodic, &lookup_challenges); + + let full = accumulate(&fractions); + let num_cols = full.width; + let num_rows = main.height(); + debug_assert_eq!( + full.values.len(), + (num_rows + 1) * num_cols, + "accumulate output buffer is sized for num_rows + 1 rows", + ); + + // `accumulate` emits `num_rows + 1` rows; take the committed final from col 0 of the + // trailing row and truncate in place to avoid allocating a throwaway last-row Vec. + let mut data = full.values; + let committed_final = data[num_rows * num_cols]; + data.truncate(num_rows * num_cols); + + let aux_trace = RowMajorMatrix::new(data, num_cols); + (aux_trace, vec![committed_final]) +} + +// LOOKUP FRACTIONS +// ================================================================================================ + +/// Single flat fraction + counts buffer shared between the prover collection phase and +/// the downstream accumulator. +/// +/// ## Layout +/// +/// ```text +/// fractions (flat, row-major by write order): +/// | row 0, col 0 | row 0, col 1 | ... | row 0, col C-1 || row 1, col 0 | ... | +/// +/// counts (flat, row-major, length = num_rows * num_cols): +/// | r0c0 | r0c1 | ... | r0c(C-1) | r1c0 | r1c1 | ... | r1c(C-1) | ... | +/// ``` +/// +/// Row `r`'s contribution to column `c` is the slice +/// `fractions[prefix .. prefix + counts[r * num_cols + c]]`, where `prefix` is the running +/// sum of earlier `counts` entries. The accumulator walks rows in order with a single +/// cursor — no separate offset array, no gather. +/// +/// No padding, no fixed stride: a row that contributes zero fractions to a column writes +/// zero entries and records `counts.push(0)`. +pub struct LookupFractions +where + F: Field, + EF: ExtensionField, +{ + /// Flat fraction buffer, packed in builder write order (see the module doc). + pub(super) fractions: Vec<(F, EF)>, + /// Flat count buffer, length `num_rows * num_cols` after a complete collection pass, + /// laid out row-major so `counts[r * num_cols + c]` is the number of fractions row + /// `r` pushed into column `c`. + pub(super) counts: Vec, + /// Per-column upper bound on fractions a single row can push. Used as the capacity + /// hint (`num_rows * Σ shape`) when allocating `fractions`, and as the reference for + /// the debug-mode overflow check in the prover builder. + pub(super) shape: Vec, + /// Number of main-trace rows this buffer is sized for. + num_rows: usize, + /// Cached `shape.len()` — the permutation column count. + num_cols: usize, +} + +impl LookupFractions +where + F: Field, + EF: ExtensionField, +{ + /// Allocate a fresh buffer sized to hold every fraction an AIR can emit across + /// `num_rows` rows. The flat fraction capacity is `num_rows * Σ shape`, so the row loop + /// does not re-allocate as long as each row stays within its declared bound. The flat + /// count capacity is `num_rows * shape.len()`. + pub fn from_shape(shape: Vec, num_rows: usize) -> Self { + let num_cols = shape.len(); + let total_fraction_capacity: usize = num_rows * shape.iter().sum::(); + let fractions = Vec::with_capacity(total_fraction_capacity); + let counts = Vec::with_capacity(num_rows * num_cols); + Self { + fractions, + counts, + shape, + num_rows, + num_cols, + } + } + + /// Number of permutation columns. + pub fn num_columns(&self) -> usize { + self.num_cols + } + + /// Total rows this buffer was sized for. + pub fn num_rows(&self) -> usize { + self.num_rows + } + + /// Per-column upper bound on fractions per row. + pub fn shape(&self) -> &[usize] { + &self.shape + } + + /// Full flat fraction buffer, packed in builder write order. Length equals + /// `Σ counts()` — i.e. the total number of fractions actually pushed. + pub fn fractions(&self) -> &[(F, EF)] { + &self.fractions + } + + /// Full flat count buffer, row-major. Length equals `num_rows * num_cols` after a + /// complete collection pass. Chunk with `counts().chunks(num_cols)` to get per-row + /// slices, or index directly as `counts()[r * num_cols + c]`. + pub fn counts(&self) -> &[usize] { + &self.counts + } +} + +// SLOW ACCUMULATOR (REFERENCE ORACLE) +// ================================================================================================ + +/// Naive per-fraction partial-sum accumulator, used as the correctness oracle for the +/// fused batch-inversion + partial-sum pass. +/// +/// Column 0 is the sole running-sum accumulator; columns 1+ are fraction columns that +/// store per-row values directly. +/// +/// Returns `aux[col]` of length `num_rows + 1`: +/// - `aux[0][0] = ZERO`, `aux[0][r+1] = aux[0][r] + Σ_col per_row_value[col]` +/// - `aux[i>0][r] = per_row_value[i]` for main row `r` +pub fn accumulate_slow(fractions: &LookupFractions) -> Vec> +where + F: Field, + EF: ExtensionField, +{ + let num_cols = fractions.num_columns(); + let num_rows = fractions.num_rows(); + let mut aux: Vec> = (0..num_cols).map(|_| vec![EF::ZERO; num_rows + 1]).collect(); + + let flat_fractions = fractions.fractions(); + let flat_counts = fractions.counts(); + debug_assert_eq!( + flat_counts.len(), + num_rows * num_cols, + "counts length {} != num_rows * num_cols {}", + flat_counts.len(), + num_rows * num_cols, + ); + + let mut per_row_value = vec![EF::ZERO; num_cols]; + let mut running_sum = EF::ZERO; + + let mut cursor = 0usize; + for (row, row_counts) in flat_counts.chunks(num_cols).enumerate() { + for (col, &count) in row_counts.iter().enumerate() { + let mut sum = EF::ZERO; + for &(m, d) in &flat_fractions[cursor..cursor + count] { + let d_inv = d + .try_inverse() + .expect("LogUp denominator must be non-zero (bus_prefix is never zero)"); + sum += d_inv * m; + } + per_row_value[col] = sum; + cursor += count; + } + + // Fraction columns: store per-row value at aux[col][row] (aux_curr convention). + for col in 1..num_cols { + aux[col][row] = per_row_value[col]; + } + + // Accumulator (col 0): running sum of ALL columns' per-row values. + let row_total: EF = per_row_value.iter().copied().sum(); + running_sum += row_total; + aux[0][row + 1] = running_sum; + } + debug_assert_eq!( + cursor, + flat_fractions.len(), + "cursor {cursor} != total fractions {}", + flat_fractions.len(), + ); + + aux +} + +// FUSED ACCUMULATOR (FAST PATH) +// ================================================================================================ + +/// Materialise the LogUp auxiliary trace from collected fractions. +/// +/// Takes the flat `(multiplicity, denominator)` buffer produced by the prover collection +/// phase and returns the complete aux trace as a row-major matrix. Column 0 is the +/// running-sum accumulator; columns 1+ store per-row fraction sums directly. +/// +/// ## Output layout +/// +/// Returns a [`RowMajorMatrix`] with `num_rows + 1` rows and `num_cols` columns. +/// Let `fᵢ(r) = Σⱼ mⱼ · dⱼ⁻¹` be the sum of fractions assigned to column `i` on row `r`: +/// +/// - Fraction columns (i > 0): `output[r][i] = fᵢ(r)` +/// - Accumulator (col 0): `output[0][0] = 0`, `output[r+1][0] = output[r][0] + Σᵢ fᵢ(r)` +/// +/// ## Algorithm +/// +/// **Prepass.** Build `row_frac_offsets` for O(1) row-range lookup into the flat buffer. +/// +/// **Phase 1 (parallel).** Split rows into fixed-size chunks. +/// Each chunk independently: batch-inverts its denominators (Montgomery trick), computes +/// `fᵢ(r)` for every `(row, col)`, writes fraction columns into the output matrix, and +/// records the row total `t(r) = Σᵢ fᵢ(r)` into a side buffer. +/// +/// **Phase 2 (sequential).** Prefix-sum over `t(r)` to fill the accumulator column: +/// `acc(r+1) = acc(r) + t(r)`. This step is inherently sequential (cross-row dependency) +/// but touches only one scalar per row. +pub fn accumulate(fractions: &LookupFractions) -> RowMajorMatrix +where + F: Field, + EF: ExtensionField, +{ + let num_cols = fractions.num_columns(); + let num_rows = fractions.num_rows(); + let out_rows = num_rows + 1; + + let mut output_data = vec![EF::ZERO; out_rows * num_cols]; + + let flat_fractions = fractions.fractions(); + let flat_counts = fractions.counts(); + debug_assert_eq!( + flat_counts.len(), + num_rows * num_cols, + "counts length {} != num_rows * num_cols {}", + flat_counts.len(), + num_rows * num_cols, + ); + + if num_rows == 0 || flat_fractions.is_empty() { + return RowMajorMatrix::new(output_data, num_cols); + } + + // Prepass: fraction-start offset for every row (length num_rows + 1). row_frac_offsets[r] = + // start of row r's fractions in flat_fractions; row_frac_offsets[num_rows] = total count. + let row_frac_offsets = compute_row_frac_offsets(flat_counts, num_rows, num_cols); + debug_assert_eq!(row_frac_offsets.len(), num_rows + 1); + debug_assert_eq!(row_frac_offsets[num_rows], flat_fractions.len()); + + // Phase 1 operates on rows 0..num_rows of the output buffer. It writes fraction + // columns (i > 0) and leaves col 0 untouched (still zero). The side buffer + // row_totals collects t(r) = Σᵢ fᵢ(r) for phase 2's prefix sum. + let frac_region = &mut output_data[..num_rows * num_cols]; + let mut row_totals: Vec = vec![EF::ZERO; num_rows]; + + let rows_per_chunk = ACCUMULATE_ROWS_PER_CHUNK; + + let phase1 = |(chunk_idx, (chunk_out, totals_slice)): (usize, (&mut [EF], &mut [EF]))| { + let row_lo = chunk_idx * rows_per_chunk; + let row_hi = (row_lo + rows_per_chunk).min(num_rows); + let chunk_rows = row_hi - row_lo; + let frac_lo = row_frac_offsets[row_lo]; + let frac_hi = row_frac_offsets[row_hi]; + let chunk_fracs = &flat_fractions[frac_lo..frac_hi]; + let chunk_counts = &flat_counts[row_lo * num_cols..row_hi * num_cols]; + debug_assert_eq!(chunk_out.len(), chunk_rows * num_cols); + debug_assert_eq!(totals_slice.len(), chunk_rows); + + if chunk_fracs.is_empty() { + return; + } + + // Batch-invert and scale: scratch[j] = mⱼ · dⱼ⁻¹ (ready to sum). + // Allocated once per chunk (~1.5 K elements ≈ 24 KiB, L1-resident). + let mut scratch: Vec = vec![EF::ZERO; chunk_fracs.len()]; + invert_and_scale(chunk_fracs, &mut scratch); + + let mut per_row_value: Vec = vec![EF::ZERO; num_cols]; + let mut cursor = 0usize; + for row_in_chunk in 0..chunk_rows { + let row_counts = &chunk_counts[row_in_chunk * num_cols..(row_in_chunk + 1) * num_cols]; + let out_row_base = row_in_chunk * num_cols; + + // f_i(r) = sum_j scratch[j] (scratch already holds m_j * d_j^-1). + for (col, &count) in row_counts.iter().enumerate() { + let end = cursor + count; + let sum = scratch[cursor..end].iter().copied().sum(); + per_row_value[col] = sum; + cursor = end; + } + + // output[r][i] = fᵢ(r) for fraction columns i > 0. + let out_row = &mut chunk_out[out_row_base..out_row_base + num_cols]; + out_row[1..].copy_from_slice(&per_row_value[1..]); + + // t(r) = Σᵢ fᵢ(r), consumed by phase 2. + totals_slice[row_in_chunk] = per_row_value.iter().copied().sum(); + } + debug_assert_eq!(cursor, chunk_fracs.len()); + }; + + #[cfg(not(feature = "concurrent"))] + { + frac_region + .chunks_mut(rows_per_chunk * num_cols) + .zip(row_totals.chunks_mut(rows_per_chunk)) + .enumerate() + .for_each(phase1); + } + #[cfg(feature = "concurrent")] + { + use miden_crypto::parallel::*; + frac_region + .par_chunks_mut(rows_per_chunk * num_cols) + .zip(row_totals.par_chunks_mut(rows_per_chunk)) + .enumerate() + .for_each(phase1); + } + + // Phase 2: acc(0) = 0, acc(r+1) = acc(r) + t(r). + // Writes col 0 of rows 1..=num_rows; row 0 col 0 stays at zero from the allocation. + let mut acc = EF::ZERO; + for r in 0..num_rows { + acc += row_totals[r]; + output_data[(r + 1) * num_cols] = acc; + } + + RowMajorMatrix::new(output_data, num_cols) +} + +/// Forward scan over the flat `counts` buffer producing per-row fraction-start offsets. +/// +/// Returns a `Vec` of length `num_rows + 1` where `offsets[r]` is the starting index +/// of row `r`'s fractions in the flat `fractions.fractions()` buffer and `offsets[num_rows]` +/// equals the total fraction count. Sequential (O(num_rows · num_cols) `usize` adds). +fn compute_row_frac_offsets(flat_counts: &[usize], num_rows: usize, num_cols: usize) -> Vec { + debug_assert_eq!(flat_counts.len(), num_rows * num_cols); + let mut offsets = Vec::with_capacity(num_rows + 1); + let mut acc = 0usize; + offsets.push(0); + for row_counts in flat_counts.chunks(num_cols) { + for &count in row_counts { + acc += count; + } + offsets.push(acc); + } + offsets +} + +/// Montgomery batch inversion fused with multiplicity scaling: writes `scratch[j] = mⱼ · dⱼ⁻¹` +/// using one field inversion + O(N) multiplications. +/// +/// The backward sweep multiplies each inverse by `mⱼ` (an `EF × F` mul, cheaper than +/// `EF × EF`) so the caller gets ready-to-sum fraction values without a second pass. +/// +/// # Panics +/// +/// Panics if the denominator product is zero (would indicate an upstream bug — individual +/// `dⱼ` are never zero because of the nonzero `bus_prefix[bus]` term). +fn invert_and_scale(chunk_fracs: &[(F, EF)], scratch: &mut [EF]) +where + F: Field, + EF: ExtensionField, +{ + debug_assert_eq!(scratch.len(), chunk_fracs.len()); + debug_assert!(!chunk_fracs.is_empty()); + + // Forward pass: scratch[i] = d₀ · d₁ · … · dᵢ (prefix products of denominators). + let mut acc = chunk_fracs[0].1; + scratch[0] = acc; + for i in 1..chunk_fracs.len() { + acc *= chunk_fracs[i].1; + scratch[i] = acc; + } + + // One field inversion — amortised over the whole chunk. + let mut running_inv = scratch[scratch.len() - 1] + .try_inverse() + .expect("LogUp denominator product must be non-zero (bus_prefix is never zero)"); + + // Backward sweep: scratch[i] = mᵢ · dᵢ⁻¹. + // + // Loop invariant (entering iteration i, for i = n-1 down to 1): + // running_inv = (dᵢ · dᵢ₊₁ · … · dₙ₋₁)⁻¹ + // scratch[i-1] = d₀ · d₁ · … · dᵢ₋₁ (left over from the forward pass) + // + // Then: + // dᵢ⁻¹ = scratch[i-1] · running_inv + // (prefix-product cancels every factor except dᵢ⁻¹ inside running_inv). + // We scale by mᵢ (EF × F, cheaper than EF × EF) to yield the fraction directly, then + // fold dᵢ into running_inv so the invariant holds for iteration i-1. + // After the loop: running_inv = d₀⁻¹, ready for the i = 0 case below. + for i in (1..chunk_fracs.len()).rev() { + let (m_i, d_i) = chunk_fracs[i]; + scratch[i] = scratch[i - 1] * running_inv * m_i; + running_inv *= d_i; + } + // i = 0: running_inv = d₀⁻¹. + scratch[0] = running_inv * chunk_fracs[0].0; +} + +// TESTS +// ================================================================================================ + +#[cfg(test)] +mod tests { + use miden_core::{ + field::{PrimeCharacteristicRing, QuadFelt}, + utils::Matrix, + }; + + use super::*; + use crate::{ + Felt, + lookup::{LookupAir, LookupBuilder}, + }; + + // Small deterministic LCG — reproducible stream for random-fixture cross-check tests. + // We don't need cryptographic quality, just determinism. + struct Lcg(u64); + impl Lcg { + fn next(&mut self) -> u64 { + self.0 = self.0.wrapping_mul(6364136223846793005).wrapping_add(1442695040888963407); + self.0 + } + fn felt(&mut self) -> Felt { + // Take the high 32 bits to avoid the near-zero-biasing of low bits. + Felt::new_unchecked(self.next() >> 32) + } + fn quad(&mut self) -> QuadFelt { + QuadFelt::new([self.felt(), self.felt()]) + } + } + + /// Build a `LookupFractions` fixture of the given shape and row count, filled with + /// reproducibly-random non-zero denominators and arbitrary base-field multiplicities. + /// Shared helper for the cross-check tests. + fn random_fixture( + shape: &[usize], + num_rows: usize, + seed: u64, + ) -> LookupFractions { + let mut rng = Lcg(seed); + let mut fx: LookupFractions = LookupFractions { + fractions: Vec::with_capacity(num_rows * shape.iter().sum::()), + counts: Vec::with_capacity(num_rows * shape.len()), + shape: shape.to_vec(), + num_rows, + num_cols: shape.len(), + }; + for _row in 0..num_rows { + for &max_count in shape { + let count = (rng.next() as usize) % (max_count + 1); + for _ in 0..count { + let m = rng.felt(); + // Rejection sample until we get a non-zero denominator. With a 64-bit + // Goldilocks field and random draws, this basically never loops. + let d = loop { + let candidate = rng.quad(); + if candidate != QuadFelt::ZERO { + break candidate; + } + }; + fx.fractions.push((m, d)); + } + fx.counts.push(count); + } + } + fx + } + + /// Assert that `accumulate`'s row-major matrix output matches `accumulate_slow`'s per-column + /// `Vec>` output element-by-element. Shared check used by the single-chunk and + /// multi-chunk regression tests. + fn assert_matrix_matches_slow( + slow: &[Vec], + fast: &RowMajorMatrix, + num_cols: usize, + num_rows: usize, + ) { + assert_eq!(fast.width(), num_cols, "fast.width() mismatch"); + assert_eq!(fast.height(), num_rows + 1, "fast.height() mismatch"); + assert_eq!(slow.len(), num_cols, "slow column count mismatch"); + for (col, slow_col) in slow.iter().enumerate() { + assert_eq!(slow_col.len(), num_rows + 1, "slow col {col} row count mismatch"); + for (row, &s) in slow_col.iter().enumerate() { + let f = fast.values[row * num_cols + col]; + assert_eq!(s, f, "row {row} col {col} differs: slow={s:?} fast={f:?}",); + } + } + } + + /// Minimal `LookupAir` used to drive `LookupFractions::from_shape` without pulling in the + /// real Miden air. Only `num_columns()` and `column_shape()` are exercised; the + /// other methods return sentinel values and `eval` is a no-op. + struct FakeAir { + shape: [usize; 2], + } + + impl LookupAir for FakeAir { + fn num_columns(&self) -> usize { + self.shape.len() + } + fn column_shape(&self) -> &[usize] { + &self.shape + } + fn max_message_width(&self) -> usize { + 0 + } + fn num_bus_ids(&self) -> usize { + 0 + } + fn eval(&self, _builder: &mut LB) {} + } + + fn fixture(shape: [usize; 2], num_rows: usize) -> LookupFractions { + LookupFractions::from_shape(shape.to_vec(), num_rows) + } + + /// `accumulate_slow` returns `num_rows + 1` entries per column. Column 0 is a running + /// sum that also folds in column 1's per-row values. Column 1 is a fraction column + /// storing only per-row values (no cross-row accumulation). + /// + /// Layout fed in: + /// + /// ```text + /// row 0: col 0 pushes 2, col 1 pushes 0 + /// row 1: col 0 pushes 1, col 1 pushes 1 + /// + /// fractions = [(1, d1), (2, d2), (1, d1), (2, d2)] + /// counts = [2, 0, 1, 1] + /// ``` + #[test] + fn accumulate_slow_hand_crafted() { + let one = Felt::new_unchecked(1); + let two = Felt::new_unchecked(2); + let d1 = QuadFelt::new([Felt::new_unchecked(3), Felt::new_unchecked(0)]); + let d2 = QuadFelt::new([Felt::new_unchecked(5), Felt::new_unchecked(0)]); + + let mut fx = fixture([2, 1], 2); + // Row 0 + fx.fractions.push((one, d1)); + fx.fractions.push((two, d2)); + fx.counts.push(2); // col 0 + fx.counts.push(0); // col 1 + // Row 1 + fx.fractions.push((one, d1)); + fx.counts.push(1); // col 0 + fx.fractions.push((two, d2)); + fx.counts.push(1); // col 1 + + let aux = accumulate_slow(&fx); + assert_eq!(aux.len(), 2); + assert_eq!(aux[0].len(), 3); + assert_eq!(aux[1].len(), 3); + + let d1_inv = d1.try_inverse().unwrap(); + let d2_inv = d2.try_inverse().unwrap(); + + // Row 0: col 0 own = 1/d1 + 2/d2, col 1 own = 0 + // Row 1: col 0 own = 1/d1, col 1 own = 2/d2 + let row0_col0 = d1_inv + d2_inv.double(); + let row1_col0 = d1_inv; + let row1_col1 = d2_inv.double(); + + // Column 0 (accumulator): [0, row0_col0+0, prev + row1_col0 + row1_col1] + assert_eq!(aux[0][0], QuadFelt::ZERO); + assert_eq!(aux[0][1], row0_col0); + assert_eq!(aux[0][2], row0_col0 + row1_col0 + row1_col1); + + // Column 1 (fraction, aux_curr): [0, 2/d2, 0] + // Row 0: col 1 has no fractions → aux[1][0] = 0 + // Row 1: col 1 has 2/d2 → aux[1][1] = 2/d2 + // Row 2 (extra row): don't care (committed final) + assert_eq!(aux[1][0], QuadFelt::ZERO); + assert_eq!(aux[1][1], row1_col1); + } + + /// `LookupFractions::from_shape` sizes the flat `fractions` Vec with `num_rows * Σ shape` + /// capacity and the flat `counts` Vec with `num_rows * num_cols` capacity (so neither + /// reallocates in the hot loop). Both start empty. + #[test] + fn new_reserves_capacity() { + let air = FakeAir { shape: [3, 5] }; + let fx: LookupFractions = + LookupFractions::from_shape(air.shape.to_vec(), 10); + + assert_eq!(fx.num_columns(), 2); + assert_eq!(fx.num_rows(), 10); + assert_eq!(fx.shape(), &[3, 5]); + assert!(fx.fractions.capacity() >= 10 * (3 + 5)); + assert!(fx.counts.capacity() >= 10 * 2); + assert!(fx.fractions.is_empty()); + assert!(fx.counts.is_empty()); + } + + /// Single-chunk random cross-check: a tiny fixture (32 rows) fits inside one + /// [`ACCUMULATE_ROWS_PER_CHUNK`] chunk, so phase 2's prefix scan and phase 3's offset + /// add are both trivial (zero offset), and this test only exercises phase 1's fused + /// Montgomery + walk path. + #[test] + fn accumulate_matches_accumulate_slow_random() { + const SHAPE: [usize; 3] = [2, 1, 3]; + const NUM_ROWS: usize = 32; + const _: () = assert!( + NUM_ROWS < ACCUMULATE_ROWS_PER_CHUNK, + "must stay in one chunk to test phase 1", + ); + + let fx = random_fixture(&SHAPE, NUM_ROWS, 0x00c0_ffee_beef_c0de); + let slow = accumulate_slow(&fx); + let fast = accumulate(&fx); + assert_matrix_matches_slow(&slow, &fast, SHAPE.len(), NUM_ROWS); + } + + /// Multi-chunk regression test: a fixture spanning multiple + /// [`ACCUMULATE_ROWS_PER_CHUNK`]-row chunks (with a deliberately short trailing chunk) + /// exercises phase 2's prefix-sum path. The trailing `+ 7` rows ensure the last + /// chunk is smaller than the others and that `num_rows % rows_per_chunk != 0`, catching + /// any off-by-one in the last-chunk bounds. + #[test] + fn accumulate_multi_chunk_matches_accumulate_slow() { + const SHAPE: [usize; 4] = [1, 2, 3, 1]; + const NUM_ROWS: usize = ACCUMULATE_ROWS_PER_CHUNK * 3 + 7; + + let fx = random_fixture(&SHAPE, NUM_ROWS, 0xdead_beef_cafe_babe); + let slow = accumulate_slow(&fx); + let fast = accumulate(&fx); + assert_matrix_matches_slow(&slow, &fast, SHAPE.len(), NUM_ROWS); + } + + /// Empty-trace smoke test: `num_rows = 0` must return a 1-row, `num_cols`-wide zero + /// matrix (the initial condition) without touching the inversion path. + #[test] + fn accumulate_empty_trace() { + let shape = vec![2usize, 3, 1]; + let num_cols = shape.len(); + let fx: LookupFractions = LookupFractions { + fractions: Vec::new(), + counts: Vec::new(), + shape, + num_rows: 0, + num_cols, + }; + let aux = accumulate(&fx); + assert_eq!(aux.width(), num_cols); + assert_eq!(aux.height(), 1); + assert!(aux.values.iter().all(|v| *v == QuadFelt::ZERO)); + } +} diff --git a/air/src/lookup/builder.rs b/air/src/lookup/builder.rs new file mode 100644 index 0000000000..8860afaf41 --- /dev/null +++ b/air/src/lookup/builder.rs @@ -0,0 +1,533 @@ +//! Closure-based builder traits for the LogUp lookup-argument API. +//! +//! The lookup-air refactor introduces the trait stack that sits on top of +//! `LookupAir`: +//! +//! - [`LookupBuilder`] — the top-level handle mirroring the subset of `LiftedAirBuilder` a lookup +//! author actually needs (trace access plus per-column scoping). It hides `assert_*` / `when_*` / +//! permutation plumbing and does not expose the verifier challenges. +//! - [`LookupColumn`] — per-column handle returned by [`LookupBuilder::next_column`]. It owns the +//! boundary between groups; its only job is to open a group (either the simple path or the +//! cached-encoding dual path). +//! - [`LookupGroup`] — the simple, challenge-free interaction API used by bus authors. Every method +//! here takes a `LookupMessage`; the enclosing adapter is responsible for encoding it under α + Σ +//! βⁱ · payload. +//! - [`LookupBatch`] — a short-lived handle returned inside [`LookupGroup::batch`]. Represents a +//! set of simultaneous interactions that share the outer group's flag. +//! - [`LookupGroup`] also exposes optional encoding primitives (`bus_prefix`, `beta_powers`, +//! `insert_encoded`) for the cached-encoding path. Default implementations panic; only the +//! constraint-path adapter overrides them with real bodies. +//! +//! No adapter impls live in this file; the bounds here are chosen so that both the +//! constraint-path adapter (which forwards to an inner `LiftedAirBuilder`, carrying +//! symbolic `AB::Expr` / `AB::ExprEF` associated types) and the prover-path adapter +//! (instantiated with the concrete `F` / `EF` field types) can satisfy them. + +use miden_core::field::{Algebra, ExtensionField, Field, PrimeCharacteristicRing}; +use miden_crypto::stark::air::WindowAccess; + +use super::message::LookupMessage; + +// DEGREE ANNOTATION +// ================================================================================================ + +/// Expected post-flag `(V, U)` contribution for one interaction or scope. +/// +/// Every builder method takes a `Deg` as its last argument so authors can +/// declare the expected degrees inline. Production adapters ignore the value +/// (it is `Copy` and dead-code-eliminated after inlining). A debug adapter +/// can compare the declared degrees against the symbolic expression it just +/// accumulated and panic with the interaction's `name` if they disagree. +/// +/// - `v`: degree of the numerator (`V`) contribution after multiplying by the surrounding flag. +/// - `u`: degree of the denominator (`U`) contribution after multiplying by the surrounding flag. +/// +/// Field order mirrors the `(V, U)` tuple convention used throughout the +/// adapter code: numerator first, denominator second. +/// +/// ## Semantics by call site +/// +/// - **Single interactions** ([`LookupGroup::add`], `remove`, `insert`, `insert_encoded`, and the +/// corresponding [`LookupBatch`] methods): `(v, u) = (deg(m · D) + deg(f), deg(D) + deg(f))` +/// where `m` is the interaction's signed multiplicity, `D` is its denominator polynomial, and `f` +/// is the gating flag (the enclosing batch flag for `LookupBatch` methods). The standalone +/// post-flag contribution this interaction would make if folded directly into the enclosing +/// group's `(V_g, U_g)`. +/// +/// - **Batch outer** ([`LookupGroup::batch`]): the post-flag contribution the *whole* batch makes +/// to the enclosing group's `(V_g, U_g)` — `(deg(N) + deg(f), deg(D) + deg(f))` where `(N, D)` is +/// the running pair the inner-loop body accumulates and `f` is the batch flag. The pre-flag `(N, +/// D)` is mechanically derivable from the inner-loop body — `((k − 1) · d_v, k · d_v)` for `k` +/// interactions of inner denominator degree `d_v` — so it is documented inline at each batch site +/// rather than carried in the struct. +/// +/// - **Group / column scope** ([`LookupColumn::group`], `group_with_cached_encoding`, +/// [`LookupBuilder::next_column`]): the total post-flag `(V, U)` contribution of the group / +/// column to the surrounding accumulator. Useful as a budget audit number when the author wants +/// to assert what the scope as a whole contributes. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct Deg { + pub v: usize, + pub u: usize, +} + +// LOOKUP BUILDER +// ================================================================================================ + +/// The trace-reading handle handed to a [`super::LookupAir`] implementation. +/// +/// `LookupBuilder` deliberately mirrors the subset of `LiftedAirBuilder`'s +/// associated types needed to read `main` and `periodic_values`. It is +/// **not** a sub-trait of `AirBuilder`: the constraint +/// emission surface (`assert_zero` / `when_first_row` / …) and the +/// permutation column plumbing stay hidden, which keeps the simple lookup +/// path free of challenge access. +/// +/// Implementors must not shortcut the per-column scoping: a [`super::LookupAir`] +/// author that opens `n` columns must issue exactly `n` calls to +/// [`LookupBuilder::next_column`], matching [`super::LookupAir::num_columns`]. +/// +/// ## Associated-type layout +/// +/// The base-field stack (`F`, `Expr`, `Var`) and extension-field stack +/// (`EF`, `ExprEF`, `VarEF`) mirror the upstream `AirBuilder` / +/// `ExtensionBuilder` split one-for-one; `Algebra` on `Expr` lets the +/// lookup author multiply main-trace variables with arbitrary expressions +/// without crossing trait boundaries. `PeriodicVar` / `MainWindow` come +/// from `PeriodicAirBuilder` / `AirBuilder` respectively and are passed +/// through the adapter unchanged. +/// +/// The per-column handle is a generic associated type +/// ([`Self::Column`](Self::Column)) so that each `column(...)` call can +/// borrow from `self` without outliving the closure. Its bound pins the +/// expression and extension-variable types to keep them in sync with the +/// outer builder. +pub trait LookupBuilder: Sized { + // --- base field stack (copied from AirBuilder) --- + + /// Underlying base field. Lookups only pin `Field` here (not the wider + /// `PrimeCharacteristicRing`) because the extension-field associated + /// types below require an `ExtensionField` relationship, and + /// `ExtensionField` itself bounds on `Field`. + type F: Field; + + /// Expression type over base-field elements. Must be an algebra over + /// both `Self::F` (for constants) and `Self::Var` (for trace + /// variables), matching upstream `AirBuilder::Expr`. + type Expr: Algebra + Algebra; + + /// Variable type over base-field trace cells. Held by value, so bound + /// only by `Into + Copy + Send + Sync`; the full arithmetic + /// bound soup from `AirBuilder::Var` is not required here because the + /// `Algebra` bound on `Expr` lets callers convert before + /// composing. + type Var: Into + Copy + Send + Sync; + + // --- extension field stack (copied from ExtensionBuilder) --- + + /// Extension field used by the auxiliary trace and the LogUp + /// accumulators. + type EF: ExtensionField; + + /// Expression type over extension-field elements; must be an algebra + /// over both `Self::Expr` (to lift base expressions) and `Self::EF` + /// (for extension-field constants). + type ExprEF: Algebra + Algebra; + + /// Variable type over extension-field trace cells (permutation + /// columns and the α/β challenges). + type VarEF: Into + Copy + Send + Sync; + + // --- auxiliary trace access types --- + + /// Periodic column value at the current row (copied from + /// `PeriodicAirBuilder::PeriodicVar`). + type PeriodicVar: Into + Copy; + + /// Two-row window over the main trace, returned as-is from the + /// underlying builder. Pinned to [`WindowAccess`] + `Clone` so a + /// lookup author can split it into `current_slice()` / `next_slice()` + /// and pass either to `borrow`-based view types without re-reading + /// the handle. + type MainWindow: WindowAccess + Clone; + + /// Per-column handle opened by [`Self::next_column`]. Holds the adapter's per-column + /// state (running `(V, U)` on the constraint path, fraction collector on the prover + /// path) for the column's closure. + type Column<'a>: LookupColumn + where + Self: 'a; + + // ---- trace access ---- + + /// Two-row main trace window. Pass-through to the wrapped builder. + fn main(&self) -> Self::MainWindow; + + /// Periodic column values at the current row. + fn periodic_values(&self) -> &[Self::PeriodicVar]; + + // ---- per-column scoping ---- + + /// Open a fresh permutation column and evaluate `f` inside it. + /// + /// The implementation is responsible for: + /// + /// 1. Wiring the column handle to the adapter's internal state (current `acc` / `acc_next` for + /// the constraint path; the per-column fraction buffer slot for the prover path). + /// 2. Running the closure, which must describe at least one group via [`LookupColumn::group`] + /// or [`LookupColumn::group_with_cached_encoding`]. + /// 3. Finalizing the column on close (emitting boundary + transition constraints, or draining + /// the column's fraction pair). + /// 4. Advancing to the next permutation column index so the next call targets a fresh + /// accumulator. + /// + /// The closure's return value `R` is forwarded unchanged. + fn next_column<'a, R>(&'a mut self, f: impl FnOnce(&mut Self::Column<'a>) -> R, deg: Deg) -> R; +} + +// LOOKUP COLUMN +// ================================================================================================ + +/// Per-column handle returned by [`LookupBuilder::next_column`]. +/// +/// The only decision a column makes is how to open a group: either the +/// simple path via [`group`](Self::group) or the dual cached-encoding path +/// via [`group_with_cached_encoding`](Self::group_with_cached_encoding). +/// +/// Multiple groups may be opened per column; the adapter is responsible +/// for composing them according to the column accumulator algebra +/// (`V ← V·U_g + V_g·U`, `U ← U·U_g`). Groups opened inside the same +/// column are assumed *product-closed*, not mutually exclusive. +pub trait LookupColumn { + /// Expression type over base-field elements. Pinned to + /// [`LookupBuilder::Expr`] through [`LookupBuilder::Column`]. + type Expr: PrimeCharacteristicRing + Clone; + + /// Expression type over extension-field elements. Pinned to + /// [`LookupBuilder::ExprEF`] through [`LookupBuilder::Column`]. The + /// [`Algebra`] bound lets [`LookupMessage::encode`] + /// multiply an `Expr`-typed payload slot by an `ExprEF`-typed + /// β-power without manually lifting. + type ExprEF: PrimeCharacteristicRing + Clone + Algebra; + + /// Per-group handle used for the simple (challenge-free) path. + type Group<'a>: LookupGroup + where + Self: 'a; + + /// Open a group using the simple, challenge-free API. + /// + /// Every interaction added inside the closure is folded into this + /// group's `(V_g, U_g)` pair; on close, the column composes the pair + /// into its running accumulator. + fn group<'a>(&'a mut self, name: &'static str, f: impl FnOnce(&mut Self::Group<'a>), deg: Deg); + + /// Open a group with two sibling descriptions for the same + /// interaction set. + /// + /// - `canonical` runs on the prover path. It sees the simple [`LookupGroup`] surface — no + /// challenges, no `insert_encoded`. Zero-valued flag closures are skipped by the backing + /// fraction collector. + /// - `encoded` runs on the constraint path. It sees the same [`LookupGroup`] surface, plus the + /// encoding primitives `beta_powers()`, `bus_prefix()`, and `insert_encoded()`. Authors use + /// this to precompute shared encoding fragments (e.g. a common `α + β·addr` prefix) and reuse + /// them across mutually-exclusive variants. + /// + /// Both closures must produce mathematically identical `(V, U)` + /// pairs; the split is purely an optimization for expensive + /// extension-field arithmetic on the symbolic path. Adapters are + /// free to drop whichever closure they do not use. + fn group_with_cached_encoding<'a>( + &'a mut self, + name: &'static str, + canonical: impl FnOnce(&mut Self::Group<'a>), + encoded: impl FnOnce(&mut Self::Group<'a>), + deg: Deg, + ); +} + +// LOOKUP GROUP +// ================================================================================================ + +/// Simple, challenge-free interaction API opened inside a +/// [`LookupColumn`]. +/// +/// Authors call `add` / `remove` / `insert` to describe one flag-gated +/// interaction at a time, or `batch` to describe several simultaneous +/// interactions that share a single outer flag. +/// +/// All methods take the message through an `impl FnOnce() -> M` closure +/// so the prover-path adapter can skip the construction (and any +/// expensive derivation) when `flag == 0`. +pub trait LookupGroup { + /// Expression type over base-field elements. Pinned to + /// [`LookupBuilder::Expr`] through the column. The + /// `PrimeCharacteristicRing` bound keeps [`LookupMessage`] happy when + /// authors pass messages through `add` / `remove` / `insert`. + type Expr: PrimeCharacteristicRing + Clone; + + /// Expression type over extension-field elements. Pinned to + /// [`LookupBuilder::ExprEF`] through the column. The + /// [`Algebra`] bound mirrors [`LookupColumn::ExprEF`] + /// and lets [`LookupMessage::encode`] use `ExprEF × Expr` products. + type ExprEF: PrimeCharacteristicRing + Clone + Algebra; + + /// Transient handle returned by [`batch`](Self::batch). GAT so the + /// batch can borrow from `self` (and therefore from the column and + /// the outer builder) for the duration of the closure. + type Batch<'b>: LookupBatch + where + Self: 'b; + + /// Add a single interaction with multiplicity `+1`, gated by `flag`. + /// + /// `msg` is deferred so the adapter can skip both the construction + /// and the encoding when `flag == 0` on the prover path. + /// + /// The default delegates to [`insert`](Self::insert) with multiplicity `ONE`. + /// Adapters may override for optimization (e.g. the constraint path avoids + /// the redundant `flag * ONE` symbolic node). + fn add(&mut self, name: &'static str, flag: Self::Expr, msg: impl FnOnce() -> M, deg: Deg) + where + M: LookupMessage, + { + self.insert(name, flag, Self::Expr::ONE, msg, deg); + } + + /// Add a single interaction with multiplicity `-1`, gated by `flag`. + /// + /// The default delegates to [`insert`](Self::insert) with multiplicity `NEG_ONE`. + fn remove(&mut self, name: &'static str, flag: Self::Expr, msg: impl FnOnce() -> M, deg: Deg) + where + M: LookupMessage, + { + self.insert(name, flag, Self::Expr::NEG_ONE, msg, deg); + } + + /// Add a single interaction with explicit signed multiplicity, gated + /// by `flag`. + /// + /// `multiplicity` is a base-field expression so callers can mix + /// trace columns, constants, and boolean selectors freely. + fn insert( + &mut self, + name: &'static str, + flag: Self::Expr, + multiplicity: Self::Expr, + msg: impl FnOnce() -> M, + deg: Deg, + ) where + M: LookupMessage; + + /// Open a batch of simultaneous interactions that all share the + /// single outer flag `flag`. + /// + /// Inside the closure, messages are passed by value (see + /// [`LookupBatch`]): the flag-zero skip is handled once at the batch + /// level, so per-interaction closures are redundant. + /// + /// Multiple batches inside the same [`LookupGroup`] are **not** + /// checked for mutual exclusion; adapters assume the author upholds + /// this invariant (matching the existing `RationalSet` contract). + fn batch<'a>( + &'a mut self, + name: &'static str, + flag: Self::Expr, + build: impl FnOnce(&mut Self::Batch<'a>), + deg: Deg, + ); + + // ---- encoding primitives (cached-encoding path only) ---- + + /// Precomputed powers `[β⁰, β¹, …, β^(W-1)]`, where + /// `W = max_message_width` from the enclosing + /// [`LookupAir`](super::LookupAir). + /// + /// The slice length is exactly `W` — there is **no** trailing `β^W` + /// entry, because that power is the per-bus step baked into every + /// [`Challenges::bus_prefix`](super::Challenges) entry + /// at builder-construction time. Authors that want to build their + /// own encoded denominator loop should iterate over `beta_powers()` + /// directly and slice to their own message width. + /// + /// Returned as extension-field expressions; the adapter materializes + /// the powers once at construction time (as `AB::ExprEF` on the + /// constraint path) and serves them back by reference. + /// + /// # Panics + /// + /// Default implementation panics — only valid inside the `encoded` + /// closure of [`LookupColumn::group_with_cached_encoding`]. + fn beta_powers(&self) -> &[Self::ExprEF] { + panic!( + "beta_powers() is only available inside the `encoded` closure of group_with_cached_encoding" + ) + } + + /// Look up the precomputed bus prefix + /// `bus_prefix[bus_id] = α + (bus_id + 1) · β^W` for the given + /// coarse bus ID. + /// + /// Returns an owned [`Self::ExprEF`] by cloning the entry — the + /// underlying storage is a `Box<[ExprEF]>` on the adapter and + /// `ExprEF` is typically a ring element, so cloning is cheap. + /// + /// # Panics + /// + /// Default implementation panics — only valid inside the `encoded` + /// closure of [`LookupColumn::group_with_cached_encoding`]. + /// Also panics if `bus_id` is out of bounds of the adapter's + /// `num_bus_ids`. + fn bus_prefix(&self, bus_id: usize) -> Self::ExprEF { + let _ = bus_id; + panic!( + "bus_prefix() is only available inside the `encoded` closure of group_with_cached_encoding" + ) + } + + /// Add a flag-gated interaction whose denominator is already an + /// extension-field expression. + /// + /// - `flag`: base-field selector. Zero flags are skipped by the prover-path adapter + /// (constraint-path evaluates unconditionally). + /// - `multiplicity`: base-field signed multiplicity. + /// - `encoded`: closure producing the final denominator. Run once on the constraint path. On + /// the prover path the adapter may skip the call entirely when `flag == 0`. + /// + /// # Panics + /// + /// Default implementation panics — only valid inside the `encoded` + /// closure of [`LookupColumn::group_with_cached_encoding`]. + fn insert_encoded( + &mut self, + _name: &'static str, + _flag: Self::Expr, + _multiplicity: Self::Expr, + _encoded: impl FnOnce() -> Self::ExprEF, + _deg: Deg, + ) { + panic!( + "insert_encoded() is only available inside the `encoded` closure of group_with_cached_encoding" + ) + } +} + +// LOOKUP BATCH +// ================================================================================================ + +/// Transient handle exposed inside [`LookupGroup::batch`]. +/// +/// A batch groups several simultaneously-active interactions under a +/// single outer flag, emitted by the enclosing group. The flag-zero skip +/// is performed once by the group when the batch opens, so within the +/// batch the message can be built unconditionally and is taken by value +/// (not through a closure). +/// +/// Kept as a separate trait rather than a concrete helper struct because +/// the constraint-path and prover-path adapters need different backing +/// storage (`RationalSet` vs `FractionCollector`) and expressing that +/// split through a GAT on [`LookupGroup::Batch`] is cleaner than bolting +/// a second generic parameter onto a shared struct. +pub trait LookupBatch { + /// Expression type over base-field elements. Must match the + /// enclosing group's `Expr`. `PrimeCharacteristicRing` is required + /// by [`LookupMessage`] (passed by value into the `add` / `remove` / + /// `insert` methods below). + type Expr: PrimeCharacteristicRing + Clone; + + /// Expression type over extension-field elements. Must match the + /// enclosing group's `ExprEF` — [`LookupMessage::encode`] returns an + /// extension-field value and the batch's underlying algebra operates + /// on that type. The [`Algebra`] bound mirrors the + /// enclosing group's `ExprEF` bound. + type ExprEF: PrimeCharacteristicRing + Clone + Algebra; + + /// Absorb an interaction with multiplicity `+1`. + /// + /// The default delegates to [`insert`](Self::insert) with multiplicity `ONE`. + fn add(&mut self, name: &'static str, msg: M, deg: Deg) + where + M: LookupMessage, + { + self.insert(name, Self::Expr::ONE, msg, deg); + } + + /// Absorb an interaction with multiplicity `-1`. + /// + /// The default delegates to [`insert`](Self::insert) with multiplicity `NEG_ONE`. + fn remove(&mut self, name: &'static str, msg: M, deg: Deg) + where + M: LookupMessage, + { + self.insert(name, Self::Expr::NEG_ONE, msg, deg); + } + + /// Absorb an interaction with arbitrary signed multiplicity. + fn insert(&mut self, name: &'static str, multiplicity: Self::Expr, msg: M, deg: Deg) + where + M: LookupMessage; + + /// Absorb an interaction with an already-encoded denominator. + fn insert_encoded( + &mut self, + name: &'static str, + multiplicity: Self::Expr, + encoded: impl FnOnce() -> Self::ExprEF, + deg: Deg, + ); +} + +// BOUNDARY BUILDER +// ================================================================================================ + +/// Handle for emitting **once-per-proof** "outer" interactions — contributions to the +/// LogUp sum that are not tied to any main-trace row. +/// +/// Typical sources are committed-final boundary terminals (kernel ROM init, block hash +/// seed, log-precompile terminals, public-input bus seeds). Each emission contributes +/// one signed fraction to the overall balance; no column / row / group scoping, no +/// flag gating, no `Deg` (boundary terms are plain field elements, not polynomials). +/// +/// Used by [`super::LookupAir::eval_boundary`]. Default implementations on the trait +/// are a no-op, so AIRs with no boundary contributions don't need to override it. +pub trait BoundaryBuilder { + /// Base field for boundary-interaction multiplicities and encoded message slots. + type F: Field; + + /// Extension field used by [`LookupMessage::encode`] — matches the enclosing + /// `LookupAir`'s `LB::EF`. + type EF: ExtensionField; + + /// Public values passed to the proof (the `public_values` slice threaded through + /// `prove_stark`). + fn public_values(&self) -> &[Self::F]; + + /// Variable-length public inputs (e.g. kernel felts). Matches the layout the + /// prover hands to `miden_crypto::stark::prover::prove_single`. + fn var_len_public_inputs(&self) -> &[&[Self::F]]; + + /// Emit a boundary interaction with multiplicity `+1`. + /// + /// The default delegates to [`insert`](Self::insert) with multiplicity `ONE`. + fn add(&mut self, name: &'static str, msg: M) + where + M: LookupMessage, + { + self.insert(name, Self::F::ONE, msg); + } + + /// Emit a boundary interaction with multiplicity `-1`. + /// + /// The default delegates to [`insert`](Self::insert) with multiplicity `NEG_ONE`. + fn remove(&mut self, name: &'static str, msg: M) + where + M: LookupMessage, + { + self.insert(name, Self::F::NEG_ONE, msg); + } + + /// Emit a boundary interaction with an arbitrary signed multiplicity. + fn insert(&mut self, name: &'static str, multiplicity: Self::F, msg: M) + where + M: LookupMessage; +} diff --git a/air/src/lookup/challenges.rs b/air/src/lookup/challenges.rs new file mode 100644 index 0000000000..9fab9f989c --- /dev/null +++ b/air/src/lookup/challenges.rs @@ -0,0 +1,155 @@ +//! Unified bus challenge encoding with per-bus domain separation. +//! +//! Provides [`Challenges`], a single struct for encoding multiset/LogUp bus messages +//! as `bus_prefix[bus] + `. Each bus interaction type gets a unique +//! prefix to ensure domain separation. +//! +//! This type is used by: +//! +//! - **AIR constraints** (symbolic expressions): `Challenges` +//! - **Processor aux trace builders** (concrete field elements): `Challenges` +//! - **Verifier** (`reduced_aux_values`): `Challenges` +//! +//! See [`super::message`] for the standard coefficient index layout. + +use alloc::{boxed::Box, vec::Vec}; +use core::ops::{AddAssign, Mul}; + +use miden_core::field::PrimeCharacteristicRing; + +/// Encodes multiset/LogUp contributions as **bus_prefix\[bus\] + \**. +/// +/// - `alpha`: randomness base (kept public for direct access by range checker etc.) +/// - `beta_powers`: precomputed powers `[beta^0, beta^1, ..., beta^(max_message_width-1)]` +/// - `bus_prefix`: per-bus domain separation constants `bus_prefix[i] = alpha + (i+1) * +/// beta^max_message_width` +/// +/// The challenges are derived from permutation randomness: +/// - `alpha = challenges[0]` +/// - `beta = challenges[1]` +/// +/// Widths (`beta_powers.len()` and `bus_prefix.len()`) come from the [`LookupAir`]'s +/// `max_message_width()` / `num_bus_ids()` at construction time. The struct is built +/// once and read-only thereafter — `Box<[EF]>` over `Vec` drops the unused +/// capacity word and signals fixed length. +/// +/// [`LookupAir`]: crate::lookup::LookupAir +pub struct Challenges { + pub alpha: EF, + pub beta_powers: Box<[EF]>, + /// Per-bus domain separation: `bus_prefix[i] = alpha + (i+1) * gamma` + /// where `gamma = beta^max_message_width`. + pub bus_prefix: Box<[EF]>, +} + +impl Challenges { + /// Builds `alpha`, precomputed `beta` powers, and per-bus prefixes sized from the + /// [`LookupAir`]'s `max_message_width()` / `num_bus_ids()`. + /// + /// `beta_powers` holds `max_message_width` entries (indices `0..max_message_width`). + /// `bus_prefix` holds `num_bus_ids` entries. + /// `gamma = beta^max_message_width` (one power beyond the highest `beta_powers` index). + /// + /// [`LookupAir`]: crate::lookup::LookupAir + pub fn new(alpha: EF, beta: EF, max_message_width: usize, num_bus_ids: usize) -> Self { + assert!(max_message_width > 0, "max_message_width must be non-zero"); + + let mut beta_powers: Vec = Vec::with_capacity(max_message_width); + beta_powers.push(EF::ONE); + for i in 1..max_message_width { + beta_powers.push(beta_powers[i - 1].clone() * beta.clone()); + } + let beta_powers = beta_powers.into_boxed_slice(); + + // gamma = beta^max_message_width (one power beyond the message range) + let gamma = beta_powers[max_message_width - 1].clone() * beta; + + let bus_prefix: Box<[EF]> = (0..num_bus_ids) + .map(|i| alpha.clone() + gamma.clone() * EF::from_u32((i as u32) + 1)) + .collect(); + + Self { alpha, beta_powers, bus_prefix } + } + + /// Encodes as **bus_prefix\[bus\] + sum(beta_powers\[i\] * elem\[i\])** with K consecutive + /// elements. + /// + /// The `bus` parameter selects the bus interaction type for domain separation. + #[inline(always)] + pub fn encode(&self, bus: usize, elems: [BF; K]) -> EF + where + EF: Mul + AddAssign, + { + debug_assert!( + K <= self.beta_powers.len(), + "Message length {K} exceeds beta_powers capacity ({})", + self.beta_powers.len(), + ); + debug_assert!( + bus < self.bus_prefix.len(), + "Bus index {bus} exceeds bus_prefix length ({})", + self.bus_prefix.len(), + ); + let mut acc = self.bus_prefix[bus].clone(); + for (i, elem) in elems.into_iter().enumerate() { + acc += self.beta_powers[i].clone() * elem; + } + acc + } + + /// Returns **sum(beta_powers\[offset + i\] * elems\[i\])**. + /// + /// Unlike [`Self::encode`], this does **not** add a bus prefix — callers compose it + /// with their own prefix and other contributions when a single message absorbs + /// multiple slices at different β offsets (e.g. addr at β⁰, payload at β²). + #[inline(always)] + pub fn inner_product_at(&self, offset: usize, elems: &[BF]) -> EF + where + EF: Mul + AddAssign, + { + debug_assert!( + offset + elems.len() <= self.beta_powers.len(), + "inner_product_at range {}..{} exceeds beta_powers length ({})", + offset, + offset + elems.len(), + self.beta_powers.len(), + ); + let mut acc = EF::ZERO; + for (i, elem) in elems.iter().enumerate() { + acc += self.beta_powers[offset + i].clone() * elem.clone(); + } + acc + } + + /// Encodes as **bus_prefix\[bus\] + sum(beta_powers\[layout\[i\]\] * values\[i\])** using + /// sparse positions. + /// + /// The `bus` parameter selects the bus interaction type for domain separation. + #[inline(always)] + pub fn encode_sparse( + &self, + bus: usize, + layout: [usize; K], + values: [BF; K], + ) -> EF + where + EF: Mul + AddAssign, + { + debug_assert!( + bus < self.bus_prefix.len(), + "Bus index {bus} exceeds bus_prefix length ({})", + self.bus_prefix.len(), + ); + let mut acc = self.bus_prefix[bus].clone(); + for (idx, value) in layout.into_iter().zip(values) { + debug_assert!( + idx < self.beta_powers.len(), + "encode_sparse index {} exceeds beta_powers length ({})", + idx, + self.beta_powers.len() + ); + acc += self.beta_powers[idx].clone() * value; + } + acc + } +} diff --git a/air/src/lookup/constraint.rs b/air/src/lookup/constraint.rs new file mode 100644 index 0000000000..a6334966bc --- /dev/null +++ b/air/src/lookup/constraint.rs @@ -0,0 +1,501 @@ +//! Constraint-path adapter for the closure-based lookup API. +//! +//! Implements [`LookupBuilder`] over any `LiftedAirBuilder`. Each column's +//! constraints are emitted inline during [`LookupBuilder::next_column`]. +//! +//! ## LogUp constraint structure +//! +//! The aux trace has one **accumulator** (col 0) and several **fraction columns** (cols 1+). +//! Each bus interaction on row `r` contributes a rational term `mᵢ / dᵢ` to one of the +//! columns. Because the verifier cannot check rational equations directly, each column +//! stores the *numerator–denominator pair* `(Nᵢ, Dᵢ)` — the cross-multiplied sum of all +//! interactions assigned to that column on row `r`. The constraints then check: +//! +//! - **Fraction columns** (i > 0): `Dᵢ · acc[i] - Nᵢ = 0` on transition rows. This asserts that the +//! prover-supplied value `acc[i]` equals `Nᵢ/Dᵢ`, the sum of fractions for column `i` on that +//! row. +//! +//! - **Accumulator** (col 0): the single running sum across the entire trace. +//! - `when_first: acc[0] = 0` — starts at zero. +//! - `when_transition: D₀ · (acc_next[0] - Σᵢ acc[i]) - N₀ = 0` — the next accumulator value +//! equals the current value plus every column's per-row contribution (including col 0's own +//! interactions folded via `N₀/D₀`). +//! - `when_last: acc[0] = committed_final` — binds the final sum to the value committed +//! during the Fiat-Shamir transcript, ensuring the global LogUp sum is correct. +//! +//! ## Algebra location +//! +//! Per Amendment B the per-interaction encoding lives inside each +//! [`LookupMessage::encode`] body, so the adapter carries **no scratch +//! buffer**: every `add` / `remove` / `insert` body is a two-liner that +//! calls `msg.encode(self.challenges)` and absorbs the resulting +//! `AB::ExprEF` denominator into the running `(V, U)` (group) or +//! `(N, D)` (batch) pair. +//! +//! The running-pair updates are also inlined at every call site (no +//! `absorb_single` / `absorb` helpers), which lets the `add` / `remove` +//! paths skip the `flag * E::ONE` / `flag * E::NEG_ONE` multiplication +//! — on the constraint path that shrinks the symbolic tree by one node +//! per single-interaction call. +//! +//! ## Challenge handling +//! +//! The top-level [`ConstraintLookupBuilder`] reads α/β out of +//! `ab.permutation_randomness()[0..2]` exactly once at construction time +//! and stores them in a [`Challenges`], which +//! precomputes both the β-power table (β⁰..β^(W-1)) and the bus-prefix +//! table (`bus_prefix[i] = α + (i + 1) · β^W`) sized from the +//! [`LookupAir`] passed to [`ConstraintLookupBuilder::new`]. The cached +//! challenges flow through the per-column / per-group handles by shared +//! reference, so each interaction sees the same precomputed tables +//! without reconstructing them. +//! +//! The permutation column slices are *not* cached — each +//! [`LookupBuilder::next_column`] call re-queries `ab.permutation()` to pick +//! up the current-row / next-row `VarEF` values. `ab.permutation()` is +//! cheap (it builds a window over references) and not caching keeps the +//! builder small. + +use core::marker::PhantomData; + +use miden_core::field::PrimeCharacteristicRing; +use miden_crypto::stark::air::{ExtensionBuilder, LiftedAirBuilder, WindowAccess}; + +use super::{ + Challenges, Deg, LookupAir, LookupBatch, LookupBuilder, LookupColumn, LookupGroup, + LookupMessage, +}; + +// CONSTRAINT LOOKUP BUILDER +// ================================================================================================ + +/// Constraint-path [`LookupBuilder`] over a wrapped [`LiftedAirBuilder`]. +/// +/// Column 0 is the sole running-sum accumulator; columns 1+ are fraction columns. +/// All constraints are emitted inline during [`LookupBuilder::next_column`]. +pub struct ConstraintLookupBuilder<'ab, AB> +where + AB: LiftedAirBuilder + 'ab, +{ + ab: &'ab mut AB, + challenges: Challenges, + column_idx: usize, +} + +impl<'ab, AB> ConstraintLookupBuilder<'ab, AB> +where + AB: LiftedAirBuilder, +{ + pub fn new(ab: &'ab mut AB, air: &A) -> Self + where + A: LookupAir, + { + let (alpha, beta): (AB::ExprEF, AB::ExprEF) = { + let r = ab.permutation_randomness(); + (r[0].into(), r[1].into()) + }; + let challenges = + Challenges::::new(alpha, beta, air.max_message_width(), air.num_bus_ids()); + + Self { ab, challenges, column_idx: 0 } + } +} + +impl<'ab, AB> LookupBuilder for ConstraintLookupBuilder<'ab, AB> +where + AB: LiftedAirBuilder, +{ + type F = AB::F; + type Expr = AB::Expr; + type Var = AB::Var; + + type EF = AB::EF; + type ExprEF = AB::ExprEF; + type VarEF = AB::VarEF; + + type PeriodicVar = AB::PeriodicVar; + + type MainWindow = AB::MainWindow; + + type Column<'a> + = ConstraintColumn<'a, AB> + where + Self: 'a, + AB: 'a; + + fn main(&self) -> Self::MainWindow { + self.ab.main() + } + + fn periodic_values(&self) -> &[Self::PeriodicVar] { + self.ab.periodic_values() + } + + fn next_column<'a, R>( + &'a mut self, + f: impl FnOnce(&mut Self::Column<'a>) -> R, + _deg: Deg, + ) -> R { + // Open the column with an empty `(V, U) = (0, 1)` accumulator. + // The column only holds a shared borrow of the challenges and + // the two running-pair slots — the `&mut AB` stays on the + // builder and is only reached back into for the constraint + // emission below. + let mut col = ConstraintColumn { + challenges: &self.challenges, + u: AB::ExprEF::ONE, + v: AB::ExprEF::ZERO, + _phantom: PhantomData, + }; + let result = f(&mut col); + let ConstraintColumn { u, v, .. } = col; + + // Pick up permutation column values now that the column borrow is released. + let col_idx = self.column_idx; + self.column_idx += 1; + + if col_idx == 0 { + let (acc, acc_next, committed_final) = { + let mp = self.ab.permutation(); + let acc: AB::ExprEF = mp.current_slice()[0].into(); + let acc_next: AB::ExprEF = mp.next_slice()[0].into(); + let committed_final: AB::ExprEF = self.ab.permutation_values()[0].clone().into(); + (acc, acc_next, committed_final) + }; + + // Σ_i acc[i] across all permutation columns. + let all_curr_sum = { + let mp = self.ab.permutation(); + let current = mp.current_slice(); + let mut sum: AB::ExprEF = current[0].into(); + for &aux_i in ¤t[1..] { + sum += aux_i.into(); + } + sum + }; + + // when_first: acc[0] = 0 + // when_transition: D₀ · (acc_next[0] - Σᵢ acc[i]) - N₀ = 0 + // when_last: acc[0] = committed_final + // + // The natural closing check would fold the last row's interactions into the + // boundary constraint, but `when_last_row`'s selector adds a polynomial factor + // that would push some columns past the degree budget. Our model assumes the + // last row never fires any interactions (V = 0, U = 1), so we use the + // lower-degree form: `acc − committed_final = 0`. The fraction columns below + // enforce this algebraically via `when_last_row acc[i] = 0`. + self.ab.when_first_row().assert_zero_ext(acc.clone()); + self.ab.when_transition().assert_zero_ext(u * (acc_next - all_curr_sum) - v); + self.ab.when_last_row().assert_eq_ext(acc, committed_final); + } else { + // when_transition: Dᵢ · acc[i] - Nᵢ = 0 + // when_last: acc[i] = 0 — no bus may fire on the padding row; this + // is the invariant col 0's closing check + // assumes. + let acc_curr: AB::ExprEF = { + let mp = self.ab.permutation(); + mp.current_slice()[col_idx].into() + }; + self.ab.when_transition().assert_zero_ext(u * acc_curr.clone() - v); + self.ab.when_last_row().assert_zero_ext(acc_curr); + } + + result + } +} + +// CONSTRAINT COLUMN +// ================================================================================================ + +/// Per-column handle returned by [`ConstraintLookupBuilder::next_column`]. +/// +/// Holds only the running `(V, U)` accumulator and a shared borrow of +/// the precomputed [`Challenges`]. The wrapped `&mut AB` and the +/// permutation `acc` / `acc_next` values do **not** live on the column +/// — the enclosing `next_column` method handles finalization +/// directly after the closure returns. +pub struct ConstraintColumn<'a, AB> +where + AB: LiftedAirBuilder + 'a, +{ + challenges: &'a Challenges, + u: AB::ExprEF, + v: AB::ExprEF, + _phantom: PhantomData, +} + +impl<'a, AB> ConstraintColumn<'a, AB> +where + AB: LiftedAirBuilder, +{ + /// Compose an inner-group `(V_g, U_g)` pair into this column's + /// running `(V, U)` using the cross-multiplication rule + /// `V ← V·U_g + V_g·U`, `U ← U·U_g`. + fn fold_group(&mut self, u_g: AB::ExprEF, v_g: AB::ExprEF) { + self.v = self.v.clone() * u_g.clone() + v_g * self.u.clone(); + self.u = self.u.clone() * u_g; + } +} + +impl<'a, AB> LookupColumn for ConstraintColumn<'a, AB> +where + AB: LiftedAirBuilder, +{ + type Expr = AB::Expr; + type ExprEF = AB::ExprEF; + + type Group<'g> + = ConstraintGroup<'g, AB> + where + Self: 'g, + AB: 'g; + + fn group<'g>( + &'g mut self, + _name: &'static str, + f: impl FnOnce(&mut Self::Group<'g>), + _deg: Deg, + ) { + let mut group = ConstraintGroup { + challenges: self.challenges, + u: AB::ExprEF::ONE, + v: AB::ExprEF::ZERO, + _phantom: PhantomData, + }; + f(&mut group); + let ConstraintGroup { u, v, .. } = group; + self.fold_group(u, v); + } + + fn group_with_cached_encoding<'g>( + &'g mut self, + _name: &'static str, + _canonical: impl FnOnce(&mut Self::Group<'g>), + encoded: impl FnOnce(&mut Self::Group<'g>), + _deg: Deg, + ) { + // Constraint path: only the `encoded` closure runs; the + // `canonical` closure is dropped unused. This matches the plan's + // split where `canonical` is the prover-path description. + let mut group = ConstraintGroup { + challenges: self.challenges, + u: AB::ExprEF::ONE, + v: AB::ExprEF::ZERO, + _phantom: PhantomData, + }; + encoded(&mut group); + let ConstraintGroup { u, v, .. } = group; + self.fold_group(u, v); + } +} + +// CONSTRAINT GROUP +// ================================================================================================ + +/// Per-group handle for the constraint path. +/// +/// Implements [`LookupGroup`] with working `beta_powers`, `bus_prefix`, +/// and `insert_encoded` overrides (the constraint path always has the +/// precomputed challenge tables available). +/// +/// Accumulates an internal `(V_g, U_g)` pair as the author calls +/// `add` / `remove` / `insert` / `batch`. The column consumes the pair +/// via `ConstraintColumn::fold_group` once the group closure returns. +/// +/// Each per-interaction `add` / `remove` / `insert` body calls +/// `msg.encode(self.challenges)` directly and folds the resulting +/// denominator into `(V_g, U_g)` inline — no intermediate scratch +/// buffer and no helper method call. +pub struct ConstraintGroup<'a, AB> +where + AB: LiftedAirBuilder + 'a, +{ + challenges: &'a Challenges, + u: AB::ExprEF, + v: AB::ExprEF, + _phantom: PhantomData, +} + +impl<'a, AB> LookupGroup for ConstraintGroup<'a, AB> +where + AB: LiftedAirBuilder, +{ + type Expr = AB::Expr; + type ExprEF = AB::ExprEF; + + type Batch<'b> + = ConstraintBatch<'b, AB> + where + Self: 'b, + AB: 'b; + + fn add(&mut self, _name: &'static str, flag: Self::Expr, msg: impl FnOnce() -> M, _deg: Deg) + where + M: LookupMessage, + { + // `add` = multiplicity +1. `V_g += flag · 1 = flag`, skipping + // the redundant multiplication that a generic `insert` would + // emit. + let v = msg().encode(self.challenges); + self.u += (v - AB::ExprEF::ONE) * flag.clone(); + self.v += flag; + } + + fn remove( + &mut self, + _name: &'static str, + flag: Self::Expr, + msg: impl FnOnce() -> M, + _deg: Deg, + ) where + M: LookupMessage, + { + // `remove` = multiplicity −1. `V_g += flag · (−1) = −flag`. + let v = msg().encode(self.challenges); + self.u += (v - AB::ExprEF::ONE) * flag.clone(); + self.v -= flag; + } + + fn insert( + &mut self, + _name: &'static str, + flag: Self::Expr, + multiplicity: Self::Expr, + msg: impl FnOnce() -> M, + _deg: Deg, + ) where + M: LookupMessage, + { + // General case: `V_g += flag · multiplicity`. + let v = msg().encode(self.challenges); + self.u += (v - AB::ExprEF::ONE) * flag.clone(); + self.v += flag * multiplicity; + } + + fn batch<'b>( + &'b mut self, + _name: &'static str, + flag: Self::Expr, + build: impl FnOnce(&mut Self::Batch<'b>), + _deg: Deg, + ) { + // Batch algebra: start with `(N, D) = (0, 1)`, run `build`, + // then fold the final `(N, D)` into `(V_g, U_g)` via + // `V_g += N · flag`, `U_g += (D − 1) · flag`. + let mut batch = ConstraintBatch { + challenges: self.challenges, + n: AB::ExprEF::ZERO, + d: AB::ExprEF::ONE, + _phantom: PhantomData, + }; + build(&mut batch); + let ConstraintBatch { n, d, .. } = batch; + self.u += (d - AB::ExprEF::ONE) * flag.clone(); + self.v += n * flag; + } + + fn beta_powers(&self) -> &[Self::ExprEF] { + &self.challenges.beta_powers[..] + } + + fn bus_prefix(&self, bus_id: usize) -> Self::ExprEF { + self.challenges.bus_prefix[bus_id].clone() + } + + fn insert_encoded( + &mut self, + _name: &'static str, + flag: Self::Expr, + multiplicity: Self::Expr, + encoded: impl FnOnce() -> Self::ExprEF, + _deg: Deg, + ) { + // Same `(V_g, U_g)` update as `insert`, but the denominator + // comes straight from the user's pre-computed closure instead + // of a `LookupMessage::encode` call. + let v = encoded(); + self.u += (v - AB::ExprEF::ONE) * flag.clone(); + self.v += flag * multiplicity; + } +} + +// CONSTRAINT BATCH +// ================================================================================================ + +/// Batch handle returned by [`LookupGroup::batch`]. +/// +/// Wraps an internal `(N, D)` pair and absorbs each interaction via the +/// cross-multiplication rule `N' = N·v + m·D`, `D' = D·v`. The +/// enclosing [`ConstraintGroup::batch`] folds the final `(N, D)` into +/// the group's `(V_g, U_g)` using the outer flag. +/// +/// Per-interaction encoding lives on the message itself +/// ([`LookupMessage::encode`]), and the `(N, D)` update is inlined at +/// every call site (no `absorb` helper) so the `add` / `remove` paths +/// can skip the `m · D` multiplication when `m = ±1`. +pub struct ConstraintBatch<'a, AB> +where + AB: LiftedAirBuilder + 'a, +{ + challenges: &'a Challenges, + n: AB::ExprEF, + d: AB::ExprEF, + _phantom: PhantomData, +} + +impl<'a, AB> LookupBatch for ConstraintBatch<'a, AB> +where + AB: LiftedAirBuilder, +{ + type Expr = AB::Expr; + type ExprEF = AB::ExprEF; + + fn add(&mut self, _name: &'static str, msg: M, _deg: Deg) + where + M: LookupMessage, + { + // `m = 1`: `(N, D) ← (N·v + D, D·v)`. Skips the `m · D` mul. + let v = msg.encode(self.challenges); + let d_prev = self.d.clone(); + self.n = self.n.clone() * v.clone() + d_prev; + self.d = self.d.clone() * v; + } + + fn remove(&mut self, _name: &'static str, msg: M, _deg: Deg) + where + M: LookupMessage, + { + // `m = −1`: `(N, D) ← (N·v − D, D·v)`. + let v = msg.encode(self.challenges); + let d_prev = self.d.clone(); + self.n = self.n.clone() * v.clone() - d_prev; + self.d = self.d.clone() * v; + } + + fn insert(&mut self, _name: &'static str, multiplicity: Self::Expr, msg: M, _deg: Deg) + where + M: LookupMessage, + { + // General case: `(N, D) ← (N·v + m·D, D·v)`. + let v = msg.encode(self.challenges); + let d_prev = self.d.clone(); + self.n = self.n.clone() * v.clone() + d_prev * multiplicity; + self.d = self.d.clone() * v; + } + + fn insert_encoded( + &mut self, + _name: &'static str, + multiplicity: Self::Expr, + encoded: impl FnOnce() -> Self::ExprEF, + _deg: Deg, + ) { + // Same as `insert`, but the denominator is a user-supplied + // pre-encoded `ExprEF` instead of a `LookupMessage::encode` + // call. + let v = encoded(); + let d_prev = self.d.clone(); + self.n = self.n.clone() * v.clone() + d_prev * multiplicity; + self.d = self.d.clone() * v; + } +} diff --git a/air/src/lookup/debug/mod.rs b/air/src/lookup/debug/mod.rs new file mode 100644 index 0000000000..5d7635c627 --- /dev/null +++ b/air/src/lookup/debug/mod.rs @@ -0,0 +1,19 @@ +//! Generic debug surface for the LogUp lookup-argument API. +//! +//! Split into two regimes: +//! +//! | Module | Regime | +//! |--------|--------| +//! | [`validation`] | AIR self-checks — run against the `LookupAir` itself, no execution trace needed. One entry point, [`validation::validate`] / `.validate()`. | +//! | [`trace`] | Concrete-trace debugging — balance accumulator + per-column `(V, U)` oracle folds + mutex checks over a real main trace. | + +pub mod trace; +pub mod validation; + +pub use trace::{ + BalanceReport, DebugBoundaryEmitter, DebugTraceBuilder, MutualExclusionViolation, Unmatched, + check_trace_balance, collect_column_oracle_folds, +}; +pub use validation::{ + ValidateLayout, ValidateLookupAir, ValidationBuilder, ValidationError, validate, +}; diff --git a/air/src/lookup/debug/trace/builder.rs b/air/src/lookup/debug/trace/builder.rs new file mode 100644 index 0000000000..d0cf84d59e --- /dev/null +++ b/air/src/lookup/debug/trace/builder.rs @@ -0,0 +1,416 @@ +//! `DebugTraceBuilder` — the `LookupBuilder` adapter that updates +//! [`super::DebugTraceState`] per row of a concrete main trace. +//! +//! Pure implementation detail: instantiation happens inside +//! `super::run_trace_walk`. The builder, column, group, and batch handles all collapse +//! their associated types to `Felt` / `QuadFelt`. + +use alloc::{format, string::ToString}; + +use miden_core::field::{PrimeCharacteristicRing, QuadFelt}; +use miden_crypto::stark::air::RowWindow; + +use super::{ + super::super::{ + BoundaryBuilder, Challenges, Deg, LookupBatch, LookupBuilder, LookupColumn, LookupGroup, + LookupMessage, + }, + DebugTraceState, MutualExclusionViolation, PushRecord, +}; +use crate::Felt; + +// BUILDER +// ================================================================================================ + +/// Real-trace `LookupBuilder` that updates [`super::DebugTraceState`] per row. +pub struct DebugTraceBuilder<'a> { + main: RowWindow<'a, Felt>, + periodic_values: &'a [Felt], + challenges: &'a Challenges, + state: &'a mut DebugTraceState, + row_idx: usize, + column_idx: usize, +} + +impl<'a> DebugTraceBuilder<'a> { + pub fn new( + main: RowWindow<'a, Felt>, + periodic_values: &'a [Felt], + challenges: &'a Challenges, + state: &'a mut DebugTraceState, + row_idx: usize, + ) -> Self { + Self { + main, + periodic_values, + challenges, + state, + row_idx, + column_idx: 0, + } + } +} + +impl<'a> LookupBuilder for DebugTraceBuilder<'a> { + type F = Felt; + type Expr = Felt; + type Var = Felt; + + type EF = QuadFelt; + type ExprEF = QuadFelt; + type VarEF = QuadFelt; + + type PeriodicVar = Felt; + + type MainWindow = RowWindow<'a, Felt>; + + type Column<'c> + = DebugTraceColumn<'c> + where + Self: 'c; + + fn main(&self) -> Self::MainWindow { + self.main + } + + fn periodic_values(&self) -> &[Self::PeriodicVar] { + self.periodic_values + } + + fn next_column<'c, R>( + &'c mut self, + f: impl FnOnce(&mut Self::Column<'c>) -> R, + _deg: Deg, + ) -> R { + let mut col = DebugTraceColumn { + challenges: self.challenges, + state: &mut *self.state, + row_idx: self.row_idx, + column_idx: self.column_idx, + next_group_idx: 0, + }; + let result = f(&mut col); + self.column_idx += 1; + result + } +} + +// COLUMN +// ================================================================================================ + +pub struct DebugTraceColumn<'c> { + challenges: &'c Challenges, + state: &'c mut DebugTraceState, + row_idx: usize, + column_idx: usize, + next_group_idx: usize, +} + +impl<'c> DebugTraceColumn<'c> { + /// Common path shared by `group` and `group_with_cached_encoding`. Opens a group, + /// drives the caller's closure, folds the group's `(V_g, U_g)` into the column's + /// running `(V_col, U_col)`, and (for cached-encoding groups) records any mutex + /// violation. + fn open_group<'g>( + &'g mut self, + is_cached_encoding: bool, + f: impl FnOnce(&mut DebugTraceGroup<'g>), + ) { + let group_idx = self.next_group_idx; + let column_idx = self.column_idx; + let row_idx = self.row_idx; + + let mut group = DebugTraceGroup { + challenges: self.challenges, + state: &mut *self.state, + u: QuadFelt::ONE, + v: QuadFelt::ZERO, + row_idx, + column_idx, + group_idx, + check_mutex: is_cached_encoding, + active_flag_count: 0, + }; + f(&mut group); + + if group.check_mutex && group.active_flag_count > 1 { + group.state.mutex_violations.push(MutualExclusionViolation { + row: row_idx, + column_idx, + group_idx, + active_flags: group.active_flag_count, + }); + } + // Fold `(V_g, U_g)` into `(V_col, U_col)`: (V, U) ← (V·U_g + V_g·U, U·U_g) + let (v_col, u_col) = group.state.column_folds[column_idx]; + group.state.column_folds[column_idx] = (v_col * group.u + group.v * u_col, u_col * group.u); + + self.next_group_idx += 1; + } +} + +impl<'c> LookupColumn for DebugTraceColumn<'c> { + type Expr = Felt; + type ExprEF = QuadFelt; + + type Group<'g> + = DebugTraceGroup<'g> + where + Self: 'g; + + fn group<'g>( + &'g mut self, + _name: &'static str, + f: impl FnOnce(&mut Self::Group<'g>), + _deg: Deg, + ) { + self.open_group(false, f); + } + + fn group_with_cached_encoding<'g>( + &'g mut self, + _name: &'static str, + canonical: impl FnOnce(&mut Self::Group<'g>), + _encoded: impl FnOnce(&mut Self::Group<'g>), + _deg: Deg, + ) { + // Run only the canonical closure: both closures must describe the same + // interaction set by contract (`DebugStructureBuilder` verifies their folds + // agree on sampled rows), and running both here would double-count balance + // multiplicities. + self.open_group(true, canonical); + } +} + +// GROUP +// ================================================================================================ + +pub struct DebugTraceGroup<'g> { + challenges: &'g Challenges, + state: &'g mut DebugTraceState, + u: QuadFelt, + v: QuadFelt, + row_idx: usize, + column_idx: usize, + group_idx: usize, + /// `true` for `group_with_cached_encoding` — triggers the mutex check at group close. + check_mutex: bool, + active_flag_count: usize, +} + +impl<'g> DebugTraceGroup<'g> { + /// Count active flags for mutex checks. Only meaningful when `check_mutex == true`, + /// but cheap enough to run unconditionally. + fn track_mutex(&mut self, flag: Felt) { + if self.check_mutex && flag != Felt::ZERO { + self.active_flag_count += 1; + } + } + + /// Push one `(multiplicity, denom)` into both the balance map and the push log, + /// with the group's current `(row, col, group)` source coordinates. + fn record(&mut self, msg_repr: alloc::string::String, denom: QuadFelt, multiplicity: Felt) { + *self.state.balances.entry(denom).or_insert(Felt::ZERO) += multiplicity; + self.state.push_log.push(PushRecord { + row: self.row_idx, + column_idx: self.column_idx, + group_idx: self.group_idx, + msg_repr, + denom, + multiplicity, + }); + } +} + +impl<'g> LookupGroup for DebugTraceGroup<'g> { + type Expr = Felt; + type ExprEF = QuadFelt; + + type Batch<'b> + = DebugTraceBatch<'b> + where + Self: 'b; + + fn insert( + &mut self, + _name: &'static str, + flag: Felt, + multiplicity: Felt, + msg: impl FnOnce() -> M, + _deg: Deg, + ) where + M: LookupMessage, + { + self.track_mutex(flag); + if flag == Felt::ZERO { + return; + } + let built = msg(); + let v_msg = built.encode(self.challenges); + self.record(format!("{built:?}"), v_msg, multiplicity); + self.u += (v_msg - QuadFelt::ONE) * flag; + self.v += flag * multiplicity; + } + + fn batch<'b>( + &'b mut self, + _name: &'static str, + flag: Felt, + build: impl FnOnce(&mut Self::Batch<'b>), + _deg: Deg, + ) { + self.track_mutex(flag); + let active = flag != Felt::ZERO; + let (n, d) = { + let mut batch = DebugTraceBatch { + challenges: self.challenges, + state: &mut *self.state, + active, + n: QuadFelt::ZERO, + d: QuadFelt::ONE, + row_idx: self.row_idx, + column_idx: self.column_idx, + group_idx: self.group_idx, + }; + build(&mut batch); + (batch.n, batch.d) + }; + self.u += (d - QuadFelt::ONE) * flag; + self.v += n * flag; + } + + fn beta_powers(&self) -> &[QuadFelt] { + &self.challenges.beta_powers[..] + } + + fn bus_prefix(&self, bus_id: usize) -> QuadFelt { + self.challenges.bus_prefix[bus_id] + } + + fn insert_encoded( + &mut self, + _name: &'static str, + flag: Felt, + multiplicity: Felt, + encoded: impl FnOnce() -> QuadFelt, + _deg: Deg, + ) { + self.track_mutex(flag); + if flag == Felt::ZERO { + return; + } + let v_msg = encoded(); + self.record("".to_string(), v_msg, multiplicity); + self.u += (v_msg - QuadFelt::ONE) * flag; + self.v += flag * multiplicity; + } +} + +// BATCH +// ================================================================================================ + +pub struct DebugTraceBatch<'b> { + challenges: &'b Challenges, + state: &'b mut DebugTraceState, + /// `false` if the outer group's flag was zero — batch-level short-circuit for balance + /// accumulation. `(N, D)` still tracks normally so the outer group's `(V_g, U_g)` fold + /// stays correct. + active: bool, + n: QuadFelt, + d: QuadFelt, + /// Source coordinates inherited from the enclosing group for push-log records. + row_idx: usize, + column_idx: usize, + group_idx: usize, +} + +impl<'b> DebugTraceBatch<'b> { + fn record(&mut self, msg_repr: alloc::string::String, denom: QuadFelt, multiplicity: Felt) { + *self.state.balances.entry(denom).or_insert(Felt::ZERO) += multiplicity; + self.state.push_log.push(PushRecord { + row: self.row_idx, + column_idx: self.column_idx, + group_idx: self.group_idx, + msg_repr, + denom, + multiplicity, + }); + } +} + +impl<'b> LookupBatch for DebugTraceBatch<'b> { + type Expr = Felt; + type ExprEF = QuadFelt; + + fn insert(&mut self, _name: &'static str, multiplicity: Felt, msg: M, _deg: Deg) + where + M: LookupMessage, + { + let v_msg = msg.encode(self.challenges); + if self.active { + self.record(format!("{msg:?}"), v_msg, multiplicity); + } + let d_prev = self.d; + self.n = self.n * v_msg + d_prev * multiplicity; + self.d *= v_msg; + } + + fn insert_encoded( + &mut self, + _name: &'static str, + multiplicity: Felt, + encoded: impl FnOnce() -> QuadFelt, + _deg: Deg, + ) { + let v_msg = encoded(); + if self.active { + self.record("".to_string(), v_msg, multiplicity); + } + let d_prev = self.d; + self.n = self.n * v_msg + d_prev * multiplicity; + self.d *= v_msg; + } +} + +// BOUNDARY EMITTER +// ================================================================================================ + +/// `BoundaryBuilder` impl that writes once-per-proof emissions into the same +/// [`DebugTraceState`] as the per-row `DebugTraceBuilder`. Emissions are tagged with +/// `row: usize::MAX` and `msg_repr` prefixed `[boundary:]` so they're visible +/// in the report as originating outside the trace. +pub struct DebugBoundaryEmitter<'a> { + pub(super) challenges: &'a Challenges, + pub(super) state: &'a mut DebugTraceState, + pub(super) public_values: &'a [Felt], + pub(super) var_len_public_inputs: &'a [&'a [Felt]], +} + +impl<'a> BoundaryBuilder for DebugBoundaryEmitter<'a> { + type F = Felt; + type EF = QuadFelt; + + fn public_values(&self) -> &[Felt] { + self.public_values + } + + fn var_len_public_inputs(&self) -> &[&[Felt]] { + self.var_len_public_inputs + } + + fn insert(&mut self, name: &'static str, multiplicity: Felt, msg: M) + where + M: LookupMessage, + { + let denom = msg.encode(self.challenges); + *self.state.balances.entry(denom).or_insert(Felt::ZERO) += multiplicity; + self.state.push_log.push(PushRecord { + row: usize::MAX, + column_idx: usize::MAX, + group_idx: usize::MAX, + msg_repr: format!("[boundary:{name}] {msg:?}"), + denom, + multiplicity, + }); + } +} diff --git a/air/src/lookup/debug/trace/mod.rs b/air/src/lookup/debug/trace/mod.rs new file mode 100644 index 0000000000..cc183bf71c --- /dev/null +++ b/air/src/lookup/debug/trace/mod.rs @@ -0,0 +1,309 @@ +//! Combined real-trace balance + per-column `(V, U)` oracle debug surface. +//! +//! One walk over a concrete main trace, row by row, produces three outputs projected +//! out of the shared `run_trace_walk` driver: +//! +//! - **Balance** — signed multiplicities keyed by encoded denominator. Any residual at the end of +//! the walk is an unmatched interaction. +//! - **Push log** — a [`PushRecord`] per interaction emission, capturing pre-encoding payload, +//! encoded denominator, signed multiplicity, and `(row, column, group)` source coordinates. +//! Joined back against the balance map at finalize time so each unmatched denominator lists the +//! exact pushes that summed to it. +//! - **Column oracle folds** — per-row per-column `(V_col, U_col)` pairs computed via the +//! constraint-path cross-multiplication rule, used by the processor's LogUp cross-check. +//! +//! Layout: +//! +//! - [`builder`] — the `DebugTraceBuilder` (plus column / group / batch handles) that drives each +//! per-row walk. +//! - This file — the report types ([`BalanceReport`], [`Unmatched`], [`PushRecord`], …), the +//! row-by-row `run_trace_walk` driver, and the two public entry points. + +use alloc::{string::String, vec, vec::Vec}; +use core::{borrow::Borrow, fmt}; +use std::collections::HashMap; + +use miden_core::{ + field::{PrimeCharacteristicRing, QuadFelt}, + utils::{Matrix, RowMajorMatrix}, +}; +use miden_crypto::stark::air::RowWindow; + +use super::super::{Challenges, LookupAir}; +use crate::Felt; + +pub mod builder; + +pub use builder::{ + DebugBoundaryEmitter, DebugTraceBatch, DebugTraceBuilder, DebugTraceColumn, DebugTraceGroup, +}; + +// REPORT TYPES +// ================================================================================================ + +/// An unmatched interaction: an encoded denom with non-zero net multiplicity after walking +/// the full trace. +#[derive(Debug, Clone)] +pub struct Unmatched { + pub denom: QuadFelt, + /// Net signed multiplicity modulo the field prime. + pub net_multiplicity: Felt, + /// Every push that landed on this encoded denominator during the walk, in emission + /// order. The caller can bucket these by `msg_repr` / column / row to isolate the + /// specific emit that left the denom unbalanced. + pub contributions: Vec, +} + +/// One interaction emission captured during a trace walk. +/// +/// Populated for every push that passes its flag check, regardless of whether the +/// interaction eventually balances. When a denom lands in [`BalanceReport::unmatched`], +/// the join against the push log shows exactly which emits (row, column, group, +/// payload) summed to the residual multiplicity. +#[derive(Debug, Clone)] +pub struct PushRecord { + pub row: usize, + pub column_idx: usize, + pub group_idx: usize, + /// `format!("{:?}", msg)` of the `LookupMessage` instance. `""` for + /// `insert_encoded` sites, where only the pre-computed denominator is known. + pub msg_repr: String, + pub denom: QuadFelt, + pub multiplicity: Felt, +} + +/// Per-row mutual-exclusion violation inside a cached-encoding group. +#[derive(Debug, Clone)] +pub struct MutualExclusionViolation { + pub row: usize, + pub column_idx: usize, + pub group_idx: usize, + pub active_flags: usize, +} + +/// Full report returned by [`check_trace_balance`]. +#[derive(Debug, Default)] +pub struct BalanceReport { + pub unmatched: Vec, + pub mutex_violations: Vec, +} + +impl BalanceReport { + pub fn is_ok(&self) -> bool { + self.unmatched.is_empty() && self.mutex_violations.is_empty() + } +} + +impl fmt::Display for BalanceReport { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// How many contributing pushes to print per unmatched denom before truncating. + const MAX_CONTRIB_LINES: usize = 4; + + if self.is_ok() { + return writeln!(f, "BalanceReport: OK"); + } + writeln!( + f, + "BalanceReport: {} unmatched, {} mutex violations", + self.unmatched.len(), + self.mutex_violations.len(), + )?; + for u in &self.unmatched { + writeln!(f, " denom {:?} net multiplicity {:?}", u.denom, u.net_multiplicity)?; + for r in u.contributions.iter().take(MAX_CONTRIB_LINES) { + writeln!( + f, + " row={} col={} group={} mult={:?} msg={}", + r.row, r.column_idx, r.group_idx, r.multiplicity, r.msg_repr, + )?; + } + if u.contributions.len() > MAX_CONTRIB_LINES { + writeln!( + f, + " … {} more contributions", + u.contributions.len() - MAX_CONTRIB_LINES, + )?; + } + } + for m in &self.mutex_violations { + writeln!( + f, + " mutex violation at row {} col {} group {}: {} active flags", + m.row, m.column_idx, m.group_idx, m.active_flags, + )?; + } + Ok(()) + } +} + +// STATE +// ================================================================================================ + +/// Scratch state threaded through [`DebugTraceBuilder`] for every row in the walk. The +/// driver creates one instance per walk; it resets `column_folds` at the start of each +/// row and keeps `balances` / `push_log` / `mutex_violations` accumulating across rows. +pub struct DebugTraceState { + /// Signed-multiplicity accumulator keyed by encoded denominator. Sorted at + /// finalize time for deterministic output. + pub(super) balances: HashMap, + /// Per-push record of every interaction emission. Joined against `balances` in + /// [`finalize`] so each unmatched denom carries its source pushes. + pub(super) push_log: Vec, + pub(super) mutex_violations: Vec, + /// Per-column `(V_col, U_col)`. Reset to `(ZERO, ONE)` at the start of each row by + /// [`run_trace_walk`]. + pub(super) column_folds: Vec<(QuadFelt, QuadFelt)>, +} + +// ENTRY POINTS +// ================================================================================================ + +/// Walk a complete main trace and return the balance report (unmatched interactions + +/// mutex violations). +/// +/// Includes boundary contributions from [`LookupAir::eval_boundary`], so a fully +/// closed AIR produces `BalanceReport::is_ok() == true`. `var_len_public_inputs` is +/// the same shape the prover hands to `miden_crypto::stark::prover::prove_single` +/// (e.g. `&[&kernel_felts]`); pass `&[]` if the AIR has no variable-length public +/// inputs or no boundary contributions that consume them. +pub fn check_trace_balance( + air: &A, + main_trace: &RowMajorMatrix, + periodic_columns: &[Vec], + public_values: &[Felt], + var_len_public_inputs: &[&[Felt]], + challenges: &Challenges, +) -> BalanceReport +where + for<'a> A: LookupAir>, +{ + run_trace_walk( + air, + main_trace, + periodic_columns, + public_values, + var_len_public_inputs, + challenges, + ) + .balance +} + +/// Walk a complete main trace and return the per-row constraint-path `(V_col, U_col)` +/// folds. `folds[r][col]` is the fold for column `col` at row `r`. +/// +/// Does not incorporate boundary contributions — the folds are a per-row property of +/// the main trace, independent of once-per-proof outer emissions. +pub fn collect_column_oracle_folds( + air: &A, + main_trace: &RowMajorMatrix, + periodic_columns: &[Vec], + public_values: &[Felt], + challenges: &Challenges, +) -> Vec> +where + for<'a> A: LookupAir>, +{ + run_trace_walk(air, main_trace, periodic_columns, public_values, &[], challenges).folds_per_row +} + +// SHARED DRIVER +// ================================================================================================ + +struct TraceWalkOutput { + balance: BalanceReport, + folds_per_row: Vec>, +} + +/// Shared row-by-row driver used by both public entry points. Each row gets a fresh +/// [`DebugTraceBuilder`] with column folds reset to `(ZERO, ONE)`; the balance accumulator +/// persists across rows, the folds snapshot at row end. +fn run_trace_walk( + air: &A, + main_trace: &RowMajorMatrix, + periodic_columns: &[Vec], + public_values: &[Felt], + var_len_public_inputs: &[&[Felt]], + challenges: &Challenges, +) -> TraceWalkOutput +where + for<'a> A: LookupAir>, +{ + let num_rows = main_trace.height(); + let width = main_trace.width(); + let flat: &[Felt] = main_trace.values.borrow(); + let num_cols = air.num_columns(); + + let mut state = DebugTraceState { + balances: HashMap::new(), + push_log: Vec::new(), + mutex_violations: Vec::new(), + column_folds: vec![(QuadFelt::ZERO, QuadFelt::ONE); num_cols], + }; + let mut folds_per_row: Vec> = Vec::with_capacity(num_rows); + let mut periodic_row: Vec = vec![Felt::ZERO; periodic_columns.len()]; + + for r in 0..num_rows { + let curr = &flat[r * width..(r + 1) * width]; + let nxt_idx = (r + 1) % num_rows; + let next = &flat[nxt_idx * width..(nxt_idx + 1) * width]; + let window = RowWindow::from_two_rows(curr, next); + + for (i, col) in periodic_columns.iter().enumerate() { + periodic_row[i] = col[r % col.len()]; + } + + // Reset per-row folds; balances and mutex_violations persist. + for fold in state.column_folds.iter_mut() { + *fold = (QuadFelt::ZERO, QuadFelt::ONE); + } + + { + let mut lb = DebugTraceBuilder::new(window, &periodic_row, challenges, &mut state, r); + air.eval(&mut lb); + } + + folds_per_row.push(state.column_folds.clone()); + } + + // Boundary / outer interactions (once per proof, no row): kernel init, block + // hash, log-precompile terminals, …. Accumulates into the same balance map as + // the per-row trace emissions — a fully closed AIR produces `is_ok() == true`. + { + let mut boundary = DebugBoundaryEmitter { + challenges, + state: &mut state, + public_values, + var_len_public_inputs, + }; + air.eval_boundary(&mut boundary); + } + + TraceWalkOutput { balance: finalize(state), folds_per_row } +} + +fn finalize(state: DebugTraceState) -> BalanceReport { + let DebugTraceState { balances, push_log, mutex_violations, .. } = state; + + // Group every push by its encoded denom so each unmatched denom can pull its + // contributing records in O(1). Preserves emission order within each bucket. + let mut contrib_by_denom: HashMap> = HashMap::new(); + for record in push_log { + contrib_by_denom.entry(record.denom).or_default().push(record); + } + + let mut unmatched = Vec::new(); + for (denom, net) in balances { + if net == Felt::ZERO { + continue; + } + let contributions = contrib_by_denom.remove(&denom).unwrap_or_default(); + unmatched.push(Unmatched { + denom, + net_multiplicity: net, + contributions, + }); + } + // Sort for deterministic output — `HashMap` iteration order is arbitrary. + unmatched.sort_by_key(|u| u.denom); + BalanceReport { unmatched, mutex_violations } +} diff --git a/air/src/lookup/debug/validation.rs b/air/src/lookup/debug/validation.rs new file mode 100644 index 0000000000..2aec7f9557 --- /dev/null +++ b/air/src/lookup/debug/validation.rs @@ -0,0 +1,673 @@ +//! Single AIR self-validation entry point, backed by one unified walker. +//! +//! Exposes one free function, [`validate`], and one extension trait, +//! [`ValidateLookupAir`], so any qualifying [`LookupAir`] can be checked with +//! `air.validate(layout)`. One short-circuit [`Result<(), ValidationError>`] covers: +//! +//! - `num_columns` declared vs observed (the walker counts `next_column` calls). +//! - Per-group and per-column `Deg { n, d }` declared vs observed (via +//! [`SymbolicExpression::degree_multiple`] on the running `(V, U)`). +//! - Cached-encoding canonical vs encoded `(V, U)` equivalence, checked by evaluating the symbolic +//! difference `U_c·V_e − U_e·V_c` at a random row. +//! - Simple-group scope: no illegal `insert_encoded` outside the `encoded` closure. +//! +//! The global max-degree budget is **not** checked here — the STARK prover's +//! quotient validation already enforces it and duplicating that check muddies +//! this module's purpose. + +use alloc::vec::Vec; +use core::{fmt, marker::PhantomData}; + +use miden_core::field::{PrimeCharacteristicRing, QuadFelt}; +use miden_crypto::{ + rand::random_felt, + stark::air::{ + AirBuilder, PeriodicAirBuilder, PermutationAirBuilder, + symbolic::{ + BaseEntry, BaseLeaf, ExtEntry, ExtLeaf, SymbolicAirBuilder, SymbolicExpr, + SymbolicExpression, SymbolicExpressionExt, SymbolicVariable, SymbolicVariableExt, + }, + }, +}; + +use super::super::{ + Challenges, Deg, LookupAir, LookupBatch, LookupBuilder, LookupColumn, LookupGroup, + LookupMessage, +}; +use crate::Felt; + +type Inner = SymbolicAirBuilder; +type Expr = SymbolicExpression; +type ExprEF = SymbolicExpressionExt; + +// VALIDATION ERROR +// ================================================================================================ + +/// First problem [`validate`] observed. See the module docstring for the per-check +/// semantics; each variant corresponds to one of the checks. +#[derive(Clone, Debug)] +pub enum ValidationError { + /// [`LookupAir::num_columns`] disagreed with the number of `next_column` calls + /// issued by `eval`. + NumColumnsMismatch { declared: usize, observed: usize }, + /// A column's declared `Deg` differs from the observed symbolic degree of + /// its accumulated `(V, U)`. Declared degrees are authoritative and must + /// match exactly — loose upper bounds are rejected. + ColumnDegreeMismatch { + column_idx: usize, + declared: Deg, + observed: Deg, + }, + /// A group's declared `Deg` differs from the observed symbolic degree of + /// the group's `(V, U)` fold. Declared degrees are authoritative and must + /// match exactly — loose upper bounds are rejected. + GroupDegreeMismatch { + column_idx: usize, + group_idx: usize, + name: &'static str, + declared: Deg, + observed: Deg, + }, + /// A cached-encoding group's canonical and encoded closures produced different + /// `(V, U)` pairs: the symbolic difference `V_c·U_e − V_e·U_c` evaluated to a + /// non-zero `QuadFelt` at the sampled random row. + EncodingMismatch { + column_idx: usize, + group_idx: usize, + name: &'static str, + diff: QuadFelt, + }, + /// A simple-mode group called `insert_encoded`, which is only legal inside the + /// `encoded` closure of `group_with_cached_encoding`. + ScopeViolation { + column_idx: usize, + group_idx: usize, + name: &'static str, + }, +} + +impl fmt::Display for ValidationError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::NumColumnsMismatch { declared, observed } => { + write!(f, "num_columns mismatch: declared {declared}, observed {observed}") + }, + Self::ColumnDegreeMismatch { column_idx, declared, observed } => write!( + f, + "column[{column_idx}] degree mismatch: declared (v={}, u={}), observed (v={}, u={})", + declared.v, declared.u, observed.v, observed.u, + ), + Self::GroupDegreeMismatch { + column_idx, + group_idx, + name, + declared, + observed, + } => write!( + f, + "column[{column_idx}] group[{group_idx}] {name:?} degree mismatch: declared (v={}, u={}), observed (v={}, u={})", + declared.v, declared.u, observed.v, observed.u, + ), + Self::EncodingMismatch { column_idx, group_idx, name, diff } => write!( + f, + "column[{column_idx}] group[{group_idx}] {name:?} cached-encoding mismatch: V_c·U_e − V_e·U_c = {diff:?}", + ), + Self::ScopeViolation { column_idx, group_idx, name } => write!( + f, + "column[{column_idx}] group[{group_idx}] {name:?} simple group called insert_encoded", + ), + } + } +} + +// LAYOUT +// ================================================================================================ + +/// Subset of the full `AirLayout` struct that [`validate`] actually consumes. Kept +/// local so callers don't need to thread prover-only fields (permutation width, +/// committed final count) through just to run the self-check. +#[derive(Clone, Copy, Debug)] +pub struct ValidateLayout { + pub trace_width: usize, + pub num_public_values: usize, + pub num_periodic_columns: usize, + pub permutation_width: usize, + pub num_permutation_challenges: usize, + pub num_permutation_values: usize, +} + +impl ValidateLayout { + fn to_symbolic(self) -> miden_crypto::stark::air::symbolic::AirLayout { + miden_crypto::stark::air::symbolic::AirLayout { + preprocessed_width: 0, + main_width: self.trace_width, + num_public_values: self.num_public_values, + permutation_width: self.permutation_width, + num_permutation_challenges: self.num_permutation_challenges, + num_permutation_values: self.num_permutation_values, + num_periodic_columns: self.num_periodic_columns, + } + } +} + +// VALIDATE +// ================================================================================================ + +/// Run every AIR self-check in one walk. +/// +/// Short-circuits on the first problem. See [`ValidationError`] for the variants. +pub fn validate(air: &A, layout: ValidateLayout) -> Result<(), ValidationError> +where + for<'ab, 'r> A: LookupAir>, +{ + // Sample a single random row valuation shared by the symbolic and concrete + // sides. `alpha`/`beta` are instantiated twice: once as symbolic `Challenge` + // leaves inside `SymbolicAirBuilder::permutation_randomness`, and once as + // concrete `QuadFelt`s in `row_valuation`. The evaluator below maps + // `ExtEntry::Challenge { index: 0/1 }` back to these concrete values. + let current: Vec = (0..layout.trace_width).map(|_| random_felt()).collect(); + let next: Vec = (0..layout.trace_width).map(|_| random_felt()).collect(); + let periodic: Vec = (0..layout.num_periodic_columns).map(|_| random_felt()).collect(); + let alpha = QuadFelt::new([random_felt(), random_felt()]); + let beta = QuadFelt::new([random_felt(), random_felt()]); + + let mut sym = SymbolicAirBuilder::::new(layout.to_symbolic()); + let row_valuation = RowValuation { + current: ¤t, + next: &next, + periodic: &periodic, + alpha, + beta, + }; + let mut builder = ValidationBuilder::new(&mut sym, air, row_valuation); + air.eval(&mut builder); + match builder.take_error() { + Some(err) => Err(err), + None => Ok(()), + } +} + +// EXTENSION TRAIT +// ================================================================================================ + +/// Extension trait that adapts [`validate`] into a method on any qualifying +/// [`LookupAir`]. Call sites write `MyLookupAir.validate(layout)` instead of +/// `validate(&MyLookupAir, layout)`. +pub trait ValidateLookupAir { + fn validate(&self, layout: ValidateLayout) -> Result<(), ValidationError>; +} + +impl ValidateLookupAir for A +where + for<'ab, 'r> A: LookupAir>, +{ + fn validate(&self, layout: ValidateLayout) -> Result<(), ValidationError> { + validate(self, layout) + } +} + +// ROW VALUATION +// ================================================================================================ + +/// Concrete valuation used to evaluate symbolic `(V, U)` trees when the walker +/// needs a numeric answer (cached-encoding equivalence). +#[derive(Clone, Copy)] +struct RowValuation<'r> { + current: &'r [Felt], + next: &'r [Felt], + periodic: &'r [Felt], + /// `Challenge[0]` in any `SymbolicExpressionExt` tree. + alpha: QuadFelt, + /// `Challenge[1]` in any `SymbolicExpressionExt` tree. + beta: QuadFelt, +} + +impl<'r> RowValuation<'r> { + fn eval_base(&self, expr: &Expr) -> Felt { + match expr { + SymbolicExpr::Leaf(leaf) => self.eval_base_leaf(leaf), + SymbolicExpr::Add { x, y, .. } => self.eval_base(x) + self.eval_base(y), + SymbolicExpr::Sub { x, y, .. } => self.eval_base(x) - self.eval_base(y), + SymbolicExpr::Neg { x, .. } => -self.eval_base(x), + SymbolicExpr::Mul { x, y, .. } => self.eval_base(x) * self.eval_base(y), + } + } + + fn eval_base_leaf(&self, leaf: &BaseLeaf) -> Felt { + match leaf { + BaseLeaf::Constant(c) => *c, + BaseLeaf::Variable(SymbolicVariable { entry, index, .. }) => match entry { + BaseEntry::Main { offset: 0 } => self.current[*index], + BaseEntry::Main { offset: 1 } => self.next[*index], + BaseEntry::Periodic => self.periodic[*index], + BaseEntry::Main { offset } => { + panic!("unexpected main offset {offset} in LookupAir::eval") + }, + // LookupBuilder doesn't expose preprocessed or public values, and + // LookupAir::eval can't construct these leaves. + BaseEntry::Preprocessed { .. } | BaseEntry::Public => { + panic!("unexpected {entry:?} leaf in LookupAir::eval") + }, + }, + // Selector leaves are only produced by `AirBuilder::is_first_row` / etc., + // which LookupBuilder does not expose. + BaseLeaf::IsFirstRow | BaseLeaf::IsLastRow | BaseLeaf::IsTransition => { + panic!("selector leaf {leaf:?} unexpected in LookupAir::eval") + }, + } + } + + fn eval_ext(&self, expr: &ExprEF) -> QuadFelt { + match expr { + SymbolicExpr::Leaf(leaf) => self.eval_ext_leaf(leaf), + SymbolicExpr::Add { x, y, .. } => self.eval_ext(x) + self.eval_ext(y), + SymbolicExpr::Sub { x, y, .. } => self.eval_ext(x) - self.eval_ext(y), + SymbolicExpr::Neg { x, .. } => -self.eval_ext(x), + SymbolicExpr::Mul { x, y, .. } => self.eval_ext(x) * self.eval_ext(y), + } + } + + fn eval_ext_leaf(&self, leaf: &ExtLeaf) -> QuadFelt { + match leaf { + ExtLeaf::Base(inner) => self.eval_base(inner).into(), + ExtLeaf::ExtConstant(c) => *c, + ExtLeaf::ExtVariable(SymbolicVariableExt { entry, index, .. }) => match entry { + ExtEntry::Challenge => match *index { + 0 => self.alpha, + 1 => self.beta, + i => panic!("unexpected challenge index {i} in LookupAir::eval"), + }, + // LookupBuilder doesn't expose permutation columns or permutation + // values — the prover-side builder is the only one that touches them. + ExtEntry::Permutation { .. } | ExtEntry::PermutationValue => { + panic!("unexpected {entry:?} leaf in LookupAir::eval") + }, + }, + } + } +} + +// BUILDER +// ================================================================================================ + +/// Unified walker that cross-checks `(V, U)` degrees, cached-encoding equivalence, +/// and simple-group scope in a single pass over [`LookupAir::eval`]. The first +/// error observed is preserved in an internal slot; any later problem is ignored +/// so [`validate`] can short-circuit cleanly once `eval` returns. +pub struct ValidationBuilder<'ab, 'r> { + ab: &'ab mut Inner, + sym_challenges: Challenges, + row_valuation: RowValuation<'r>, + column_idx: usize, + declared_columns: usize, + error: Option, +} + +impl<'ab, 'r> ValidationBuilder<'ab, 'r> { + fn new(ab: &'ab mut Inner, air: &A, row_valuation: RowValuation<'r>) -> Self + where + A: LookupAir, + { + let (alpha, beta): (ExprEF, ExprEF) = { + let r = ab.permutation_randomness(); + (r[0].into(), r[1].into()) + }; + let sym_challenges = + Challenges::::new(alpha, beta, air.max_message_width(), air.num_bus_ids()); + Self { + ab, + sym_challenges, + row_valuation, + column_idx: 0, + declared_columns: air.num_columns(), + error: None, + } + } + + fn take_error(mut self) -> Option { + if self.error.is_none() && self.column_idx != self.declared_columns { + self.error = Some(ValidationError::NumColumnsMismatch { + declared: self.declared_columns, + observed: self.column_idx, + }); + } + self.error + } +} + +impl<'ab, 'r> LookupBuilder for ValidationBuilder<'ab, 'r> { + type F = Felt; + type Expr = Expr; + type Var = SymbolicVariable; + + type EF = QuadFelt; + type ExprEF = ExprEF; + type VarEF = SymbolicVariableExt; + + type PeriodicVar = SymbolicVariable; + + type MainWindow = ::MainWindow; + + type Column<'c> + = ValidationColumn<'c, 'r> + where + Self: 'c; + + fn main(&self) -> Self::MainWindow { + self.ab.main() + } + + fn periodic_values(&self) -> &[Self::PeriodicVar] { + self.ab.periodic_values() + } + + fn next_column<'c, R>(&'c mut self, f: impl FnOnce(&mut Self::Column<'c>) -> R, deg: Deg) -> R { + let column_idx = self.column_idx; + self.column_idx += 1; + + let already_errored = self.error.is_some(); + let mut col = ValidationColumn { + challenges: &self.sym_challenges, + row_valuation: self.row_valuation, + u: ExprEF::ONE, + v: ExprEF::ZERO, + column_idx, + next_group_idx: 0, + error: None, + _phantom: PhantomData, + }; + let result = f(&mut col); + + if !already_errored { + if let Some(err) = col.error.take() { + self.error = Some(err); + } else { + let observed = Deg { + v: col.v.degree_multiple(), + u: col.u.degree_multiple(), + }; + if observed != deg { + self.error = Some(ValidationError::ColumnDegreeMismatch { + column_idx, + declared: deg, + observed, + }); + } + } + } + + result + } +} + +// COLUMN +// ================================================================================================ + +pub struct ValidationColumn<'c, 'r> { + challenges: &'c Challenges, + row_valuation: RowValuation<'r>, + u: ExprEF, + v: ExprEF, + column_idx: usize, + next_group_idx: usize, + /// First group-level error observed while walking this column, drained by + /// [`ValidationBuilder::next_column`] after the closure returns. + error: Option, + _phantom: PhantomData<&'c ()>, +} + +impl<'c, 'r> ValidationColumn<'c, 'r> { + fn fold_group(&mut self, u_g: ExprEF, v_g: ExprEF) { + self.v = self.v.clone() * u_g.clone() + v_g * self.u.clone(); + self.u = self.u.clone() * u_g; + } + + fn check_group_degree( + &mut self, + name: &'static str, + group_idx: usize, + declared: Deg, + u: &ExprEF, + v: &ExprEF, + ) { + if self.error.is_some() { + return; + } + let observed = Deg { + v: v.degree_multiple(), + u: u.degree_multiple(), + }; + if observed != declared { + self.error = Some(ValidationError::GroupDegreeMismatch { + column_idx: self.column_idx, + group_idx, + name, + declared, + observed, + }); + } + } +} + +/// Build a fresh group scoped to `challenges`. Taken as a free function (not a +/// method) so calling it doesn't borrow the containing `ValidationColumn` — +/// the caller can still mutate `self.error` while the group is alive. +fn fresh_group<'g>( + challenges: &'g Challenges, + inside_encoded_closure: bool, +) -> ValidationGroup<'g> { + ValidationGroup { + challenges, + u: ExprEF::ONE, + v: ExprEF::ZERO, + inside_encoded_closure, + used_insert_encoded: false, + } +} + +impl<'c, 'r> LookupColumn for ValidationColumn<'c, 'r> { + type Expr = Expr; + type ExprEF = ExprEF; + + type Group<'g> + = ValidationGroup<'g> + where + Self: 'g; + + fn group<'g>(&'g mut self, name: &'static str, f: impl FnOnce(&mut Self::Group<'g>), deg: Deg) { + let group_idx = self.next_group_idx; + self.next_group_idx += 1; + + let mut group = fresh_group(self.challenges, false); + f(&mut group); + let ValidationGroup { u, v, used_insert_encoded, .. } = group; + + if self.error.is_none() && used_insert_encoded { + self.error = Some(ValidationError::ScopeViolation { + column_idx: self.column_idx, + group_idx, + name, + }); + } + self.check_group_degree(name, group_idx, deg, &u, &v); + self.fold_group(u, v); + } + + fn group_with_cached_encoding<'g>( + &'g mut self, + name: &'static str, + canonical: impl FnOnce(&mut Self::Group<'g>), + encoded: impl FnOnce(&mut Self::Group<'g>), + deg: Deg, + ) { + let group_idx = self.next_group_idx; + self.next_group_idx += 1; + + let mut canon = fresh_group(self.challenges, false); + canonical(&mut canon); + + let mut enc = fresh_group(self.challenges, true); + encoded(&mut enc); + + // Cached-encoding equivalence: the two closures must agree on `(V, U)` + // up to cross-multiplication, i.e. `V_c·U_e − V_e·U_c == 0`. We don't + // rely on symbolic simplification to zero — we evaluate the difference + // at the shared random row. + if self.error.is_none() { + let diff_expr = canon.v.clone() * enc.u.clone() - enc.v.clone() * canon.u; + let diff = self.row_valuation.eval_ext(&diff_expr); + if diff != QuadFelt::ZERO { + self.error = Some(ValidationError::EncodingMismatch { + column_idx: self.column_idx, + group_idx, + name, + diff, + }); + } + } + + // Degree check and column fold use the `encoded` half, consistent with + // the production constraint path which only emits the encoded form. + let ValidationGroup { u, v, .. } = enc; + self.check_group_degree(name, group_idx, deg, &u, &v); + self.fold_group(u, v); + } +} + +// GROUP +// ================================================================================================ + +pub struct ValidationGroup<'g> { + challenges: &'g Challenges, + u: ExprEF, + v: ExprEF, + /// Set when this group was opened via the `encoded` closure of + /// `group_with_cached_encoding`; toggles the legal use of `insert_encoded`. + inside_encoded_closure: bool, + /// `true` if `insert_encoded` was called outside its legal scope. The column + /// inspects this flag at close time and raises `ScopeViolation` if the group + /// was simple. + used_insert_encoded: bool, +} + +impl<'g> LookupGroup for ValidationGroup<'g> { + type Expr = Expr; + type ExprEF = ExprEF; + + type Batch<'b> + = ValidationBatch<'b> + where + Self: 'b; + + fn add(&mut self, _name: &'static str, flag: Expr, msg: impl FnOnce() -> M, _deg: Deg) + where + M: LookupMessage, + { + let v_msg = msg().encode(self.challenges); + self.u += (v_msg - ExprEF::ONE) * flag.clone(); + self.v += flag; + } + + fn remove(&mut self, _name: &'static str, flag: Expr, msg: impl FnOnce() -> M, _deg: Deg) + where + M: LookupMessage, + { + let v_msg = msg().encode(self.challenges); + self.u += (v_msg - ExprEF::ONE) * flag.clone(); + self.v -= flag; + } + + fn insert( + &mut self, + _name: &'static str, + flag: Expr, + multiplicity: Expr, + msg: impl FnOnce() -> M, + _deg: Deg, + ) where + M: LookupMessage, + { + let v_msg = msg().encode(self.challenges); + self.u += (v_msg - ExprEF::ONE) * flag.clone(); + self.v += flag * multiplicity; + } + + fn batch<'b>( + &'b mut self, + _name: &'static str, + flag: Expr, + build: impl FnOnce(&mut Self::Batch<'b>), + _deg: Deg, + ) { + let mut batch = ValidationBatch { + challenges: self.challenges, + n: ExprEF::ZERO, + d: ExprEF::ONE, + }; + build(&mut batch); + let ValidationBatch { n, d, .. } = batch; + self.u += (d - ExprEF::ONE) * flag.clone(); + self.v += n * flag; + } + + fn beta_powers(&self) -> &[ExprEF] { + &self.challenges.beta_powers[..] + } + + fn bus_prefix(&self, bus_id: usize) -> ExprEF { + self.challenges.bus_prefix[bus_id].clone() + } + + fn insert_encoded( + &mut self, + _name: &'static str, + flag: Expr, + multiplicity: Expr, + encoded: impl FnOnce() -> ExprEF, + _deg: Deg, + ) { + if !self.inside_encoded_closure { + self.used_insert_encoded = true; + } + let v_msg = encoded(); + self.u += (v_msg - ExprEF::ONE) * flag.clone(); + self.v += flag * multiplicity; + } +} + +// BATCH +// ================================================================================================ + +pub struct ValidationBatch<'b> { + challenges: &'b Challenges, + n: ExprEF, + d: ExprEF, +} + +impl<'b> LookupBatch for ValidationBatch<'b> { + type Expr = Expr; + type ExprEF = ExprEF; + + fn insert(&mut self, _name: &'static str, multiplicity: Expr, msg: M, _deg: Deg) + where + M: LookupMessage, + { + let v_msg = msg.encode(self.challenges); + let d_prev = self.d.clone(); + self.n = self.n.clone() * v_msg.clone() + d_prev * multiplicity; + self.d = self.d.clone() * v_msg; + } + + fn insert_encoded( + &mut self, + _name: &'static str, + multiplicity: Expr, + encoded: impl FnOnce() -> ExprEF, + _deg: Deg, + ) { + let v_msg = encoded(); + let d_prev = self.d.clone(); + self.n = self.n.clone() * v_msg.clone() + d_prev * multiplicity; + self.d = self.d.clone() * v_msg; + } +} diff --git a/air/src/lookup/message.rs b/air/src/lookup/message.rs new file mode 100644 index 0000000000..92d57bbe24 --- /dev/null +++ b/air/src/lookup/message.rs @@ -0,0 +1,42 @@ +//! Bus-message encoding contract for the closure-based lookup API. +//! +//! Each message encodes itself against borrowed [`Challenges`]. +//! +//! ## Encoding contract +//! +//! Given a reference to [`Challenges`](crate::lookup::Challenges), a message produces +//! the denominator +//! +//! ```text +//! bus_prefix[bus] + Σ_{k=0..width} β^k · values[k] +//! ``` +//! +//! where `bus_prefix[i] = α + (i + 1) · β^W` is precomputed at builder construction time +//! and `W = MAX_MESSAGE_WIDTH`. Interaction-specific bus prefixes also provide domain +//! separation; payloads then begin directly at `β⁰`. + +use miden_core::field::{Algebra, PrimeCharacteristicRing}; + +use crate::lookup::Challenges; + +// TRAIT +// ================================================================================================ + +/// A bus message: encodes itself as a LogUp denominator against a borrowed +/// [`Challenges`] table. +/// +/// `E` is the base-field expression type (typically `AB::Expr` on the constraint path and +/// `F` on the prover path); `EF` is the matching extension-field expression type +/// (`AB::ExprEF` / `EF` respectively). The [`Algebra`] bound on `EF` lets each message +/// multiply a base-field payload by an `EF`-typed β-power without manually lifting. +/// +/// Implementors start from the selected bus prefix and fold each payload value +/// against `challenges.beta_powers[k]`. +pub trait LookupMessage: core::fmt::Debug +where + E: PrimeCharacteristicRing + Clone, + EF: PrimeCharacteristicRing + Clone + Algebra, +{ + /// Encode this message as a LogUp denominator. See module docs for the encoding contract. + fn encode(&self, challenges: &Challenges) -> EF; +} diff --git a/air/src/lookup/mod.rs b/air/src/lookup/mod.rs new file mode 100644 index 0000000000..59255ecc9d --- /dev/null +++ b/air/src/lookup/mod.rs @@ -0,0 +1,113 @@ +//! Generic `LookupAir` / `LookupBuilder` lookup-argument module. +//! +//! Holds the field-polymorphic core of the closure-based LogUp machinery: the +//! [`LookupAir`] trait, the [`LookupBuilder`] / [`LookupColumn`] / [`LookupGroup`] / +//! [`LookupBatch`] surface, the [`Challenges`] struct, the [`LookupMessage`] encode trait, +//! the two-path adapters ([`ConstraintLookupBuilder`] for symbolic constraint +//! evaluation, [`ProverLookupBuilder`] for concrete-row fraction collection), the +//! [`LookupFractions`] accumulator, and the [`build_logup_aux_trace`] / +//! [`build_lookup_fractions`] drivers. +//! +//! This module is deliberately free of Miden-specific types so it can be extracted into +//! its own crate without further disentangling. The Miden-side wiring (aggregator AIR, +//! bus message structs, aux-trace builder, bus identifiers) is surfaced separately +//! through [`crate::logup`]. + +pub mod aux_builder; +pub mod builder; +pub mod challenges; +pub mod constraint; +#[cfg(feature = "std")] +pub mod debug; +pub mod message; +pub mod prover; + +pub use aux_builder::{LookupFractions, accumulate, accumulate_slow, build_logup_aux_trace}; +pub use builder::{BoundaryBuilder, Deg, LookupBatch, LookupBuilder, LookupColumn, LookupGroup}; +pub use challenges::Challenges; +pub use constraint::ConstraintLookupBuilder; +pub use message::LookupMessage; +pub use prover::{ProverLookupBuilder, build_lookup_fractions}; + +// LOOKUP AIR +// ================================================================================================ + +/// A declarative LogUp lookup argument. +/// +/// Shaped the same way as `p3_air::Air`: generic over the builder +/// the caller picks, and evaluated once per logical "row pair" (the +/// constraint path visits every row symbolically, the prover path visits +/// every concrete row). +/// +/// The trait carries both the static *shape* (column count, payload +/// width bound, bus-id upper bound) and the `eval` method that actually +/// emits the interactions. Adapter constructors take a `&impl +/// LookupAir` and read the shape via the trait — the `LB` type +/// parameter is pinned to the adapter itself, so there is no +/// ambiguity when the blanket `impl LookupAir +/// for MyAir` implementations apply. +/// +/// ## Contract +/// +/// - [`num_columns()`](Self::num_columns) must match the number of `LookupBuilder::next_column` +/// calls issued from [`eval`](Self::eval) — the adapter advances its internal column index each +/// time the closure returns and will panic (or produce undefined constraints) on a mismatch. +/// - [`max_message_width()`](Self::max_message_width) must be ≥ the widest payload any message in +/// the AIR emits. It counts **only** contiguous payload slots — the bus identifier is handled +/// separately through the precomputed bus-prefix table. +/// - [`num_bus_ids()`](Self::num_bus_ids) must be ≥ the largest bus ID any message in the AIR +/// emits, plus one; the adapter precomputes exactly that many bus prefixes and indexes into the +/// table with `bus_id as usize`. +pub trait LookupAir { + /// Number of permutation columns this argument occupies. + fn num_columns(&self) -> usize; + + /// Per-column upper bound on the number of fractions a single row can push. + /// + /// Length must equal [`num_columns()`](Self::num_columns). Each entry is the + /// **mutual-exclusion-aware** max — i.e. the largest active branch count taken across + /// all mutually exclusive groups inside the column, not the sum of every structural + /// `add` / `remove` / `insert` / `batch` push site. + /// + /// The prover-path adapter uses this to size the dense per-column fraction buffer + /// (`Vec::with_capacity`) so the hot row loop never re-allocates. + fn column_shape(&self) -> &[usize]; + + /// Upper bound on the **payload** width of any message emitted by + /// [`eval`](Self::eval), exclusive of the bus identifier slot. + fn max_message_width(&self) -> usize; + + /// Upper bound on any bus ID this AIR emits through + /// [`LookupMessage::encode`], + /// plus one. The adapter pre-computes that many bus prefixes at + /// construction time and indexes into the table with + /// `bus_id as usize`. + fn num_bus_ids(&self) -> usize; + + /// Evaluate the lookup argument, describing its interactions through + /// the builder's closure API. + fn eval(&self, builder: &mut LB); + + /// Emit boundary / "outer" interactions — once-per-proof contributions that don't + /// come from any main-trace row. + /// + /// Typical sources are committed-final terminals and public-input-driven seed + /// emissions (kernel ROM init, block hash seed, log-precompile terminals). + /// These close out buses whose per-row [`eval`](Self::eval) contributions alone + /// don't cancel. + /// + /// Consumed today only by the real-trace debug walker in + /// [`crate::lookup::debug::trace`], which combines per-row and boundary emissions + /// into a single balance check. The constraint and prover paths don't call this + /// method yet — boundary terms still flow through `when_first_row` / `when_last_row` + /// flag selectors inside [`eval`](Self::eval) until they are refactored to read + /// from here too. + /// + /// Default is a no-op so AIRs with no boundary contributions don't need to + /// override it. + fn eval_boundary(&self, _boundary: &mut B) + where + B: BoundaryBuilder, + { + } +} diff --git a/air/src/lookup/prover.rs b/air/src/lookup/prover.rs new file mode 100644 index 0000000000..bb4c33a19e --- /dev/null +++ b/air/src/lookup/prover.rs @@ -0,0 +1,654 @@ +//! Prover-path adapter — pushes individual `(m, v)` fractions per +//! interaction into a dense per-column flat [`LookupFractions`] buffer +//! owned by the caller. +//! +//! Implements [`LookupBuilder`] for concrete base-field rows. Where the +//! [constraint-path adapter](super::constraint::ConstraintLookupBuilder) +//! emits symbolic `(V, U)` constraint expressions against a +//! `LiftedAirBuilder`, this adapter consumes two concrete rows of +//! base-field values and **pushes the individual fractions** each +//! interaction contributes — one `(multiplicity, denominator)` entry per +//! active interaction, appended to the current column's flat Vec inside +//! [`LookupFractions`]. +//! +//! ## Runtime shape +//! +//! The caller: +//! +//! 1. Builds one [`Challenges`] once, outside the per-row loop. +//! 2. Allocates one [`LookupFractions`] once via [`LookupFractions::from_shape`], sized from +//! [`LookupAir::column_shape`]. Each column's internal Vec is `Vec::with_capacity(num_rows * +//! shape[col])` so pushes in the row loop never re-allocate. +//! 3. For each row pair, constructs a `ProverLookupBuilder` (cheap — just stores pointers), calls +//! `air.eval(&mut lb)`, then drops the builder. `column(f)` records how many fractions the row +//! pushed into `LookupFractions::counts_per_row[col]`, so the downstream accumulator can later +//! slice each row's contribution out via a running cursor without a separate offsets array. +//! +//! ## Flag-zero skip +//! +//! `add` / `remove` / `insert` short-circuit on `flag == F::ZERO`, +//! avoiding both the `msg.encode()` call and the Vec push when the +//! interaction is inactive. `batch(flag, build)` sets an `active` bit on +//! the child `ProverBatch` so individual pushes inside the batch skip +//! work together when the outer flag is zero. +//! +//! ## Encoded-group collapse +//! +//! Per the plan (§Prover-path adapter) the cached-encoding split is +//! collapsed on the prover side: [`LookupColumn::group`] and +//! [`LookupColumn::group_with_cached_encoding`] both open a +//! [`ProverGroup`] against the same column fraction `Vec`, and the +//! cached-encoding variant runs only the `canonical` closure (the +//! `encoded` closure is dropped unused, since the canonical description +//! is always the cheapest path for concrete rows). + +use alloc::{vec, vec::Vec}; +use core::borrow::Borrow; + +use miden_core::{ + field::{ExtensionField, Field}, + utils::{Matrix, RowMajorMatrix}, +}; +use miden_crypto::stark::air::RowWindow; + +use super::{ + Challenges, Deg, LookupAir, LookupBatch, LookupBuilder, LookupColumn, LookupFractions, + LookupGroup, LookupMessage, +}; + +// PROVER LOOKUP BUILDER +// ================================================================================================ + +/// Concrete-row `LookupBuilder` running on two rows of base-field values. +/// +/// See the module docs for the full runtime shape. Parameterised +/// by the base field `F` and the extension field `EF`; every `Expr` / +/// `Var` / `VarEF` etc. associated type collapses to `F` or `EF` +/// directly — there is no symbolic tree on the prover side. +pub struct ProverLookupBuilder<'a, F, EF> +where + F: Field, + EF: ExtensionField, +{ + main: RowWindow<'a, F>, + periodic_values: &'a [F], + challenges: &'a Challenges, + /// Dense per-column fraction buffers shared across all rows. Each + /// [`LookupBuilder::next_column`] call appends the current row's fractions to the end of + /// `fractions.fractions[column_idx]` and pushes the row's interaction count into + /// `fractions.counts_per_row[column_idx]`. + fractions: &'a mut LookupFractions, + column_idx: usize, +} + +impl<'a, F, EF> ProverLookupBuilder<'a, F, EF> +where + F: Field, + EF: ExtensionField, +{ + /// Create a new prover-path adapter for one row pair. + /// + /// - `main`: two-row window over the current and next base-field rows. + /// - `periodic_values`: periodic columns at the current row. + /// - `challenges`: precomputed LogUp challenges (shared across every row — the caller builds + /// this once outside the row loop and passes a shared reference here). + /// - `air`: the lookup shape (used only for a debug assertion that `fractions.num_columns() == + /// air.num_columns()`; the builder never calls `air.eval` itself — that's the caller's job). + /// - `fractions`: dense per-column fraction buffers, sized once via + /// [`LookupFractions::from_shape`] and re-used across every row of the same trace. + /// + /// # Panics + /// + /// Panics in debug builds if `fractions.num_columns() != air.num_columns()`. + pub fn new( + main: RowWindow<'a, F>, + periodic_values: &'a [F], + challenges: &'a Challenges, + air: &A, + fractions: &'a mut LookupFractions, + ) -> Self + where + A: LookupAir, + { + debug_assert_eq!( + fractions.num_columns(), + air.num_columns(), + "fractions buffer must be pre-sized to air.num_columns()", + ); + Self { + main, + periodic_values, + challenges, + fractions, + column_idx: 0, + } + } +} + +// BUILD LOOKUP FRACTIONS DRIVER +// ================================================================================================ + +/// Walk a complete main trace through [`ProverLookupBuilder`] and return the dense +/// [`LookupFractions`] buffer the collection phase produces. +/// +/// Generic over the base field `F` and extension field `EF`. The caller supplies the +/// main trace and periodic columns — this function does row slicing, periodic-column +/// indexing, and fraction collection. Concrete AIRs wrap this with their own +/// periodic-column layout. +/// +/// # Arguments +/// +/// - `air`: the [`LookupAir`] to evaluate. +/// - `main_trace`: row-major main execution trace. Row access is zero-copy via +/// `main_trace.values.borrow()`. +/// - `periodic_columns`: one `Vec` per periodic column, each with its own period. +/// - `challenges`: precomputed LogUp challenges (shared across every row). +/// +/// # Panics +/// +/// Panics in debug builds if any row pushes more fractions into a column than that +/// column's declared [`LookupAir::column_shape`] bound — this indicates the emitter's +/// `MAX_INTERACTIONS_PER_ROW` const is too low and needs to be bumped. +pub fn build_lookup_fractions( + air: &A, + main_trace: &RowMajorMatrix, + periodic_columns: &[Vec], + challenges: &Challenges, +) -> LookupFractions +where + F: Field, + EF: ExtensionField, + for<'a> A: LookupAir>, +{ + let num_rows = main_trace.height(); + let width = main_trace.width(); + let flat: &[F] = main_trace.values.borrow(); + + let shape = air.column_shape().to_vec(); + let mut fractions = LookupFractions::from_shape(shape, num_rows); + + // Per-row periodic slice, filled in place each row — no per-iteration allocation. + let mut periodic_row: Vec = vec![F::ZERO; periodic_columns.len()]; + + for r in 0..num_rows { + let curr = &flat[r * width..(r + 1) * width]; + let nxt_idx = (r + 1) % num_rows; + let next = &flat[nxt_idx * width..(nxt_idx + 1) * width]; + let window = RowWindow::from_two_rows(curr, next); + + for (i, col) in periodic_columns.iter().enumerate() { + periodic_row[i] = col[r % col.len()]; + } + + let mut lb = + ProverLookupBuilder::new(window, &periodic_row, challenges, air, &mut fractions); + air.eval(&mut lb); + } + + debug_assert_eq!( + fractions.counts().len(), + num_rows * fractions.num_columns(), + "counts buffer should have exactly num_rows * num_cols entries after collection", + ); + fractions +} + +impl<'a, F, EF> LookupBuilder for ProverLookupBuilder<'a, F, EF> +where + F: Field, + EF: ExtensionField, +{ + type F = F; + type Expr = F; + type Var = F; + + type EF = EF; + type ExprEF = EF; + type VarEF = EF; + + type PeriodicVar = F; + + type MainWindow = RowWindow<'a, F>; + + type Column<'c> + = ProverColumn<'c, F, EF> + where + Self: 'c; + + fn main(&self) -> Self::MainWindow { + self.main + } + + fn periodic_values(&self) -> &[Self::PeriodicVar] { + self.periodic_values + } + + fn next_column<'c, R>( + &'c mut self, + f: impl FnOnce(&mut Self::Column<'c>) -> R, + _deg: Deg, + ) -> R { + let idx = self.column_idx; + let vec = &mut self.fractions.fractions; + let counts = &mut self.fractions.counts; + let shape_col = self.fractions.shape[idx]; + let start_len = vec.len(); + + let (result, pushed) = { + let mut col = ProverColumn { + challenges: self.challenges, + fractions: vec, + }; + let result = f(&mut col); + (result, col.fractions.len() - start_len) + }; + debug_assert!( + pushed <= shape_col, + "column {idx} exceeded its shape bound: pushed {pushed}, shape says {shape_col}", + ); + counts.push(pushed); + self.column_idx += 1; + result + } +} + +// PROVER COLUMN +// ================================================================================================ + +/// Per-column handle returned by [`ProverLookupBuilder::next_column`]. +/// +/// Holds a mutable borrow of the column's per-row fraction `Vec`. Each +/// group opened inside the column reborrows the same `Vec` and pushes +/// fractions onto it — no intermediate `(N, D)` state, no +/// cross-denominator clearing. +pub struct ProverColumn<'c, F, EF> +where + F: Field, + EF: ExtensionField, +{ + challenges: &'c Challenges, + fractions: &'c mut Vec<(F, EF)>, +} + +impl<'c, F, EF> LookupColumn for ProverColumn<'c, F, EF> +where + F: Field, + EF: ExtensionField, +{ + type Expr = F; + type ExprEF = EF; + + type Group<'g> + = ProverGroup<'g, F, EF> + where + Self: 'g; + + fn group<'g>( + &'g mut self, + _name: &'static str, + f: impl FnOnce(&mut Self::Group<'g>), + _deg: Deg, + ) { + let mut group = ProverGroup { + challenges: self.challenges, + fractions: &mut *self.fractions, + }; + f(&mut group) + } + + fn group_with_cached_encoding<'g>( + &'g mut self, + name: &'static str, + canonical: impl FnOnce(&mut Self::Group<'g>), + _encoded: impl FnOnce(&mut Self::Group<'g>), + deg: Deg, + ) { + // Prover path runs only the `canonical` closure; both closures must describe + // identical interaction sets, so the `encoded` fast path has no advantage on + // concrete rows and is discarded. + self.group(name, canonical, deg); + } +} + +// PROVER GROUP +// ================================================================================================ + +/// Per-group handle used for both the simple and cached-encoding paths +/// on the prover side. +/// +/// Pushes individual `(multiplicity, denominator)` fractions onto the +/// column's per-row `Vec`. No `(N, D)` state, no cross-denominator +/// clearing — LogUp's aux-trace builder consumes individual fractions +/// downstream. +/// +/// ## Boolean-flag convention +/// +/// The `flag` parameter on `add` / `remove` / `insert` is treated as a +/// 0/1 boolean selector: if `flag == F::ZERO` the interaction is +/// skipped entirely (no encode, no push); otherwise the push happens +/// with the canonical multiplicity (`+1` for `add`, `-1` for `remove`, +/// `multiplicity` for `insert`). This matches the constraint path's +/// `(V_g, U_g)` algebra, which silently assumes flag is 0 or 1 — +/// non-boolean flags produce wrong results on both sides. +/// +/// ## Encoded-group methods +/// +/// The encoding primitives (`beta_powers`, `bus_prefix`, `insert_encoded`) +/// use the default panicking implementations from [`LookupGroup`] — the +/// prover path always runs the `canonical` closure, never the `encoded` +/// one, so these methods should never be reached. +pub struct ProverGroup<'g, F, EF> +where + F: Field, + EF: ExtensionField, +{ + challenges: &'g Challenges, + fractions: &'g mut Vec<(F, EF)>, +} + +impl<'g, F, EF> LookupGroup for ProverGroup<'g, F, EF> +where + F: Field, + EF: ExtensionField, +{ + type Expr = F; + type ExprEF = EF; + + type Batch<'b> + = ProverBatch<'b, F, EF> + where + Self: 'b; + + fn insert( + &mut self, + _name: &'static str, + flag: F, + multiplicity: F, + msg: impl FnOnce() -> M, + _deg: Deg, + ) where + M: LookupMessage, + { + if flag == F::ZERO { + return; + } + let v = msg().encode(self.challenges); + self.fractions.push((multiplicity, v)); + } + + fn batch<'b>( + &'b mut self, + _name: &'static str, + flag: F, + build: impl FnOnce(&mut Self::Batch<'b>), + _deg: Deg, + ) { + // When `active == false` every push inside the batch is a no-op — the + // `msg.encode()` call is skipped too. The `build` closure still runs so + // it can produce its `R` return value without requiring `R: Default`. + let active = flag != F::ZERO; + let mut batch = ProverBatch { + challenges: self.challenges, + fractions: &mut *self.fractions, + active, + }; + build(&mut batch) + } +} + +// PROVER BATCH +// ================================================================================================ + +/// Transient handle returned by [`LookupGroup::batch`] on the prover path. +/// +/// Holds the same mutable borrow of the column's fraction `Vec` as the +/// enclosing [`ProverGroup`], plus an `active` flag copied from the +/// outer `batch(flag, …)` call. When `active == false` every push is a +/// no-op — the `msg.encode()` call is skipped too, so inactive batches +/// do essentially no work. +/// +/// Each push appends one fraction entry when active. There's no `(N, D)` state +/// inside the batch — LogUp's aux-trace builder handles the combination downstream. +pub struct ProverBatch<'b, F, EF> +where + F: Field, + EF: ExtensionField, +{ + challenges: &'b Challenges, + fractions: &'b mut Vec<(F, EF)>, + active: bool, +} + +impl<'b, F, EF> LookupBatch for ProverBatch<'b, F, EF> +where + F: Field, + EF: ExtensionField, +{ + type Expr = F; + type ExprEF = EF; + + fn insert(&mut self, _name: &'static str, multiplicity: F, msg: M, _deg: Deg) + where + M: LookupMessage, + { + if !self.active { + return; + } + let v = msg.encode(self.challenges); + self.fractions.push((multiplicity, v)); + } + + fn insert_encoded( + &mut self, + _name: &'static str, + multiplicity: F, + encoded: impl FnOnce() -> EF, + _deg: Deg, + ) { + if !self.active { + return; + } + let v = encoded(); + self.fractions.push((multiplicity, v)); + } +} + +// TESTS +// ================================================================================================ + +#[cfg(test)] +mod tests { + extern crate std; + + use std::{vec, vec::Vec}; + + use miden_core::field::{PrimeCharacteristicRing, QuadFelt}; + use miden_crypto::stark::air::RowWindow; + + use super::*; + use crate::{ + Felt, + lookup::{Deg, LookupAir, accumulate_slow, message::LookupMessage}, + }; + + /// Minimal `LookupMessage` used by [`SmokeAir`] to drive a `Vec::push` into the + /// prover builder's fraction buffer. Encodes to `bus_prefix[0] + β⁰·value`, which is + /// always non-zero for non-trivial challenges (so `accumulate_slow` can `try_inverse` + /// without blowing up). + #[derive(Clone, Copy, Debug)] + struct SmokeMsg { + value: Felt, + } + + impl LookupMessage for SmokeMsg { + fn encode(&self, challenges: &Challenges) -> QuadFelt { + challenges.bus_prefix[0] + challenges.beta_powers[0] * self.value + } + } + + /// Two-column stand-in for the real Miden lookup AIR, with a handcrafted `eval` body + /// that respects its own shape on **every** row — no mutual-exclusion assumptions, so + /// random (non-trace) input data drives it without tripping the shape debug_assert. + /// + /// - Column 0 always pushes 2 fractions (one `add`, one `remove`) with shape 2. + /// - Column 1 pushes 1 fraction via an inside-batch `insert` with shape 1. + struct SmokeAir; + + const SMOKE_SHAPE: [usize; 2] = [2, 1]; + + impl LookupAir for SmokeAir + where + LB: LookupBuilder, + { + fn num_columns(&self) -> usize { + 2 + } + fn column_shape(&self) -> &[usize] { + &SMOKE_SHAPE + } + fn max_message_width(&self) -> usize { + 1 + } + fn num_bus_ids(&self) -> usize { + 1 + } + fn eval(&self, builder: &mut LB) { + builder.next_column( + |col| { + col.group( + "smoke_grp_0", + |g| { + g.add( + "smoke_add", + Felt::ONE, + || SmokeMsg { value: Felt::ONE }, + Deg { v: 0, u: 0 }, + ); + g.remove( + "smoke_remove", + Felt::ONE, + || SmokeMsg { value: Felt::new_unchecked(2) }, + Deg { v: 0, u: 0 }, + ); + }, + Deg { v: 0, u: 0 }, + ); + }, + Deg { v: 0, u: 0 }, + ); + builder.next_column( + |col| { + col.group( + "smoke_grp_1", + |g| { + g.batch( + "smoke_batch", + Felt::ONE, + |b| { + b.insert( + "smoke_batch_insert", + Felt::ONE, + SmokeMsg { value: Felt::new_unchecked(3) }, + Deg { v: 0, u: 0 }, + ); + }, + Deg { v: 0, u: 0 }, + ); + }, + Deg { v: 0, u: 0 }, + ); + }, + Deg { v: 0, u: 0 }, + ); + } + } + + /// End-to-end collection sanity check: run `SmokeAir::eval` through + /// `ProverLookupBuilder` over several rows and verify the per-column counts match the + /// handcrafted `eval` body, that `accumulate_slow` produces a `num_rows + 1`-long + /// output per column starting at zero, and that the running sum monotonically grows + /// by the expected amount each row. + #[test] + fn prover_lookup_builder_collects_into_fractions() { + const NUM_ROWS: usize = 8; + + let air = SmokeAir; + + // Any reasonable non-zero challenges — SmokeMsg encodes to `bus_prefix[0] + v` + // which is non-zero as long as the challenges are. + let alpha = QuadFelt::new([Felt::new_unchecked(7), Felt::new_unchecked(11)]); + let beta = QuadFelt::new([Felt::new_unchecked(13), Felt::new_unchecked(17)]); + // SmokeAir hard-codes `max_message_width = 1` / `num_bus_ids = 1` in its + // `LookupAir` impl — the trait-method path can't be called directly because + // `LookupAir` is generic over `LB` and disambiguation fails at a value call. + let challenges = Challenges::::new(alpha, beta, 1, 1); + + // `SmokeAir::eval` never touches the main trace, periodic columns, or public + // values — pass dummy zero-length slices. + let empty_row: Vec = vec![]; + let periodic_values: Vec = vec![]; + + let shape = + >>::column_shape(&air) + .to_vec(); + let mut fractions = LookupFractions::::from_shape(shape, NUM_ROWS); + + for _row in 0..NUM_ROWS { + let window = RowWindow::from_two_rows(&empty_row, &empty_row); + let mut lb = ProverLookupBuilder::new( + window, + &periodic_values, + &challenges, + &air, + &mut fractions, + ); + air.eval(&mut lb); + } + + // Two columns, counts buffer has num_rows * num_cols entries. + assert_eq!(fractions.num_columns(), 2); + assert_eq!(fractions.shape(), &SMOKE_SHAPE); + assert_eq!(fractions.counts().len(), NUM_ROWS * 2); + + // Per-row counts: column 0 pushes 2, column 1 pushes 1. Total = 3 per row. + for row_counts in fractions.counts().chunks(2) { + assert_eq!(row_counts, &[2, 1]); + } + assert_eq!(fractions.fractions().len(), 3 * NUM_ROWS); + + // Every pushed fraction has a non-zero denominator and the expected + // multiplicity pattern. Within each row the builder writes col 0 (add 1, + // remove 1) then col 1 (insert 1 with multiplicity 1), so the flat order is + // [(+1, d1), (-1, d2), (+1, d3)] repeated NUM_ROWS times. + for (i, (m, d)) in fractions.fractions().iter().enumerate() { + assert_ne!(*d, QuadFelt::ZERO); + let expected_m = match i % 3 { + 0 => Felt::ONE, + 1 => Felt::NEG_ONE, + _ => Felt::ONE, + }; + assert_eq!(*m, expected_m); + } + + let aux = accumulate_slow(&fractions); + assert_eq!(aux.len(), 2); + for col_aux in &aux { + assert_eq!(col_aux.len(), NUM_ROWS + 1); + } + assert_eq!(aux[0][0], QuadFelt::ZERO, "accumulator initial must be zero"); + + let d1 = SmokeMsg { value: Felt::ONE }.encode(&challenges); + let d2 = SmokeMsg { value: Felt::new_unchecked(2) }.encode(&challenges); + let d3 = SmokeMsg { value: Felt::new_unchecked(3) }.encode(&challenges); + let delta0 = d1.try_inverse().unwrap() - d2.try_inverse().unwrap(); + let delta1 = d3.try_inverse().unwrap(); + // Column 0 (accumulator): each row delta = own fraction + col 1's fraction. + for r in 0..NUM_ROWS { + assert_eq!(aux[0][r + 1] - aux[0][r], delta0 + delta1); + } + // Column 1 (fraction, aux_curr): value at row r is the per-row fraction. + for &entry in aux[1].iter().take(NUM_ROWS) { + assert_eq!(entry, delta1); + } + } +} diff --git a/air/src/snapshots/miden_air__config__tests__relation_digest_matches_current_air.snap b/air/src/snapshots/miden_air__config__tests__relation_digest_matches_current_air.snap new file mode 100644 index 0000000000..d2b9b1a836 --- /dev/null +++ b/air/src/snapshots/miden_air__config__tests__relation_digest_matches_current_air.snap @@ -0,0 +1,7 @@ +--- +source: air/src/config.rs +expression: snapshot +--- +num_inputs: 562 +num_eval_gates: 5524 +relation_digest: [2564365500194292689, 7963649451118915546, 13003513905888733288, 3704785727996306162] diff --git a/air/src/trace/aux_trace.rs b/air/src/trace/aux_trace.rs deleted file mode 100644 index 25fa5d6517..0000000000 --- a/air/src/trace/aux_trace.rs +++ /dev/null @@ -1,49 +0,0 @@ -//! Auxiliary trace builder trait for dependency inversion. -//! -//! This trait allows ProcessorAir to build auxiliary traces without depending -//! on the processor crate, avoiding circular dependencies. - -use miden_core::utils::RowMajorMatrix; - -use crate::Felt; - -/// Trait for building auxiliary traces from main trace and challenges. -/// -/// # Why This Trait Exists -/// -/// This trait serves to avoid circular dependencies: -/// - `ProcessorAir` (in this crate) needs to build auxiliary traces during proving -/// - The actual aux building logic lives in the `processor` crate -/// - But `processor` already depends on `air` for trace types and constraints -/// - Direct coupling would create: `air` → `processor` → `air` -/// -/// The trait breaks the cycle: -/// - `air` defines the interface (this trait) -/// - `processor` implements the interface (concrete aux builders) -/// - `prover` injects the implementation: `ProcessorAir::with_aux_builder(impl)` -/// -/// The trait works with row-major matrices (i.e., Plonky3 format). -pub trait AuxTraceBuilder: Send + Sync { - /// Builds auxiliary trace in row-major format from the main trace. - /// - /// Takes the main trace in row-major format (as provided by Plonky3) and - /// returns the auxiliary trace also in row-major format. - fn build_aux_columns( - &self, - main_trace: &RowMajorMatrix, - challenges: &[EF], - ) -> RowMajorMatrix; -} - -/// Dummy implementation for () to support ProcessorAir without aux trace builders (e.g., in -/// verifier). This implementation should never be called since ProcessorAir::build_aux_trace -/// returns None when aux_builder is None. -impl AuxTraceBuilder for () { - fn build_aux_columns( - &self, - _main_trace: &RowMajorMatrix, - _challenges: &[EF], - ) -> RowMajorMatrix { - panic!("No aux trace builder configured - this should never be called") - } -} diff --git a/air/src/trace/challenges.rs b/air/src/trace/challenges.rs deleted file mode 100644 index 4ca7537231..0000000000 --- a/air/src/trace/challenges.rs +++ /dev/null @@ -1,78 +0,0 @@ -//! Unified bus challenge encoding. -//! -//! Provides [`Challenges`], a single struct for encoding multiset/LogUp bus messages -//! as `alpha + `. This type is used by: -//! -//! - **AIR constraints** (symbolic expressions): `Challenges` -//! - **Processor aux trace builders** (concrete field elements): `Challenges` -//! - **Verifier** (`reduced_aux_values`): `Challenges` -//! -//! See [`super::bus_message`] for the standard coefficient index layout. - -use core::ops::{AddAssign, Mul}; - -use miden_core::field::PrimeCharacteristicRing; - -use super::MAX_MESSAGE_WIDTH; - -/// Encodes multiset/LogUp contributions as **alpha + **. -/// -/// - `alpha`: randomness base -/// - `beta_powers`: precomputed powers `[beta^0, beta^1, ..., beta^(MAX_MESSAGE_WIDTH-1)]` -/// -/// The challenges are derived from permutation randomness: -/// - `alpha = challenges[0]` -/// - `beta = challenges[1]` -/// -/// Precomputed once and passed by reference to all bus components. -pub struct Challenges { - pub alpha: EF, - pub beta_powers: [EF; MAX_MESSAGE_WIDTH], -} - -impl Challenges { - /// Builds `alpha` and precomputed `beta` powers. - pub fn new(alpha: EF, beta: EF) -> Self { - let mut beta_powers = core::array::from_fn(|_| EF::ONE); - for i in 1..MAX_MESSAGE_WIDTH { - beta_powers[i] = beta_powers[i - 1].clone() * beta.clone(); - } - Self { alpha, beta_powers } - } - - /// Encodes as **alpha + sum(beta_powers\[i\] * elem\[i\])** with K consecutive elements. - #[inline(always)] - pub fn encode(&self, elems: [BF; K]) -> EF - where - EF: Mul + AddAssign, - BF: Clone, - { - const { assert!(K <= MAX_MESSAGE_WIDTH, "Message length exceeds beta_powers capacity") }; - let mut acc = self.alpha.clone(); - for (i, elem) in elems.iter().enumerate() { - acc += self.beta_powers[i].clone() * elem.clone(); - } - acc - } - - /// Encodes as **alpha + sum(beta_powers\[layout\[i\]\] * values\[i\])** using sparse positions. - #[inline(always)] - pub fn encode_sparse(&self, layout: [usize; K], values: [BF; K]) -> EF - where - EF: Mul + AddAssign, - BF: Clone, - { - let mut acc = self.alpha.clone(); - for i in 0..K { - let idx = layout[i]; - debug_assert!( - idx < self.beta_powers.len(), - "encode_sparse index {} exceeds beta_powers length ({})", - idx, - self.beta_powers.len() - ); - acc += self.beta_powers[idx].clone() * values[i].clone(); - } - acc - } -} diff --git a/air/src/trace/chiplets/ace.rs b/air/src/trace/chiplets/ace.rs index b3ed9eaf6d..858ade61ee 100644 --- a/air/src/trace/chiplets/ace.rs +++ b/air/src/trace/chiplets/ace.rs @@ -2,18 +2,14 @@ use crate::trace::chiplets::Felt; // --- CONSTANTS ---------------------------------------------------------------------------------- -/// Unique label ACE operation, computed as the chiplet selector with the bits reversed, plus one. -/// `selector = [1, 1, 1, 0]`, `flag = rev(selector) + 1 = [0, 1, 1, 1] + 1 = 8` -pub const ACE_INIT_LABEL: Felt = Felt::new(0b0111 + 1); - /// Total number of columns making up the ACE chiplet. pub const ACE_CHIPLET_NUM_COLS: usize = 16; /// Offset of the `ID1` wire used when encoding an ACE instruction. -pub const ACE_INSTRUCTION_ID1_OFFSET: Felt = Felt::new(1 << 30); +pub const ACE_INSTRUCTION_ID1_OFFSET: Felt = Felt::new_unchecked(1 << 30); /// Offset of the `ID2` wire used when encoding an ACE instruction. -pub const ACE_INSTRUCTION_ID2_OFFSET: Felt = Felt::new(1 << 60); +pub const ACE_INSTRUCTION_ID2_OFFSET: Felt = Felt::new_unchecked(1 << 60); // --- OPERATION SELECTORS ------------------------------------------------------------------------ diff --git a/air/src/trace/chiplets/bitwise.rs b/air/src/trace/chiplets/bitwise.rs index 5ba1738af2..4dd2dc16c8 100644 --- a/air/src/trace/chiplets/bitwise.rs +++ b/air/src/trace/chiplets/bitwise.rs @@ -16,15 +16,9 @@ pub const OP_CYCLE_LEN: usize = 8; /// Specifies a bitwise AND operation. pub const BITWISE_AND: Felt = ZERO; -/// Unique label computed as 1 plus the full chiplet selector with the bits reversed. -/// `selector = [1, 0 | 0]`, `flag = rev(selector) + 1 = [0 | 0, 1] + 1 = 2` -pub const BITWISE_AND_LABEL: Felt = Felt::new(0b001 + 1); /// Specifies a bitwise XOR operation. pub const BITWISE_XOR: Felt = ONE; -/// Unique label computed as 1 plus the full chiplet selector with the bits reversed. -/// `selector = [1, 0 | 1]`, `flag = rev(selector) + 1 = [1 | 0, 1] + 1 = 6` -pub const BITWISE_XOR_LABEL: Felt = Felt::new(0b101 + 1); // --- INPUT DECOMPOSITION ------------------------------------------------------------------------ diff --git a/air/src/trace/chiplets/hasher.rs b/air/src/trace/chiplets/hasher.rs index 47464327c0..e6136603cd 100644 --- a/air/src/trace/chiplets/hasher.rs +++ b/air/src/trace/chiplets/hasher.rs @@ -15,7 +15,7 @@ use core::ops::Range; pub use miden_core::{Word, crypto::hash::Poseidon2 as Hasher}; -use super::{Felt, HASH_KERNEL_VTABLE_AUX_TRACE_OFFSET, ONE, ZERO, create_range}; +use super::{Felt, ONE, ZERO, create_range}; // TYPES ALIASES // ================================================================================================ @@ -76,23 +76,54 @@ pub const DIGEST_RANGE: Range = Hasher::DIGEST_RANGE; /// Number of round steps used to complete a single permutation. /// -/// For Poseidon2, we model a permutation as 31 step transitions, resulting in a 32-row cycle. +/// For Poseidon2, the permutation consists of 31 step transitions (1 init linear + 8 external +/// + 22 internal). These are packed into a 16-row cycle. pub const NUM_ROUNDS: usize = miden_core::chiplets::hasher::NUM_ROUNDS; /// Index of the last row in a permutation cycle (0-based). -pub const LAST_CYCLE_ROW: usize = NUM_ROUNDS; -pub const LAST_CYCLE_ROW_FELT: Felt = Felt::new(LAST_CYCLE_ROW as u64); +pub const LAST_CYCLE_ROW: usize = HASH_CYCLE_LEN - 1; +pub const LAST_CYCLE_ROW_FELT: Felt = Felt::new_unchecked(LAST_CYCLE_ROW as u64); /// Number of selector columns in the trace. pub const NUM_SELECTORS: usize = 3; /// The number of rows in the execution trace required to compute a permutation of Poseidon2. -/// This is equal to 32. -pub const HASH_CYCLE_LEN: usize = NUM_ROUNDS.next_power_of_two(); -pub const HASH_CYCLE_LEN_FELT: Felt = Felt::new(HASH_CYCLE_LEN as u64); +/// +/// The 16-row packed cycle compresses the 31 permutation steps by: +/// - Merging init linear + ext1 into one row +/// - Packing 3 internal rounds per row (7 rows for 21 rounds) +/// - Merging int22 + ext5 into one row Result: 1 + 3 + 7 + 1 + 3 + 1 = 16 rows. +pub const HASH_CYCLE_LEN: usize = 16; +pub const HASH_CYCLE_LEN_FELT: Felt = Felt::new_unchecked(HASH_CYCLE_LEN as u64); + +/// Index of the node_index column. Holds the Merkle tree node index on controller rows. +/// This column is reused to hold the permutation request multiplicity on perm segment rows. +pub const NODE_INDEX_COL_IDX: usize = NUM_SELECTORS + STATE_WIDTH; + +/// Index of the mrupdate_id column (domain separator for sibling table across MRUPDATE ops). +pub const MRUPDATE_ID_COL_IDX: usize = NODE_INDEX_COL_IDX + 1; + +/// Index of the is_boundary column (1 on boundary rows: first input or last output of each +/// operation, 0 otherwise). +pub const IS_BOUNDARY_COL_IDX: usize = MRUPDATE_ID_COL_IDX + 1; + +/// Index of the direction_bit column. On Merkle controller rows, holds the extracted direction +/// bit from the node index. Zero on non-Merkle rows and perm segment rows. +pub const DIRECTION_BIT_COL_IDX: usize = IS_BOUNDARY_COL_IDX + 1; -/// Number of columns in Hasher execution trace. There is one additional column for the node index. -pub const TRACE_WIDTH: usize = NUM_SELECTORS + STATE_WIDTH + 1; +/// Index of the s_perm column (0 = controller region, 1 = permutation segment). +pub const S_PERM_COL_IDX: usize = DIRECTION_BIT_COL_IDX + 1; + +/// Number of columns in Hasher execution trace. +/// 3 selectors + 12 state + node_index + mrupdate_id + is_boundary + direction_bit + s_perm = 20. +pub const TRACE_WIDTH: usize = S_PERM_COL_IDX + 1; + +/// Number of controller rows per permutation request (one input + one output). +pub const CONTROLLER_ROWS_PER_PERMUTATION: usize = 2; + +/// Felt version of [CONTROLLER_ROWS_PER_PERMUTATION] for address arithmetic. +pub const CONTROLLER_ROWS_PER_PERM_FELT: Felt = + Felt::new_unchecked(CONTROLLER_ROWS_PER_PERMUTATION as u64); // --- Transition selectors ----------------------------------------------------------------------- @@ -100,47 +131,24 @@ pub const TRACE_WIDTH: usize = NUM_SELECTORS + STATE_WIDTH + 1; /// executing linear hash computation. These selectors can also be used for a simple 2-to-1 hash /// computation. pub const LINEAR_HASH: Selectors = [ONE, ZERO, ZERO]; -/// Unique label computed as 1 plus the full chiplet selector with the bits reversed. -/// `selector = [0 | 1, 0, 0]`, `flag = rev(selector) + 1 = [0, 0, 1 | 0] + 1 = 3` -pub const LINEAR_HASH_LABEL: u8 = 0b0010 + 1; - /// Specifies a start of Merkle path verification computation or absorption of a new path node /// into the hasher state. pub const MP_VERIFY: Selectors = [ONE, ZERO, ONE]; -/// Unique label computed as 1 plus the full chiplet selector with the bits reversed. -/// `selector = [0 | 1, 0, 1]`, `flag = rev(selector) + 1 = [1, 0, 1 | 0] + 1 = 11` -pub const MP_VERIFY_LABEL: u8 = 0b1010 + 1; /// Specifies a start of Merkle path verification or absorption of a new path node into the hasher /// state for the "old" node value during Merkle root update computation. pub const MR_UPDATE_OLD: Selectors = [ONE, ONE, ZERO]; -/// Unique label computed as 1 plus the full chiplet selector with the bits reversed. -/// `selector = [0 | 1, 1, 0]`, `flag = rev(selector) + 1 = [0, 1, 1 | 0] + 1 = 7` -pub const MR_UPDATE_OLD_LABEL: u8 = 0b0110 + 1; /// Specifies a start of Merkle path verification or absorption of a new path node into the hasher /// state for the "new" node value during Merkle root update computation. pub const MR_UPDATE_NEW: Selectors = [ONE, ONE, ONE]; -/// Unique label computed as 1 plus the full chiplet selector with the bits reversed. -/// `selector = [0 | 1, 1, 1]`, `flag = rev(selector) + 1 = [1, 1, 1 | 0] + 1 = 15` -pub const MR_UPDATE_NEW_LABEL: u8 = 0b1110 + 1; /// Specifies a completion of a computation such that only the hash result (values in h0, h1, h2 /// h3) is returned. pub const RETURN_HASH: Selectors = [ZERO, ZERO, ZERO]; -/// Unique label computed as 1 plus the full chiplet selector with the bits reversed. -/// `selector = [0 | 0, 0, 0]`, `flag = rev(selector) + 1 = [0, 0, 0 | 0] + 1 = 1` -#[expect(clippy::identity_op)] -pub const RETURN_HASH_LABEL: u8 = 0b0000 + 1; /// Specifies a completion of a computation such that the entire hasher state (values in h0 through /// h11) is returned. pub const RETURN_STATE: Selectors = [ZERO, ZERO, ONE]; -/// Unique label computed as 1 plus the full chiplet selector with the bits reversed. -/// `selector = [0 | 0, 0, 1]`, `flag = rev(selector) + 1 = [1, 0, 0 | 0] + 1 = 9` -pub const RETURN_STATE_LABEL: u8 = 0b1000 + 1; - -// --- Column accessors in the auxiliary trace ---------------------------------------------------- -/// Index of the auxiliary trace column tracking the state of the sibling table. -pub const P1_COL_IDX: usize = HASH_KERNEL_VTABLE_AUX_TRACE_OFFSET; +// NOTE: Selectors s0/s1/s2 are unconstrained on perm segment rows. diff --git a/air/src/trace/chiplets/kernel_rom.rs b/air/src/trace/chiplets/kernel_rom.rs deleted file mode 100644 index 57a4a82c81..0000000000 --- a/air/src/trace/chiplets/kernel_rom.rs +++ /dev/null @@ -1,32 +0,0 @@ -use super::Felt; - -// CONSTANTS -// ================================================================================================ - -/// Number of columns needed to record an execution trace of the kernel ROM chiplet. -pub const TRACE_WIDTH: usize = 5; - -// --- OPERATION SELECTORS ------------------------------------------------------------------------ - -// All kernel ROM bus labels encode the chiplet selector [1, 1, 1, 1, 0], appended with the internal -// selector `s_first` which indicates whether the chiplet should respond to an `init` or `call` -// request. The value of the flag is derived following the usual convention, i.e., -// adding one to the big-endian representation of the full selector. - -/// Specifies a kernel procedure call operation to access a procedure in the kernel ROM. -/// -/// The label is constructed as follows: -/// - Chiplet selector: [1, 1, 1, 1, 0] -/// - s_first value: 0 -/// - Combined selector: [1, 1, 1, 1, 0 | 0] -/// - Reverse bits and add 1 to get final label value: [0 | 0, 1, 1, 1, 1] + 1 = 16 -pub const KERNEL_PROC_CALL_LABEL: Felt = Felt::new(0b001111 + 1); - -/// Specified the label of the kernel ROM initialization request by the verifier. -/// -/// The label is constructed as follows: -/// - Chiplet selector: [1, 1, 1, 1, 0] -/// - s_first value: 1 -/// - Combined selector: [1, 1, 1, 1, 0 | 1] -/// - Reverse bits and add 1 to get final label value: [1 | 0, 1, 1, 1, 1] + 1 = 48 -pub const KERNEL_PROC_INIT_LABEL: Felt = Felt::new(0b101111 + 1); diff --git a/air/src/trace/chiplets/memory.rs b/air/src/trace/chiplets/memory.rs index 8b2475ce76..9bc7330d78 100644 --- a/air/src/trace/chiplets/memory.rs +++ b/air/src/trace/chiplets/memory.rs @@ -6,7 +6,7 @@ use super::{Felt, ONE, Range, ZERO, create_range}; // ================================================================================================ /// Number of columns needed to record an execution trace of the memory chiplet. -pub const TRACE_WIDTH: usize = 15; +pub const TRACE_WIDTH: usize = 17; // --- OPERATION SELECTORS ------------------------------------------------------------------------ @@ -19,33 +19,6 @@ pub const MEMORY_ACCESS_ELEMENT: Felt = ZERO; /// Specifies the value of the `ELEMENT_OR_WORD` column when the operation is over a word. pub const MEMORY_ACCESS_WORD: Felt = ONE; -// --- BUS LABELS ------------------------------------------------------------------------ - -// All bus labels encode the chiplet selector (1, 1, 0), as well as the read/write and element/word -// columns. The purpose of the label is to force the chiplet to assign the correct values to the -// read/write and element/word columns. We also include the chiplet selector as a unique identifier -// for memory chiplet labels (to ensure they don't collide with labels from other chiplets). - -/// Unique label when r/w=0 and e/w=0, computed as the full chiplet selector with the bits reversed, -/// plus one. -/// `selector = [1, 1, 0 | 0, 0]`, `flag = rev(selector) + 1 = [0, 0 | 0, 1, 1] + 1 = 4` -pub const MEMORY_WRITE_ELEMENT_LABEL: u8 = 0b00011 + 1; - -/// Unique label when r/w=0 and e/w=1, computed as the full chiplet selector with the bits reversed, -/// plus one. -/// `selector = [1, 1, 0 | 0, 1]`, `flag = rev(selector) + 1 = [1, 0 | 0, 1, 1] + 1 = 20` -pub const MEMORY_WRITE_WORD_LABEL: u8 = 0b10011 + 1; - -/// Unique label when r/w=1 and e/w=0, computed as the full chiplet selector with the bits reversed, -/// plus one. -/// `selector = [1, 1, 0 | 1, 0]`, `flag = rev(selector) + 1 = [0, 1 | 0, 1, 1] + 1 = 12` -pub const MEMORY_READ_ELEMENT_LABEL: u8 = 0b01011 + 1; - -/// Unique label when r/w=1 and e/w=1, computed as the full chiplet selector with the bits reversed, -/// plus one. -/// `selector = [1, 1, 0 | 1, 1]`, `flag = rev(selector) + 1 = [1, 1 | 0, 1, 1] + 1 = 28` -pub const MEMORY_READ_WORD_LABEL: u8 = 0b11011 + 1; - // --- COLUMN ACCESSOR INDICES WITHIN THE CHIPLET ------------------------------------------------- /// Column to hold whether the operation is a read or write. @@ -78,3 +51,11 @@ pub const D_INV_COL_IDX: usize = D1_COL_IDX + 1; /// Column to hold the flag indicating whether the current memory operation is in the same word and /// same context as the previous operation. pub const FLAG_SAME_CONTEXT_AND_WORD: usize = D_INV_COL_IDX + 1; + +/// Column for the lower 16 bits of the word index (word_addr / 4). +/// Used for range-checking that memory addresses are valid 32-bit values. +pub const WORD_ADDR_LO_COL_IDX: usize = FLAG_SAME_CONTEXT_AND_WORD + 1; + +/// Column for the upper 16 bits of the word index (word_addr / 4). +/// Used for range-checking that memory addresses are valid 32-bit values. +pub const WORD_ADDR_HI_COL_IDX: usize = WORD_ADDR_LO_COL_IDX + 1; diff --git a/air/src/trace/chiplets/mod.rs b/air/src/trace/chiplets/mod.rs index bf2fec08ec..4628b8cffc 100644 --- a/air/src/trace/chiplets/mod.rs +++ b/air/src/trace/chiplets/mod.rs @@ -2,12 +2,11 @@ use core::ops::Range; use miden_core::{Felt, ONE, ZERO, utils::range as create_range}; -use super::{CHIPLETS_OFFSET, HASH_KERNEL_VTABLE_AUX_TRACE_OFFSET}; +use super::CHIPLETS_OFFSET; pub mod ace; pub mod bitwise; pub mod hasher; -pub mod kernel_rom; pub mod memory; // CONSTANTS // ================================================================================================ @@ -23,6 +22,9 @@ pub const NUM_ACE_SELECTORS: usize = 4; /// The number of columns in the chiplets which are used as selectors for the kernel ROM chiplet. pub const NUM_KERNEL_ROM_SELECTORS: usize = 5; +/// Number of columns needed to record an execution trace of the kernel ROM chiplet. +pub const KERNEL_ROM_TRACE_WIDTH: usize = 5; + /// The first column of the hash chiplet. pub const HASHER_TRACE_OFFSET: usize = CHIPLETS_OFFSET + NUM_HASHER_SELECTORS; /// The first column of the bitwise chiplet. @@ -53,6 +55,14 @@ pub const HASHER_RATE_COL_RANGE: Range = Range { }; /// The index of the hasher's node index column in the execution trace. pub const HASHER_NODE_INDEX_COL_IDX: usize = HASHER_STATE_COL_RANGE.end; +/// The index of the hasher's mrupdate_id column in the execution trace. +pub const HASHER_MRUPDATE_ID_COL_IDX: usize = HASHER_TRACE_OFFSET + hasher::MRUPDATE_ID_COL_IDX; +/// The index of the hasher's is_boundary column in the execution trace. +pub const HASHER_IS_BOUNDARY_COL_IDX: usize = HASHER_TRACE_OFFSET + hasher::IS_BOUNDARY_COL_IDX; +/// The index of the hasher's direction_bit column in the execution trace. +pub const HASHER_DIRECTION_BIT_COL_IDX: usize = HASHER_TRACE_OFFSET + hasher::DIRECTION_BIT_COL_IDX; +/// The index of the hasher's s_perm column in the execution trace. +pub const HASHER_S_PERM_COL_IDX: usize = HASHER_TRACE_OFFSET + hasher::S_PERM_COL_IDX; // --- GLOBALLY-INDEXED CHIPLET COLUMN ACCESSORS: BITWISE ----------------------------------------- @@ -123,3 +133,7 @@ pub const MEMORY_D_INV_COL_IDX: usize = MEMORY_TRACE_OFFSET + memory::D_INV_COL_ /// and same word as the previous operation. pub const MEMORY_FLAG_SAME_CONTEXT_AND_WORD: usize = MEMORY_TRACE_OFFSET + memory::FLAG_SAME_CONTEXT_AND_WORD; +/// The index of the memory's word address low 16-bit limb column in the execution trace. +pub const MEMORY_WORD_ADDR_LO_COL_IDX: usize = MEMORY_TRACE_OFFSET + memory::WORD_ADDR_LO_COL_IDX; +/// The index of the memory's word address high 16-bit limb column in the execution trace. +pub const MEMORY_WORD_ADDR_HI_COL_IDX: usize = MEMORY_TRACE_OFFSET + memory::WORD_ADDR_HI_COL_IDX; diff --git a/air/src/trace/decoder/mod.rs b/air/src/trace/decoder/mod.rs index 8ee0d3d54a..863aaa438e 100644 --- a/air/src/trace/decoder/mod.rs +++ b/air/src/trace/decoder/mod.rs @@ -2,8 +2,6 @@ use core::ops::Range; use miden_core::{Felt, ONE, ZERO, operations::Operation, utils::range}; -use super::DECODER_AUX_TRACE_OFFSET; - // CONSTANTS // ================================================================================================ @@ -90,17 +88,6 @@ pub const IS_CALL_FLAG_COL_IDX: usize = HASHER_STATE_RANGE.start + 6; /// Index of a flag column which indicates whether an ending block is a SYSCALL block. pub const IS_SYSCALL_FLAG_COL_IDX: usize = HASHER_STATE_RANGE.start + 7; -// --- Column accessors in the auxiliary columns -------------------------------------------------- - -/// Running product column representing block stack table. -pub const P1_COL_IDX: usize = DECODER_AUX_TRACE_OFFSET; - -/// Running product column representing block hash table -pub const P2_COL_IDX: usize = DECODER_AUX_TRACE_OFFSET + 1; - -/// Running product column representing op group table. -pub const P3_COL_IDX: usize = DECODER_AUX_TRACE_OFFSET + 2; - // --- GLOBALLY-INDEXED DECODER COLUMN ACCESSORS -------------------------------------------------- pub const DECODER_OP_BITS_OFFSET: usize = super::DECODER_TRACE_OFFSET + OP_BITS_OFFSET; pub const DECODER_USER_OP_HELPERS_OFFSET: usize = diff --git a/air/src/trace/main_trace.rs b/air/src/trace/main_trace.rs index a6e6c81850..d6c5fdb736 100644 --- a/air/src/trace/main_trace.rs +++ b/air/src/trace/main_trace.rs @@ -1,29 +1,31 @@ use alloc::vec::Vec; use core::{ borrow::{Borrow, BorrowMut}, - ops::{Deref, Range}, + ops::Range, }; use miden_core::{ Felt, ONE, WORD_SIZE, Word, ZERO, field::PrimeCharacteristicRing, - utils::{ColMatrix, RowMajorMatrix, range}, + utils::{Matrix, RowMajorMatrix, range}, }; use super::{ CHIPLETS_OFFSET, CHIPLETS_WIDTH, CLK_COL_IDX, CTX_COL_IDX, DECODER_TRACE_OFFSET, - DECODER_TRACE_WIDTH, FN_HASH_OFFSET, RANGE_CHECK_TRACE_WIDTH, RowIndex, STACK_TRACE_OFFSET, - STACK_TRACE_WIDTH, + DECODER_TRACE_WIDTH, FN_HASH_OFFSET, RANGE_CHECK_TRACE_OFFSET, RANGE_CHECK_TRACE_WIDTH, + RowIndex, STACK_TRACE_OFFSET, STACK_TRACE_WIDTH, TRACE_WIDTH, chiplets::{ - BITWISE_A_COL_IDX, BITWISE_B_COL_IDX, BITWISE_OUTPUT_COL_IDX, HASHER_NODE_INDEX_COL_IDX, - HASHER_STATE_COL_RANGE, MEMORY_CLK_COL_IDX, MEMORY_CTX_COL_IDX, MEMORY_IDX0_COL_IDX, - MEMORY_IDX1_COL_IDX, MEMORY_V_COL_RANGE, MEMORY_WORD_COL_IDX, NUM_ACE_SELECTORS, + BITWISE_A_COL_IDX, BITWISE_B_COL_IDX, BITWISE_OUTPUT_COL_IDX, HASHER_DIRECTION_BIT_COL_IDX, + HASHER_IS_BOUNDARY_COL_IDX, HASHER_MRUPDATE_ID_COL_IDX, HASHER_NODE_INDEX_COL_IDX, + HASHER_S_PERM_COL_IDX, HASHER_STATE_COL_RANGE, MEMORY_CLK_COL_IDX, MEMORY_CTX_COL_IDX, + MEMORY_IDX0_COL_IDX, MEMORY_IDX1_COL_IDX, MEMORY_V_COL_RANGE, MEMORY_WORD_ADDR_HI_COL_IDX, + MEMORY_WORD_ADDR_LO_COL_IDX, MEMORY_WORD_COL_IDX, NUM_ACE_SELECTORS, ace::{ CLK_IDX, CTX_IDX, EVAL_OP_IDX, ID_0_IDX, ID_1_IDX, ID_2_IDX, M_0_IDX, M_1_IDX, PTR_IDX, READ_NUM_EVAL_IDX, SELECTOR_BLOCK_IDX, SELECTOR_START_IDX, V_0_0_IDX, V_0_1_IDX, V_1_0_IDX, V_1_1_IDX, V_2_0_IDX, V_2_1_IDX, }, - hasher::{DIGEST_LEN, HASH_CYCLE_LEN, LAST_CYCLE_ROW, STATE_WIDTH}, + hasher::{DIGEST_LEN, STATE_WIDTH}, }, decoder::{ GROUP_COUNT_COL_IDX, HASHER_STATE_OFFSET, IN_SPAN_COL_IDX, IS_CALL_FLAG_COL_IDX, @@ -90,49 +92,268 @@ impl BorrowMut> for [T] { // MAIN TRACE MATRIX // ================================================================================================ +/// Storage backing [`MainTrace`]: `Parts` from `build_trace`, `RowMajor` from the prover, or +/// `Transposed` (`W×N` row-major of an `N×W` trace) for aux trace construction. +#[derive(Debug)] +enum TraceStorage { + Parts { + core_rm: Vec, + chiplets_rm: Vec, + range_checker_cols: [Vec; 2], + num_rows: usize, + }, + RowMajor(RowMajorMatrix), + Transposed { + matrix: RowMajorMatrix, + num_cols: usize, + num_rows: usize, + }, +} + #[derive(Debug)] pub struct MainTrace { - columns: ColMatrix, + storage: TraceStorage, last_program_row: RowIndex, } -impl Deref for MainTrace { - type Target = ColMatrix; +/// Number of columns in the core (row-major) part of [`TraceStorage::Parts`]. +const CORE_WIDTH: usize = RANGE_CHECK_TRACE_OFFSET; - fn deref(&self) -> &Self::Target { - &self.columns - } -} +// TODO: Could be tailored more efficiently? +#[cfg(feature = "concurrent")] +const ROW_MAJOR_CHUNK_SIZE: usize = 512; impl MainTrace { - pub fn new(main_trace: ColMatrix, last_program_row: RowIndex) -> Self { - Self { columns: main_trace, last_program_row } + /// Creates a `MainTrace` from a [`RowMajorMatrix`]. + pub fn new(matrix: RowMajorMatrix, last_program_row: RowIndex) -> Self { + Self { + storage: TraceStorage::RowMajor(matrix), + last_program_row, + } } - /// Converts this column-major `MainTrace` into a row-major matrix. + /// Builds from `build_trace` outputs: core and chiplets row-major, range checker column + /// vectors. + pub fn from_parts( + core_rm: Vec, + chiplets_rm: Vec, + range_checker_cols: [Vec; 2], + num_rows: usize, + last_program_row: RowIndex, + ) -> Self { + assert_eq!(core_rm.len(), num_rows * CORE_WIDTH); + assert_eq!(chiplets_rm.len(), num_rows * CHIPLETS_WIDTH); + assert_eq!(range_checker_cols[0].len(), num_rows); + assert_eq!(range_checker_cols[1].len(), num_rows); + Self { + storage: TraceStorage::Parts { + core_rm, + chiplets_rm, + range_checker_cols, + num_rows, + }, + last_program_row, + } + } + + /// `transposed` is `main.transpose()` where `main` was `num_rows × num_cols`. + pub fn from_transposed(transposed: RowMajorMatrix, last_program_row: RowIndex) -> Self { + let num_cols = transposed.height(); + let num_rows = transposed.width(); + Self { + storage: TraceStorage::Transposed { matrix: transposed, num_cols, num_rows }, + last_program_row, + } + } + + /// Get matrix element at `(row, col)`. + /// + /// # Panics + /// Panics if the row or column is out of bounds. + #[inline] + pub fn get(&self, row: RowIndex, col: usize) -> Felt { + let r = row.as_usize(); + match &self.storage { + TraceStorage::Parts { + core_rm, + chiplets_rm, + range_checker_cols, + num_rows, + } => { + assert!(r < *num_rows, "main trace row index in bounds"); + assert!(col < TRACE_WIDTH, "main trace column index in bounds"); + + if col < CORE_WIDTH { + core_rm[r * CORE_WIDTH + col] + } else { + let nc = col - CORE_WIDTH; + if nc < RANGE_CHECK_TRACE_WIDTH { + range_checker_cols[nc][r] + } else { + chiplets_rm[r * CHIPLETS_WIDTH + (nc - RANGE_CHECK_TRACE_WIDTH)] + } + } + }, + TraceStorage::RowMajor(matrix) => { + let row_slice = matrix.row_slice(r).expect("main trace row index in bounds"); + assert!(col < row_slice.len(), "main trace column index in bounds"); + row_slice[col] + }, + TraceStorage::Transposed { matrix, num_cols, .. } => { + let col_slice = matrix.row_slice(col).expect("main trace column index in bounds"); + assert!(r < col_slice.len(), "main trace row index in bounds"); + debug_assert_eq!(col_slice.len(), matrix.width()); + debug_assert_eq!(matrix.height(), *num_cols); + col_slice[r] + }, + } + } + + /// Returns the stored width (number of columns). + #[inline] + pub fn width(&self) -> usize { + match &self.storage { + TraceStorage::Parts { .. } => TRACE_WIDTH, + TraceStorage::RowMajor(matrix) => matrix.width(), + TraceStorage::Transposed { num_cols, .. } => *num_cols, + } + } + + /// Row-major matrix of this trace. pub fn to_row_major(&self) -> RowMajorMatrix { - let num_rows = self.columns.num_rows(); - let mut col_major_data = Vec::with_capacity(num_rows * self.columns.num_cols()); - for col in self.columns.columns() { - col_major_data.extend_from_slice(col); + match &self.storage { + TraceStorage::RowMajor(matrix) => matrix.clone(), + TraceStorage::Transposed { matrix, .. } => matrix.transpose(), + TraceStorage::Parts { + core_rm, + chiplets_rm, + range_checker_cols, + num_rows, + } => { + let h = *num_rows; + let w = TRACE_WIDTH; + let cw = CHIPLETS_WIDTH; + + let total = h * w; + let mut data = Vec::with_capacity(total); + // SAFETY: the loop below writes exactly `h * w` elements. + #[allow(clippy::uninit_vec)] + unsafe { + data.set_len(total); + } + + let fill_rows = |chunk: &mut [Felt], start_row: usize| { + let chunk_rows = chunk.len() / w; + for i in 0..chunk_rows { + let row = start_row + i; + let dst = &mut chunk[i * w..(i + 1) * w]; + dst[..CORE_WIDTH] + .copy_from_slice(&core_rm[row * CORE_WIDTH..(row + 1) * CORE_WIDTH]); + dst[CORE_WIDTH] = range_checker_cols[0][row]; + dst[CORE_WIDTH + 1] = range_checker_cols[1][row]; + dst[CORE_WIDTH + 2..CORE_WIDTH + 2 + cw] + .copy_from_slice(&chiplets_rm[row * cw..(row + 1) * cw]); + } + }; + + #[cfg(not(feature = "concurrent"))] + fill_rows(&mut data, 0); + + #[cfg(feature = "concurrent")] + { + use miden_crypto::parallel::*; + let rows_per_chunk = ROW_MAJOR_CHUNK_SIZE; + data.par_chunks_mut(rows_per_chunk * w).enumerate().for_each( + |(chunk_idx, chunk)| { + fill_rows(chunk, chunk_idx * rows_per_chunk); + }, + ); + } + + RowMajorMatrix::new(data, w) + }, } - // Treat the flat column-major data as a "row-major" matrix with width = num_rows - // (i.e. each "row" is one original column), then transpose to get true row-major. - RowMajorMatrix::new(col_major_data, num_rows).transpose() } pub fn num_rows(&self) -> usize { - self.columns.num_rows() + match &self.storage { + TraceStorage::Parts { num_rows, .. } => *num_rows, + TraceStorage::RowMajor(matrix) => matrix.height(), + TraceStorage::Transposed { num_rows, .. } => *num_rows, + } } pub fn last_program_row(&self) -> RowIndex { self.last_program_row } + /// Copies one logical row into `row` (must be at least as long as the stored width). + pub fn read_row_into(&self, row_idx: usize, row: &mut [Felt]) { + let w = self.width(); + assert!(row.len() >= w, "row buffer too small for main trace"); + match &self.storage { + TraceStorage::RowMajor(matrix) => { + let slice = matrix.row_slice(row_idx).expect("row index in bounds"); + row[..w].copy_from_slice(&slice); + }, + TraceStorage::Parts { + core_rm, chiplets_rm, range_checker_cols, .. + } => { + row[..CORE_WIDTH] + .copy_from_slice(&core_rm[row_idx * CORE_WIDTH..(row_idx + 1) * CORE_WIDTH]); + row[CORE_WIDTH] = range_checker_cols[0][row_idx]; + row[CORE_WIDTH + 1] = range_checker_cols[1][row_idx]; + row[CORE_WIDTH + 2..CORE_WIDTH + 2 + CHIPLETS_WIDTH].copy_from_slice( + &chiplets_rm[row_idx * CHIPLETS_WIDTH..(row_idx + 1) * CHIPLETS_WIDTH], + ); + }, + TraceStorage::Transposed { matrix, num_cols, .. } => { + for (col_idx, cell) in row[..*num_cols].iter_mut().enumerate() { + *cell = unsafe { matrix.get_unchecked(col_idx, row_idx) }; + } + }, + } + } + + /// Returns one column as a new vector. + pub fn get_column(&self, col_idx: usize) -> Vec { + let h = self.num_rows(); + match &self.storage { + TraceStorage::Parts { + core_rm, chiplets_rm, range_checker_cols, .. + } => { + assert!(col_idx < TRACE_WIDTH, "main trace column index in bounds"); + if col_idx < CORE_WIDTH { + (0..h).map(|r| core_rm[r * CORE_WIDTH + col_idx]).collect() + } else { + let nc = col_idx - CORE_WIDTH; + if nc < RANGE_CHECK_TRACE_WIDTH { + range_checker_cols[nc].clone() + } else { + let cc = nc - RANGE_CHECK_TRACE_WIDTH; + (0..h).map(|r| chiplets_rm[r * CHIPLETS_WIDTH + cc]).collect() + } + } + }, + TraceStorage::RowMajor(_) => { + (0..h).map(|r| self.get(RowIndex::from(r), col_idx)).collect() + }, + TraceStorage::Transposed { matrix, .. } => { + let row_slice = matrix.row_slice(col_idx).expect("column index in bounds"); + row_slice[..h].to_vec() + }, + } + } + + /// Iterates over all columns (materialises each one). + pub fn columns(&self) -> impl Iterator> + '_ { + (0..self.width()).map(|c| self.get_column(c)) + } + #[cfg(any(test, feature = "testing"))] pub fn get_column_range(&self, range: Range) -> Vec> { range.fold(vec![], |mut acc, col_idx| { - acc.push(self.get_column(col_idx).to_vec()); + acc.push(self.get_column(col_idx)); acc }) } @@ -142,12 +363,12 @@ impl MainTrace { /// Returns the value of the clk column at row i. pub fn clk(&self, i: RowIndex) -> Felt { - self.columns.get_column(CLK_COL_IDX)[i] + self.get(i, CLK_COL_IDX) } /// Returns the value of the ctx column at row i. pub fn ctx(&self, i: RowIndex) -> Felt { - self.columns.get_column(CTX_COL_IDX)[i] + self.get(i, CTX_COL_IDX) } // DECODER COLUMNS @@ -155,7 +376,7 @@ impl MainTrace { /// Returns the value in the block address column at the row i. pub fn addr(&self, i: RowIndex) -> Felt { - self.columns.get_column(DECODER_TRACE_OFFSET)[i] + self.get(i, DECODER_TRACE_OFFSET) } /// Helper method to detect change of address. @@ -165,15 +386,14 @@ impl MainTrace { /// The i-th decoder helper register at `row`. pub fn helper_register(&self, i: usize, row: RowIndex) -> Felt { - self.columns.get_column(DECODER_TRACE_OFFSET + USER_OP_HELPERS_OFFSET + i)[row] + self.get(row, DECODER_TRACE_OFFSET + USER_OP_HELPERS_OFFSET + i) } /// Returns the hasher state at row i. pub fn decoder_hasher_state(&self, i: RowIndex) -> [Felt; NUM_HASHER_COLUMNS] { let mut state = [ZERO; NUM_HASHER_COLUMNS]; for (idx, col_idx) in DECODER_HASHER_RANGE.enumerate() { - let column = self.columns.get_column(col_idx); - state[idx] = column[i]; + state[idx] = self.get(i, col_idx); } state } @@ -182,7 +402,7 @@ impl MainTrace { pub fn decoder_hasher_state_first_half(&self, i: RowIndex) -> Word { let mut state = [ZERO; DIGEST_LEN]; for (col, s) in state.iter_mut().enumerate() { - *s = self.columns.get_column(DECODER_TRACE_OFFSET + HASHER_STATE_OFFSET + col)[i]; + *s = self.get(i, DECODER_TRACE_OFFSET + HASHER_STATE_OFFSET + col); } state.into() } @@ -192,62 +412,59 @@ impl MainTrace { const SECOND_WORD_OFFSET: usize = 4; let mut state = [ZERO; DIGEST_LEN]; for (col, s) in state.iter_mut().enumerate() { - *s = self - .columns - .get_column(DECODER_TRACE_OFFSET + HASHER_STATE_OFFSET + SECOND_WORD_OFFSET + col) - [i]; + *s = self.get(i, DECODER_TRACE_OFFSET + HASHER_STATE_OFFSET + SECOND_WORD_OFFSET + col); } state.into() } /// Returns a specific element from the hasher state at row i. pub fn decoder_hasher_state_element(&self, element: usize, i: RowIndex) -> Felt { - self.columns.get_column(DECODER_TRACE_OFFSET + HASHER_STATE_OFFSET + element)[i] + self.get(i, DECODER_TRACE_OFFSET + HASHER_STATE_OFFSET + element) } /// Returns the current function hash (i.e., root) at row i. pub fn fn_hash(&self, i: RowIndex) -> [Felt; DIGEST_LEN] { let mut state = [ZERO; DIGEST_LEN]; for (col, s) in state.iter_mut().enumerate() { - *s = self.columns.get_column(FN_HASH_OFFSET + col)[i]; + *s = self.get(i, FN_HASH_OFFSET + col); } state } /// Returns the `is_loop_body` flag at row i. pub fn is_loop_body_flag(&self, i: RowIndex) -> Felt { - self.columns.get_column(DECODER_TRACE_OFFSET + IS_LOOP_BODY_FLAG_COL_IDX)[i] + self.get(i, DECODER_TRACE_OFFSET + IS_LOOP_BODY_FLAG_COL_IDX) } /// Returns the `is_loop` flag at row i. pub fn is_loop_flag(&self, i: RowIndex) -> Felt { - self.columns.get_column(DECODER_TRACE_OFFSET + IS_LOOP_FLAG_COL_IDX)[i] + self.get(i, DECODER_TRACE_OFFSET + IS_LOOP_FLAG_COL_IDX) } /// Returns the `is_call` flag at row i. pub fn is_call_flag(&self, i: RowIndex) -> Felt { - self.columns.get_column(DECODER_TRACE_OFFSET + IS_CALL_FLAG_COL_IDX)[i] + self.get(i, DECODER_TRACE_OFFSET + IS_CALL_FLAG_COL_IDX) } /// Returns the `is_syscall` flag at row i. pub fn is_syscall_flag(&self, i: RowIndex) -> Felt { - self.columns.get_column(DECODER_TRACE_OFFSET + IS_SYSCALL_FLAG_COL_IDX)[i] + self.get(i, DECODER_TRACE_OFFSET + IS_SYSCALL_FLAG_COL_IDX) } /// Returns the operation batch flags at row i. This indicates the number of op groups in /// the current batch that is being processed. pub fn op_batch_flag(&self, i: RowIndex) -> [Felt; NUM_OP_BATCH_FLAGS] { [ - self.columns.get(DECODER_TRACE_OFFSET + OP_BATCH_FLAGS_OFFSET, i.into()), - self.columns.get(DECODER_TRACE_OFFSET + OP_BATCH_FLAGS_OFFSET + 1, i.into()), - self.columns.get(DECODER_TRACE_OFFSET + OP_BATCH_FLAGS_OFFSET + 2, i.into()), + self.get(i, DECODER_TRACE_OFFSET + OP_BATCH_FLAGS_OFFSET), + self.get(i, DECODER_TRACE_OFFSET + OP_BATCH_FLAGS_OFFSET + 1), + self.get(i, DECODER_TRACE_OFFSET + OP_BATCH_FLAGS_OFFSET + 2), ] } /// Returns the operation group count. This indicates the number of operation that remain /// to be executed in the current span block. pub fn group_count(&self, i: RowIndex) -> Felt { - self.columns.get_column(DECODER_TRACE_OFFSET + GROUP_COUNT_COL_IDX)[i] + self.get(i, DECODER_TRACE_OFFSET + GROUP_COUNT_COL_IDX) } /// Returns the delta between the current and next group counts. @@ -257,20 +474,18 @@ impl MainTrace { /// Returns the `in_span` flag at row i. pub fn is_in_span(&self, i: RowIndex) -> Felt { - self.columns.get_column(DECODER_TRACE_OFFSET + IN_SPAN_COL_IDX)[i] + self.get(i, DECODER_TRACE_OFFSET + IN_SPAN_COL_IDX) } /// Constructs the i-th op code value from its individual bits. pub fn get_op_code(&self, i: RowIndex) -> Felt { - let col_b0 = self.columns.get_column(DECODER_TRACE_OFFSET + 1); - let col_b1 = self.columns.get_column(DECODER_TRACE_OFFSET + 2); - let col_b2 = self.columns.get_column(DECODER_TRACE_OFFSET + 3); - let col_b3 = self.columns.get_column(DECODER_TRACE_OFFSET + 4); - let col_b4 = self.columns.get_column(DECODER_TRACE_OFFSET + 5); - let col_b5 = self.columns.get_column(DECODER_TRACE_OFFSET + 6); - let col_b6 = self.columns.get_column(DECODER_TRACE_OFFSET + 7); - let [b0, b1, b2, b3, b4, b5, b6] = - [col_b0[i], col_b1[i], col_b2[i], col_b3[i], col_b4[i], col_b5[i], col_b6[i]]; + let b0 = self.get(i, DECODER_TRACE_OFFSET + 1); + let b1 = self.get(i, DECODER_TRACE_OFFSET + 2); + let b2 = self.get(i, DECODER_TRACE_OFFSET + 3); + let b3 = self.get(i, DECODER_TRACE_OFFSET + 4); + let b4 = self.get(i, DECODER_TRACE_OFFSET + 5); + let b5 = self.get(i, DECODER_TRACE_OFFSET + 6); + let b6 = self.get(i, DECODER_TRACE_OFFSET + 7); b0 + b1 * Felt::from_u64(2) + b2 * Felt::from_u64(4) + b3 * Felt::from_u64(8) @@ -287,15 +502,15 @@ impl MainTrace { /// Returns a flag indicating whether the current operation induces a left shift of the operand /// stack. pub fn is_left_shift(&self, i: RowIndex) -> bool { - let b0 = self.columns.get(DECODER_TRACE_OFFSET + 1, i.into()); - let b1 = self.columns.get(DECODER_TRACE_OFFSET + 2, i.into()); - let b2 = self.columns.get(DECODER_TRACE_OFFSET + 3, i.into()); - let b3 = self.columns.get(DECODER_TRACE_OFFSET + 4, i.into()); - let b4 = self.columns.get(DECODER_TRACE_OFFSET + 5, i.into()); - let b5 = self.columns.get(DECODER_TRACE_OFFSET + 6, i.into()); - let b6 = self.columns.get(DECODER_TRACE_OFFSET + 7, i.into()); - let e0 = self.columns.get(DECODER_TRACE_OFFSET + OP_BITS_EXTRA_COLS_OFFSET, i.into()); - let h5 = self.columns.get(DECODER_TRACE_OFFSET + IS_LOOP_FLAG_COL_IDX, i.into()); + let b0 = self.get(i, DECODER_TRACE_OFFSET + 1); + let b1 = self.get(i, DECODER_TRACE_OFFSET + 2); + let b2 = self.get(i, DECODER_TRACE_OFFSET + 3); + let b3 = self.get(i, DECODER_TRACE_OFFSET + 4); + let b4 = self.get(i, DECODER_TRACE_OFFSET + 5); + let b5 = self.get(i, DECODER_TRACE_OFFSET + 6); + let b6 = self.get(i, DECODER_TRACE_OFFSET + 7); + let e0 = self.get(i, DECODER_TRACE_OFFSET + OP_BITS_EXTRA_COLS_OFFSET); + let h5 = self.get(i, DECODER_TRACE_OFFSET + IS_LOOP_FLAG_COL_IDX); // group with left shift effect grouped by a common prefix ([b6, b5, b4] == [ZERO, ONE, ZERO])|| @@ -314,13 +529,13 @@ impl MainTrace { /// Returns a flag indicating whether the current operation induces a right shift of the operand /// stack. pub fn is_right_shift(&self, i: RowIndex) -> bool { - let b0 = self.columns.get(DECODER_TRACE_OFFSET + 1, i.into()); - let b1 = self.columns.get(DECODER_TRACE_OFFSET + 2, i.into()); - let b2 = self.columns.get(DECODER_TRACE_OFFSET + 3, i.into()); - let b3 = self.columns.get(DECODER_TRACE_OFFSET + 4, i.into()); - let b4 = self.columns.get(DECODER_TRACE_OFFSET + 5, i.into()); - let b5 = self.columns.get(DECODER_TRACE_OFFSET + 6, i.into()); - let b6 = self.columns.get(DECODER_TRACE_OFFSET + 7, i.into()); + let b0 = self.get(i, DECODER_TRACE_OFFSET + 1); + let b1 = self.get(i, DECODER_TRACE_OFFSET + 2); + let b2 = self.get(i, DECODER_TRACE_OFFSET + 3); + let b3 = self.get(i, DECODER_TRACE_OFFSET + 4); + let b4 = self.get(i, DECODER_TRACE_OFFSET + 5); + let b5 = self.get(i, DECODER_TRACE_OFFSET + 6); + let b6 = self.get(i, DECODER_TRACE_OFFSET + 7); // group with right shift effect grouped by a common prefix [b6, b5, b4] == [ZERO, ONE, ONE]|| @@ -335,12 +550,12 @@ impl MainTrace { /// Returns the value of the stack depth column at row i. pub fn stack_depth(&self, i: RowIndex) -> Felt { - self.columns.get_column(STACK_TRACE_OFFSET + B0_COL_IDX)[i] + self.get(i, STACK_TRACE_OFFSET + B0_COL_IDX) } /// Returns the element at row i in a given stack trace column. pub fn stack_element(&self, column: usize, i: RowIndex) -> Felt { - self.columns.get_column(STACK_TRACE_OFFSET + column)[i] + self.get(i, STACK_TRACE_OFFSET + column) } /// Returns a word from the stack starting at `start` index at row i, in LE order. @@ -358,13 +573,13 @@ impl MainTrace { /// Returns the address of the top element in the stack overflow table at row i. pub fn parent_overflow_address(&self, i: RowIndex) -> Felt { - self.columns.get_column(STACK_TRACE_OFFSET + B1_COL_IDX)[i] + self.get(i, STACK_TRACE_OFFSET + B1_COL_IDX) } /// Returns a flag indicating whether the overflow stack is non-empty. pub fn is_non_empty_overflow(&self, i: RowIndex) -> bool { - let b0 = self.columns.get_column(STACK_TRACE_OFFSET + B0_COL_IDX)[i]; - let h0 = self.columns.get_column(STACK_TRACE_OFFSET + H0_COL_IDX)[i]; + let b0 = self.get(i, STACK_TRACE_OFFSET + B0_COL_IDX); + let h0 = self.get(i, STACK_TRACE_OFFSET + H0_COL_IDX); (b0 - Felt::from_u64(16)) * h0 == ONE } @@ -373,174 +588,210 @@ impl MainTrace { /// Returns chiplet column number 0 at row i. pub fn chiplet_selector_0(&self, i: RowIndex) -> Felt { - self.columns.get_column(CHIPLETS_OFFSET)[i] + self.get(i, CHIPLETS_OFFSET) } /// Returns chiplet column number 1 at row i. pub fn chiplet_selector_1(&self, i: RowIndex) -> Felt { - self.columns.get_column(CHIPLETS_OFFSET + 1)[i] + self.get(i, CHIPLETS_OFFSET + 1) } /// Returns chiplet column number 2 at row i. pub fn chiplet_selector_2(&self, i: RowIndex) -> Felt { - self.columns.get_column(CHIPLETS_OFFSET + 2)[i] + self.get(i, CHIPLETS_OFFSET + 2) } /// Returns chiplet column number 3 at row i. pub fn chiplet_selector_3(&self, i: RowIndex) -> Felt { - self.columns.get_column(CHIPLETS_OFFSET + 3)[i] + self.get(i, CHIPLETS_OFFSET + 3) } /// Returns chiplet column number 4 at row i. pub fn chiplet_selector_4(&self, i: RowIndex) -> Felt { - self.columns.get_column(CHIPLETS_OFFSET + 4)[i] + self.get(i, CHIPLETS_OFFSET + 4) } /// Returns chiplet column number 5 at row i. pub fn chiplet_selector_5(&self, i: RowIndex) -> Felt { - self.columns.get_column(CHIPLETS_OFFSET + 5)[i] + self.get(i, CHIPLETS_OFFSET + 5) } - /// Returns `true` if a row is part of the hash chiplet. + /// Returns `true` if a row is part of the hash chiplet (controller or permutation). pub fn is_hash_row(&self, i: RowIndex) -> bool { - self.chiplet_selector_0(i) == ZERO + self.chiplet_selector_0(i) == ONE || self.chiplet_s_perm(i) == ONE } /// Returns the (full) state of the hasher chiplet at row i. pub fn chiplet_hasher_state(&self, i: RowIndex) -> [Felt; STATE_WIDTH] { let mut state = [ZERO; STATE_WIDTH]; for (idx, col_idx) in HASHER_STATE_COL_RANGE.enumerate() { - let column = self.columns.get_column(col_idx); - state[idx] = column[i]; + state[idx] = self.get(i, col_idx); } state } /// Returns the hasher's node index column at row i pub fn chiplet_node_index(&self, i: RowIndex) -> Felt { - self.columns.get(HASHER_NODE_INDEX_COL_IDX, i.into()) + self.get(i, HASHER_NODE_INDEX_COL_IDX) + } + + /// Returns the hasher's mrupdate_id column at row i (domain separator for sibling table). + pub fn chiplet_mrupdate_id(&self, i: RowIndex) -> Felt { + self.get(i, HASHER_MRUPDATE_ID_COL_IDX) + } + + /// Returns the hasher's is_boundary column at row i (1 on boundary rows: first input or last + /// output of an operation). + pub fn chiplet_is_boundary(&self, i: RowIndex) -> Felt { + self.get(i, HASHER_IS_BOUNDARY_COL_IDX) + } + + /// Returns the hasher's direction_bit column at row i. On Merkle controller rows this holds + /// the direction bit extracted from the node index; zero on non-Merkle and perm segment rows. + pub fn chiplet_direction_bit(&self, i: RowIndex) -> Felt { + self.get(i, HASHER_DIRECTION_BIT_COL_IDX) + } + + /// Returns the hasher's s_perm column at row i (0=controller, 1=permutation segment). + pub fn chiplet_s_perm(&self, i: RowIndex) -> Felt { + self.get(i, HASHER_S_PERM_COL_IDX) + } + + /// Returns the memory's word address low 16-bit limb at row i. + pub fn chiplet_memory_word_addr_lo(&self, i: RowIndex) -> Felt { + self.get(i, MEMORY_WORD_ADDR_LO_COL_IDX) + } + + /// Returns the memory's word address high 16-bit limb at row i. + pub fn chiplet_memory_word_addr_hi(&self, i: RowIndex) -> Felt { + self.get(i, MEMORY_WORD_ADDR_HI_COL_IDX) } /// Returns `true` if a row is part of the bitwise chiplet. + /// Active when virtual s0=1 (s_ctrl=0, s_perm=0) and s1=0. pub fn is_bitwise_row(&self, i: RowIndex) -> bool { - self.chiplet_selector_0(i) == ONE && self.chiplet_selector_1(i) == ZERO + self.chiplet_selector_0(i) == ZERO + && self.chiplet_s_perm(i) == ZERO + && self.chiplet_selector_1(i) == ZERO } /// Returns the bitwise column holding the aggregated value of input `a` at row i. pub fn chiplet_bitwise_a(&self, i: RowIndex) -> Felt { - self.columns.get_column(BITWISE_A_COL_IDX)[i] + self.get(i, BITWISE_A_COL_IDX) } /// Returns the bitwise column holding the aggregated value of input `b` at row i. pub fn chiplet_bitwise_b(&self, i: RowIndex) -> Felt { - self.columns.get_column(BITWISE_B_COL_IDX)[i] + self.get(i, BITWISE_B_COL_IDX) } /// Returns the bitwise column holding the aggregated value of the output at row i. pub fn chiplet_bitwise_z(&self, i: RowIndex) -> Felt { - self.columns.get_column(BITWISE_OUTPUT_COL_IDX)[i] + self.get(i, BITWISE_OUTPUT_COL_IDX) } /// Returns `true` if a row is part of the memory chiplet. + /// Active when virtual s0=1 (s_ctrl=0, s_perm=0) and s1=1, s2=0. pub fn is_memory_row(&self, i: RowIndex) -> bool { - self.chiplet_selector_0(i) == ONE + self.chiplet_selector_0(i) == ZERO + && self.chiplet_s_perm(i) == ZERO && self.chiplet_selector_1(i) == ONE && self.chiplet_selector_2(i) == ZERO } /// Returns the i-th row of the chiplet column containing memory context. pub fn chiplet_memory_ctx(&self, i: RowIndex) -> Felt { - self.columns.get_column(MEMORY_CTX_COL_IDX)[i] + self.get(i, MEMORY_CTX_COL_IDX) } /// Returns the i-th row of the chiplet column containing memory address. pub fn chiplet_memory_word(&self, i: RowIndex) -> Felt { - self.columns.get_column(MEMORY_WORD_COL_IDX)[i] + self.get(i, MEMORY_WORD_COL_IDX) } /// Returns the i-th row of the chiplet column containing 0th bit of the word index. pub fn chiplet_memory_idx0(&self, i: RowIndex) -> Felt { - self.columns.get_column(MEMORY_IDX0_COL_IDX)[i] + self.get(i, MEMORY_IDX0_COL_IDX) } /// Returns the i-th row of the chiplet column containing 1st bit of the word index. pub fn chiplet_memory_idx1(&self, i: RowIndex) -> Felt { - self.columns.get_column(MEMORY_IDX1_COL_IDX)[i] + self.get(i, MEMORY_IDX1_COL_IDX) } /// Returns the i-th row of the chiplet column containing clock cycle. pub fn chiplet_memory_clk(&self, i: RowIndex) -> Felt { - self.columns.get_column(MEMORY_CLK_COL_IDX)[i] + self.get(i, MEMORY_CLK_COL_IDX) } /// Returns the i-th row of the chiplet column containing the zeroth memory value element. pub fn chiplet_memory_value_0(&self, i: RowIndex) -> Felt { - self.columns.get_column(MEMORY_V_COL_RANGE.start)[i] + self.get(i, MEMORY_V_COL_RANGE.start) } /// Returns the i-th row of the chiplet column containing the first memory value element. pub fn chiplet_memory_value_1(&self, i: RowIndex) -> Felt { - self.columns.get_column(MEMORY_V_COL_RANGE.start + 1)[i] + self.get(i, MEMORY_V_COL_RANGE.start + 1) } /// Returns the i-th row of the chiplet column containing the second memory value element. pub fn chiplet_memory_value_2(&self, i: RowIndex) -> Felt { - self.columns.get_column(MEMORY_V_COL_RANGE.start + 2)[i] + self.get(i, MEMORY_V_COL_RANGE.start + 2) } /// Returns the i-th row of the chiplet column containing the third memory value element. pub fn chiplet_memory_value_3(&self, i: RowIndex) -> Felt { - self.columns.get_column(MEMORY_V_COL_RANGE.start + 3)[i] + self.get(i, MEMORY_V_COL_RANGE.start + 3) } /// Returns `true` if a row is part of the ACE chiplet. + /// Active when virtual s0=1 (s_ctrl=0, s_perm=0) and s1=1, s2=1, s3=0. pub fn is_ace_row(&self, i: RowIndex) -> bool { - self.chiplet_selector_0(i) == ONE + self.chiplet_selector_0(i) == ZERO + && self.chiplet_s_perm(i) == ZERO && self.chiplet_selector_1(i) == ONE && self.chiplet_selector_2(i) == ONE && self.chiplet_selector_3(i) == ZERO } pub fn chiplet_ace_start_selector(&self, i: RowIndex) -> Felt { - self.columns - .get_column(CHIPLETS_OFFSET + NUM_ACE_SELECTORS + SELECTOR_START_IDX)[i] + self.get(i, CHIPLETS_OFFSET + NUM_ACE_SELECTORS + SELECTOR_START_IDX) } pub fn chiplet_ace_block_selector(&self, i: RowIndex) -> Felt { - self.columns - .get_column(CHIPLETS_OFFSET + NUM_ACE_SELECTORS + SELECTOR_BLOCK_IDX)[i] + self.get(i, CHIPLETS_OFFSET + NUM_ACE_SELECTORS + SELECTOR_BLOCK_IDX) } pub fn chiplet_ace_ctx(&self, i: RowIndex) -> Felt { - self.columns.get_column(CHIPLETS_OFFSET + NUM_ACE_SELECTORS + CTX_IDX)[i] + self.get(i, CHIPLETS_OFFSET + NUM_ACE_SELECTORS + CTX_IDX) } pub fn chiplet_ace_ptr(&self, i: RowIndex) -> Felt { - self.columns.get_column(CHIPLETS_OFFSET + NUM_ACE_SELECTORS + PTR_IDX)[i] + self.get(i, CHIPLETS_OFFSET + NUM_ACE_SELECTORS + PTR_IDX) } pub fn chiplet_ace_clk(&self, i: RowIndex) -> Felt { - self.columns.get_column(CHIPLETS_OFFSET + NUM_ACE_SELECTORS + CLK_IDX)[i] + self.get(i, CHIPLETS_OFFSET + NUM_ACE_SELECTORS + CLK_IDX) } pub fn chiplet_ace_eval_op(&self, i: RowIndex) -> Felt { - self.columns.get_column(CHIPLETS_OFFSET + NUM_ACE_SELECTORS + EVAL_OP_IDX)[i] + self.get(i, CHIPLETS_OFFSET + NUM_ACE_SELECTORS + EVAL_OP_IDX) } pub fn chiplet_ace_num_eval_rows(&self, i: RowIndex) -> Felt { - self.columns.get_column(CHIPLETS_OFFSET + NUM_ACE_SELECTORS + READ_NUM_EVAL_IDX)[i] + self.get(i, CHIPLETS_OFFSET + NUM_ACE_SELECTORS + READ_NUM_EVAL_IDX) } pub fn chiplet_ace_id_0(&self, i: RowIndex) -> Felt { - self.columns.get_column(CHIPLETS_OFFSET + NUM_ACE_SELECTORS + ID_0_IDX)[i] + self.get(i, CHIPLETS_OFFSET + NUM_ACE_SELECTORS + ID_0_IDX) } pub fn chiplet_ace_v_0_0(&self, i: RowIndex) -> Felt { - self.columns.get_column(CHIPLETS_OFFSET + NUM_ACE_SELECTORS + V_0_0_IDX)[i] + self.get(i, CHIPLETS_OFFSET + NUM_ACE_SELECTORS + V_0_0_IDX) } pub fn chiplet_ace_v_0_1(&self, i: RowIndex) -> Felt { - self.columns.get_column(CHIPLETS_OFFSET + NUM_ACE_SELECTORS + V_0_1_IDX)[i] + self.get(i, CHIPLETS_OFFSET + NUM_ACE_SELECTORS + V_0_1_IDX) } pub fn chiplet_ace_wire_0(&self, i: RowIndex) -> [Felt; 3] { @@ -552,15 +803,15 @@ impl MainTrace { } pub fn chiplet_ace_id_1(&self, i: RowIndex) -> Felt { - self.columns.get_column(CHIPLETS_OFFSET + NUM_ACE_SELECTORS + ID_1_IDX)[i] + self.get(i, CHIPLETS_OFFSET + NUM_ACE_SELECTORS + ID_1_IDX) } pub fn chiplet_ace_v_1_0(&self, i: RowIndex) -> Felt { - self.columns.get_column(CHIPLETS_OFFSET + NUM_ACE_SELECTORS + V_1_0_IDX)[i] + self.get(i, CHIPLETS_OFFSET + NUM_ACE_SELECTORS + V_1_0_IDX) } pub fn chiplet_ace_v_1_1(&self, i: RowIndex) -> Felt { - self.columns.get_column(CHIPLETS_OFFSET + NUM_ACE_SELECTORS + V_1_1_IDX)[i] + self.get(i, CHIPLETS_OFFSET + NUM_ACE_SELECTORS + V_1_1_IDX) } pub fn chiplet_ace_wire_1(&self, i: RowIndex) -> [Felt; 3] { @@ -572,15 +823,15 @@ impl MainTrace { } pub fn chiplet_ace_id_2(&self, i: RowIndex) -> Felt { - self.columns.get_column(CHIPLETS_OFFSET + NUM_ACE_SELECTORS + ID_2_IDX)[i] + self.get(i, CHIPLETS_OFFSET + NUM_ACE_SELECTORS + ID_2_IDX) } pub fn chiplet_ace_v_2_0(&self, i: RowIndex) -> Felt { - self.columns.get_column(CHIPLETS_OFFSET + NUM_ACE_SELECTORS + V_2_0_IDX)[i] + self.get(i, CHIPLETS_OFFSET + NUM_ACE_SELECTORS + V_2_0_IDX) } pub fn chiplet_ace_v_2_1(&self, i: RowIndex) -> Felt { - self.columns.get_column(CHIPLETS_OFFSET + NUM_ACE_SELECTORS + V_2_1_IDX)[i] + self.get(i, CHIPLETS_OFFSET + NUM_ACE_SELECTORS + V_2_1_IDX) } pub fn chiplet_ace_wire_2(&self, i: RowIndex) -> [Felt; 3] { @@ -592,11 +843,11 @@ impl MainTrace { } pub fn chiplet_ace_m_1(&self, i: RowIndex) -> Felt { - self.columns.get_column(CHIPLETS_OFFSET + NUM_ACE_SELECTORS + M_1_IDX)[i] + self.get(i, CHIPLETS_OFFSET + NUM_ACE_SELECTORS + M_1_IDX) } pub fn chiplet_ace_m_0(&self, i: RowIndex) -> Felt { - self.columns.get_column(CHIPLETS_OFFSET + NUM_ACE_SELECTORS + M_0_IDX)[i] + self.get(i, CHIPLETS_OFFSET + NUM_ACE_SELECTORS + M_0_IDX) } pub fn chiplet_ace_is_read_row(&self, i: RowIndex) -> bool { @@ -608,8 +859,10 @@ impl MainTrace { } /// Returns `true` if a row is part of the kernel chiplet. + /// Active when virtual s0=1 (s_ctrl=0, s_perm=0) and s1=1, s2=1, s3=1, s4=0. pub fn is_kernel_row(&self, i: RowIndex) -> bool { - self.chiplet_selector_0(i) == ONE + self.chiplet_selector_0(i) == ZERO + && self.chiplet_s_perm(i) == ZERO && self.chiplet_selector_1(i) == ONE && self.chiplet_selector_2(i) == ONE && self.chiplet_selector_3(i) == ONE @@ -619,73 +872,64 @@ impl MainTrace { /// Returns true when the i-th row of the `s_first` column in the kernel chiplet is one, i.e., /// when this is the first row in a range of rows containing the same kernel proc hash. pub fn chiplet_kernel_is_first_hash_row(&self, i: RowIndex) -> bool { - self.columns.get_column(CHIPLETS_OFFSET + 5)[i] == ONE + self.get(i, CHIPLETS_OFFSET + 5) == ONE } /// Returns the i-th row of the chiplet column containing the zeroth element of the kernel /// procedure root. pub fn chiplet_kernel_root_0(&self, i: RowIndex) -> Felt { - self.columns.get_column(CHIPLETS_OFFSET + 6)[i] + self.get(i, CHIPLETS_OFFSET + 6) } /// Returns the i-th row of the chiplet column containing the first element of the kernel /// procedure root. pub fn chiplet_kernel_root_1(&self, i: RowIndex) -> Felt { - self.columns.get_column(CHIPLETS_OFFSET + 7)[i] + self.get(i, CHIPLETS_OFFSET + 7) } /// Returns the i-th row of the chiplet column containing the second element of the kernel /// procedure root. pub fn chiplet_kernel_root_2(&self, i: RowIndex) -> Felt { - self.columns.get_column(CHIPLETS_OFFSET + 8)[i] + self.get(i, CHIPLETS_OFFSET + 8) } /// Returns the i-th row of the chiplet column containing the third element of the kernel /// procedure root. pub fn chiplet_kernel_root_3(&self, i: RowIndex) -> Felt { - self.columns.get_column(CHIPLETS_OFFSET + 9)[i] + self.get(i, CHIPLETS_OFFSET + 9) } - // MERKLE PATH HASHING SELECTORS + // MERKLE ROOT UPDATE SELECTORS // -------------------------------------------------------------------------------------------- - - /// Returns `true` if the hasher chiplet flags indicate the initialization of verifying - /// a Merkle path to an old node during Merkle root update procedure (MRUPDATE). + // + // The MRUPDATE operation has two legs, each traversing the same Merkle path: + // - MV (Merkle Verify old path): inserts siblings into the sibling table + // - MU (Merkle Update new path): removes siblings from the sibling table + // + // MPVERIFY (read-only path verification) does not interact with the sibling table. + + /// Returns `true` if row `i` is an MR_UPDATE_OLD (Merkle Verify) hasher controller input row. + /// + /// These rows appear during the old-path leg of a Merkle root update (MRUPDATE). Each + /// MV input row inserts a sibling into the virtual sibling table via the hash_kernel bus. pub fn f_mv(&self, i: RowIndex) -> bool { - i.as_usize().is_multiple_of(HASH_CYCLE_LEN) - && self.chiplet_selector_0(i) == ZERO - && self.chiplet_selector_1(i) == ONE - && self.chiplet_selector_2(i) == ONE - && self.chiplet_selector_3(i) == ZERO - } - - /// Returns `true` if the hasher chiplet flags indicate the continuation of verifying - /// a Merkle path to an old node during Merkle root update procedure (MRUPDATE). - pub fn f_mva(&self, i: RowIndex) -> bool { - (i.as_usize() % HASH_CYCLE_LEN == LAST_CYCLE_ROW) - && self.chiplet_selector_0(i) == ZERO - && self.chiplet_selector_1(i) == ONE - && self.chiplet_selector_2(i) == ONE - && self.chiplet_selector_3(i) == ZERO + self.chiplet_selector_0(i) == ONE // s_ctrl=1 (controller row) + && self.chiplet_s_perm(i) == ZERO // controller region + && self.chiplet_selector_1(i) == ONE // s0=1 (input row) + && self.chiplet_selector_2(i) == ONE // s1=1 (MR_UPDATE_OLD) + && self.chiplet_selector_3(i) == ZERO // s2=0 } - /// Returns `true` if the hasher chiplet flags indicate the initialization of verifying - /// a Merkle path to a new node during Merkle root update procedure (MRUPDATE). + /// Returns `true` if row `i` is an MR_UPDATE_NEW (Merkle Update) hasher controller input row. + /// + /// These rows appear during the new-path leg of a Merkle root update (MRUPDATE). Each + /// MU input row removes a sibling from the virtual sibling table via the hash_kernel bus. + /// The sibling table balance ensures the old and new paths use the same siblings. pub fn f_mu(&self, i: RowIndex) -> bool { - i.as_usize().is_multiple_of(HASH_CYCLE_LEN) - && self.chiplet_selector_0(i) == ZERO - && self.chiplet_selector_1(i) == ONE - && self.chiplet_selector_2(i) == ONE - && self.chiplet_selector_3(i) == ONE - } - - /// Returns `true` if the hasher chiplet flags indicate the continuation of verifying - /// a Merkle path to a new node during Merkle root update procedure (MRUPDATE). - pub fn f_mua(&self, i: RowIndex) -> bool { - (i.as_usize() % HASH_CYCLE_LEN == LAST_CYCLE_ROW) - && self.chiplet_selector_0(i) == ZERO - && self.chiplet_selector_1(i) == ONE - && self.chiplet_selector_2(i) == ONE - && self.chiplet_selector_3(i) == ONE + self.chiplet_selector_0(i) == ONE // s_ctrl=1 (controller row) + && self.chiplet_s_perm(i) == ZERO // controller region + && self.chiplet_selector_1(i) == ONE // s0=1 (input row) + && self.chiplet_selector_2(i) == ONE // s1=1 (MR_UPDATE_NEW) + && self.chiplet_selector_3(i) == ONE // s2=1 } } diff --git a/air/src/trace/mod.rs b/air/src/trace/mod.rs index 7086da5430..af5d5a52fa 100644 --- a/air/src/trace/mod.rs +++ b/air/src/trace/mod.rs @@ -1,11 +1,7 @@ use core::ops::Range; -use chiplets::hasher::RATE_LEN; use miden_core::utils::range; -mod challenges; -pub use challenges::Challenges; - pub mod chiplets; pub mod decoder; pub mod range; @@ -28,7 +24,7 @@ pub const MIN_TRACE_LEN: usize = 64; // ------------------------------------------------------------------------------------------------ // system decoder stack range checks chiplets -// (6 columns) (24 columns) (19 columns) (2 columns) (20 columns) +// (6 columns) (24 columns) (19 columns) (2 columns) (21 columns) // ├───────────────┴───────────────┴───────────────┴───────────────┴─────────────────┤ pub const SYS_TRACE_OFFSET: usize = 0; @@ -50,9 +46,6 @@ pub const STACK_TRACE_OFFSET: usize = DECODER_TRACE_RANGE.end; pub const STACK_TRACE_WIDTH: usize = 19; pub const STACK_TRACE_RANGE: Range = range(STACK_TRACE_OFFSET, STACK_TRACE_WIDTH); -/// Label for log_precompile transcript state messages on the virtual table bus. -pub const LOG_PRECOMPILE_LABEL: u8 = miden_core::operations::opcodes::LOGPRECOMPILE; - pub mod log_precompile { use core::ops::Range; @@ -114,7 +107,7 @@ pub const RANGE_CHECK_TRACE_RANGE: Range = // Chiplets trace pub const CHIPLETS_OFFSET: usize = RANGE_CHECK_TRACE_RANGE.end; -pub const CHIPLETS_WIDTH: usize = 20; +pub const CHIPLETS_WIDTH: usize = 21; pub const CHIPLETS_RANGE: Range = range(CHIPLETS_OFFSET, CHIPLETS_WIDTH); /// Shared chiplet selector columns at the start of the chiplets segment. @@ -126,73 +119,32 @@ pub const CHIPLET_S3_COL_IDX: usize = CHIPLET_SELECTORS_RANGE.start + 3; pub const CHIPLET_S4_COL_IDX: usize = CHIPLET_SELECTORS_RANGE.start + 4; pub const TRACE_WIDTH: usize = CHIPLETS_OFFSET + CHIPLETS_WIDTH; -pub const PADDED_TRACE_WIDTH: usize = TRACE_WIDTH.next_multiple_of(RATE_LEN); // AUXILIARY COLUMNS LAYOUT // ------------------------------------------------------------------------------------------------ +// +// The auxiliary trace is the LogUp lookup-argument segment built by +// [`crate::ProcessorAir`]'s `AuxBuilder` impl. It has 7 columns: 4 main-trace LogUp +// columns followed by 3 chiplet-trace LogUp columns. See +// [`crate::constraints::lookup::main_air::MainLookupAir`] and +// [`crate::constraints::lookup::chiplet_air::ChipletLookupAir`] for the per-column +// contents. -// decoder stack range checks chiplets -// (3 columns) (1 column) (1 column) (3 column) -// ├─────────────────────┴──────────────────────┴────────────────────┴───────────────────┤ - -/// Decoder auxiliary columns -pub const DECODER_AUX_TRACE_OFFSET: usize = 0; -pub const DECODER_AUX_TRACE_WIDTH: usize = 3; -pub const DECODER_AUX_TRACE_RANGE: Range = - range(DECODER_AUX_TRACE_OFFSET, DECODER_AUX_TRACE_WIDTH); - -/// Stack auxiliary columns -pub const STACK_AUX_TRACE_OFFSET: usize = DECODER_AUX_TRACE_RANGE.end; -pub const STACK_AUX_TRACE_WIDTH: usize = 1; -pub const STACK_AUX_TRACE_RANGE: Range = - range(STACK_AUX_TRACE_OFFSET, STACK_AUX_TRACE_WIDTH); - -/// Range check auxiliary columns -pub const RANGE_CHECK_AUX_TRACE_OFFSET: usize = STACK_AUX_TRACE_RANGE.end; -pub const RANGE_CHECK_AUX_TRACE_WIDTH: usize = 1; -pub const RANGE_CHECK_AUX_TRACE_RANGE: Range = - range(RANGE_CHECK_AUX_TRACE_OFFSET, RANGE_CHECK_AUX_TRACE_WIDTH); - -/// Chiplets virtual table auxiliary column. -/// -/// This column combines two virtual tables: -/// -/// 1. Hash chiplet's sibling table, -/// 2. Kernel ROM chiplet's kernel procedure table. -pub const HASH_KERNEL_VTABLE_AUX_TRACE_OFFSET: usize = RANGE_CHECK_AUX_TRACE_RANGE.end; -pub const HASHER_AUX_TRACE_WIDTH: usize = 1; -pub const HASHER_AUX_TRACE_RANGE: Range = - range(HASH_KERNEL_VTABLE_AUX_TRACE_OFFSET, HASHER_AUX_TRACE_WIDTH); - -/// Chiplets bus auxiliary columns. -pub const CHIPLETS_BUS_AUX_TRACE_OFFSET: usize = HASHER_AUX_TRACE_RANGE.end; -pub const CHIPLETS_BUS_AUX_TRACE_WIDTH: usize = 1; -pub const CHIPLETS_BUS_AUX_TRACE_RANGE: Range = - range(CHIPLETS_BUS_AUX_TRACE_OFFSET, CHIPLETS_BUS_AUX_TRACE_WIDTH); - -/// ACE chiplet wiring bus. -pub const ACE_CHIPLET_WIRING_BUS_OFFSET: usize = CHIPLETS_BUS_AUX_TRACE_RANGE.end; -pub const ACE_CHIPLET_WIRING_BUS_WIDTH: usize = 1; -pub const ACE_CHIPLET_WIRING_BUS_RANGE: Range = - range(ACE_CHIPLET_WIRING_BUS_OFFSET, ACE_CHIPLET_WIRING_BUS_WIDTH); - -/// Auxiliary trace segment width. -pub const AUX_TRACE_WIDTH: usize = ACE_CHIPLET_WIRING_BUS_RANGE.end; +/// Auxiliary trace segment width — see the LogUp aux trace layout above. +pub const AUX_TRACE_WIDTH: usize = crate::LOGUP_AUX_TRACE_WIDTH; /// Number of random challenges used for auxiliary trace constraints. pub const AUX_TRACE_RAND_CHALLENGES: usize = 2; -/// Maximum number of coefficients used in bus message encodings. -pub const MAX_MESSAGE_WIDTH: usize = 16; - /// Bus message coefficient indices. /// /// These define the standard positions for encoding bus messages using the pattern: -/// `alpha + sum(beta_powers\[i\] * elem\[i\])` where: -/// - `alpha` is the randomness base (accessed directly as `.alpha`) +/// `bus_prefix[bus] + sum(beta_powers\[i\] * elem\[i\])` where: +/// - `bus_prefix[bus]` is the per-bus domain-separated base (see `BusId` in +/// `constraints::lookup::logup_msg`) /// - `beta_powers\[i\] = beta^i` are the powers of beta /// -/// These indices refer to positions in the `beta_powers` array, not including alpha. +/// These indices refer to positions in the `beta_powers` array, not including the bus prefix. /// /// This layout is shared between: /// - AIR constraint builders (symbolic expressions): `Challenges` diff --git a/air/src/trace/range.rs b/air/src/trace/range.rs index 3081bbe3a8..2181164518 100644 --- a/air/src/trace/range.rs +++ b/air/src/trace/range.rs @@ -1,4 +1,4 @@ -use super::{RANGE_CHECK_AUX_TRACE_OFFSET, RANGE_CHECK_TRACE_OFFSET}; +use super::RANGE_CHECK_TRACE_OFFSET; // CONSTANTS // ================================================================================================ @@ -9,9 +9,3 @@ use super::{RANGE_CHECK_AUX_TRACE_OFFSET, RANGE_CHECK_TRACE_OFFSET}; pub const M_COL_IDX: usize = RANGE_CHECK_TRACE_OFFSET; /// A column to hold the values being range-checked. pub const V_COL_IDX: usize = RANGE_CHECK_TRACE_OFFSET + 1; - -// --- Column accessors in the auxiliary columns -------------------------------------------------- - -/// The running product column used for verifying that the range check lookups performed in the -/// Stack and the Memory chiplet match the values checked in the Range Checker. -pub const B_RANGE_COL_IDX: usize = RANGE_CHECK_AUX_TRACE_OFFSET; diff --git a/air/src/trace/rows.rs b/air/src/trace/rows.rs index 521f401ad7..b2b3b6870b 100644 --- a/air/src/trace/rows.rs +++ b/air/src/trace/rows.rs @@ -1,4 +1,4 @@ -use alloc::boxed::Box; +use alloc::{boxed::Box, vec::Vec}; use core::{ fmt::{Display, Formatter}, ops::{Add, AddAssign, Bound, Index, IndexMut, Mul, RangeBounds, Sub, SubAssign}, @@ -271,6 +271,13 @@ impl IndexMut for [T] { } } +impl Index for Vec { + type Output = T; + fn index(&self, i: RowIndex) -> &Self::Output { + &self.as_slice()[i] + } +} + impl RangeBounds for RowIndex { fn start_bound(&self) -> Bound<&Self> { Bound::Included(self) diff --git a/air/tests/ace_codegen.rs b/air/tests/ace_codegen.rs new file mode 100644 index 0000000000..d4c477855a --- /dev/null +++ b/air/tests/ace_codegen.rs @@ -0,0 +1,185 @@ +use miden_ace_codegen::{ + AceConfig, AceError, EXT_DEGREE, InputKey, LayoutKind, build_ace_circuit_for_air, + build_ace_dag_for_air, emit_circuit, + testing::{ + eval_dag, eval_folded_constraints, eval_periodic_values, eval_quotient, fill_inputs, + zps_for_chunk, + }, +}; +use miden_air::{LiftedAir, ProcessorAir}; +use miden_core::{Felt, field::QuadFelt}; +use miden_crypto::{ + field::{Field, PrimeCharacteristicRing}, + stark::air::symbolic::{AirLayout, SymbolicAirBuilder}, +}; + +#[test] +fn processor_air_dag_matches_manual_eval() { + let air = ProcessorAir; + let config = AceConfig { + num_quotient_chunks: 2, + num_vlpi_groups: 0, + layout: LayoutKind::Native, + }; + let artifacts = build_ace_dag_for_air::<_, Felt, QuadFelt>(&air, config).unwrap(); + let layout = artifacts.layout.clone(); + let inputs: Vec = fill_inputs(&layout); + let z_k = inputs[layout.index(InputKey::ZK).unwrap()]; + let periodic_values = eval_periodic_values::( + &LiftedAir::::periodic_columns(&air), + z_k, + ); + + let air_layout = AirLayout { + preprocessed_width: 0, + main_width: layout.counts.width, + num_public_values: layout.counts.num_public, + permutation_width: layout.counts.aux_width, + num_permutation_challenges: layout.counts.num_randomness, + num_permutation_values: LiftedAir::::num_aux_values(&air), + num_periodic_columns: layout.counts.num_periodic, + }; + let mut builder = SymbolicAirBuilder::::new(air_layout); + LiftedAir::::eval(&air, &mut builder); + + let acc = eval_folded_constraints( + &builder.base_constraints(), + &builder.extension_constraints(), + &builder.constraint_layout(), + &inputs, + &layout, + &periodic_values, + ); + let z_pow_n = inputs[layout.index(InputKey::ZPowN).unwrap()]; + let vanishing = z_pow_n - QuadFelt::ONE; + let expected = acc - eval_quotient::(&layout, &inputs) * vanishing; + + let actual = eval_dag(&artifacts.dag, &inputs, &layout).unwrap(); + assert_eq!(actual, expected); +} + +#[test] +fn processor_air_dag_rejects_mismatched_layout() { + let air = ProcessorAir; + let dag_config = AceConfig { + num_quotient_chunks: 8, + num_vlpi_groups: 0, + layout: LayoutKind::Native, + }; + let layout_config = AceConfig { + num_quotient_chunks: 1, + num_vlpi_groups: 0, + layout: LayoutKind::Native, + }; + + let dag = build_ace_dag_for_air::<_, Felt, QuadFelt>(&air, dag_config).unwrap().dag; + let wrong_layout = + build_ace_dag_for_air::<_, Felt, QuadFelt>(&air, layout_config).unwrap().layout; + let inputs: Vec = fill_inputs(&wrong_layout); + + let err = eval_dag(&dag, &inputs, &wrong_layout).unwrap_err(); + assert!( + matches!(err, AceError::InvalidInputLayout { .. }), + "expected InvalidInputLayout, got {err:?}" + ); +} + +#[test] +#[allow(clippy::print_stdout)] +fn processor_air_chiplet_rows() { + let air = ProcessorAir; + let config = AceConfig { + num_quotient_chunks: 8, + num_vlpi_groups: 1, + layout: LayoutKind::Masm, + }; + + let circuit = build_ace_circuit_for_air::<_, Felt, QuadFelt>(&air, config).unwrap(); + let encoded = circuit.to_ace().unwrap(); + let read_rows = encoded.num_read_rows(); + let eval_rows = encoded.num_eval_rows(); + let total_rows = read_rows + eval_rows; + + println!( + "ACE chiplet rows (ProcessorAir): read={}, eval={}, total={}, inputs={}, constants={}, nodes={}", + read_rows, + eval_rows, + total_rows, + encoded.num_inputs(), + encoded.num_constants(), + encoded.num_nodes() + ); +} + +#[test] +fn synthetic_ood_adjusts_quotient_to_zero() { + let config = AceConfig { + num_quotient_chunks: 8, + num_vlpi_groups: 0, + layout: LayoutKind::Masm, + }; + + let artifacts = + build_ace_dag_for_air::<_, Felt, QuadFelt>(&ProcessorAir, config).expect("ace dag"); + let circuit = emit_circuit(&artifacts.dag, artifacts.layout.clone()).expect("ace circuit"); + + let mut inputs: Vec = fill_inputs(&artifacts.layout); + let root = circuit.eval(&inputs).expect("circuit eval"); + + let z_pow_n = inputs[artifacts.layout.index(InputKey::ZPowN).unwrap()]; + let vanishing = z_pow_n - QuadFelt::ONE; + let zps_0 = zps_for_chunk::(&artifacts.layout, &inputs, 0); + let delta = root * (zps_0 * vanishing).inverse(); + + let idx = artifacts + .layout + .index(InputKey::QuotientChunkCoord { offset: 0, chunk: 0, coord: 0 }) + .unwrap(); + inputs[idx] += delta; + + let result = circuit.eval(&inputs).expect("circuit eval"); + assert!(result.is_zero(), "ACE circuit must evaluate to zero"); +} + +#[test] +fn quotient_next_inputs_do_not_affect_eval() { + let config = AceConfig { + num_quotient_chunks: 8, + num_vlpi_groups: 0, + layout: LayoutKind::Masm, + }; + + let artifacts = + build_ace_dag_for_air::<_, Felt, QuadFelt>(&ProcessorAir, config).expect("ace dag"); + let circuit = emit_circuit(&artifacts.dag, artifacts.layout.clone()).expect("ace circuit"); + + let mut inputs: Vec = fill_inputs(&artifacts.layout); + + let root = circuit.eval(&inputs).expect("circuit eval"); + let z_pow_n = inputs[artifacts.layout.index(InputKey::ZPowN).unwrap()]; + let vanishing = z_pow_n - QuadFelt::ONE; + let zps_0 = zps_for_chunk::(&artifacts.layout, &inputs, 0); + let delta = root * (zps_0 * vanishing).inverse(); + let idx = artifacts + .layout + .index(InputKey::QuotientChunkCoord { offset: 0, chunk: 0, coord: 0 }) + .unwrap(); + inputs[idx] += delta; + assert!( + circuit.eval(&inputs).expect("circuit eval").is_zero(), + "precondition: zero root" + ); + + for chunk in 0..artifacts.layout.counts.num_quotient_chunks { + for coord in 0..EXT_DEGREE { + let idx = artifacts + .layout + .index(InputKey::QuotientChunkCoord { offset: 1, chunk, coord }) + .unwrap(); + inputs[idx] += QuadFelt::from(Felt::new_unchecked(123 + (chunk * 7 + coord) as u64)); + } + } + + let result = circuit.eval(&inputs).expect("circuit eval"); + assert!(result.is_zero(), "quotient_next should not affect ACE eval"); +} diff --git a/benches/synthetic-bench/Cargo.toml b/benches/synthetic-bench/Cargo.toml new file mode 100644 index 0000000000..c2a858f751 --- /dev/null +++ b/benches/synthetic-bench/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "miden-vm-synthetic-bench" +version.workspace = true +edition.workspace = true +license.workspace = true +authors.workspace = true +homepage.workspace = true +repository.workspace = true +publish = false + +[lints] +workspace = true + +[dependencies] +miden-processor = { workspace = true, features = ["concurrent"] } +miden-vm = { path = "../../miden-vm", features = ["concurrent"] } +serde = { workspace = true, features = ["std"] } +serde_json = { workspace = true, features = ["std"] } +thiserror = { workspace = true, features = ["std"] } + +[dev-dependencies] +criterion = { workspace = true } + +[[bench]] +name = "synthetic_bench" +harness = false diff --git a/benches/synthetic-bench/README.md b/benches/synthetic-bench/README.md new file mode 100644 index 0000000000..d7074041a9 --- /dev/null +++ b/benches/synthetic-bench/README.md @@ -0,0 +1,227 @@ +# miden-vm-synthetic-bench + +Criterion benchmark that reproduces the **proving-cost brackets** of a real +workload from a small JSON snapshot, without depending on any +producer-side runtime code. + +## Approach + +STARK proving cost is dominated by the padded power-of-two lengths of the +execution trace's segments. Everything else -- per-chiplet row counts, +instruction mix, which procedures get called -- is second-order once the +brackets are known. + +This crate takes a snapshot of per-segment trace-row counts captured by +an external producer (e.g. `protocol/bin/bench-transaction/`'s +`bench-tx.json`), generates a tiny MASM program whose execution +reproduces those brackets, and runs `execute` + `execute_and_prove` +Criterion groups against it. The result is a VM-level regression detector +that isolates *prover* changes from *workload* changes without depending +on the producer's machinery. + +## Pipeline (per bench run) + +Each bench invocation rebuilds every synthetic program from scratch, +so the numbers always reflect the current commit's VM -- there are no +stale calibration constants checked into the repo. + +1. **Calibrate (once)** -- run each MASM snippet as `repeat.K ...` and + divide the resulting per-component row counts by `K` to learn how + many core/hasher/memory/... rows a single iteration costs *on this + VM*. Running this on every bench invocation is what keeps the + bench honest across VM changes: if `hperm` gets cheaper tomorrow, + tomorrow's iteration count grows to compensate, and the target + bracket is still hit. + +For each scenario in every producer file under `snapshots/` (or the +single file in `SYNTH_SNAPSHOT`): + +2. **Load scenario** -- read the target row counts from the producer's + `trace` section. See [Snapshot format](#snapshot-format). +3. **Solve** -- pick an iteration count for each snippet so that their + combined row contributions add up to the scenario's target. We do + this by fixed-point refinement: start from zero, and on each pass + update every snippet's count from the current guesses of the others, + clamping negatives to zero. A handful of passes is enough because + each snippet is designed to drive mostly *one* component, so the + counts barely depend on each other and the sweep converges quickly. + (For the linear-algebra reader: this is Jacobi iteration on a + near-diagonal matrix with a non-negativity projection.) +4. **Emit** -- wrap each snippet's body in a `repeat.N ... end` block, + concatenate, and enclose in `begin ... end`. The output is the MASM + program that Criterion actually runs. +5. **Verify** -- execute the emitted program, measure its real row + counts, and assert that `padded_core_side` and `padded_chiplets` + match the scenario's. A bracket miss fails the bench; smaller drift + inside the same bracket is reported but tolerated, because proving + cost is driven by the padded length, not the raw count. + +## Snippets + +Five patterns cover every component the solver targets: + +| Snippet | Body | Drives | +|---------------|----------------------------------------------|-------------------------------| +| `hasher` | `hperm` | Poseidon2 hasher chiplet | +| `bitwise` | `u32split u32xor` | bitwise chiplet | +| `u32arith` | `u32assert2 push.65537 add swap push.65537 add swap` | range chiplet | +| `memory` | `dup.4 mem_storew_le dup.4 mem_loadw_le movup.4 push.262148 add movdn.4` | memory chiplet | +| `decoder_pad` | `swap dup.1 add` | core (decoder + stack) | + +`u32arith` and `memory` use banded counters (strides of 65537 and +262148) so that their 16-bit limbs form disjoint contiguous bands, +keeping the range chiplet from deduplicating limb values across +iterations. + +The solver has no snippets targeting the ACE or kernel-ROM chiplets. + +- **ACE** is reachable from plain MASM, but exercising it requires + building an arithmetic circuit and preparing a memory region for its + READ section -- more setup than the other snippets warrant, and not + currently done here. +- **Kernel-ROM** rows are a small, near-constant contribution in + practice, so we simplify by folding them into the memory target + rather than driving them directly. + +Since snapshots still carry row counts for both, they're **folded into +the memory target** -- growing memory ops preserves the overall +chiplet-trace length and therefore the chiplet bracket. + +One producer-side caveat: the consumer can measure `ace_chiplet_len()` +when it runs synthetic programs, but a producer pinned to an older +`miden-processor` may report `ace_rows: 0` until that dependency +exposes the accessor. Treat zero ACE rows in a snapshot as a producer +visibility limitation, not as proof that the VM emitted no ACE rows. + +## Snapshot format + +A producer JSON file is a map of scenario keys to entries. Each entry +must carry a `trace` section; any sibling fields (cycle counts, +metadata, ...) are silently ignored. Inside `trace`, the AIR-side +totals (`core_rows`, `chiplets_rows`, `range_rows`) are the verifier's +hard contract; nested `chiplets_shape` is an advisory per-chiplet +breakdown. The loader checks +`trace.chiplets_rows == sum(trace.chiplets_shape) + 1`. + +```json +{ + "consume single P2ID note": { + "trace": { + "core_rows": 77699, + "chiplets_rows": 123129, + "range_rows": 20203, + "chiplets_shape": { + "hasher_rows": 120352, + "bitwise_rows": 416, + "memory_rows": 2297, + "kernel_rom_rows": 63, + "ace_rows": 0 + } + } + } +} +``` + +Snapshots live in `snapshots/`. The bench loads every `*.json` file in +that directory and runs one Criterion group per `(producer_file, +scenario_key)` pair, named `/`. See the +[Running](#running) section below for `SYNTH_SNAPSHOT` / +`SYNTH_SCENARIO` filters. + +There is no schema-version field; the on-disk shape is the contract. +If the producer changes that shape, the loader fails loudly (serde +error or chiplet-sum mismatch). Update both repos together. + +## Verifier contract + +Once the emitted program has run, the verifier compares its actual +row counts against the scenario's targets and decides whether the +bench passed. The checks come in three tiers -- **hard**, **soft**, +and **info** -- graded by how directly each number maps to proving +cost. There's also one free-standing **warning** for snippet-balance +regressions. + +### Hard checks -- fail the bench + +Proving cost is dominated by the padded (power-of-two) length of each +trace segment, not by the raw row count. So the only assertions that +can fail the bench are on two padded proxies: + +- `padded_core_side = max(64, next_pow2(max(core_rows, range_rows)))` + -- the non-chiplets side of the AIR. +- `padded_chiplets = max(64, next_pow2(chiplets_rows))`. + +These two can land in *different* brackets on the same workload -- +`consume two P2ID notes`, for example, has `padded_core_side = 131072` +but `padded_chiplets = 262144`. Checking them independently catches a +bracket miss on either side that a single global `padded_total` check +would hide. + +### Soft checks -- report, don't fail + +`core_rows` and `chiplets_rows` are compared against the targets +within a 2% band. A drift inside that band is harmless for proving +cost (same bracket either way), so the bench only reports it. A +drift that *crosses* a bracket is already caught by the hard tier +above, so this tier exists purely to surface in-bracket near-misses +worth noticing. + +### Info -- no judgement + +Per-chiplet deltas (hasher/bitwise/memory/...) from `shape` are +printed for visibility but never asserted. Some divergence is +unavoidable: MAST hashing at program init contributes hasher rows +that the synthetic program can't suppress, so a snapshot with +`core_rows / hasher_rows > 4` cannot be per-chiplet-matched even +though it still matches both padded brackets. See `src/snippets.rs` +for the cases where this structural mismatch shows up. + +### Warning -- range dominates + +If `range_rows` turns out to be the largest unpadded component in +either the target or the actual shape, the bench prints a warning. +The solver treats range as a derived quantity driven mostly by u32 +arithmetic; if it starts setting the bracket, snippet balance has +drifted and should be revisited. + +## Refreshing snapshots from a producer + +Snapshots travel by hand so that producer and consumer can evolve +independently. For the `protocol/bin/bench-transaction/` producer: + +1. In `protocol`: `cargo run --release --bin bench-transaction --features concurrent`. +2. Copy `bin/bench-transaction/bench-tx.json` over + `miden-vm/benches/synthetic-bench/snapshots/bench-tx.json`. +3. Run `cargo bench -p miden-vm-synthetic-bench` and verify + `=> BRACKET MATCH` for every scenario in the printed verifier + tables. + +If a kernel change moves a scenario into a different padded bucket, +the `committed_snapshots_load` test in `src/snapshot.rs` fails with +the producer/scenario pair and the new bracket -- update +`COMMITTED_SCENARIO_EXPECTATIONS` accordingly. + +## Running + +```sh +cargo bench -p miden-vm-synthetic-bench +``` + +Env vars: + +- `SYNTH_SNAPSHOT=` -- bench only the specified producer JSON + (instead of iterating over every `snapshots/*.json`). +- `SYNTH_SCENARIO=` -- restrict to scenarios whose slugified + key contains this slugified substring. Both sides are slugified + before comparison, so `"P2ID"`, `"p2id"`, `"P2ID note"`, and + `"p2id-note"` all match `"consume single P2ID note"`. +- `SYNTH_MASM_WRITE=1` -- dump each emitted MASM program to + `target/synthetic_bench___.masm` for + inspection. + +The `prove` and `verify` axes use `HashFunction::Poseidon2` for STARK +proof generation (see the `BENCH_HASH` constant in `benches/synthetic_bench.rs`). + +## License + +This project is dual-licensed under the [MIT](http://opensource.org/licenses/MIT) and [Apache 2.0](https://opensource.org/license/apache-2-0) licenses. diff --git a/benches/synthetic-bench/benches/synthetic_bench.rs b/benches/synthetic-bench/benches/synthetic_bench.rs new file mode 100644 index 0000000000..faa066946b --- /dev/null +++ b/benches/synthetic-bench/benches/synthetic_bench.rs @@ -0,0 +1,428 @@ +//! Synthetic VM benchmark driven by row-count snapshots. +//! +//! Pipeline each bench run: +//! 1. Calibrate each snippet's per-iteration cost against the current VM (shared across all +//! snapshots in this run). +//! 2. For each producer JSON (every `snapshots/*.json`, or the single file in `SYNTH_SNAPSHOT`), +//! load every scenario it contains and: solve for per-snippet iteration counts, emit the +//! resulting MASM program, check it lands in the scenario's padded-trace bracket, and run four +//! Criterion benches per scenario -- `exec`, `trace_prep`, `prove`, `verify`. +//! +//! Env vars: +//! - `SYNTH_SNAPSHOT`: path to a single producer JSON; if set, only this file is benched. Otherwise +//! every `snapshots/*.json` in the manifest dir is used. +//! - `SYNTH_SCENARIO`: if set, restrict to scenarios whose slugified key contains this slugified +//! substring (case- and separator-insensitive; `"P2ID"`, `"p2id"`, `"P2ID note"`, and +//! `"p2id-note"` all match `"consume single P2ID note"`). +//! - `SYNTH_MASM_WRITE`: if set, write the emitted MASM to +//! `target/synthetic_bench___.masm`. + +use std::{hint::black_box, path::PathBuf, time::Duration}; + +use criterion::{BatchSize, Criterion, SamplingMode, criterion_group, criterion_main}; +use miden_processor::{ + DefaultHost, ExecutionOptions, FastProcessor, StackInputs, advice::AdviceInputs, +}; +use miden_vm::{Assembler, HashFunction, Program, ProgramInfo, ProvingOptions, prove_sync}; +use miden_vm_synthetic_bench::{ + calibrator::{Calibration, calibrate, measure_program}, + snapshot::{TraceShape, TraceSnapshot}, + snippets::{SNIPPETS, memory_max_iters, u32arith_max_iters}, + solver::{Plan, emit, solve}, + verifier::VerificationReport, +}; + +/// Hash function used for STARK `prove` and `verify` axes. +const BENCH_HASH: HashFunction = HashFunction::Poseidon2; + +/// Builds the per-iteration inputs shared by the `exec` and `trace_prep` axes. +fn processor_inputs(program: &Program) -> (DefaultHost, Program, FastProcessor) { + let host = DefaultHost::default(); + let processor = FastProcessor::new_with_options( + StackInputs::default(), + AdviceInputs::default(), + ExecutionOptions::default(), + ) + .expect("processor advice inputs should fit advice map limits"); + (host, program.clone(), processor) +} + +fn resolve_snapshot_paths() -> Vec { + if let Ok(explicit) = std::env::var("SYNTH_SNAPSHOT") { + return vec![PathBuf::from(explicit)]; + } + let snapshots_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("snapshots"); + let mut paths: Vec = std::fs::read_dir(&snapshots_dir) + .unwrap_or_else(|e| panic!("failed to read {}: {e}", snapshots_dir.display())) + .filter_map(|entry| entry.ok().map(|e| e.path())) + .filter(|p| p.extension().and_then(|e| e.to_str()) == Some("json")) + .collect(); + paths.sort(); + assert!(!paths.is_empty(), "no snapshots found under {}", snapshots_dir.display()); + paths +} + +/// Lower-case ASCII slug; non-alphanumerics collapse to single `-` separators. +fn slugify(s: &str) -> String { + let mut out = String::with_capacity(s.len()); + let mut last_was_dash = true; + for ch in s.chars() { + if ch.is_ascii_alphanumeric() { + out.push(ch.to_ascii_lowercase()); + last_was_dash = false; + } else if !last_was_dash { + out.push('-'); + last_was_dash = true; + } + } + while out.ends_with('-') { + out.pop(); + } + out +} + +fn synthetic_bench(c: &mut Criterion) { + let calibration = calibrate().expect("failed to calibrate snippets"); + println!("\n=== calibration (rows/iter)"); + for snippet in SNIPPETS { + let cost = calibration[snippet.name]; + println!( + " {:<14} core={:7.3} hasher={:6.3} bitwise={:6.3} memory={:6.3} range={:6.3}", + snippet.name, cost.core, cost.hasher, cost.bitwise, cost.memory, cost.range, + ); + } + + // Slugify the filter so substring-matching is case- and separator-insensitive + // (`SYNTH_SCENARIO=P2ID` matches `consume-single-p2id-note` etc.). + let scenario_filter = std::env::var("SYNTH_SCENARIO").ok().map(|s| slugify(&s)); + let mut benched_anything = false; + for path in resolve_snapshot_paths() { + let producer_stem = + path.file_stem().and_then(|s| s.to_str()).unwrap_or("unknown").to_string(); + let mut scenarios = TraceSnapshot::load_all(&path) + .unwrap_or_else(|e| panic!("failed to load snapshot at {}: {e}", path.display())); + scenarios.sort_by_key(|(_, snap)| snap.trace.chiplets_rows); + for (scenario_key, snapshot) in scenarios { + let scenario_slug = slugify(&scenario_key); + if let Some(filter) = &scenario_filter + && !scenario_slug.contains(filter.as_str()) + { + continue; + } + bench_one_scenario( + c, + &calibration, + &producer_stem, + &scenario_key, + &scenario_slug, + &snapshot, + ); + benched_anything = true; + } + } + assert!(benched_anything, "no scenarios matched (filter: {scenario_filter:?})"); +} + +fn bench_one_scenario( + c: &mut Criterion, + calibration: &Calibration, + producer_stem: &str, + scenario_key: &str, + scenario_slug: &str, + snapshot: &TraceSnapshot, +) { + println!("\n=== scenario: {producer_stem} / {scenario_key}"); + println!( + " trace: core={} chiplets={} range={} (padded_total={})", + snapshot.trace.core_rows, + snapshot.trace.chiplets_rows, + snapshot.trace.range_rows, + snapshot.trace.padded_total(), + ); + println!( + " shape: hasher={} bitwise={} memory={} kernel_rom={} ace={}", + snapshot.shape.hasher_rows, + snapshot.shape.bitwise_rows, + snapshot.shape.memory_rows, + snapshot.shape.kernel_rom_rows, + snapshot.shape.ace_rows, + ); + if snapshot.shape.substituted_rows() > 0 { + println!( + " note: {} rows (ace={} + kernel_rom={}) folded into memory target", + snapshot.shape.substituted_rows(), + snapshot.shape.ace_rows, + snapshot.shape.kernel_rom_rows, + ); + } + + let target_shape = snapshot.shape(); + let mut plan = solve(calibration, &target_shape); + range_correction_pass(&mut plan, &target_shape); + assert_counters_fit(&plan); + + println!("\n=== plan"); + for snippet in SNIPPETS { + println!(" {:<14} iters={}", snippet.name, plan.iters(snippet.name),); + } + + let source = emit(&plan); + if std::env::var("SYNTH_MASM_WRITE").is_ok() { + let out = PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("target") + .join(format!("synthetic_bench_{producer_stem}__{scenario_slug}.masm")); + std::fs::create_dir_all(out.parent().expect("parent")) + .expect("create target dir for MASM dump"); + std::fs::write(&out, &source).expect("write MASM dump"); + println!("\n=== wrote MASM dump to {}", out.display()); + } + + let actual = measure_program(&source).expect("measure emitted program"); + let report = VerificationReport::new(target_shape, actual); + println!("\n=== verification\n{report}"); + assert!( + report.brackets_match(), + "emitted program lands in a different padded-trace bracket than the scenario target", + ); + + let program = Assembler::default() + .assemble_program(&source) + .expect("assemble emitted program"); + + let mut group = c.benchmark_group(format!("{producer_stem}/{scenario_slug}")); + group + .sampling_mode(SamplingMode::Flat) + .sample_size(30) + .warm_up_time(Duration::from_millis(1000)) + .measurement_time(Duration::from_secs(30)); + + // Four axes per scenario: + // exec -- FastProcessor::execute_sync (no trace data) + // trace_prep -- FastProcessor::execute_trace_inputs_sync (the input to prove_from_trace_sync) + // prove -- prove_sync (= trace_prep + STARK prove) + // verify -- miden_vm::verify against a proof generated once outside the timed loop + group.bench_function("exec", |b| { + b.iter_batched( + || processor_inputs(&program), + |(mut host, program, processor)| { + black_box(processor.execute_sync(&program, &mut host).expect("exec")); + }, + BatchSize::SmallInput, + ); + }); + + group.bench_function("trace_prep", |b| { + b.iter_batched( + || processor_inputs(&program), + |(mut host, program, processor)| { + black_box( + processor.execute_trace_inputs_sync(&program, &mut host).expect("trace_prep"), + ); + }, + BatchSize::SmallInput, + ); + }); + + group.bench_function("prove", |b| { + b.iter_batched( + || { + let host = DefaultHost::default(); + let stack = StackInputs::default(); + let advice = AdviceInputs::default(); + (host, program.clone(), stack, advice) + }, + |(mut host, program, stack, advice)| { + black_box( + prove_sync( + &program, + stack, + advice, + &mut host, + ExecutionOptions::default(), + ProvingOptions::new(BENCH_HASH), + ) + .expect("prove"), + ); + }, + BatchSize::SmallInput, + ); + }); + + // Generate one proof outside the timed loop so prove_sync time isn't counted toward verify. + let program_info = ProgramInfo::from(program.clone()); + let (stack_outputs, proof) = { + let mut host = DefaultHost::default(); + prove_sync( + &program, + StackInputs::default(), + AdviceInputs::default(), + &mut host, + ExecutionOptions::default(), + ProvingOptions::new(BENCH_HASH), + ) + .expect("prove for verify setup") + }; + group.bench_function("verify", |b| { + b.iter_batched( + || (program_info.clone(), StackInputs::default(), stack_outputs, proof.clone()), + |(program_info, stack_inputs, stack_outputs, proof)| { + black_box( + miden_vm::verify(program_info, stack_inputs, stack_outputs, proof) + .expect("verify"), + ); + }, + BatchSize::SmallInput, + ); + }); + + group.finish(); +} + +/// Panic if any snippet's plan iteration count would overflow its counter beyond `u32::MAX` (which +/// would trip `u32assert2` or a memory op at runtime). Cheap safeguard in case a snapshot with +/// unusually large range or memory targets gets fed in. +fn assert_counters_fit(plan: &Plan) { + let u32arith = plan.iters("u32arith"); + assert!( + u32arith <= u32arith_max_iters(), + "u32arith iters ({}) would overflow its u32 counter (max {}); \ + revisit the banded-counter start constants", + u32arith, + u32arith_max_iters(), + ); + let memory = plan.iters("memory"); + assert!( + memory <= memory_max_iters(), + "memory iters ({}) would overflow its u32 address counter (max {}); \ + revisit the banded-address start constants", + memory, + memory_max_iters(), + ); +} + +// RANGE CORRECTION PASS +// ------------------------------------------------------------------------ +// +// Range's trace length is not perfectly linear under composition, so the primary solver can leave +// a few-percent residual. This pass closes it by measuring marginal rates and applying a combo of +// `+u32arith -hasher -decoder_pad` that lifts range while keeping core and chiplets approximately +// fixed. Memory is deliberately left alone so the emitted memory-chiplet workload stays +// representative. + +#[derive(Debug, Clone, Copy)] +struct MarginalRates { + core: f64, + chiplets: f64, + range: f64, +} + +const CORRECTION_PROBE_DELTA: u64 = 256; +const CORRECTION_TOLERANCE: f64 = 0.01; +const CORRECTION_MAX_PASSES: usize = 2; + +fn measure_plan(plan: &Plan) -> TraceShape { + let source = emit(plan); + measure_program(&source).expect("measure emitted plan") +} + +fn measure_marginal( + base_plan: &Plan, + base_shape: TraceShape, + snippet: &'static str, + delta: u64, +) -> MarginalRates { + let mut probe = base_plan.clone(); + probe.add(snippet, delta); + let shape = measure_plan(&probe); + let d = delta as f64; + MarginalRates { + core: (shape.totals.core_rows as f64 - base_shape.totals.core_rows as f64) / d, + chiplets: (shape.totals.chiplets_rows as f64 - base_shape.totals.chiplets_rows as f64) / d, + range: (shape.totals.range_rows as f64 - base_shape.totals.range_rows as f64) / d, + } +} + +/// Solve for `(add_u32arith, sub_hasher, sub_pad)` that lifts range by `range_residual` while +/// holding core and chiplets approximately fixed. Returns `None` if the 2x2 system for the two +/// subtractions is degenerate, any coefficient comes out negative, or the net range gain is +/// non-positive. +fn solve_range_correction( + range_residual: f64, + u32arith: MarginalRates, + hasher: MarginalRates, + decoder_pad: MarginalRates, +) -> Option<(u64, u64, u64)> { + if range_residual <= 0.0 { + return None; + } + // Solve per unit of u32arith: + // hasher.core * y + decoder_pad.core * z = u32arith.core + // hasher.chiplets * y + decoder_pad.chiplets * z = u32arith.chiplets + let det = hasher.core * decoder_pad.chiplets - decoder_pad.core * hasher.chiplets; + if det.abs() < 1e-9 { + return None; + } + let y_per_x = + (u32arith.core * decoder_pad.chiplets - decoder_pad.core * u32arith.chiplets) / det; + let z_per_x = (hasher.core * u32arith.chiplets - u32arith.core * hasher.chiplets) / det; + if y_per_x < 0.0 || z_per_x < 0.0 { + return None; + } + let net_range_per_x = u32arith.range - hasher.range * y_per_x - decoder_pad.range * z_per_x; + if net_range_per_x <= 0.0 { + return None; + } + let x = (range_residual / net_range_per_x).round(); + if x <= 0.0 { + return None; + } + Some((x as u64, (x * y_per_x).round() as u64, (x * z_per_x).round() as u64)) +} + +fn range_correction_pass(plan: &mut Plan, target: &TraceShape) { + let target_range = target.totals.range_rows; + if target_range == 0 { + return; + } + let tolerance = (target_range as f64 * CORRECTION_TOLERANCE) as u64; + for pass in 0..CORRECTION_MAX_PASSES { + let actual = measure_plan(plan); + let actual_range = actual.totals.range_rows; + let residual = target_range as i64 - actual_range as i64; + println!( + "\n=== range correction pass {}: target={} actual={} residual={}", + pass + 1, + target_range, + actual_range, + residual, + ); + if residual <= tolerance as i64 { + // Already within band, or overshoot (residual <= 0). + return; + } + + let u32arith = measure_marginal(plan, actual, "u32arith", CORRECTION_PROBE_DELTA); + let hasher = measure_marginal(plan, actual, "hasher", CORRECTION_PROBE_DELTA); + let decoder_pad = measure_marginal(plan, actual, "decoder_pad", CORRECTION_PROBE_DELTA); + + match solve_range_correction(residual as f64, u32arith, hasher, decoder_pad) { + Some((add_u32arith, sub_hasher, sub_pad)) => { + let sub_hasher = sub_hasher.min(plan.iters("hasher")); + let sub_pad = sub_pad.min(plan.iters("decoder_pad")); + println!( + " applying: +u32arith {add_u32arith} -hasher {sub_hasher} -decoder_pad {sub_pad}" + ); + plan.add("u32arith", add_u32arith); + plan.sub_saturating("hasher", sub_hasher); + plan.sub_saturating("decoder_pad", sub_pad); + }, + None => { + println!(" no valid local correction found"); + return; + }, + } + } +} + +criterion_group!(benches, synthetic_bench); +criterion_main!(benches); diff --git a/benches/synthetic-bench/snapshots/bench-tx.json b/benches/synthetic-bench/snapshots/bench-tx.json new file mode 100644 index 0000000000..41a28815d3 --- /dev/null +++ b/benches/synthetic-bench/snapshots/bench-tx.json @@ -0,0 +1,151 @@ +{ + "consume single P2ID note": { + "prologue": 3491, + "notes_processing": 1761, + "note_execution": { + "0xcc9b6800b67338071874f6f8bcb9716c31a7b97626064eef34a713e2068fe21e": 1721 + }, + "tx_script_processing": 42, + "epilogue": { + "total": 72345, + "auth_procedure": 70843, + "after_tx_cycles_obtained": 612 + }, + "trace": { + "core_rows": 77683, + "chiplets_rows": 123159, + "range_rows": 20179, + "chiplets_shape": { + "hasher_rows": 120384, + "bitwise_rows": 416, + "memory_rows": 2294, + "kernel_rom_rows": 64, + "ace_rows": 0 + } + } + }, + "consume two P2ID notes": { + "prologue": 4527, + "notes_processing": 3600, + "note_execution": { + "0x621c91b9a914d27fbc7e5d9a743e2ac72593e2b96d74d22edf3443b04ab01fbd": 1721, + "0xdc6a6014e58b417f8ed38e7092e7c885a534a27fcd746a20200bf1bc8e1b976d": 1830 + }, + "tx_script_processing": 42, + "epilogue": { + "total": 72293, + "auth_procedure": 70817, + "after_tx_cycles_obtained": 612 + }, + "trace": { + "core_rows": 80506, + "chiplets_rows": 141290, + "range_rows": 20129, + "chiplets_shape": { + "hasher_rows": 138240, + "bitwise_rows": 592, + "memory_rows": 2389, + "kernel_rom_rows": 68, + "ace_rows": 0 + } + } + }, + "create single P2ID note": { + "prologue": 1756, + "notes_processing": 32, + "note_execution": {}, + "tx_script_processing": 1659, + "epilogue": { + "total": 73237, + "auth_procedure": 71055, + "after_tx_cycles_obtained": 612 + }, + "trace": { + "core_rows": 76728, + "chiplets_rows": 118595, + "range_rows": 20011, + "chiplets_shape": { + "hasher_rows": 115968, + "bitwise_rows": 328, + "memory_rows": 2235, + "kernel_rom_rows": 63, + "ace_rows": 0 + } + } + }, + "consume CLAIM note (L1 to Miden)": { + "prologue": 2887, + "notes_processing": 28554, + "note_execution": { + "0xd7d99970e9793cd134b13b9f4894bdb10c2f80aafd3656cb390d76cf079e9958": 28514 + }, + "tx_script_processing": 42, + "epilogue": { + "total": 4090, + "auth_procedure": 880, + "after_tx_cycles_obtained": 612 + }, + "trace": { + "core_rows": 35617, + "chiplets_rows": 147222, + "range_rows": 2407, + "chiplets_shape": { + "hasher_rows": 141248, + "bitwise_rows": 2624, + "memory_rows": 3277, + "kernel_rom_rows": 72, + "ace_rows": 0 + } + } + }, + "consume CLAIM note (L2 to Miden)": { + "prologue": 2887, + "notes_processing": 40804, + "note_execution": { + "0xccad52dbae536daa8e0c5888e712446cc3aeb8f5dd455b907a31d6972eb89163": 40764 + }, + "tx_script_processing": 42, + "epilogue": { + "total": 4090, + "auth_procedure": 880, + "after_tx_cycles_obtained": 612 + }, + "trace": { + "core_rows": 47867, + "chiplets_rows": 189924, + "range_rows": 2649, + "chiplets_shape": { + "hasher_rows": 182464, + "bitwise_rows": 2880, + "memory_rows": 4507, + "kernel_rom_rows": 72, + "ace_rows": 0 + } + } + }, + "consume B2AGG note (bridge-out)": { + "prologue": 3708, + "notes_processing": 145469, + "note_execution": { + "0x4214c8b99dc2ec5fb56584e35555762a379dd506904a4203a151691f7b2f7d9a": 145429 + }, + "tx_script_processing": 42, + "epilogue": { + "total": 13753, + "auth_procedure": 880, + "after_tx_cycles_obtained": 612 + }, + "trace": { + "core_rows": 163016, + "chiplets_rows": 911692, + "range_rows": 4111, + "chiplets_shape": { + "hasher_rows": 896832, + "bitwise_rows": 2608, + "memory_rows": 12042, + "kernel_rom_rows": 209, + "ace_rows": 0 + } + } + } +} diff --git a/benches/synthetic-bench/src/calibrator.rs b/benches/synthetic-bench/src/calibrator.rs new file mode 100644 index 0000000000..8e73f56e63 --- /dev/null +++ b/benches/synthetic-bench/src/calibrator.rs @@ -0,0 +1,255 @@ +//! Calibration and measurement helpers. +//! +//! Each snippet is run as a `repeat.K` loop, measured through the real trace builder, and +//! converted into per-iteration row costs. Calibration happens on every bench run so the synthetic +//! adapts to the current VM's row accounting. + +use std::collections::BTreeMap; + +use miden_processor::{DefaultHost, FastProcessor, StackInputs, trace::build_trace}; +use miden_vm::Assembler; + +use crate::{ + snapshot::{TraceBreakdown, TraceShape, TraceTotals}, + snippets::{self, Component, SNIPPETS}, +}; + +pub const CALIBRATION_ITERS: u64 = 1000; + +// MEASUREMENT +// ------------------------------------------------------------------------ + +/// Assemble and execute `source`, returning the shape of the resulting execution trace. Wraps +/// assembler + fast processor + trace builder. +pub fn measure_program(source: &str) -> Result { + let program = Assembler::default() + .assemble_program(source) + .map_err(|e| MeasurementError::Assembly(format!("{e}")))?; + + let mut host = DefaultHost::default(); + let processor = FastProcessor::new(StackInputs::default()); + let trace_inputs = processor + .execute_trace_inputs_sync(&program, &mut host) + .map_err(|e| MeasurementError::Execution(format!("{e}")))?; + let trace = + build_trace(trace_inputs).map_err(|e| MeasurementError::TraceBuild(format!("{e}")))?; + let summary = trace.trace_len_summary(); + let chiplets = summary.chiplets_trace_len(); + + let breakdown = TraceBreakdown { + hasher_rows: chiplets.hash_chiplet_len() as u64, + bitwise_rows: chiplets.bitwise_chiplet_len() as u64, + memory_rows: chiplets.memory_chiplet_len() as u64, + kernel_rom_rows: chiplets.kernel_rom_len() as u64, + ace_rows: chiplets.ace_chiplet_len() as u64, + }; + let totals = TraceTotals { + core_rows: summary.main_trace_len() as u64, + chiplets_rows: chiplets.trace_len() as u64, + range_rows: summary.range_trace_len() as u64, + }; + + // Cross-check our derived formulas against the processor's authoritative values; a drift here + // means the AIR-side definitions have moved and the rest of the pipeline will silently + // miscalibrate. + let derived_chiplets = breakdown.chiplets_sum(); + if totals.chiplets_rows != derived_chiplets { + return Err(MeasurementError::InvariantDrift { + quantity: "chiplets_total", + processor: totals.chiplets_rows, + derived: derived_chiplets, + }); + } + let derived_padded = totals.padded_total(); + let processor_padded = summary.padded_trace_len() as u64; + if derived_padded != processor_padded { + return Err(MeasurementError::InvariantDrift { + quantity: "padded_total", + processor: processor_padded, + derived: derived_padded, + }); + } + + Ok(TraceShape::new(totals, breakdown)) +} + +#[derive(Debug, thiserror::Error)] +pub enum MeasurementError { + #[error("failed to assemble program: {0}")] + Assembly(String), + #[error("failed to execute program: {0}")] + Execution(String), + #[error("failed to build trace: {0}")] + TraceBuild(String), + /// One of our derived formulas drifted from the processor's authoritative value; AIR-side + /// definitions have probably changed and the snapshot/verifier formulas need updating. + #[error( + "invariant drift: {quantity} from processor = {processor}, but our derivation = {derived}" + )] + InvariantDrift { + quantity: &'static str, + processor: u64, + derived: u64, + }, +} + +// CALIBRATION +// ------------------------------------------------------------------------ + +/// Per-iteration row rates, kept as `f64` and rounded by the solver. +#[derive(Debug, Clone, Copy, Default)] +pub struct IterCost { + pub core: f64, + pub hasher: f64, + pub bitwise: f64, + pub memory: f64, + pub range: f64, +} + +impl IterCost { + pub fn get(&self, component: Component) -> f64 { + match component { + Component::Core => self.core, + Component::Hasher => self.hasher, + Component::Bitwise => self.bitwise, + Component::Memory => self.memory, + Component::Range => self.range, + } + } +} + +/// Per-snippet rows-per-iter across every tracked component. Cross-terms (e.g. a non-zero hasher +/// rate on the `decoder_pad` snippet) are measured so the solver can subtract them. +pub type Calibration = BTreeMap<&'static str, IterCost>; + +/// Run every snippet through a single-point calibration at [`CALIBRATION_ITERS`] and record +/// per-iter cost in each component. +pub fn calibrate() -> Result { + let mut cal = Calibration::new(); + for snippet in SNIPPETS { + let source = snippets::wrap_program(&snippets::render(snippet, CALIBRATION_ITERS)); + let shape = measure_program(&source)?; + cal.insert(snippet.name, per_iter_cost(shape, CALIBRATION_ITERS)); + } + Ok(cal) +} + +fn per_iter_cost(shape: TraceShape, iters: u64) -> IterCost { + let k = iters as f64; + IterCost { + core: shape.totals.core_rows as f64 / k, + hasher: shape.breakdown.hasher_rows as f64 / k, + bitwise: shape.breakdown.bitwise_rows as f64 / k, + memory: shape.breakdown.memory_rows as f64 / k, + range: shape.totals.range_rows as f64 / k, + } +} + +#[cfg(test)] +mod tests { + use super::*; + + // MEASUREMENT TESTS + // -------------------------------------------------------------------- + + #[test] + fn measures_trivial_program() { + // `measure_program()` already cross-checks our derived totals against the processor's + // authoritative values; this test just smoke-checks basic measurement. + let shape = measure_program("begin push.1 drop end").expect("measure"); + assert!(shape.totals.core_rows > 0, "main trace should include framing rows"); + assert!(shape.totals.padded_total().is_power_of_two()); + } + + #[test] + fn hperm_adds_rows_beyond_baseline() { + let baseline = measure_program("begin push.1 drop end").expect("baseline"); + let with_hperm = + measure_program("begin padw padw padw hperm dropw dropw dropw end").expect("hperm"); + assert!( + with_hperm.breakdown.hasher_rows > baseline.breakdown.hasher_rows, + "hperm should add hasher rows above the baseline ({} vs {})", + with_hperm.breakdown.hasher_rows, + baseline.breakdown.hasher_rows, + ); + } + + // CALIBRATION TESTS + // -------------------------------------------------------------------- + + fn cal() -> Calibration { + calibrate().expect("calibration should succeed") + } + + #[test] + fn every_snippet_has_an_entry() { + let c = cal(); + for snippet in SNIPPETS { + assert!(c.contains_key(snippet.name), "missing calibration for {}", snippet.name); + } + } + + #[test] + fn hasher_snippet_is_hasher_dominant() { + let c = cal(); + let hasher = c["hasher"]; + let pad = c["decoder_pad"]; + assert!( + hasher.hasher > pad.hasher * 10.0, + "hasher/iter ({}) not dominant over decoder_pad leak ({})", + hasher.hasher, + pad.hasher, + ); + } + + #[test] + fn bitwise_snippet_rows_match_op_cycle_len() { + let c = cal(); + let bitwise = c["bitwise"]; + // OP_CYCLE_LEN = 8 per u32 bitwise op. + assert!( + bitwise.bitwise >= 7.5, + "bitwise per-iter ({}) below OP_CYCLE_LEN", + bitwise.bitwise + ); + assert!( + bitwise.bitwise <= 9.0, + "bitwise per-iter ({}) above OP_CYCLE_LEN", + bitwise.bitwise + ); + } + + #[test] + fn memory_snippet_two_rows_per_iter() { + let c = cal(); + let memory = c["memory"]; + assert!(memory.memory >= 1.5, "memory per-iter ({}) too low", memory.memory); + assert!(memory.memory <= 2.5, "memory per-iter ({}) too high", memory.memory); + } + + #[test] + fn u32arith_snippet_drives_range() { + let c = cal(); + let arith = c["u32arith"]; + let pad = c["decoder_pad"]; + assert!( + arith.range > pad.range * 5.0, + "u32arith range/iter ({}) should dominate the baseline decoder_pad range/iter ({})", + arith.range, + pad.range, + ); + } + + #[test] + fn decoder_pad_is_core_dominant() { + let c = cal(); + let pad = c["decoder_pad"]; + assert!(pad.core > 1.0, "decoder_pad core/iter should be > 1.0"); + assert!( + pad.core > pad.hasher * 3.0, + "decoder_pad core ({}) should dominate hasher ({})", + pad.core, + pad.hasher, + ); + } +} diff --git a/benches/synthetic-bench/src/lib.rs b/benches/synthetic-bench/src/lib.rs new file mode 100644 index 0000000000..028f4ed86b --- /dev/null +++ b/benches/synthetic-bench/src/lib.rs @@ -0,0 +1,18 @@ +//! Synthetic benchmark generator for VM-level proving regression tests. +//! +//! Given a snapshot of per-component trace row counts captured by an external producer, +//! this crate calibrates a small catalog of MASM snippets against the current VM, solves +//! for iteration counts, emits a synthetic program, and verifies that the program lands +//! in the target core/chiplets padded brackets. +//! +//! The snapshot schema has two tiers: +//! - `trace`: hard totals (`core_rows`, `chiplets_rows`, `range_rows`) +//! - `shape`: advisory per-chiplet breakdown used by the solver +//! +//! See `README.md` for design rationale. + +pub mod calibrator; +pub mod snapshot; +pub mod snippets; +pub mod solver; +pub mod verifier; diff --git a/benches/synthetic-bench/src/snapshot.rs b/benches/synthetic-bench/src/snapshot.rs new file mode 100644 index 0000000000..59ad5370ba --- /dev/null +++ b/benches/synthetic-bench/src/snapshot.rs @@ -0,0 +1,475 @@ +//! Snapshot schema for the VM-side synthetic benchmark. +//! +//! A producer JSON file (e.g. `bench-tx.json` from `protocol/bin/bench-transaction/`) maps +//! scenario keys to entries; only the `trace` section of each entry is consumed. +//! +//! `trace` carries the AIR-side row totals used by the verifier (`core_rows`, `chiplets_rows`, +//! `range_rows`). `shape` (nested under `trace`) is an advisory per-chiplet breakdown used by the +//! solver. The loader checks `trace.chiplets_rows == shape.chiplets_sum()`. + +use std::{collections::BTreeMap, path::Path}; + +use serde::Deserialize; + +/// Mirrors `miden_air::trace::MIN_TRACE_LEN`. Keep in sync when the processor's minimum padded +/// length changes. +const MIN_TRACE_LEN: u64 = 64; + +/// A single scenario's trace snapshot, extracted from a producer JSON file. +/// +/// On disk, the chiplet breakdown is nested under `trace` as `chiplets_shape` +/// (`{ "trace": { "core_rows": ..., "chiplets_shape": ... } }`). Here it's hoisted to a sibling +/// of `trace` and renamed `shape` so callers can write `snap.shape.hasher_rows` instead of +/// `snap.trace.chiplets_shape.hasher_rows`; `RawScenarioEntry` / `RawTrace` below bridge the +/// layouts at deserialization time. +#[derive(Debug, Clone)] +pub struct TraceSnapshot { + /// Hard-target totals. The verifier's bracket check operates on these. + pub trace: TraceTotals, + /// Advisory per-chiplet breakdown used by the solver for shaping. + pub shape: TraceBreakdown, +} + +/// Hard-target aggregates -- the verifier's primary contract. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct TraceTotals { + /// System + decoder + stack trace length. + pub core_rows: u64, + /// Total chiplets trace length, matching `ChipletsLengths::trace_len` in the processor (sum of + /// per-chiplet lengths + 1 mandatory padding row). + pub chiplets_rows: u64, + /// Range-checker trace length. Derived from memory + bitwise activity; not independently + /// targeted but tracked so the verifier can warn if it ever dominates. + pub range_rows: u64, +} + +/// Per-chiplet row counts. Advisory only -- the solver uses these to size individual snippets so +/// the synthetic program stays representative (hasher work looks like hasher work, not a pile of +/// decoder-pad), but the verifier does not treat individual values as hard targets. +#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Eq)] +pub struct TraceBreakdown { + pub hasher_rows: u64, + pub bitwise_rows: u64, + pub memory_rows: u64, + /// Kernel ROM rows. Not drivable from plain MASM; folded into memory. + #[serde(default)] + pub kernel_rom_rows: u64, + /// ACE chiplet rows. Not drivable from plain MASM; folded into memory. Some producer versions + /// may report this as zero until their processor dependency exposes the ACE trace accessor. + #[serde(default)] + pub ace_rows: u64, +} + +/// In-memory bundle used by the solver and verifier; not serialized. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct TraceShape { + pub totals: TraceTotals, + pub breakdown: TraceBreakdown, +} + +impl TraceTotals { + /// Padded power-of-two bracket for the non-chiplet side of the trace: + /// `next_pow2(max(core_rows, range_rows))`. Under the current AIR this covers core + /// (system/decoder/stack) and range together; if a future AIR separates them, this accessor + /// can be revisited. + pub fn padded_core_side(&self) -> u64 { + self.core_rows.max(self.range_rows).next_power_of_two().max(MIN_TRACE_LEN) + } + + /// Padded power-of-two bracket for the chiplets side of the trace. + pub fn padded_chiplets(&self) -> u64 { + self.chiplets_rows.next_power_of_two().max(MIN_TRACE_LEN) + } + + /// Single global padded length as reported by the processor's + /// `TraceLenSummary::padded_trace_len`. Used by the calibrator to cross-check our derived + /// formulas against the prover. + pub fn padded_total(&self) -> u64 { + self.core_rows + .max(self.range_rows) + .max(self.chiplets_rows) + .next_power_of_two() + .max(MIN_TRACE_LEN) + } + + /// True iff `range_rows` is the largest unpadded component. + pub fn range_dominates(&self) -> bool { + self.range_rows > self.core_rows && self.range_rows > self.chiplets_rows + } +} + +impl TraceBreakdown { + /// Sum of all chiplet sub-traces plus the mandatory +1 padding row, matching + /// `ChipletsLengths::trace_len` in the processor. Used as the loader's consistency check + /// against `TraceTotals::chiplets_rows`. + pub fn chiplets_sum(&self) -> u64 { + self.hasher_rows + + self.bitwise_rows + + self.memory_rows + + self.kernel_rom_rows + + self.ace_rows + + 1 + } + + /// Memory-row target the solver aims for: snapshot memory plus ACE and kernel_rom (both + /// unreachable from plain MASM) folded in. + pub fn memory_target(&self) -> u64 { + self.memory_rows + self.kernel_rom_rows + self.ace_rows + } + + /// Rows folded into the memory target from unreachable chiplets. + pub fn substituted_rows(&self) -> u64 { + self.kernel_rom_rows + self.ace_rows + } +} + +impl TraceShape { + pub fn new(totals: TraceTotals, breakdown: TraceBreakdown) -> Self { + Self { totals, breakdown } + } +} + +impl TraceSnapshot { + /// Load every scenario in a producer JSON file, returning `(scenario_key, snapshot)` pairs in + /// alphabetical order. Each scenario's trace section is extracted; cycle counts and other + /// per-scenario fields are ignored. + pub fn load_all(path: impl AsRef) -> Result, SnapshotError> { + let path_str = path.as_ref().display().to_string(); + let bytes = std::fs::read(path.as_ref()) + .map_err(|source| SnapshotError::Io { path: path_str, source })?; + let raw: BTreeMap = + serde_json::from_slice(&bytes).map_err(SnapshotError::Parse)?; + + let mut out = Vec::with_capacity(raw.len()); + for (key, entry) in raw { + let trace = TraceTotals { + core_rows: entry.trace.core_rows, + chiplets_rows: entry.trace.chiplets_rows, + range_rows: entry.trace.range_rows, + }; + let shape = entry.trace.chiplets_shape; + let expected = shape.chiplets_sum(); + if trace.chiplets_rows != expected { + return Err(SnapshotError::InconsistentChipletsTotal { + scenario: key, + from_trace: trace.chiplets_rows, + from_shape: expected, + }); + } + out.push((key, TraceSnapshot { trace, shape })); + } + Ok(out) + } + + /// Combined target shape that the solver and verifier consume. + pub fn shape(&self) -> TraceShape { + TraceShape::new(self.trace, self.shape) + } +} + +/// Each scenario entry in a producer JSON. The producer also writes cycle counts at the top level +/// (`prologue`, `epilogue`, ...), but the consumer ignores everything except `trace`. +#[derive(Deserialize)] +struct RawScenarioEntry { + trace: RawTrace, +} + +#[derive(Deserialize)] +struct RawTrace { + core_rows: u64, + chiplets_rows: u64, + range_rows: u64, + chiplets_shape: TraceBreakdown, +} + +#[derive(Debug, thiserror::Error)] +pub enum SnapshotError { + #[error("failed to read snapshot at {path}: {source}")] + Io { + path: String, + #[source] + source: std::io::Error, + }, + #[error("failed to parse snapshot JSON: {0}")] + Parse(#[source] serde_json::Error), + #[error( + "snapshot inconsistency in scenario {scenario:?}: trace.chiplets_rows = {from_trace} but shape sums to {from_shape}" + )] + InconsistentChipletsTotal { + scenario: String, + from_trace: u64, + from_shape: u64, + }, +} + +#[cfg(test)] +mod tests { + use super::*; + + /// Expected padded brackets for each committed scenario. Keyed by `(producer_stem, + /// scenario_key)` since each producer file holds many scenarios. A mismatch means refresh + /// the snapshot from the producer before updating these numbers. + /// + /// Mirrors `COMMITTED_SCENARIO_EXPECTATIONS` in `protocol/bin/bench-transaction/`'s test + /// module; refresh both together when a kernel change moves a bracket. + struct CommittedScenarioExpectation { + producer_stem: &'static str, + scenario_key: &'static str, + padded_core_side: u64, + padded_chiplets: u64, + } + + const COMMITTED_SCENARIO_EXPECTATIONS: &[CommittedScenarioExpectation] = &[ + CommittedScenarioExpectation { + producer_stem: "bench-tx", + scenario_key: "consume single P2ID note", + padded_core_side: 131_072, + padded_chiplets: 131_072, + }, + CommittedScenarioExpectation { + producer_stem: "bench-tx", + scenario_key: "consume two P2ID notes", + padded_core_side: 131_072, + padded_chiplets: 262_144, + }, + CommittedScenarioExpectation { + producer_stem: "bench-tx", + scenario_key: "create single P2ID note", + padded_core_side: 131_072, + padded_chiplets: 131_072, + }, + CommittedScenarioExpectation { + producer_stem: "bench-tx", + scenario_key: "consume CLAIM note (L1 to Miden)", + padded_core_side: 65_536, + padded_chiplets: 262_144, + }, + CommittedScenarioExpectation { + producer_stem: "bench-tx", + scenario_key: "consume CLAIM note (L2 to Miden)", + padded_core_side: 65_536, + padded_chiplets: 262_144, + }, + CommittedScenarioExpectation { + producer_stem: "bench-tx", + scenario_key: "consume B2AGG note (bridge-out)", + padded_core_side: 262_144, + padded_chiplets: 1_048_576, + }, + ]; + + fn expectation_for( + producer_stem: &str, + scenario_key: &str, + ) -> Option<&'static CommittedScenarioExpectation> { + COMMITTED_SCENARIO_EXPECTATIONS.iter().find(|expected| { + expected.producer_stem == producer_stem && expected.scenario_key == scenario_key + }) + } + + fn sample_shape() -> (TraceTotals, TraceBreakdown) { + let breakdown = TraceBreakdown { + hasher_rows: 200, + bitwise_rows: 50, + memory_rows: 300, + kernel_rom_rows: 40, + ace_rows: 60, + }; + let totals = TraceTotals { + core_rows: 1000, + chiplets_rows: breakdown.chiplets_sum(), + range_rows: 100, + }; + (totals, breakdown) + } + + #[test] + fn memory_target_folds_ace_and_kernel_rom() { + let (_, b) = sample_shape(); + assert_eq!(b.memory_target(), 400); + assert_eq!(b.substituted_rows(), 100); + // 200 + 50 + 300 + 40 + 60 + 1 padding row = 651 + assert_eq!(b.chiplets_sum(), 651); + } + + #[test] + fn padded_totals_match_processor_formula() { + let (t, _) = sample_shape(); + // max(1000, 100, 651) = 1000 → next pow2 = 1024 + assert_eq!(t.padded_total(), 1024); + // core + range: max(1000, 100) = 1000 → 1024 + assert_eq!(t.padded_core_side(), 1024); + // chiplets alone: 651 → 1024 + assert_eq!(t.padded_chiplets(), 1024); + } + + #[test] + fn padded_total_clamps_to_min_trace_len() { + let totals = TraceTotals { + core_rows: 1, + chiplets_rows: 1, + range_rows: 0, + }; + assert_eq!(totals.padded_total(), MIN_TRACE_LEN); + assert_eq!(totals.padded_core_side(), MIN_TRACE_LEN); + assert_eq!(totals.padded_chiplets(), MIN_TRACE_LEN); + } + + #[test] + fn range_dominates_is_detected() { + let totals = TraceTotals { + core_rows: 100, + chiplets_rows: 200, + range_rows: 500, + }; + assert!(totals.range_dominates()); + let totals = TraceTotals { + core_rows: 500, + chiplets_rows: 200, + range_rows: 100, + }; + assert!(!totals.range_dominates()); + } + + #[test] + fn committed_snapshots_load() { + use std::collections::BTreeSet; + + let snapshots_dir = Path::new(env!("CARGO_MANIFEST_DIR")).join("snapshots"); + let entries = std::fs::read_dir(&snapshots_dir) + .unwrap_or_else(|e| panic!("read {}: {e}", snapshots_dir.display())); + + // Defer the table-vs-files check to the end so a single test run reports all drift, + // not just the first mismatch. + let mut discovered: BTreeSet<(String, String)> = BTreeSet::new(); + let mut unexpected: BTreeSet<(String, String)> = BTreeSet::new(); + for entry in entries { + let path = entry.expect("dir entry").path(); + if path.extension().and_then(|e| e.to_str()) != Some("json") { + continue; + } + let producer_stem = + path.file_stem().and_then(|s| s.to_str()).expect("producer stem").to_string(); + let scenarios = TraceSnapshot::load_all(&path) + .unwrap_or_else(|e| panic!("load {}: {e}", path.display())); + assert!(!scenarios.is_empty(), "{} contained no scenarios", path.display()); + for (key, snap) in &scenarios { + assert!(snap.trace.core_rows > 0, "{key}: core_rows must be > 0"); + assert!(snap.trace.chiplets_rows > 0, "{key}: chiplets_rows must be > 0"); + assert_eq!( + snap.trace.chiplets_rows, + snap.shape.chiplets_sum(), + "{key}: chiplets_rows must equal sum(shape) + 1", + ); + + match expectation_for(&producer_stem, key) { + Some(expected) => { + assert_eq!( + snap.trace.padded_core_side(), + expected.padded_core_side, + "{producer_stem}/{key}: padded_core_side moved to a different bracket; \ + refresh the snapshot and update COMMITTED_SCENARIO_EXPECTATIONS", + ); + assert_eq!( + snap.trace.padded_chiplets(), + expected.padded_chiplets, + "{producer_stem}/{key}: padded_chiplets moved to a different bracket; \ + refresh the snapshot and update COMMITTED_SCENARIO_EXPECTATIONS", + ); + discovered.insert((producer_stem.clone(), key.clone())); + }, + None => { + unexpected.insert((producer_stem.clone(), key.clone())); + }, + } + } + } + + let expected: BTreeSet<(String, String)> = COMMITTED_SCENARIO_EXPECTATIONS + .iter() + .map(|e| (e.producer_stem.to_string(), e.scenario_key.to_string())) + .collect(); + let missing: BTreeSet<_> = expected.difference(&discovered).cloned().collect(); + assert!( + unexpected.is_empty() && missing.is_empty(), + "committed scenarios drifted from COMMITTED_SCENARIO_EXPECTATIONS in snapshot.rs:\n \ + unexpected (in snapshots/ but not in the table -- add an entry): {unexpected:?}\n \ + missing (in the table but not in any snapshots/*.json -- refresh the snapshot or remove the entry): {missing:?}", + ); + } + + #[test] + fn missing_optional_fields_default_to_zero() { + let minimal = r#"{ + "consume single P2ID note": { + "trace": { + "core_rows": 100, + "chiplets_rows": 11, + "range_rows": 50, + "chiplets_shape": { "hasher_rows": 10, "bitwise_rows": 0, "memory_rows": 0 } + } + } + }"#; + let tmp = std::env::temp_dir().join("synthetic-bench-defaults.json"); + std::fs::write(&tmp, minimal).unwrap(); + let scenarios = TraceSnapshot::load_all(&tmp).expect("load defaults snapshot"); + let _ = std::fs::remove_file(&tmp); + let (_, snap) = &scenarios[0]; + assert_eq!(snap.shape.kernel_rom_rows, 0); + assert_eq!(snap.shape.ace_rows, 0); + } + + #[test] + fn rejects_inconsistent_chiplets_total() { + // chiplets_rows says 500 but the breakdown sums to 11 (10 + 0 + 0 + 0 + 0 + 1). + let mismatched = r#"{ + "broken": { + "trace": { + "core_rows": 100, + "chiplets_rows": 500, + "range_rows": 0, + "chiplets_shape": { "hasher_rows": 10, "bitwise_rows": 0, "memory_rows": 0 } + } + } + }"#; + let tmp = std::env::temp_dir().join("synthetic-bench-chiplets-mismatch.json"); + std::fs::write(&tmp, mismatched).unwrap(); + let err = TraceSnapshot::load_all(&tmp).expect_err("expected inconsistency rejection"); + let _ = std::fs::remove_file(&tmp); + assert!(matches!(err, SnapshotError::InconsistentChipletsTotal { .. })); + } + + #[test] + fn ignores_extra_fields_per_scenario() { + // Real bench-tx.json has cycle-count siblings (prologue, epilogue, ...) the loader must + // tolerate. + let realistic = r#"{ + "consume single P2ID note": { + "prologue": 3501, + "notes_processing": 1761, + "epilogue": { "total": 72351 }, + "trace": { + "core_rows": 77699, + "chiplets_rows": 123129, + "range_rows": 20203, + "chiplets_shape": { + "hasher_rows": 120352, + "bitwise_rows": 416, + "memory_rows": 2297, + "kernel_rom_rows": 63, + "ace_rows": 0 + } + } + } + }"#; + let tmp = std::env::temp_dir().join("synthetic-bench-realistic.json"); + std::fs::write(&tmp, realistic).unwrap(); + let scenarios = TraceSnapshot::load_all(&tmp).expect("load realistic snapshot"); + let _ = std::fs::remove_file(&tmp); + assert_eq!(scenarios.len(), 1); + let (key, snap) = &scenarios[0]; + assert_eq!(key, "consume single P2ID note"); + assert_eq!(snap.trace.core_rows, 77_699); + assert_eq!(snap.shape.hasher_rows, 120_352); + } +} diff --git a/benches/synthetic-bench/src/snippets.rs b/benches/synthetic-bench/src/snippets.rs new file mode 100644 index 0000000000..ecd7ebb18b --- /dev/null +++ b/benches/synthetic-bench/src/snippets.rs @@ -0,0 +1,228 @@ +//! Static catalog of MASM snippets that drive individual VM components. +//! +//! The patterns are deliberately few and natural -- they mirror work a real transaction does, +//! rather than one synthetic op per chiplet: +//! +//! - **hasher** drives the Poseidon2 chiplet via repeated `hperm`. The state evolves between +//! iterations (one `padw padw padw` as setup, no reset), so each permutation has a distinct input +//! and the hasher AIR's multiplicity column does not collapse them. +//! - **bitwise** drives the bitwise chiplet via `u32split + u32xor`. +//! - **u32arith** drives the range checker via two banded u32 counters, advancing each by 65537 per +//! iter so their 16-bit halves evolve as disjoint contiguous bands. `u32assert2` issues fresh +//! range-check values each iter without cross-dedup. +//! - **memory** drives the memory chiplet. The address advances by `4 * 65537 = 262148` per iter so +//! the two 16-bit halves of the word index form disjoint contiguous bands, which also feeds the +//! range chiplet via address-limb decomposition. +//! - **decoder_pad** drives only the core (system/decoder/stack) trace so the solver can top up +//! core-trace budget without adding chiplet rows. +//! +//! Each snippet is partitioned into `setup` / `body` / `cleanup` so that the body alone can be +//! wrapped in a `repeat.N ... end` block. The body must leave stack depth unchanged -- the repeat +//! block would otherwise drift the stack each iteration. +//! +//! Note: on current `next`, decoder-only programs still incur hasher rows due to MAST hashing, so +//! low hasher targets may be unreachable; the solver clamps `hasher` iterations to zero in that +//! case. + +/// A VM component the solver targets. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)] +pub enum Component { + /// System + decoder + stack. + Core, + Hasher, + Bitwise, + Memory, + /// Range checker. Not currently a hard bracket target but the solver still sizes the + /// `u32arith` snippet against it so the synthetic's range workload is representative. + Range, +} + +/// A MASM fragment that dominantly drives one component. +#[derive(Debug, Clone, Copy)] +pub struct Snippet { + pub name: &'static str, + /// Runs once, outside the `repeat.N ... end` block. + pub setup: &'static str, + /// Runs N times inside the repeat block. Must be stack-balanced. + pub body: &'static str, + /// Runs once, outside the repeat block. + pub cleanup: &'static str, + /// The primary component this snippet drives. + pub dominant: Component, +} + +/// The full snippet catalog, in solver order: chiplet drivers first so they saturate their +/// targets, `decoder_pad` last so it absorbs leftover main-trace budget. +pub const SNIPPETS: &[Snippet] = &[ + Snippet { + name: "hasher", + setup: "padw padw padw", + body: "hperm", + cleanup: "dropw dropw dropw", + dominant: Component::Hasher, + }, + Snippet { + name: "bitwise", + setup: "push.1 neg", + body: "u32split u32xor", + cleanup: "drop", + dominant: Component::Bitwise, + }, + Snippet { + name: "u32arith", + // Two u32 counters, each advanced by `65537 = 0x0001_0001` per iter, so their four 16-bit + // half-limbs form disjoint contiguous bands at 45500+i, 50500+i, 55500+i, 60500+i (clear + // of the memory snippet's 4*w1 band, which tops out near 44800). Counters update with + // plain field `add` so only the `u32assert2` emits range-check values -- carry limbs don't + // pollute the bands. See `u32arith_max_iters` for the counter bound. + setup: "push.3637308500 push.2981938500", + body: "u32assert2 push.65537 add swap push.65537 add swap", + cleanup: "drop drop", + dominant: Component::Range, + }, + Snippet { + name: "memory", + // Advance the word-aligned address by `4 * 65537 = 262148` each iter so that both 16-bit + // halves of the word index evolve as disjoint contiguous bands. This makes the memory + // chiplet feed fresh range-check values rather than deduplicating, so the snippet also + // contributes meaningfully to the range chiplet. + // + // The start address `4 * ((10000 << 16) | 20000)` puts the address-limb bands in a high + // region that doesn't overlap u32arith's bands. The counter advances with plain field + // `add` so only the memory chiplet emits range-check values -- the update doesn't pollute + // the bands with carry-limb checks. Safe as long as the address stays below `u32::MAX`; + // see `assert_counters_fit`. + setup: "padw push.2621520000", + body: "dup.4 mem_storew_le dup.4 mem_loadw_le movup.4 push.262148 add movdn.4", + cleanup: "drop dropw", + dominant: Component::Memory, + }, + Snippet { + name: "decoder_pad", + setup: "", + body: "swap dup.1 add", + cleanup: "", + dominant: Component::Core, + }, +]; + +/// Look up a snippet by name. Only used by tests. +#[cfg(test)] +pub(crate) fn find(name: &str) -> Option<&'static Snippet> { + SNIPPETS.iter().find(|s| s.name == name) +} + +/// Assemble a single snippet into a complete program body: the setup, followed by +/// `repeat.iters body end`, followed by the cleanup. Returned text has no `begin`/`end` wrapping -- +/// caller composes multiple snippets. +pub fn render(snippet: &Snippet, iters: u64) -> String { + use std::fmt::Write; + let mut out = String::new(); + if !snippet.setup.is_empty() { + writeln!(out, " {}", snippet.setup).unwrap(); + } + if iters > 0 { + writeln!(out, " repeat.{iters}").unwrap(); + writeln!(out, " {}", snippet.body).unwrap(); + writeln!(out, " end").unwrap(); + } + if !snippet.cleanup.is_empty() { + writeln!(out, " {}", snippet.cleanup).unwrap(); + } + out +} + +/// Wrap a snippet fragment into a complete `begin ... end` program. +pub fn wrap_program(body: &str) -> String { + format!("begin\n{body}end\n") +} + +// COUNTER SAFETY +// ------------------------------------------------------------------------ +// +// Both `u32arith` and `memory` advance a counter with plain field `add`, so `u32assert2` / the +// memory chiplet would fail at runtime if the counter crossed `u32::MAX`. These helpers expose the +// per-snippet limits so callers can validate a plan before emitting. + +/// Starting value of `u32arith`'s higher counter -- the one closer to `u32::MAX` and therefore the +/// binding constraint. +const U32ARITH_COUNTER_START: u64 = 3_637_308_500; +const U32ARITH_COUNTER_STRIDE: u64 = 65_537; + +/// Starting value of `memory`'s address counter. +const MEMORY_COUNTER_START: u64 = 2_621_520_000; +const MEMORY_COUNTER_STRIDE: u64 = 262_148; + +const U32_MAX: u64 = u32::MAX as u64; + +/// Maximum iterations of `u32arith` before the `y` counter would exceed `u32::MAX` and trip the +/// next iteration's `u32assert2`. +pub fn u32arith_max_iters() -> u64 { + (U32_MAX - U32ARITH_COUNTER_START) / U32ARITH_COUNTER_STRIDE +} + +/// Maximum iterations of `memory` before the address counter would exceed `u32::MAX`. +pub fn memory_max_iters() -> u64 { + (U32_MAX - MEMORY_COUNTER_START) / MEMORY_COUNTER_STRIDE +} + +#[cfg(test)] +mod tests { + use miden_vm::Assembler; + + use super::*; + + #[test] + fn catalog_has_one_snippet_per_solver_component() { + let targets = [ + Component::Core, + Component::Hasher, + Component::Bitwise, + Component::Memory, + Component::Range, + ]; + for target in targets { + let count = SNIPPETS.iter().filter(|s| s.dominant == target).count(); + assert_eq!(count, 1, "expected exactly one snippet for {target:?}"); + } + } + + #[test] + fn each_snippet_assembles_as_a_standalone_program() { + // Fail fast: if a snippet has malformed MASM, the calibrator will blow up at bench time. + // Catch it in unit tests instead. + for snippet in SNIPPETS { + let source = wrap_program(&render(snippet, 4)); + Assembler::default() + .assemble_program(&source) + .unwrap_or_else(|e| panic!("snippet {:?} failed to assemble: {e}", snippet.name)); + } + } + + #[test] + fn counter_limits_cover_realistic_plans() { + // Realistic plans for consume/create P2ID transactions produce ~5k u32arith iters and + // ~1.2k memory iters. These guards have plenty of headroom for that regime. + assert!(u32arith_max_iters() >= 10_000); + assert!(memory_max_iters() >= 6_000); + } + + #[test] + fn render_emits_repeat_with_body() { + let snippet = find("bitwise").expect("bitwise snippet"); + let out = render(snippet, 42); + assert!(out.contains("repeat.42")); + assert!(out.contains("u32split u32xor")); + assert!(out.contains("push.1 neg")); + assert!(out.contains("drop")); + } + + #[test] + fn render_with_zero_iters_still_emits_setup_and_cleanup() { + let snippet = find("hasher").expect("hasher snippet"); + let out = render(snippet, 0); + assert!(out.contains("padw padw padw")); + assert!(out.contains("dropw dropw dropw")); + assert!(!out.contains("repeat.")); + } +} diff --git a/benches/synthetic-bench/src/solver.rs b/benches/synthetic-bench/src/solver.rs new file mode 100644 index 0000000000..91131d11ff --- /dev/null +++ b/benches/synthetic-bench/src/solver.rs @@ -0,0 +1,217 @@ +//! Solve for per-snippet iteration counts and emit the MASM program. +//! +//! The calibration matrix is close to diagonally dominant: each snippet primarily drives one +//! component and leaks small cross-terms into the others. A short Jacobi refinement with a +//! non-negativity clamp is enough for this problem size and handles infeasible targets gracefully. + +use std::collections::BTreeMap; + +use crate::{ + calibrator::Calibration, + snapshot::TraceShape, + snippets::{self, Component, SNIPPETS}, +}; + +/// Small fixed-point refinement count. The calibrated systems in this crate converge in a few +/// passes, and the clamp keeps iteration counts non-negative. +const REFINEMENT_PASSES: usize = 8; + +/// Iteration counts per snippet, ready to hand to the emitter. +/// +/// Implemented as a sparse map where absence means "zero iterations"; the newtype hides the +/// `unwrap_or(0)` convention behind [`Plan::iters`] so call sites can't forget it. +#[derive(Debug, Default, Clone)] +pub struct Plan { + entries: BTreeMap<&'static str, u64>, +} + +impl Plan { + pub fn new() -> Self { + Self::default() + } + + /// Iteration count for `name`, or 0 if the snippet has no entry. + pub fn iters(&self, name: &str) -> u64 { + self.entries.get(name).copied().unwrap_or(0) + } + + /// Set the iteration count for `name`, removing the entry entirely when `n == 0` so that + /// `iters() == 0` is equivalent to the entry being absent. + pub fn set(&mut self, name: &'static str, n: u64) { + if n == 0 { + self.entries.remove(name); + } else { + self.entries.insert(name, n); + } + } + + /// Increment the iteration count for `name` by `delta`. + pub fn add(&mut self, name: &'static str, delta: u64) { + if delta == 0 { + return; + } + self.set(name, self.iters(name) + delta); + } + + /// Decrement the iteration count for `name` by `delta`, saturating at zero. + pub fn sub_saturating(&mut self, name: &'static str, delta: u64) { + self.set(name, self.iters(name).saturating_sub(delta)); + } +} + +/// Solve for the iteration counts that reproduce `target`'s per-component row counts. Per-chiplet +/// targets come from the snapshot's advisory `shape` breakdown -- the solver uses them to keep the +/// synthetic program representative, but the verifier only hard-asserts totals/brackets. +pub fn solve(calibration: &Calibration, target: &TraceShape) -> Plan { + let mut iters: BTreeMap<&'static str, f64> = + SNIPPETS.iter().map(|s| (s.name, 0.0_f64)).collect(); + + let component_target = |c: Component| -> f64 { + match c { + Component::Core => target.totals.core_rows as f64, + Component::Hasher => target.breakdown.hasher_rows as f64, + Component::Bitwise => target.breakdown.bitwise_rows as f64, + Component::Memory => target.breakdown.memory_target() as f64, + Component::Range => target.totals.range_rows as f64, + } + }; + + for _ in 0..REFINEMENT_PASSES { + let snapshot = iters.clone(); + for snippet in SNIPPETS { + let cost = match calibration.get(snippet.name) { + Some(c) => *c, + None => continue, + }; + let rate = cost.get(snippet.dominant); + if rate <= 0.0 { + continue; + } + let target_rows = component_target(snippet.dominant); + let cross_rows: f64 = SNIPPETS + .iter() + .filter(|s| s.name != snippet.name) + .map(|s| { + let other = + calibration.get(s.name).map(|c| c.get(snippet.dominant)).unwrap_or(0.0); + other * snapshot[s.name] + }) + .sum(); + let needed = (target_rows - cross_rows).max(0.0); + iters.insert(snippet.name, needed / rate); + } + } + + let mut plan = Plan::new(); + for (name, v) in iters { + plan.set(name, v.round().max(0.0) as u64); + } + plan +} + +/// Render the plan as a single `begin ... end` program. +pub fn emit(plan: &Plan) -> String { + use std::fmt::Write; + let mut body = String::new(); + for snippet in SNIPPETS { + let n = plan.iters(snippet.name); + if n == 0 { + continue; + } + write!(body, "{}", snippets::render(snippet, n)).unwrap(); + } + snippets::wrap_program(&body) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{ + calibrator::{calibrate, measure_program}, + snapshot::{TraceBreakdown, TraceTotals}, + }; + + fn shape_of( + core_rows: u64, + range_rows: u64, + hasher: u64, + bitwise: u64, + memory: u64, + ) -> TraceShape { + let breakdown = TraceBreakdown { + hasher_rows: hasher, + bitwise_rows: bitwise, + memory_rows: memory, + kernel_rom_rows: 0, + ace_rows: 0, + }; + let totals = TraceTotals { + core_rows, + chiplets_rows: breakdown.chiplets_sum(), + range_rows, + }; + TraceShape::new(totals, breakdown) + } + + fn low_hasher_target() -> TraceShape { + // core/hasher ratio of ~8, well below the intrinsic core/4 floor. Memory kept modest + // (ratio core/memory ~30) so the test exercises the hasher-feasibility path without making + // it infeasible via memory overshoot into core. + shape_of(68900, 40000, 8200, 0, 2300) + } + + fn high_hasher_target() -> TraceShape { + // main/hasher ratio of ~2, above the intrinsic main/4 floor. + shape_of(16000, 0, 8000, 0, 0) + } + + #[test] + fn low_hasher_target_does_not_add_hperm() { + let cal = calibrate().expect("calibrate"); + let plan = solve(&cal, &low_hasher_target()); + assert_eq!( + plan.iters("hasher"), + 0, + "when the decoder (via memory + pad) already overshoots the hasher target, no hperm iterations should be added", + ); + assert!(plan.iters("memory") > 0); + } + + #[test] + fn high_hasher_target_requires_hperm() { + let cal = calibrate().expect("calibrate"); + let plan = solve(&cal, &high_hasher_target()); + assert!( + plan.iters("hasher") > 0, + "a hasher target above the main/4 floor should require hperm iterations", + ); + } + + #[test] + fn emitted_program_matches_padded_bracket() { + let cal = calibrate().expect("calibrate"); + let target = low_hasher_target(); + let plan = solve(&cal, &target); + let source = emit(&plan); + let actual = measure_program(&source).expect("measure emitted program"); + assert_eq!( + actual.totals.padded_total(), + target.totals.padded_total(), + "padded trace length must match target bracket (got {} vs {})", + actual.totals.padded_total(), + target.totals.padded_total(), + ); + } + + #[test] + fn zero_target_yields_empty_program() { + let cal = calibrate().expect("calibrate"); + let target = shape_of(0, 0, 0, 0, 0); + let plan = solve(&cal, &target); + for snippet in SNIPPETS { + assert_eq!(plan.iters(snippet.name), 0, "{}", snippet.name); + } + let source = emit(&plan); + assert_eq!(source.trim(), "begin\nend"); + } +} diff --git a/benches/synthetic-bench/src/verifier.rs b/benches/synthetic-bench/src/verifier.rs new file mode 100644 index 0000000000..c6ed583e46 --- /dev/null +++ b/benches/synthetic-bench/src/verifier.rs @@ -0,0 +1,300 @@ +//! Verification helpers for synthetic-trace matching. +//! +//! Hard checks: +//! - `padded_core_side(actual) == padded_core_side(target)` -- the current AIR's non-chiplets-side +//! bracket, `next_pow2(max(core_rows, range_rows))`. If a future AIR split gives range its own +//! segment, this check can be revised to assert separate brackets. +//! - `padded_chiplets(actual) == padded_chiplets(target)` +//! +//! Soft reporting: +//! - unpadded totals (`core_rows`, `chiplets_rows`) within [`PER_COMPONENT_TOLERANCE`] +//! - advisory breakdown deltas (info only) +//! - warning if `range_rows` dominates + +use std::fmt::{self, Display}; + +use crate::snapshot::TraceShape; + +/// Reporting tolerance for unpadded totals; never used for pass/fail. +pub const PER_COMPONENT_TOLERANCE: f64 = 0.02; + +/// Result of comparing an emitted program's measured shape against the snapshot target. +#[derive(Debug, Clone)] +pub struct VerificationReport { + pub target: TraceShape, + pub actual: TraceShape, + pub total_deltas: Vec, + pub breakdown_deltas: Vec, +} + +/// How a row-count entry participates in the verifier's reporting. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum DeltaStatus { + /// Prints `ok` if within tolerance, `out` otherwise. + Enforced, + /// Always prints `info`; used for rows the solver does not target. + Informational, +} + +/// Per-row-count comparison. +#[derive(Debug, Clone, Copy)] +pub struct ComponentDelta { + pub name: &'static str, + pub target: u64, + pub actual: u64, + pub delta_pct: f64, + pub within_tolerance: bool, + pub status: DeltaStatus, +} + +impl VerificationReport { + pub fn new(target: TraceShape, actual: TraceShape) -> Self { + let total_rows: &[(&'static str, u64, u64, DeltaStatus)] = &[ + ( + "core_rows", + target.totals.core_rows, + actual.totals.core_rows, + DeltaStatus::Enforced, + ), + ( + "chiplets_rows", + target.totals.chiplets_rows, + actual.totals.chiplets_rows, + DeltaStatus::Enforced, + ), + ( + // range_rows is derived, not independently driven. + "range_rows", + target.totals.range_rows, + actual.totals.range_rows, + DeltaStatus::Informational, + ), + ]; + let breakdown_rows: &[(&'static str, u64, u64, DeltaStatus)] = &[ + ( + "hasher", + target.breakdown.hasher_rows, + actual.breakdown.hasher_rows, + DeltaStatus::Informational, + ), + ( + "bitwise", + target.breakdown.bitwise_rows, + actual.breakdown.bitwise_rows, + DeltaStatus::Informational, + ), + ( + "memory", + target.breakdown.memory_target(), + actual.breakdown.memory_rows, + DeltaStatus::Informational, + ), + ]; + Self { + target, + actual, + total_deltas: total_rows.iter().map(|r| component_delta(*r)).collect(), + breakdown_deltas: breakdown_rows.iter().map(|r| component_delta(*r)).collect(), + } + } + + /// True when both padded proxies match their targets exactly. + pub fn brackets_match(&self) -> bool { + self.target.totals.padded_core_side() == self.actual.totals.padded_core_side() + && self.target.totals.padded_chiplets() == self.actual.totals.padded_chiplets() + } + + /// True if `range_rows` is the largest unpadded component in either side, which means snippet + /// balance should be revisited. + pub fn range_dominates(&self) -> bool { + self.target.totals.range_dominates() || self.actual.totals.range_dominates() + } +} + +fn component_delta((name, t, a, status): (&'static str, u64, u64, DeltaStatus)) -> ComponentDelta { + let delta_pct = if t == 0 { + if a == 0 { 0.0 } else { f64::INFINITY } + } else { + (a as f64 - t as f64) / t as f64 + }; + ComponentDelta { + name, + target: t, + actual: a, + delta_pct, + within_tolerance: delta_pct.abs() <= PER_COMPONENT_TOLERANCE, + status, + } +} + +impl Display for VerificationReport { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + writeln!(f, "-- hard brackets (padded power-of-two) --")?; + write_bracket_row( + f, + "padded_core_side", + self.target.totals.padded_core_side(), + self.actual.totals.padded_core_side(), + )?; + write_bracket_row( + f, + "padded_chiplets", + self.target.totals.padded_chiplets(), + self.actual.totals.padded_chiplets(), + )?; + + writeln!(f, "\n-- totals (soft: {:.0}% band) --", PER_COMPONENT_TOLERANCE * 100.0)?; + write_delta_header(f)?; + for d in &self.total_deltas { + write_delta_row(f, d)?; + } + + writeln!(f, "\n-- breakdown (info) --")?; + write_delta_header(f)?; + for d in &self.breakdown_deltas { + write_delta_row(f, d)?; + } + + writeln!(f)?; + if self.brackets_match() { + writeln!(f, "=> BRACKET MATCH")?; + } else { + writeln!(f, "=> BRACKET MISS")?; + } + if self.range_dominates() { + writeln!( + f, + "!! WARNING: range_rows dominates -- \"ignore range\" assumption is breaking" + )?; + } + Ok(()) + } +} + +fn write_delta_header(f: &mut fmt::Formatter<'_>) -> fmt::Result { + writeln!( + f, + "{:<16} {:>12} {:>12} {:>10} status", + "component", "target", "actual", "delta" + ) +} + +fn write_delta_row(f: &mut fmt::Formatter<'_>, d: &ComponentDelta) -> fmt::Result { + let delta_str = if d.delta_pct.is_finite() { + format!("{:+6.2}%", d.delta_pct * 100.0) + } else { + "+∞".to_string() + }; + let status = match d.status { + DeltaStatus::Enforced => { + if d.within_tolerance { + "ok" + } else { + "out" + } + }, + DeltaStatus::Informational => "info", + }; + writeln!( + f, + "{:<16} {:>12} {:>12} {:>10} {}", + d.name, d.target, d.actual, delta_str, status + ) +} + +fn write_bracket_row( + f: &mut fmt::Formatter<'_>, + name: &str, + target: u64, + actual: u64, +) -> fmt::Result { + let ok = if target == actual { "==" } else { "MISS" }; + writeln!(f, "{name:<16} {target:>12} {actual:>12} {ok:>10}") +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::snapshot::{TraceBreakdown, TraceTotals}; + + fn shape(core: u64, hasher: u64, memory: u64) -> TraceShape { + let breakdown = TraceBreakdown { + hasher_rows: hasher, + bitwise_rows: 0, + memory_rows: memory, + kernel_rom_rows: 0, + ace_rows: 0, + }; + let totals = TraceTotals { + core_rows: core, + chiplets_rows: breakdown.chiplets_sum(), + range_rows: 0, + }; + TraceShape::new(totals, breakdown) + } + + #[test] + fn exact_match_is_bracket_ok_and_all_within_tolerance() { + let t = shape(68000, 8000, 12000); + let r = VerificationReport::new(t, t); + assert!(r.brackets_match()); + assert!(r.total_deltas.iter().all(|d| d.within_tolerance)); + assert!(r.breakdown_deltas.iter().all(|d| d.within_tolerance)); + } + + #[test] + fn bracket_miss_is_reported_when_core_bracket_differs() { + // target.core=68000 → 131072; actual.core=30000 → 32768 (different bracket) + let target = shape(68000, 8000, 12000); + let actual = shape(30000, 2000, 1000); + let r = VerificationReport::new(target, actual); + assert!(!r.brackets_match()); + assert!(r.to_string().contains("BRACKET MISS")); + } + + #[test] + fn chiplets_bracket_can_miss_independently_of_core() { + // core is the same (same padded bracket); chiplets_rows lands in different brackets. + // target chiplets = 8000 + 12000 + 1 = 20001 → 32768 + // actual chiplets = 20000 + 30000 + 1 = 50001 → 65536 + let target = shape(40000, 8000, 12000); + let actual = shape(40000, 20000, 30000); + let r = VerificationReport::new(target, actual); + // padded_core_side: both 40000 → 65536 (same) + assert_eq!(target.totals.padded_core_side(), actual.totals.padded_core_side()); + // padded_chiplets differs + assert_ne!(target.totals.padded_chiplets(), actual.totals.padded_chiplets()); + assert!(!r.brackets_match()); + } + + #[test] + fn range_dominates_is_warned() { + let breakdown = TraceBreakdown { + hasher_rows: 100, + bitwise_rows: 0, + memory_rows: 0, + kernel_rom_rows: 0, + ace_rows: 0, + }; + let totals = TraceTotals { + core_rows: 100, + chiplets_rows: breakdown.chiplets_sum(), + range_rows: 500, + }; + let t = TraceShape::new(totals, breakdown); + let r = VerificationReport::new(t, t); + assert!(r.range_dominates()); + assert!(r.to_string().contains("range_rows dominates")); + } + + #[test] + fn per_component_overshoot_stays_within_bracket() { + // Hasher overshoots but both core and chiplets stay within their brackets. + let target = shape(68000, 8000, 12000); + let actual = shape(68000, 14000, 12000); + let r = VerificationReport::new(target, actual); + assert!(r.brackets_match()); + let hasher_delta = r.breakdown_deltas.iter().find(|d| d.name == "hasher").unwrap(); + assert!(!hasher_delta.within_tolerance); + } +} diff --git a/core/Cargo.toml b/core/Cargo.toml index a20aff1e14..6ba2a905b5 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -23,6 +23,11 @@ name = "mast_forest_merge" required-features = ["arbitrary"] harness = false +[[bench]] +name = "mast_serialization_size" +required-features = ["arbitrary"] +harness = false + [features] default = ["std"] std = [ @@ -54,7 +59,7 @@ miden-utils-sync.workspace = true # External dependencies derive_more.workspace = true -itertools.workspace = true +log.workspace = true num-derive = { version = "0.4", default-features = false } num-traits = { version = "0.2", default-features = false } proptest = { workspace = true, optional = true } @@ -67,6 +72,6 @@ criterion = { workspace = true } insta.workspace = true miden-test-serde-macros.workspace = true proptest.workspace = true -rstest = { version = "0.26" } +rstest = { workspace = true } serde_json = { workspace = true } miden-utils-testing.workspace = true diff --git a/core/benches/mast_serialization_size.rs b/core/benches/mast_serialization_size.rs new file mode 100644 index 0000000000..61c265d2ae --- /dev/null +++ b/core/benches/mast_serialization_size.rs @@ -0,0 +1,101 @@ +//! Benchmark MastForest serialization and report byte sizes for full/stripped/hashless. + +use std::hint::black_box; + +use criterion::{BenchmarkId, Criterion, Throughput, criterion_group, criterion_main}; +use miden_core::{ + mast::{MastForest, arbitrary::MastForestParams}, + serde::Serializable, +}; +use proptest::{ + arbitrary::any_with, + strategy::Strategy, + test_runner::{Config, RngAlgorithm, TestRng, TestRunner}, +}; + +/// Draw one MastForest sample from proptest's strategy space using the Arbitrary impl. +fn sample_forest(params: MastForestParams, runner: &mut TestRunner) -> MastForest { + let strat = any_with::(params); + strat.new_tree(runner).expect("strategy should be valid").current() +} + +fn serialize_sizes(forest: &MastForest) -> (usize, usize, usize) { + let full_bytes = forest.to_bytes(); + + let mut stripped_bytes = Vec::new(); + forest.write_stripped(&mut stripped_bytes); + + let mut hashless_bytes = Vec::new(); + forest.write_hashless(&mut hashless_bytes); + + (full_bytes.len(), stripped_bytes.len(), hashless_bytes.len()) +} + +fn bench_serialization_sizes(c: &mut Criterion) { + let sizes: &[usize] = &[8, 16, 32, 64, 128, 256]; + let mut group = c.benchmark_group("mast_serialization"); + + let seed = [0u8; 32]; + let mut runner = TestRunner::new_with_rng( + Config::default(), + TestRng::from_seed(RngAlgorithm::ChaCha, &seed), + ); + + for &blocks_per_forest in sizes { + let gen_params = MastForestParams { + decorators: 32, + blocks: blocks_per_forest..=blocks_per_forest, + max_joins: blocks_per_forest.min(8), + max_splits: blocks_per_forest.min(8), + max_loops: blocks_per_forest.min(4), + max_calls: blocks_per_forest.min(4), + max_syscalls: 0, + max_externals: blocks_per_forest.min(2), + max_dyns: blocks_per_forest.min(2), + }; + + let forest = sample_forest(gen_params, &mut runner); + let (full, stripped, hashless) = serialize_sizes(&forest); + eprintln!("blocks={blocks_per_forest} full={full} stripped={stripped} hashless={hashless}"); + + group.throughput(Throughput::Bytes(full as u64)); + group.bench_with_input( + BenchmarkId::new("full", blocks_per_forest), + &forest, + |b, forest| { + b.iter(|| black_box(forest.to_bytes())); + }, + ); + + group.throughput(Throughput::Bytes(stripped as u64)); + group.bench_with_input( + BenchmarkId::new("stripped", blocks_per_forest), + &forest, + |b, forest| { + b.iter(|| { + let mut bytes = Vec::new(); + forest.write_stripped(&mut bytes); + black_box(bytes); + }); + }, + ); + + group.throughput(Throughput::Bytes(hashless as u64)); + group.bench_with_input( + BenchmarkId::new("hashless", blocks_per_forest), + &forest, + |b, forest| { + b.iter(|| { + let mut bytes = Vec::new(); + forest.write_hashless(&mut bytes); + black_box(bytes); + }); + }, + ); + } + + group.finish(); +} + +criterion_group!(benches, bench_serialization_sizes); +criterion_main!(benches); diff --git a/core/src/advice/map.rs b/core/src/advice/map.rs index b98b42c4d2..9808d8eb3c 100644 --- a/core/src/advice/map.rs +++ b/core/src/advice/map.rs @@ -11,7 +11,7 @@ use alloc::{ use serde::{Deserialize, Serialize}; use crate::{ - Felt, Word, + Felt, WORD_SIZE, Word, serde::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable}, }; @@ -23,6 +23,10 @@ use crate::{ /// Each key maps to one or more field element. To access the elements, the VM can move the values /// associated with a given key onto the advice stack using `adv.push_mapval` instruction. The VM /// can also insert new values into the advice map during execution. +/// +/// This type is a policy-free container. Execution-specific size limits for live advice map state +/// are enforced by the processor's `AdviceProvider`, which owns the active execution options and +/// live resource accounting. #[derive(Debug, Clone, Default, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", serde(transparent))] @@ -71,6 +75,31 @@ impl AdviceMap { self.0.is_empty() } + /// Returns the exact serialized size of this AdviceMap in bytes. + pub(crate) fn serialized_size_hint(&self) -> usize { + let mut size = self.0.len().get_size_hint(); + for (key, values) in self.0.iter() { + size += key.get_size_hint(); + size += values.len().get_size_hint(); + for value in values.iter() { + size += value.get_size_hint(); + } + } + size + } + + /// Returns the total number of field elements stored in this advice map's keys and values. + /// + /// Each key is a word, so every entry contributes [`WORD_SIZE`] key elements plus the number + /// of value elements associated with that key. Returns `None` if the count overflows `usize`. + pub fn total_element_count(&self) -> Option { + self.0.values().try_fold(0usize, |total, values| { + WORD_SIZE + .checked_add(values.len()) + .and_then(|entry_elements| total.checked_add(entry_elements)) + }) + } + /// Gets the given key's corresponding entry in the map for in-place manipulation. pub fn entry(&mut self, key: Word) -> Entry<'_, Word, Arc<[Felt]>> { self.0.entry(key) diff --git a/core/src/advice/mod.rs b/core/src/advice/mod.rs index 24d5dbff72..c9f4510db0 100644 --- a/core/src/advice/mod.rs +++ b/core/src/advice/mod.rs @@ -149,9 +149,9 @@ mod tests { fn test_builder_push_for_adv_push() { // push_for_adv_push reverses the slice // Input: [a, b, c] -> Builder stack: [c, b, a] (c on top) - let a = Felt::new(1); - let b = Felt::new(2); - let c = Felt::new(3); + let a = Felt::new_unchecked(1); + let b = Felt::new_unchecked(2); + let c = Felt::new_unchecked(3); let mut builder = AdviceStackBuilder::new(); builder.push_for_adv_push(&[a, b, c]); @@ -163,20 +163,34 @@ mod tests { } #[test] - fn test_builder_push_for_adv_loadw() { - let word: Word = [Felt::new(1), Felt::new(2), Felt::new(3), Felt::new(4)].into(); + fn test_builder_push_word() { + let word: Word = [ + Felt::new_unchecked(1), + Felt::new_unchecked(2), + Felt::new_unchecked(3), + Felt::new_unchecked(4), + ] + .into(); let mut builder = AdviceStackBuilder::new(); - builder.push_for_adv_loadw(word); + builder.push_word(word); let advice = builder.build(); // Builder stack is [w0, w1, w2, w3] with w0 on top - assert_eq!(advice.stack, vec![Felt::new(1), Felt::new(2), Felt::new(3), Felt::new(4)]); + assert_eq!( + advice.stack, + vec![ + Felt::new_unchecked(1), + Felt::new_unchecked(2), + Felt::new_unchecked(3), + Felt::new_unchecked(4) + ] + ); } #[test] fn test_builder_push_for_adv_pipe() { - let slice: Vec = (1..=8).map(Felt::new).collect(); + let slice: Vec = (1..=8).map(Felt::new_unchecked).collect(); let mut builder = AdviceStackBuilder::new(); builder.push_for_adv_pipe(&slice); @@ -188,7 +202,7 @@ mod tests { #[test] #[should_panic(expected = "push_for_adv_pipe requires slice length to be a multiple of 8")] fn test_builder_push_for_adv_pipe_panics_on_misalignment() { - let slice: Vec = (1..=7).map(Felt::new).collect(); + let slice: Vec = (1..=7).map(Felt::new_unchecked).collect(); let mut builder = AdviceStackBuilder::new(); builder.push_for_adv_pipe(&slice); @@ -202,36 +216,58 @@ mod tests { builder.push_u64_slice(&[1, 2, 3, 4]); let advice = builder.build(); - assert_eq!(advice.stack, vec![Felt::new(1), Felt::new(2), Felt::new(3), Felt::new(4)]); + assert_eq!( + advice.stack, + vec![ + Felt::new_unchecked(1), + Felt::new_unchecked(2), + Felt::new_unchecked(3), + Felt::new_unchecked(4) + ] + ); } #[test] fn test_builder_chaining_top_first() { // First call adds elements consumed first (on top) // Second call adds elements consumed second (below) - let a = Felt::new(1); - let b = Felt::new(2); - let c = Felt::new(3); - let word: Word = [Felt::new(10), Felt::new(20), Felt::new(30), Felt::new(40)].into(); + let a = Felt::new_unchecked(1); + let b = Felt::new_unchecked(2); + let c = Felt::new_unchecked(3); + let word: Word = [ + Felt::new_unchecked(10), + Felt::new_unchecked(20), + Felt::new_unchecked(30), + Felt::new_unchecked(40), + ] + .into(); let mut builder = AdviceStackBuilder::new(); builder.push_for_adv_push(&[a, b, c]); // Consumed first - builder.push_for_adv_loadw(word); // Consumed second + builder.push_word(word); // Consumed second let advice = builder.build(); // Builder stack: [c, b, a, w0, w1, w2, w3] // (c on top from reversed [a,b,c], then word below) assert_eq!( advice.stack, - vec![c, b, a, Felt::new(10), Felt::new(20), Felt::new(30), Felt::new(40)] + vec![ + c, + b, + a, + Felt::new_unchecked(10), + Felt::new_unchecked(20), + Felt::new_unchecked(30), + Felt::new_unchecked(40) + ] ); } #[test] fn test_builder_multiple_push_for_adv_push() { // Multiple calls should maintain top-first ordering - let first = [Felt::new(1), Felt::new(2)]; - let second = [Felt::new(3), Felt::new(4)]; + let first = [Felt::new_unchecked(1), Felt::new_unchecked(2)]; + let second = [Felt::new_unchecked(3), Felt::new_unchecked(4)]; let mut builder = AdviceStackBuilder::new(); builder.push_for_adv_push(&first); // Consumed first @@ -243,6 +279,14 @@ mod tests { // So second should go BELOW first in the stack // Builder stack after first: [2, 1] // Builder stack after second: [2, 1, 4, 3] - assert_eq!(advice.stack, vec![Felt::new(2), Felt::new(1), Felt::new(4), Felt::new(3)]); + assert_eq!( + advice.stack, + vec![ + Felt::new_unchecked(2), + Felt::new_unchecked(1), + Felt::new_unchecked(4), + Felt::new_unchecked(3) + ] + ); } } diff --git a/core/src/advice/stack.rs b/core/src/advice/stack.rs index dfe92ecb9e..34b85b1f74 100644 --- a/core/src/advice/stack.rs +++ b/core/src/advice/stack.rs @@ -21,8 +21,8 @@ use crate::{Felt, Word, crypto::merkle::MerkleStore}; /// /// ```ignore /// let advice = AdviceStackBuilder::new() -/// .push_for_adv_push(&[a, b, c]) // Consumed first by adv_push.3 -/// .push_for_adv_loadw(word) // Consumed second by adv_loadw +/// .push_for_adv_push(&[a, b, c]) // Consumed first by adv_push adv_push adv_push +/// .push_word(word) // Consumed second by adv_loadw (or adv_pushw) /// .build(); /// ``` #[derive(Clone, Debug, Default)] @@ -59,14 +59,13 @@ impl AdviceStackBuilder { self } - /// Adds elements for consumption by `adv_push.n` instructions. + /// Adds elements for consumption by multiple sequential `adv_push` instructions. /// - /// After `adv_push.n`, the operand stack will have `slice[0]` on top. - /// The slice length determines n (e.g., 4-element slice → `adv_push.4`). + /// After `repeat.n adv_push end`, the operand stack will have `slice[0]` on top. /// /// # How it works /// - /// `adv_push.n` pops elements one-by-one from the advice stack and pushes each to the operand + /// Each `adv_push` pops one element from the advice stack and pushes it to the operand /// stack. Since each push goes to the top, the first-popped element ends up at the bottom /// of the n elements, and the last-popped element ends up on top. /// @@ -77,7 +76,7 @@ impl AdviceStackBuilder { /// /// ```ignore /// builder.push_for_adv_push(&[a, b, c]); - /// // MASM: adv_push.3 + /// // MASM: adv_push adv_push adv_push /// // Result: operand stack = [a, b, c, ...] with a on top /// ``` pub fn push_for_adv_push(&mut self, slice: &[Felt]) -> &mut Self { @@ -89,31 +88,20 @@ impl AdviceStackBuilder { self } - /// Adds a word for consumption by `padw adv_loadw`. + /// Adds a word for consumption by `adv_loadw` or `adv_pushw`. /// - /// After `adv_loadw`, the operand stack will have the structural word loaded directly. - /// Use `reversew` afterward to convert to canonical (little-endian) order. - /// - /// # How it works - /// - /// The `adv_loadw` instruction: - /// 1. Calls `pop_stack_word()` which pops 4 elements from front and creates - /// `Word::new(\[e0,e1,e2,e3\])` - /// 2. Places the word on the operand stack with `word\[0\]` on top, `word\[1\]` at position 1, - /// etc. - /// - /// Elements are pushed without reversal since `adv_loadw` loads the structural word directly. + /// Both instructions consume the same 4 elements from the advice stack and place them on + /// the operand stack with `word[0]` on top; they differ only in whether the top operand + /// word is overwritten (`adv_loadw`) or the stack grows by 4 (`adv_pushw`). /// /// # Example /// /// ```ignore - /// builder.push_for_adv_loadw([w0, w1, w2, w3].into()); - /// // MASM: padw adv_loadw + /// builder.push_word([w0, w1, w2, w3].into()); + /// // MASM: adv_loadw (or adv_pushw) /// // Result: operand stack = [w0, w1, w2, w3, ...] with w0 on top /// ``` - pub fn push_for_adv_loadw(&mut self, word: Word) -> &mut Self { - // Push elements without reversal. adv_loadw loads the structural word directly, - // so a `reversew` is needed afterward to get canonical order on the operand stack. + pub fn push_word(&mut self, word: Word) -> &mut Self { for elem in word.iter() { self.stack.push_back(*elem); } @@ -161,7 +149,7 @@ impl AdviceStackBuilder { /// // Elements consumed in order: 1, 2, 3, 4, 5, 6, 7, 8 /// ``` pub fn push_u64_slice(&mut self, values: &[u64]) -> &mut Self { - self.stack.extend(values.iter().map(|&v| Felt::new(v))); + self.stack.extend(values.iter().map(|&v| Felt::new_unchecked(v))); self } diff --git a/core/src/chiplets/hasher.rs b/core/src/chiplets/hasher.rs index 067d25bdb8..15bf5b4510 100644 --- a/core/src/chiplets/hasher.rs +++ b/core/src/chiplets/hasher.rs @@ -24,17 +24,19 @@ pub const STATE_WIDTH: usize = Hasher::STATE_WIDTH; /// Number of field elements in the rate portion of the hasher's state. pub const RATE_LEN: usize = 8; -/// Number of "round steps" used by the hasher chiplet per permutation. +/// Number of Poseidon2 step transitions used by the hasher reference schedule. /// /// For Poseidon2, we model the permutation as 31 step transitions. This corresponds to an -/// initial external linear layer, 4 initial external (partial) rounds, 22 internal (full) rounds, -/// and 4 terminal external (partial) rounds: +/// initial external linear layer, 4 initial external rounds, 22 internal rounds, and 4 terminal +/// external rounds: /// - step 0: initial external linear layer /// - steps 1..=4: initial external rounds /// - steps 5..=26: internal rounds /// - steps 27..=30: terminal external rounds /// -/// This yields a 32-row hasher cycle (input row + 31 steps). +/// The hasher chiplet packs this 31-step schedule into a 16-row permutation cycle, but the +/// stepwise reference API keeps the original 31-step numbering because it is convenient for tests +/// and cross-checking against the uncompressed permutation schedule. pub const NUM_ROUNDS: usize = 31; // PASS-THROUGH FUNCTIONS @@ -134,7 +136,8 @@ mod tests { assert_eq!(state_stepwise, state_permutation, "mismatch with zero state"); // Test with sequential values - let mut state_stepwise: [Felt; STATE_WIDTH] = core::array::from_fn(|i| Felt::new(i as u64)); + let mut state_stepwise: [Felt; STATE_WIDTH] = + core::array::from_fn(|i| Felt::new_unchecked(i as u64)); let mut state_permutation = state_stepwise; for i in 0..NUM_ROUNDS { @@ -146,18 +149,18 @@ mod tests { // Test with arbitrary values let mut state_stepwise: [Felt; STATE_WIDTH] = [ - Felt::new(0x123456789abcdef0_u64), - Felt::new(0xfedcba9876543210_u64), - Felt::new(0x0011223344556677_u64), - Felt::new(0x8899aabbccddeeff_u64), - Felt::new(0xdeadbeefcafebabe_u64), - Felt::new(0x1234567890abcdef_u64), - Felt::new(0x1234567890abcdef_u64), - Felt::new(0x0badc0debadf00d0_u64), - Felt::new(0x1111111111111111_u64), - Felt::new(0x2222222222222222_u64), - Felt::new(0x3333333333333333_u64), - Felt::new(0x4444444444444444_u64), + Felt::new_unchecked(0x123456789abcdef0_u64), + Felt::new_unchecked(0xfedcba9876543210_u64), + Felt::new_unchecked(0x0011223344556677_u64), + Felt::new_unchecked(0x8899aabbccddeeff_u64), + Felt::new_unchecked(0xdeadbeefcafebabe_u64), + Felt::new_unchecked(0x1234567890abcdef_u64), + Felt::new_unchecked(0x1234567890abcdef_u64), + Felt::new_unchecked(0x0badc0debadf00d0_u64), + Felt::new_unchecked(0x1111111111111111_u64), + Felt::new_unchecked(0x2222222222222222_u64), + Felt::new_unchecked(0x3333333333333333_u64), + Felt::new_unchecked(0x4444444444444444_u64), ]; let mut state_permutation = state_stepwise; @@ -173,7 +176,8 @@ mod tests { /// half-permutations produce the same result as a full permutation. #[test] fn apply_round_intermediate_states() { - let init_state: [Felt; STATE_WIDTH] = core::array::from_fn(|i| Felt::new((i + 1) as u64)); + let init_state: [Felt; STATE_WIDTH] = + core::array::from_fn(|i| Felt::new_unchecked((i + 1) as u64)); // Apply first half of rounds let mut state_half1 = init_state; @@ -193,4 +197,83 @@ mod tests { assert_eq!(state_half2, state_full, "split application doesn't match full permutation"); } + + /// Verifies that the 16-row packed permutation schedule produces the same result + /// as the reference `apply_permutation`. + /// + /// The packed schedule: + /// - init + ext1 (merged) + /// - ext2, ext3, ext4 + /// - 7 x (3 packed internal rounds) + /// - int22 + ext5 (merged) + /// - ext6, ext7, ext8 + #[test] + fn packed_16row_matches_permutation() { + let test_states: [_; 3] = [ + [Felt::ZERO; STATE_WIDTH], + core::array::from_fn(|i| Felt::new_unchecked(i as u64)), + [ + Felt::new_unchecked(0x123456789abcdef0), + Felt::new_unchecked(0xfedcba9876543210), + Felt::new_unchecked(0x0011223344556677), + Felt::new_unchecked(0x8899aabbccddeeff), + Felt::new_unchecked(0xdeadbeefcafebabe), + Felt::new_unchecked(0x1234567890abcdef), + Felt::new_unchecked(0x1234567890abcdef), + Felt::new_unchecked(0x0badc0debadf00d0), + Felt::new_unchecked(0x1111111111111111), + Felt::new_unchecked(0x2222222222222222), + Felt::new_unchecked(0x3333333333333333), + Felt::new_unchecked(0x4444444444444444), + ], + ]; + + for (idx, init_state) in test_states.iter().enumerate() { + let mut state = *init_state; + + // Init + ext1 (merged) + Hasher::apply_matmul_external(&mut state); + Hasher::add_rc(&mut state, &Hasher::ARK_EXT_INITIAL[0]); + Hasher::apply_sbox(&mut state); + Hasher::apply_matmul_external(&mut state); + + // Ext2, ext3, ext4 + for r in 1..=3 { + Hasher::add_rc(&mut state, &Hasher::ARK_EXT_INITIAL[r]); + Hasher::apply_sbox(&mut state); + Hasher::apply_matmul_external(&mut state); + } + + // 7 x (3 packed internal rounds) + for triple in 0..7_usize { + let base = triple * 3; + for k in 0..3 { + state[0] += Hasher::ARK_INT[base + k]; + state[0] = state[0].exp_const_u64::<7>(); + Hasher::matmul_internal(&mut state, Hasher::MAT_DIAG); + } + } + + // Int22 + ext5 (merged) + state[0] += Hasher::ARK_INT[21]; + state[0] = state[0].exp_const_u64::<7>(); + Hasher::matmul_internal(&mut state, Hasher::MAT_DIAG); + Hasher::add_rc(&mut state, &Hasher::ARK_EXT_TERMINAL[0]); + Hasher::apply_sbox(&mut state); + Hasher::apply_matmul_external(&mut state); + + // Ext6, ext7, ext8 + for r in 1..=3 { + Hasher::add_rc(&mut state, &Hasher::ARK_EXT_TERMINAL[r]); + Hasher::apply_sbox(&mut state); + Hasher::apply_matmul_external(&mut state); + } + + // Compare with reference + let mut reference = *init_state; + apply_permutation(&mut reference); + + assert_eq!(state, reference, "packed schedule mismatch for test state {idx}"); + } + } } diff --git a/core/src/events/mod.rs b/core/src/events/mod.rs index 11661f22de..2ca90d454c 100644 --- a/core/src/events/mod.rs +++ b/core/src/events/mod.rs @@ -69,7 +69,7 @@ impl EventId { /// Converts this event ID to a [`Felt`]. pub const fn as_felt(&self) -> Felt { - Felt::new(self.0) + Felt::new_unchecked(self.0) } /// Returns the inner `u64` representation. @@ -80,7 +80,7 @@ impl EventId { impl Display for EventId { fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { - core::fmt::Display::fmt(&self.0, f) + Display::fmt(&self.0, f) } } @@ -206,7 +206,7 @@ impl proptest::prelude::Arbitrary for EventName { Just(EventName::new("user::custom::event")), // Dynamic strings (Cow::Owned) any::<(u32, u32)>() - .prop_map(|(a, b)| EventName::from_string(format!("dynamic::event::{}::{}", a, b))), + .prop_map(|(a, b)| EventName::from_string(format!("dynamic::event::{a}::{b}"))), ] .boxed() } @@ -228,9 +228,9 @@ mod tests { // EventId constructors and conversions let id1 = EventId::from_u64(100); assert_eq!(id1.as_u64(), 100); - assert_eq!(id1.as_felt(), Felt::new(100)); + assert_eq!(id1.as_felt(), Felt::new_unchecked(100)); - let id2 = EventId::from_felt(Felt::new(200)); + let id2 = EventId::from_felt(Felt::new_unchecked(200)); assert_eq!(id2.as_u64(), 200); // EventId from name hashes consistently @@ -241,7 +241,7 @@ mod tests { // EventName constructors and conversions let name1 = EventName::new("static::event"); assert_eq!(name1.as_str(), "static::event"); - assert_eq!(format!("{}", name1), "static::event"); + assert_eq!(format!("{name1}"), "static::event"); let name2 = EventName::from_string("dynamic::event".to_string()); assert_eq!(name2.as_str(), "dynamic::event"); diff --git a/core/src/lib.rs b/core/src/lib.rs index d030618ccb..5b298c47ee 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -55,7 +55,10 @@ assertion failed: `(left matches right)` // EXPORTS // ================================================================================================ -pub use miden_crypto::{EMPTY_WORD, Felt, LexicographicWord, ONE, WORD_SIZE, Word, ZERO}; +pub use miden_crypto::{EMPTY_WORD, Felt, ONE, Word, ZERO}; + +/// The number of field elements in a Miden word. +pub const WORD_SIZE: usize = Word::NUM_ELEMENTS; pub mod advice; pub mod chiplets; @@ -135,7 +138,7 @@ pub mod prettier { /// The initial value for the frame pointer, corresponding to the start address for procedure /// locals. -pub const FMP_INIT_VALUE: Felt = Felt::new(2_u64.pow(31)); +pub const FMP_INIT_VALUE: Felt = Felt::new_unchecked(2_u64.pow(31)); /// The address where the frame pointer is stored in memory. -pub const FMP_ADDR: Felt = Felt::new(u32::MAX as u64 - 1_u64); +pub const FMP_ADDR: Felt = Felt::new_unchecked(u32::MAX as u64 - 1_u64); diff --git a/core/src/mast/debuginfo/asm_op_storage.rs b/core/src/mast/debuginfo/asm_op_storage.rs index ba3dba3fff..243688cde9 100644 --- a/core/src/mast/debuginfo/asm_op_storage.rs +++ b/core/src/mast/debuginfo/asm_op_storage.rs @@ -186,7 +186,7 @@ impl OpToAsmOpId { /// Returns all `(op_idx, AsmOpId)` pairs for the given node, or an empty vec if the /// node has no asm ops. pub fn asm_ops_for_node(&self, node_id: MastNodeId) -> Vec<(usize, AsmOpId)> { - self.inner.row(node_id).map(|r| r.to_vec()).unwrap_or_default() + self.inner.row(node_id).unwrap_or_default().to_vec() } /// Validates the CSR structure integrity. @@ -266,7 +266,7 @@ impl OpToAsmOpId { let result = Self { inner }; result.validate_csr(asm_op_count).map_err(|e| { - DeserializationError::InvalidValue(format!("OpToAsmOpId validation failed: {}", e)) + DeserializationError::InvalidValue(format!("OpToAsmOpId validation failed: {e}")) })?; Ok(result) @@ -672,7 +672,7 @@ mod tests { fn test_serialization_roundtrip_empty() { let storage = OpToAsmOpId::new(); - let mut bytes = alloc::vec::Vec::new(); + let mut bytes = Vec::new(); storage.write_into(&mut bytes); let mut reader = SliceReader::new(&bytes); @@ -699,7 +699,7 @@ mod tests { .add_asm_ops_for_node(test_node_id(2), 2, vec![(1, test_asm_op_id(2))]) .unwrap(); - let mut bytes = alloc::vec::Vec::new(); + let mut bytes = Vec::new(); storage.write_into(&mut bytes); let mut reader = SliceReader::new(&bytes); @@ -733,7 +733,7 @@ mod tests { #[test] fn test_debug_impl() { let storage = OpToAsmOpId::new(); - let debug_str = alloc::format!("{:?}", storage); + let debug_str = alloc::format!("{storage:?}"); assert!(debug_str.contains("OpToAsmOpId")); } } diff --git a/core/src/mast/debuginfo/debug_var_storage.rs b/core/src/mast/debuginfo/debug_var_storage.rs index 7ef81c9779..c8b6d50f28 100644 --- a/core/src/mast/debuginfo/debug_var_storage.rs +++ b/core/src/mast/debuginfo/debug_var_storage.rs @@ -10,6 +10,8 @@ use alloc::{ }; use miden_utils_indexing::{Idx, IndexVec}; +#[cfg(feature = "arbitrary")] +use proptest::prelude::*; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; @@ -28,6 +30,10 @@ use crate::{ /// variable information. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr( + all(feature = "arbitrary", test), + miden_test_serde_macros::serde_test(binary_serde(true)) +)] pub struct DebugVarId(u32); impl DebugVarId { @@ -38,8 +44,7 @@ impl DebugVarId { Ok(Self(value)) } else { Err(DeserializationError::InvalidValue(format!( - "DebugVarId {} exceeds bound {}", - value, bound + "DebugVarId {value} exceeds bound {bound}" ))) } } @@ -69,6 +74,16 @@ impl From for u32 { } } +#[cfg(feature = "arbitrary")] +impl Arbitrary for DebugVarId { + type Parameters = (); + type Strategy = BoxedStrategy; + + fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { + any::().prop_map(Self::from).boxed() + } +} + impl Serializable for DebugVarId { fn write_into(&self, target: &mut W) { self.0.write_into(target); @@ -257,10 +272,14 @@ impl OpToDebugVarIds { } } - if *self.op_indptr_for_var_ids.last().unwrap() != self.debug_var_ids.len() { + let &last_op_ptr = self + .op_indptr_for_var_ids + .last() + .ok_or_else(|| "op_indptr_for_var_ids is unexpectedly empty".to_string())?; + if last_op_ptr != self.debug_var_ids.len() { return Err(format!( "op_indptr_for_var_ids end {} doesn't match debug_var_ids length {}", - self.op_indptr_for_var_ids.last().unwrap(), + last_op_ptr, self.debug_var_ids.len() )); } @@ -285,11 +304,12 @@ impl OpToDebugVarIds { } let max_node_ptr = self.op_indptr_for_var_ids.len() - 1; - if *node_slice.last().unwrap() > max_node_ptr { + let &last_node_ptr = node_slice + .last() + .ok_or_else(|| "node_indptr_for_op_idx is unexpectedly empty".to_string())?; + if last_node_ptr > max_node_ptr { return Err(format!( - "node_indptr_for_op_idx end {} exceeds op_indptr bounds {}", - node_slice.last().unwrap(), - max_node_ptr + "node_indptr_for_op_idx end {last_node_ptr} exceeds op_indptr bounds {max_node_ptr}" )); } @@ -356,13 +376,15 @@ impl OpToDebugVarIds { .push(op_start) .map_err(|_| DecoratorIndexError::OperationIndex { node, operation: op_start })?; } else { - let max_op_idx = debug_vars_info.last().unwrap().0; + let max_op_idx = + debug_vars_info.last().ok_or(DecoratorIndexError::InternalStructure)?.0; let mut it = debug_vars_info.into_iter().peekable(); for op in 0..=max_op_idx { self.op_indptr_for_var_ids.push(self.debug_var_ids.len()); while it.peek().is_some_and(|(i, _)| *i == op) { - self.debug_var_ids.push(it.next().unwrap().1); + self.debug_var_ids + .push(it.next().ok_or(DecoratorIndexError::InternalStructure)?.1); } } self.op_indptr_for_var_ids.push(self.debug_var_ids.len()); @@ -461,7 +483,7 @@ impl OpToDebugVarIds { }; let mut result = Vec::new(); - for (op_offset, op_idx) in op_range.clone().enumerate() { + for (op_offset, op_idx) in op_range.enumerate() { if op_idx + 1 >= self.op_indptr_for_var_ids.len() { break; } diff --git a/core/src/mast/debuginfo/decorator_storage.rs b/core/src/mast/debuginfo/decorator_storage.rs index 3802cc8354..a0f9db2ceb 100644 --- a/core/src/mast/debuginfo/decorator_storage.rs +++ b/core/src/mast/debuginfo/decorator_storage.rs @@ -282,10 +282,14 @@ impl OpToDecoratorIds { } } - if *self.op_indptr_for_dec_ids.last().unwrap() != self.decorator_ids.len() { + let &last_op_ptr = self + .op_indptr_for_dec_ids + .last() + .ok_or_else(|| "op_indptr_for_dec_ids is unexpectedly empty".to_string())?; + if last_op_ptr != self.decorator_ids.len() { return Err(format!( "op_indptr_for_dec_ids end {} doesn't match decorator_ids length {}", - self.op_indptr_for_dec_ids.last().unwrap(), + last_op_ptr, self.decorator_ids.len() )); } @@ -311,11 +315,12 @@ impl OpToDecoratorIds { // Node pointers must be valid indices into op_indptr let max_node_ptr = self.op_indptr_for_dec_ids.len() - 1; - if *node_slice.last().unwrap() > max_node_ptr { + let &last_node_ptr = node_slice + .last() + .ok_or_else(|| "node_indptr_for_op_idx is unexpectedly empty".to_string())?; + if last_node_ptr > max_node_ptr { return Err(format!( - "node_indptr_for_op_idx end {} exceeds op_indptr bounds {}", - node_slice.last().unwrap(), - max_node_ptr + "node_indptr_for_op_idx end {last_node_ptr} exceeds op_indptr bounds {max_node_ptr}" )); } @@ -431,14 +436,16 @@ impl OpToDecoratorIds { .map_err(|_| DecoratorIndexError::OperationIndex { node, operation: op_start })?; } else { // Build op->decorator CSR for this node - let max_op_idx = decorators_info.last().unwrap().0; // input is sorted by op index + let max_op_idx = + decorators_info.last().ok_or(DecoratorIndexError::InternalStructure)?.0; // input is sorted by op index let mut it = decorators_info.into_iter().peekable(); for op in 0..=max_op_idx { // pointer to start of decorator IDs for op self.op_indptr_for_dec_ids.push(self.decorator_ids.len()); while it.peek().is_some_and(|(i, _)| *i == op) { - self.decorator_ids.push(it.next().unwrap().1); + self.decorator_ids + .push(it.next().ok_or(DecoratorIndexError::InternalStructure)?.1); } } // final sentinel for this node @@ -468,7 +475,7 @@ impl OpToDecoratorIds { node: MastNodeId, operation: usize, ) -> Result { - self.decorator_ids_for_operation(node, operation).map(|slice| slice.len()) + self.decorator_ids_for_operation(node, operation).map(<[DecoratorId]>::len) } /// Get all decorator IDs for a specific operation within a node. diff --git a/core/src/mast/debuginfo/decorator_storage/tests.rs b/core/src/mast/debuginfo/decorator_storage/tests.rs index ca8369b43d..f8b91255a5 100644 --- a/core/src/mast/debuginfo/decorator_storage/tests.rs +++ b/core/src/mast/debuginfo/decorator_storage/tests.rs @@ -201,7 +201,7 @@ fn test_empty_nodes_basic_functionality() { #[test] fn test_debug_impl() { let storage = OpToDecoratorIds::new(); - let debug_str = format!("{:?}", storage); + let debug_str = format!("{storage:?}"); assert!(debug_str.contains("OpToDecoratorIds")); } @@ -222,8 +222,8 @@ fn test_clone_and_equality() { node_indptr_for_op_idx.push(3).expect("test setup: IndexVec capacity exceeded"); let storage1 = OpToDecoratorIds::from_components( - decorator_indices.clone(), - op_indptr_for_dec_idx.clone(), + decorator_indices, + op_indptr_for_dec_idx, node_indptr_for_op_idx.clone(), ) .unwrap(); @@ -500,8 +500,7 @@ fn test_csr_and_coo_produce_same_elements() { ]; // Build COO representation as a HashMap for easy lookup during verification - let mut coo_map: alloc::collections::BTreeMap<(MastNodeId, usize), Vec> = - alloc::collections::BTreeMap::new(); + let mut coo_map: BTreeMap<(MastNodeId, usize), Vec> = BTreeMap::new(); for (node, op_idx, decorator_id) in &coo_data { coo_map.entry((*node, *op_idx)).or_default().push(*decorator_id); } @@ -562,8 +561,7 @@ fn test_csr_and_coo_produce_same_elements() { // They should be the same assert_eq!( csr_decorator_ids, coo_decorator_ids, - "CSR and COO should produce the same decorator IDs for node {:?}, op {}", - node_id, op_idx + "CSR and COO should produce the same decorator IDs for node {node_id:?}, op {op_idx}" ); } } @@ -590,8 +588,7 @@ fn test_csr_and_coo_produce_same_elements() { assert_eq!( csr_flat, expected_flat, - "Flattened CSR and COO should produce the same elements for node {:?}", - node_id + "Flattened CSR and COO should produce the same elements for node {node_id:?}" ); } } @@ -707,7 +704,7 @@ fn test_sparse_case_manual() { let result = OpToDecoratorIds::from_components(decorator_ids, op_indptr_for_dec_ids, node_indptr); - assert!(result.is_ok(), "Single node with decorator should validate: {:?}", result); + assert!(result.is_ok(), "Single node with decorator should validate: {result:?}"); } #[test] @@ -725,8 +722,7 @@ fn test_sparse_case_two_nodes() { assert!( result.is_ok(), - "Two nodes (one with decorator, one empty) should validate: {:?}", - result + "Two nodes (one with decorator, one empty) should validate: {result:?}" ); } @@ -750,7 +746,7 @@ fn test_sparse_debuginfo_round_trip() { node_indptr_for_op_idx.push(4).unwrap(); // node 5 let op_storage = OpToDecoratorIds::from_components( - decorator_ids.clone(), + decorator_ids, op_indptr_for_dec_ids, node_indptr_for_op_idx, ) diff --git a/core/src/mast/debuginfo/mod.rs b/core/src/mast/debuginfo/mod.rs index 8b6325c5c8..c24c91fe63 100644 --- a/core/src/mast/debuginfo/mod.rs +++ b/core/src/mast/debuginfo/mod.rs @@ -52,7 +52,7 @@ use serde::{Deserialize, Serialize}; use super::{AsmOpId, Decorator, DecoratorId, MastForestError, MastNodeId}; use crate::{ - LexicographicWord, Word, + Word, mast::serialization::{ StringTable, asm_op::{AsmOpDataBuilder, AsmOpInfo}, @@ -110,7 +110,7 @@ pub struct DebugInfo { /// Maps MAST root digests to procedure names for debugging purposes. #[cfg_attr(feature = "serde", serde(skip))] - procedure_names: BTreeMap>, + procedure_names: BTreeMap>, } impl DebugInfo { @@ -328,7 +328,7 @@ impl DebugInfo { &mut self, node_id: MastNodeId, decorators_info: Vec<(usize, DecoratorId)>, - ) -> Result<(), crate::mast::debuginfo::decorator_storage::DecoratorIndexError> { + ) -> Result<(), DecoratorIndexError> { self.op_decorator_storage.add_decorator_info_for_node(node_id, decorators_info) } @@ -450,7 +450,7 @@ impl DebugInfo { &mut self, node_id: MastNodeId, debug_vars_info: Vec<(usize, DebugVarId)>, - ) -> Result<(), crate::mast::debuginfo::decorator_storage::DecoratorIndexError> { + ) -> Result<(), DecoratorIndexError> { self.op_debug_var_storage.add_debug_var_info_for_node(node_id, debug_vars_info) } @@ -494,12 +494,12 @@ impl DebugInfo { /// Returns the procedure name for the given MAST root digest, if present. pub fn procedure_name(&self, digest: &Word) -> Option<&str> { - self.procedure_names.get(&LexicographicWord::from(*digest)).map(|s| s.as_ref()) + self.procedure_names.get(digest).map(AsRef::as_ref) } /// Returns an iterator over all (digest, name) pairs. pub fn procedure_names(&self) -> impl Iterator)> { - self.procedure_names.iter().map(|(key, name)| (key.into_inner(), name)) + self.procedure_names.iter().map(|(key, name)| (*key, name)) } /// Returns the number of procedure names. @@ -509,7 +509,7 @@ impl DebugInfo { /// Inserts a procedure name for the given MAST root digest. pub fn insert_procedure_name(&mut self, digest: Word, name: Arc) { - self.procedure_names.insert(LexicographicWord::from(digest), name); + self.procedure_names.insert(digest, name); } /// Inserts multiple procedure names at once. @@ -517,8 +517,7 @@ impl DebugInfo { where I: IntoIterator)>, { - self.procedure_names - .extend(names.into_iter().map(|(d, n)| (LexicographicWord::from(d), n))); + self.procedure_names.extend(names); } /// Clears all procedure names. @@ -567,6 +566,12 @@ impl DebugInfo { pub(crate) fn op_decorator_storage(&self) -> &OpToDecoratorIds { &self.op_decorator_storage } + + /// Returns the node decorator storage. + #[cfg(test)] + pub(crate) fn node_decorator_storage(&self) -> &NodeToDecoratorIds { + &self.node_decorator_storage + } } impl Serializable for DebugInfo { @@ -656,9 +661,9 @@ impl Deserializable for DebugInfo { // Note: Procedure name digests are validated at the MastForest level (in // MastForest::validate) to ensure they reference actual procedures in the forest. let procedure_names_raw: BTreeMap = Deserializable::read_from(source)?; - let procedure_names: BTreeMap> = procedure_names_raw + let procedure_names: BTreeMap> = procedure_names_raw .into_iter() - .map(|(k, v)| (LexicographicWord::from(k), Arc::from(v.as_str()))) + .map(|(k, v)| (k, Arc::from(v.as_str()))) .collect(); // 7. Read AssemblyOps (data, string table, infos) @@ -700,7 +705,7 @@ impl Deserializable for DebugInfo { }; debug_info.validate().map_err(|e| { - DeserializationError::InvalidValue(format!("DebugInfo validation failed: {}", e)) + DeserializationError::InvalidValue(format!("DebugInfo validation failed: {e}")) })?; Ok(debug_info) diff --git a/core/src/mast/merger/mod.rs b/core/src/mast/merger/mod.rs index 17634e57bd..3c94d7aa61 100644 --- a/core/src/mast/merger/mod.rs +++ b/core/src/mast/merger/mod.rs @@ -471,7 +471,7 @@ fn serialize_asm_op_content_for_node(forest: &MastForest, node_id: MastNodeId) - /// /// It maps the roots ([`MastNodeId`]s) of a forest to their new [`MastNodeId`] in the merged /// forest. See [`MastForest::merge`] for more details. -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, Default, PartialEq, Eq)] pub struct MastForestRootMap { root_maps: Vec>, } diff --git a/core/src/mast/merger/tests.rs b/core/src/mast/merger/tests.rs index 8519ed0a32..302b500675 100644 --- a/core/src/mast/merger/tests.rs +++ b/core/src/mast/merger/tests.rs @@ -138,6 +138,39 @@ fn mast_forest_merge_preserves_dyn_callness_and_digest() { assert_eq!(merged_dyncall.digest(), dyncall_digest, "dyncall digest should be preserved"); } +#[test] +fn mast_forest_merge_preserves_padded_basic_block_batches() { + let mut forest = MastForest::new(); + + let operations = vec![Operation::Add, Operation::Push(Felt::new_unchecked(100))]; + let block_id = BasicBlockNodeBuilder::new(operations.clone(), Vec::new()) + .add_to_forest(&mut forest) + .unwrap(); + forest.make_root(block_id); + + let original_block = forest[block_id].unwrap_basic_block(); + assert!( + original_block.operations().count() > original_block.raw_operations().count(), + "test input must create padded operations" + ); + let original_batches = original_block.op_batches().to_vec(); + + let (merged, root_maps) = MastForest::merge([&forest]).unwrap(); + + let merged_block_id = root_maps.map_root(0, &block_id).unwrap(); + let merged_block = merged[merged_block_id].unwrap_basic_block(); + assert_eq!( + merged_block.raw_operations().copied().collect::>(), + operations, + "merge must not treat padded operations as raw operations" + ); + assert_eq!( + merged_block.op_batches(), + original_batches, + "merge must preserve the original batch layout" + ); +} + /// Tests that Call(bar) still correctly calls the remapped bar block. /// /// [Block(foo), Call(foo)] @@ -533,7 +566,7 @@ fn mast_forest_merge_external_node_reference_with_decorator() { let trace = Decorator::Trace(1); // Build Forest A - let deco = forest_a.add_decorator(trace.clone()).unwrap(); + let deco = forest_a.add_decorator(trace).unwrap(); let foo_node_a = block_foo_with_decorators(&[deco], &[]); let foo_node_digest = block_foo_with_decorators(&[deco], &[]).build().unwrap().digest(); @@ -556,10 +589,14 @@ fn mast_forest_merge_external_node_reference_with_decorator() { .enumerate() { let id_foo_a_digest = forest_a[id_foo_a].digest(); - let digests: Vec<_> = merged.nodes().iter().map(|node| node.digest()).collect(); - assert_eq!(merged.nodes.len(), 1); - assert!(digests.contains(&id_foo_a_digest)); + assert!( + merged + .nodes() + .iter() + .map(MastNodeExt::digest) + .any(|digest| digest == id_foo_a_digest) + ); if idx == 0 { assert_root_mapping(&root_maps, vec![&forest_a.roots, &forest_b.roots], &merged.roots) @@ -592,8 +629,8 @@ fn mast_forest_merge_external_node_with_decorator() { let trace2 = Decorator::Trace(2); // Build Forest A - let deco1 = forest_a.add_decorator(trace1.clone()).unwrap(); - let deco2 = forest_a.add_decorator(trace2.clone()).unwrap(); + let deco1 = forest_a.add_decorator(trace1).unwrap(); + let deco2 = forest_a.add_decorator(trace2).unwrap(); let external_node_a = external_with_decorators(block_foo().build().unwrap().digest(), &[deco1], &[deco2]); @@ -617,10 +654,14 @@ fn mast_forest_merge_external_node_with_decorator() { assert_eq!(merged.nodes.len(), 1); let id_foo_b_digest = forest_b[id_foo_b].digest(); - let digests: Vec<_> = merged.nodes().iter().map(|node| node.digest()).collect(); - // Block foo should be unmodified. - assert!(digests.contains(&id_foo_b_digest)); + assert!( + merged + .nodes() + .iter() + .map(MastNodeExt::digest) + .any(|digest| digest == id_foo_b_digest) + ); if idx == 0 { assert_root_mapping(&root_maps, vec![&forest_a.roots, &forest_b.roots], &merged.roots) @@ -653,7 +694,7 @@ fn mast_forest_merge_external_node_and_referenced_node_have_decorators() { let trace2 = Decorator::Trace(2); // Build Forest A - let deco1_a = forest_a.add_decorator(trace1.clone()).unwrap(); + let deco1_a = forest_a.add_decorator(trace1).unwrap(); let external_node_a = external_with_decorators(block_foo().build().unwrap().digest(), &[deco1_a], &[]); @@ -663,7 +704,7 @@ fn mast_forest_merge_external_node_and_referenced_node_have_decorators() { // Build Forest B let mut forest_b = MastForest::new(); - let deco2_b = forest_b.add_decorator(trace2.clone()).unwrap(); + let deco2_b = forest_b.add_decorator(trace2).unwrap(); let foo_node_b = block_foo_with_decorators(&[deco2_b], &[]); let id_foo_b = foo_node_b.add_to_forest(&mut forest_b).unwrap(); @@ -680,10 +721,14 @@ fn mast_forest_merge_external_node_and_referenced_node_have_decorators() { assert_eq!(merged.nodes.len(), 1); let id_foo_b_digest = forest_b[id_foo_b].digest(); - let digests: Vec<_> = merged.nodes().iter().map(|node| node.digest()).collect(); - // Block foo should be unmodified. - assert!(digests.contains(&id_foo_b_digest)); + assert!( + merged + .nodes() + .iter() + .map(MastNodeExt::digest) + .any(|digest| digest == id_foo_b_digest) + ); if idx == 0 { assert_root_mapping(&root_maps, vec![&forest_a.roots, &forest_b.roots], &merged.roots) @@ -719,7 +764,7 @@ fn mast_forest_merge_multiple_external_nodes_with_decorator() { // Build Forest A let deco1_a = forest_a.add_decorator(trace1.clone()).unwrap(); - let deco2_a = forest_a.add_decorator(trace2.clone()).unwrap(); + let deco2_a = forest_a.add_decorator(trace2).unwrap(); let external_node_a = external_with_decorators(block_foo().build().unwrap().digest(), &[deco1_a], &[deco2_a]); @@ -750,10 +795,14 @@ fn mast_forest_merge_multiple_external_nodes_with_decorator() { assert_eq!(merged.nodes.len(), 1); let id_foo_b_digest = forest_b[id_foo_b].digest(); - let digests: Vec<_> = merged.nodes().iter().map(|node| node.digest()).collect(); - // Block foo should be unmodified. - assert!(digests.contains(&id_foo_b_digest)); + assert!( + merged + .nodes() + .iter() + .map(MastNodeExt::digest) + .any(|digest| digest == id_foo_b_digest) + ); if idx == 0 { assert_root_mapping(&root_maps, vec![&forest_a.roots, &forest_b.roots], &merged.roots) @@ -802,7 +851,7 @@ fn mast_forest_merge_external_dependencies() { ] .into_iter() { - let digests = merged.nodes().iter().map(|node| node.digest()).collect::>(); + let digests = merged.nodes().iter().map(MastNodeExt::digest).collect::>(); assert_eq!(merged.nodes().len(), 3); assert!(digests.contains(&forest_b[id_ext_b].digest())); assert!(digests.contains(&forest_b[id_call_b].digest())); @@ -824,8 +873,8 @@ fn mast_forest_merge_invalid_decorator_index() { // Build Forest A let mut forest_a = MastForest::new(); - let deco1_a = forest_a.add_decorator(trace1.clone()).unwrap(); - let deco2_a = forest_a.add_decorator(trace2.clone()).unwrap(); + let deco1_a = forest_a.add_decorator(trace1).unwrap(); + let deco2_a = forest_a.add_decorator(trace2).unwrap(); let id_bar_a = block_bar().add_to_forest(&mut forest_a).unwrap(); forest_a.make_root(id_bar_a); @@ -849,7 +898,12 @@ fn mast_forest_merge_advice_maps_merged() { let id_foo = block_foo().add_to_forest(&mut forest_a).unwrap(); let id_call_a = CallNodeBuilder::new(id_foo).add_to_forest(&mut forest_a).unwrap(); forest_a.make_root(id_call_a); - let key_a = Word::new([Felt::new(1), Felt::new(2), Felt::new(3), Felt::new(4)]); + let key_a = Word::new([ + Felt::new_unchecked(1), + Felt::new_unchecked(2), + Felt::new_unchecked(3), + Felt::new_unchecked(4), + ]); let value_a = vec![ONE, ONE]; forest_a.advice_map_mut().insert(key_a, value_a.clone()); @@ -857,8 +911,13 @@ fn mast_forest_merge_advice_maps_merged() { let id_bar = block_bar().add_to_forest(&mut forest_b).unwrap(); let id_call_b = CallNodeBuilder::new(id_bar).add_to_forest(&mut forest_b).unwrap(); forest_b.make_root(id_call_b); - let key_b = Word::new([Felt::new(1), Felt::new(3), Felt::new(2), Felt::new(1)]); - let value_b = vec![Felt::new(2), Felt::new(2)]; + let key_b = Word::new([ + Felt::new_unchecked(1), + Felt::new_unchecked(3), + Felt::new_unchecked(2), + Felt::new_unchecked(1), + ]); + let value_b = vec![Felt::new_unchecked(2), Felt::new_unchecked(2)]; forest_b.advice_map_mut().insert(key_b, value_b.clone()); let (merged, _root_maps) = MastForest::merge([&forest_a, &forest_b]).unwrap(); @@ -876,9 +935,14 @@ fn mast_forest_merge_advice_maps_collision() { let id_foo = block_foo().add_to_forest(&mut forest_a).unwrap(); let id_call_a = CallNodeBuilder::new(id_foo).add_to_forest(&mut forest_a).unwrap(); forest_a.make_root(id_call_a); - let key_a = Word::new([Felt::new(1), Felt::new(2), Felt::new(3), Felt::new(4)]); + let key_a = Word::new([ + Felt::new_unchecked(1), + Felt::new_unchecked(2), + Felt::new_unchecked(3), + Felt::new_unchecked(4), + ]); let value_a = vec![ONE, ONE]; - forest_a.advice_map_mut().insert(key_a, value_a.clone()); + forest_a.advice_map_mut().insert(key_a, value_a); let mut forest_b = MastForest::new(); let id_bar = block_bar().add_to_forest(&mut forest_b).unwrap(); @@ -886,8 +950,8 @@ fn mast_forest_merge_advice_maps_collision() { forest_b.make_root(id_call_b); // The key collides with key_a in the forest_a. let key_b = key_a; - let value_b = vec![Felt::new(2), Felt::new(2)]; - forest_b.advice_map_mut().insert(key_b, value_b.clone()); + let value_b = vec![Felt::new_unchecked(2), Felt::new_unchecked(2)]; + forest_b.advice_map_mut().insert(key_b, value_b); let err = MastForest::merge([&forest_a, &forest_b]).unwrap_err(); assert_matches!(err, MastForestError::AdviceMapKeyCollisionOnMerge(_)); @@ -916,7 +980,7 @@ fn mast_forest_merge_op_indexed_decorators_preservation() { // Create a block with multiple operations and op-indexed decorators let ops_a = vec![Operation::Add, Operation::Mul, Operation::Or]; let block_id_a = BasicBlockNodeBuilder::new( - ops_a.clone(), + ops_a, vec![(0, op0_a), (1, op1_a)], // Op-indexed decorators ) .with_before_enter(vec![before_enter_a, shared_deco_a]) // Use shared decorator @@ -939,7 +1003,7 @@ fn mast_forest_merge_op_indexed_decorators_preservation() { let ops_b = vec![Operation::Add, Operation::Mul, Operation::Or]; let block_id_b = BasicBlockNodeBuilder::new( - ops_b.clone(), + ops_b, vec![(0, op0_b), (2, op2_b)], // Op-indexed decorators at different positions ) .with_before_enter(vec![before_enter_b, shared_deco_b]) // Use shared decorator @@ -1001,7 +1065,7 @@ fn mast_forest_merge_op_indexed_decorators_preservation() { ); // Count how many times each decorator appears in the merged forest - let mut decorator_ref_counts = alloc::collections::BTreeMap::new(); + let mut decorator_ref_counts = BTreeMap::new(); // Check all nodes for decorator references for node in &merged.nodes { @@ -1027,8 +1091,7 @@ fn mast_forest_merge_op_indexed_decorators_preservation() { let ref_count = decorator_ref_counts.get(&deco_id).unwrap_or(&0); if ref_count == &0 { panic!( - "Decorator at index {} (value: {:?}) is not referenced anywhere in the merged forest (orphan)", - i, decorator + "Decorator at index {i} (value: {decorator:?}) is not referenced anywhere in the merged forest (orphan)" ); } } @@ -1044,7 +1107,7 @@ fn mast_forest_merge_op_indexed_decorators_preservation() { ); // Check op-indexed decorators at correct positions - let indexed_decs: alloc::collections::BTreeMap = + let indexed_decs: BTreeMap = block_a.indexed_decorator_iter(&merged).collect(); assert_eq!( @@ -1080,7 +1143,7 @@ fn mast_forest_merge_op_indexed_decorators_preservation() { ); // Check op-indexed decorators at correct positions - let indexed_decs: alloc::collections::BTreeMap = + let indexed_decs: BTreeMap = block_b.indexed_decorator_iter(&merged).collect(); assert_eq!( diff --git a/core/src/mast/mod.rs b/core/src/mast/mod.rs index 918c99cacf..d8a981903d 100644 --- a/core/src/mast/mod.rs +++ b/core/src/mast/mod.rs @@ -12,20 +12,38 @@ //! .validate()?; //! ``` //! -//! For maximum protection against denial-of-service attacks from malicious input, use -//! [`UntrustedMastForest::read_from_bytes_with_budget`] which limits memory consumption: +//! [`UntrustedMastForest::read_from_bytes`] applies default parsing and validation budgets derived +//! from the input size. Use [`UntrustedMastForest::read_from_bytes_with_budget`] to tune only the +//! wire-parsing budget, or [`UntrustedMastForest::read_from_bytes_with_budgets`] to tune both: +//! the parsing budget limits allocations driven directly by wire counts while reading the payload, +//! and the validation budget limits later helper allocations needed to materialize and check +//! stripped or hashless payloads. //! //! ```ignore //! use miden_core::mast::UntrustedMastForest; //! -//! // Budget limits pre-allocation sizes and total bytes consumed +//! // Parsing budget only //! let forest = UntrustedMastForest::read_from_bytes_with_budget(&bytes, bytes.len())? //! .validate()?; +//! +//! // Parsing budget plus explicit validation-allocation budget +//! let forest = UntrustedMastForest::read_from_bytes_with_budgets(&bytes, bytes.len(), bytes.len() * 7)? +//! .validate()?; //! ``` //! //! This recomputes all node hashes and checks structural invariants before returning a usable //! `MastForest`. Direct deserialization via `MastForest::read_from_bytes` trusts the serialized //! hashes and should only be used for data from trusted sources (e.g. compiled locally). +//! +//! In practice, the public entry points split into three policies: +//! - [`MastForest::read_from_bytes`]: trusted full deserialization; rejects hashless payloads and +//! trusts serialized non-external digests. +//! - [`SerializedMastForest::new`]: structural inspection path for local tooling; scans only the +//! layout needed for random access and may accept full, stripped, or hashless payloads, but it is +//! not an untrusted-validation entry point. +//! - [`UntrustedMastForest::read_from_bytes`] and +//! [`UntrustedMastForest::read_from_bytes_with_budgets`]: untrusted paths; parse with bounded +//! readers and require [`UntrustedMastForest::validate`] before use. use alloc::{ collections::{BTreeMap, BTreeSet}, @@ -39,6 +57,8 @@ use core::{ }; use miden_utils_sync::OnceLockCompat; +#[cfg(any(test, feature = "arbitrary"))] +use proptest::prelude::*; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; @@ -55,7 +75,7 @@ pub use node::{ }; use crate::{ - Felt, LexicographicWord, Word, + Felt, Word, advice::AdviceMap, operations::{AssemblyOp, DebugVarInfo, Decorator}, serde::{ @@ -72,6 +92,7 @@ pub use debuginfo::{ }; mod serialization; +pub use serialization::{MastForestView, MastNodeEntry, MastNodeInfo, SerializedMastForest}; mod merger; pub(crate) use merger::MastForestMerger; @@ -97,6 +118,10 @@ mod tests; /// A [`MastForest`] does not have an entrypoint, and hence is not executable. A /// [`crate::program::Program`] can be built from a [`MastForest`] to specify an entrypoint. #[derive(Clone, Debug, Default)] +#[cfg_attr( + all(feature = "arbitrary", test), + miden_test_serde_macros::serde_test(binary_serde(true)) +)] pub struct MastForest { /// All of the nodes local to the trees comprising the MAST forest. nodes: IndexVec, @@ -436,7 +461,7 @@ impl MastForest { node_ids: impl IntoIterator, ) -> Word { let mut digests: Vec = node_ids.into_iter().map(|&id| self[id].digest()).collect(); - digests.sort_unstable_by_key(|word| LexicographicWord::from(*word)); + digests.sort_unstable(); miden_crypto::hash::poseidon2::Poseidon2::merge_many(&digests) } @@ -500,8 +525,22 @@ impl MastForest { /// // let restored = MastForest::read_from_bytes(&stripped_bytes).unwrap(); /// ``` pub fn write_stripped(&self, target: &mut W) { - use serialization::StrippedMastForest; - StrippedMastForest(self).write_into(target); + serialization::write_stripped_into(self, target); + } + + /// Serializes this MastForest with the HASHLESS flag set. + /// + /// Hashless implies stripped: debug info is omitted, and digests must be recomputed during + /// validation. Trusted deserialization rejects this flag. + /// + /// Use this when producing data for untrusted validation. + pub fn write_hashless(&self, target: &mut W) { + serialization::write_hashless_into(self, target); + } + + /// Returns the exact size of stripped serialization in bytes. + pub fn stripped_size_hint(&self) -> usize { + serialization::stripped_size_hint(self) } } @@ -614,6 +653,10 @@ impl MastForest { before_enter: &[DecoratorId], after_exit: &[DecoratorId], ) { + if before_enter.is_empty() && after_exit.is_empty() { + return; + } + self.debug_info.register_node_decorators(node_id, before_enter, after_exit); } @@ -636,18 +679,7 @@ impl MastForest { // ------------------------------------------------------------------------------------------------ /// Validation methods impl MastForest { - /// Validates that all BasicBlockNodes in this forest satisfy the core invariants: - /// 1. Power-of-two number of groups in each batch - /// 2. No operation group ends with an operation requiring an immediate value - /// 3. The last operation group in a batch cannot contain operations requiring immediate values - /// 4. OpBatch structural consistency (num_groups <= BATCH_SIZE, group size <= GROUP_SIZE, - /// indptr integrity, bounds checking) - /// - /// This addresses the gap created by PR 2094, where padding NOOPs are now inserted - /// at assembly time rather than dynamically during execution, and adds comprehensive - /// structural validation to prevent deserialization-time panics. - pub fn validate(&self) -> Result<(), MastForestError> { - // Validate basic block batch invariants + fn validate_basic_block_invariants(&self) -> Result<(), MastForestError> { for (node_id_idx, node) in self.nodes.iter().enumerate() { let node_id = MastNodeId::new_unchecked(node_id_idx.try_into().expect("too many nodes")); @@ -658,7 +690,10 @@ impl MastForest { } } - // Validate that all procedure name digests correspond to procedure roots in the forest + Ok(()) + } + + fn validate_procedure_name_digests(&self) -> Result<(), MastForestError> { for (digest, _) in self.debug_info.procedure_names() { if self.find_procedure_root(digest).is_none() { return Err(MastForestError::InvalidProcedureNameDigest(digest)); @@ -668,20 +703,55 @@ impl MastForest { Ok(()) } - /// Validates topological ordering of nodes and recomputes all node hashes. - /// - /// This method iterates through all nodes in index order, verifying: - /// 1. All child references point to nodes with smaller indices (topological order) - /// 2. Each node's recomputed digest matches its stored digest + /// Validates that all BasicBlockNodes in this forest satisfy the core invariants: + /// 1. Power-of-two number of groups in each batch + /// 2. No operation group ends with an operation requiring an immediate value + /// 3. The last operation group in a batch cannot contain operations requiring immediate values + /// 4. OpBatch structural consistency (num_groups <= BATCH_SIZE, group size <= GROUP_SIZE, + /// indptr integrity, bounds checking) /// - /// # Errors + /// This also validates that each stored procedure-name digest resolves to a procedure root in + /// the forest. /// - /// Returns `MastForestError::ForwardReference` if any node references a child that - /// appears later in the forest. + /// This addresses the gap created by PR 2094, where padding NOOPs are now inserted + /// at assembly time rather than dynamically during execution, and adds comprehensive + /// structural validation to prevent deserialization-time panics. + pub fn validate(&self) -> Result<(), MastForestError> { + self.validate_basic_block_invariants()?; + self.validate_procedure_name_digests() + } + + /// Validates that stored node digests match the hashes implied by local structure. /// - /// Returns `MastForestError::HashMismatch` if any node's recomputed digest doesn't - /// match its stored digest. + /// For `External` nodes the digest is accepted as-is because it is externally provided and + /// cannot be reconstructed from local structure alone. fn validate_node_hashes(&self) -> Result<(), MastForestError> { + let computed_hashes = self.compute_node_hashes()?; + for (node_idx, (node, computed_digest)) in + self.nodes.iter().zip(computed_hashes).enumerate() + { + let expected_digest = node.digest(); + if expected_digest != computed_digest { + return Err(MastForestError::HashMismatch { + node_id: MastNodeId::new_unchecked(node_idx as u32), + expected: expected_digest, + computed: computed_digest, + }); + } + } + + Ok(()) + } + + /// Computes node hashes in topological order. + /// + /// The returned vector is aligned with node indices, so `digests[node_id as usize]` is the + /// digest of that node. + /// + /// For `External` nodes, the existing digest is returned unchanged. + /// + /// Returns [`MastForestError::ForwardReference`] if nodes are not in topological order. + fn compute_node_hashes(&self) -> Result, MastForestError> { use crate::chiplets::hasher; /// Checks that child_id references a node that appears before node_id in topological order. @@ -695,10 +765,11 @@ impl MastForest { Ok(()) } + let mut computed_hashes = Vec::with_capacity(self.nodes.len()); for (node_idx, node) in self.nodes.iter().enumerate() { let node_id = MastNodeId::new_unchecked(node_idx as u32); - // Check topological ordering and compute expected digest + // Check topological ordering and compute digest. let computed_digest = match node { MastNode::Block(block) => { let op_groups: Vec = @@ -711,8 +782,8 @@ impl MastForest { check_no_forward_ref(node_id, left_id)?; check_no_forward_ref(node_id, right_id)?; - let left_digest = self.nodes[left_id].digest(); - let right_digest = self.nodes[right_id].digest(); + let left_digest = computed_hashes[left_id.0 as usize]; + let right_digest = computed_hashes[right_id.0 as usize]; hasher::merge_in_domain(&[left_digest, right_digest], JoinNode::DOMAIN) }, MastNode::Split(split) => { @@ -721,22 +792,22 @@ impl MastForest { check_no_forward_ref(node_id, true_id)?; check_no_forward_ref(node_id, false_id)?; - let true_digest = self.nodes[true_id].digest(); - let false_digest = self.nodes[false_id].digest(); + let true_digest = computed_hashes[true_id.0 as usize]; + let false_digest = computed_hashes[false_id.0 as usize]; hasher::merge_in_domain(&[true_digest, false_digest], SplitNode::DOMAIN) }, MastNode::Loop(loop_node) => { let body_id = loop_node.body(); check_no_forward_ref(node_id, body_id)?; - let body_digest = self.nodes[body_id].digest(); + let body_digest = computed_hashes[body_id.0 as usize]; hasher::merge_in_domain(&[body_digest, Word::default()], LoopNode::DOMAIN) }, MastNode::Call(call) => { let callee_id = call.callee(); check_no_forward_ref(node_id, callee_id)?; - let callee_digest = self.nodes[callee_id].digest(); + let callee_digest = computed_hashes[callee_id.0 as usize]; let domain = if call.is_syscall() { CallNode::SYSCALL_DOMAIN } else { @@ -752,22 +823,15 @@ impl MastForest { } }, MastNode::External(_) => { - // External nodes have externally-provided digests that cannot be recomputed - continue; + // External nodes have externally-provided digests that cannot be recomputed. + node.digest() }, }; - let stored_digest = node.digest(); - if computed_digest != stored_digest { - return Err(MastForestError::HashMismatch { - node_id, - expected: stored_digest, - computed: computed_digest, - }); - } + computed_hashes.push(computed_digest); } - Ok(()) + Ok(computed_hashes) } } @@ -1022,7 +1086,7 @@ impl fmt::Display for MastNodeId { } #[cfg(any(test, feature = "arbitrary"))] -impl proptest::prelude::Arbitrary for MastNodeId { +impl Arbitrary for MastNodeId { type Parameters = (); fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { @@ -1030,7 +1094,7 @@ impl proptest::prelude::Arbitrary for MastNodeId { any::().prop_map(MastNodeId).boxed() } - type Strategy = proptest::prelude::BoxedStrategy; + type Strategy = BoxedStrategy; } // ITERATOR @@ -1073,6 +1137,10 @@ impl Iterator for SubtreeIterator<'_> { #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", serde(transparent))] +#[cfg_attr( + all(feature = "arbitrary", test), + miden_test_serde_macros::serde_test(binary_serde(true)) +)] pub struct DecoratorId(u32); impl DecoratorId { @@ -1096,8 +1164,7 @@ impl DecoratorId { Ok(Self(value)) } else { Err(DeserializationError::InvalidValue(format!( - "Invalid deserialized MAST decorator id '{}', but allows only {} decorators", - value, bound, + "Invalid deserialized MAST decorator id '{value}', but allows only {bound} decorators", ))) } } @@ -1128,6 +1195,16 @@ impl fmt::Display for DecoratorId { } } +#[cfg(feature = "arbitrary")] +impl Arbitrary for DecoratorId { + type Parameters = (); + type Strategy = BoxedStrategy; + + fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { + any::().prop_map(Self::from).boxed() + } +} + impl Serializable for DecoratorId { fn write_into(&self, target: &mut W) { self.0.write_into(target) @@ -1151,6 +1228,10 @@ impl Deserializable for DecoratorId { #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", serde(transparent))] +#[cfg_attr( + all(feature = "arbitrary", test), + miden_test_serde_macros::serde_test(binary_serde(true)) +)] pub struct AsmOpId(u32); impl AsmOpId { @@ -1180,6 +1261,16 @@ impl fmt::Display for AsmOpId { } } +#[cfg(feature = "arbitrary")] +impl Arbitrary for AsmOpId { + type Parameters = (); + type Strategy = BoxedStrategy; + + fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { + any::().prop_map(Self::from).boxed() + } +} + impl Serializable for AsmOpId { fn write_into(&self, target: &mut W) { self.0.write_into(target) @@ -1240,13 +1331,15 @@ pub enum MastForestError { expected: Word, computed: Word, }, + #[error("deserialization failed: {0}")] + Deserialization(DeserializationError), } // Custom serde implementations for MastForest that handle linked decorators properly // by delegating to the existing miden-crypto serialization which already handles // the conversion between linked and owned decorator formats. #[cfg(feature = "serde")] -impl serde::Serialize for MastForest { +impl Serialize for MastForest { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, @@ -1258,7 +1351,7 @@ impl serde::Serialize for MastForest { } #[cfg(feature = "serde")] -impl<'de> serde::Deserialize<'de> for MastForest { +impl<'de> Deserialize<'de> for MastForest { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, @@ -1275,9 +1368,9 @@ impl<'de> serde::Deserialize<'de> for MastForest { /// A [`MastForest`] deserialized from untrusted input that has not yet been validated. /// -/// This type wraps a `MastForest` that was deserialized from bytes but has not had its -/// node hashes verified. Before using the forest, callers must call [`validate()`](Self::validate) -/// to verify structural integrity and recompute all node hashes. +/// This type wraps a serialized-backed, decoded MAST representation that has not had its node +/// hashes verified. Before using the forest, callers must call [`validate()`](Self::validate) to +/// materialize and verify structural integrity and node hashes. /// /// # Usage /// @@ -1304,16 +1397,23 @@ impl<'de> serde::Deserialize<'de> for MastForest { /// 3. **Hash recomputation**: Recomputes the digest for every node and verifies it matches the /// stored digest. #[derive(Debug, Clone)] -pub struct UntrustedMastForest(MastForest); +pub struct UntrustedMastForest { + bytes: Vec, + layout: serialization::ForestLayout, + advice_map: AdviceMap, + debug_info: DebugInfo, + remaining_allocation_budget: Option, +} impl UntrustedMastForest { /// Validates the forest by checking structural invariants and recomputing all node hashes. /// /// This method performs a complete validation of the deserialized forest: /// - /// 1. Validates structural invariants (batch padding, procedure names) - /// 2. Validates topological ordering (no forward references) - /// 3. Recomputes all node hashes and compares against stored digests + /// 1. If wire node hashes are present, recomputes all non-external node hashes and requires + /// them to match the serialized digests. + /// 2. If the payload is hashless, uses the digests rebuilt during materialization. + /// 3. Validates structural invariants, topological ordering, and procedure-name roots. /// /// # Returns /// @@ -1323,32 +1423,47 @@ impl UntrustedMastForest { /// # Errors /// /// Returns an error if: + /// - Deferred materialization from serialized form fails ([`MastForestError::Deserialization`]) /// - Any basic block has invalid batch structure ([`MastForestError::InvalidBatchPadding`]) /// - Any procedure name references a non-root digest /// ([`MastForestError::InvalidProcedureNameDigest`]) /// - Any node references a child that appears later in the forest /// ([`MastForestError::ForwardReference`]) - /// - Any node's recomputed hash doesn't match its stored digest + /// - Any non-external wire digest does not match the recomputed digest /// ([`MastForestError::HashMismatch`]) + /// - Any node's digest cannot be recomputed because structural validation fails first + /// + /// Security convention: + /// - Hashless payloads rebuild non-external digests from structure during materialization. + /// - If wire node hashes are present, validation recomputes them and requires them to match. + /// - External node digests are marshaled as opaque values and are not semantically resolved + /// here. pub fn validate(self) -> Result { - let forest = self.0; + let is_hashless = self.layout.is_hashless(); + let forest = self.into_materialized().map_err(MastForestError::Deserialization)?; - // Step 1: Validate structural invariants (existing validate() checks) - forest.validate()?; + // Step 1: Validate over-specified wire hashes instead of silently rewriting them. + if !is_hashless { + forest.validate_node_hashes()?; + } - // Step 2: Validate topological ordering and recompute hashes - forest.validate_node_hashes()?; + // Step 2: Validate the recomputed forest. + forest.validate()?; Ok(forest) } /// Deserializes an [`UntrustedMastForest`] from bytes. /// - /// This method uses a [`BudgetedReader`] with a budget equal to the input size to protect - /// against denial-of-service attacks from malicious input. + /// This method uses a [`BudgetedReader`] plus a bounded validation-allocation budget derived + /// from the input size to protect against denial-of-service attacks from malicious input. + /// The default validation budget includes room for the retained serialized copy used by the + /// deferred-validation path, in addition to stripped/hashless helper allocations. Concretely, + /// the default is `bytes.len()` for parsing and `bytes.len() * 7` for validation allocations. + /// That `* 7` factor is a coarse convenience bound, not an exact peak-memory formula. /// - /// For stricter limits, use - /// [`read_from_bytes_with_budget`](Self::read_from_bytes_with_budget) with a custom budget. + /// For explicit parsing and validation limits, use + /// [`read_from_bytes_with_budgets`](Self::read_from_bytes_with_budgets). /// /// # Example /// @@ -1360,7 +1475,23 @@ impl UntrustedMastForest { /// let forest = untrusted.validate()?; /// ``` pub fn read_from_bytes(bytes: &[u8]) -> Result { - Self::read_from_bytes_with_budget(bytes, bytes.len()) + Self::read_from_bytes_with_budgets( + bytes, + bytes.len(), + serialization::default_untrusted_allocation_budget(bytes.len()), + ) + } + + /// Deserializes an [`UntrustedMastForest`] from bytes and returns the raw wire flags. + /// + /// This enables callers to inspect serializer intent flags (e.g., HASHLESS) without affecting + /// the untrusted deserialization path. + pub fn read_from_bytes_with_flags(bytes: &[u8]) -> Result<(Self, u8), DeserializationError> { + Self::read_from_bytes_with_budgets_and_flags( + bytes, + bytes.len(), + serialization::default_untrusted_allocation_budget(bytes.len()), + ) } /// Deserializes an [`UntrustedMastForest`] from bytes with a byte budget. @@ -1372,13 +1503,13 @@ impl UntrustedMastForest { /// # Arguments /// /// * `bytes` - The serialized forest bytes - /// * `budget` - Maximum bytes to consume during deserialization. Set this to `bytes.len()` for - /// typical use cases, or lower to enforce stricter limits. + /// * `budget` - Maximum bytes to consume while parsing the wire payload and pre-sizing + /// wire-driven collections via [`BudgetedReader`] /// /// # Example /// /// ```ignore - /// // Read from untrusted source with budget equal to input size + /// // Read from untrusted source with an explicit parsing budget /// let untrusted = UntrustedMastForest::read_from_bytes_with_budget(&bytes, bytes.len())?; /// /// // Validate before use @@ -1393,11 +1524,56 @@ impl UntrustedMastForest { /// /// This prevents attacks where malicious input claims an unrealistic number of elements /// (e.g., `len = 2^60`), causing excessive memory allocation before any data is read. + /// + /// To also cap stripped/hashless validation helper allocations, use + /// [`read_from_bytes_with_budgets`](Self::read_from_bytes_with_budgets). pub fn read_from_bytes_with_budget( bytes: &[u8], budget: usize, ) -> Result { let mut reader = BudgetedReader::new(SliceReader::new(bytes), budget); - Self::read_from(&mut reader) + serialization::read_untrusted_with_flags(&mut reader).map(|(forest, _flags)| forest) + } + + /// Deserializes an [`UntrustedMastForest`] from bytes with a byte budget and returns flags. + pub fn read_from_bytes_with_budget_and_flags( + bytes: &[u8], + budget: usize, + ) -> Result<(Self, u8), DeserializationError> { + let mut reader = BudgetedReader::new(SliceReader::new(bytes), budget); + serialization::read_untrusted_with_flags(&mut reader) + } + + /// Deserializes an [`UntrustedMastForest`] from bytes with separate parsing and validation + /// budgets. + /// + /// `parsing_budget` limits wire-driven parsing and collection pre-sizing. `validation_budget` + /// additionally caps tracked stripped/hashless helper allocations such as empty debug-info + /// scaffolding, digest slot tables, and rebuilt digest tables. + pub fn read_from_bytes_with_budgets( + bytes: &[u8], + parsing_budget: usize, + validation_budget: usize, + ) -> Result { + let mut reader = BudgetedReader::new(SliceReader::new(bytes), parsing_budget); + serialization::read_untrusted_with_flags_and_allocation_budget( + &mut reader, + validation_budget, + ) + .map(|(forest, _flags)| forest) + } + + /// Deserializes an [`UntrustedMastForest`] from bytes with separate parsing and validation + /// budgets and returns flags. + pub fn read_from_bytes_with_budgets_and_flags( + bytes: &[u8], + parsing_budget: usize, + validation_budget: usize, + ) -> Result<(Self, u8), DeserializationError> { + let mut reader = BudgetedReader::new(SliceReader::new(bytes), parsing_budget); + serialization::read_untrusted_with_flags_and_allocation_budget( + &mut reader, + validation_budget, + ) } } diff --git a/core/src/mast/node/basic_block_node/arbitrary.rs b/core/src/mast/node/basic_block_node/arbitrary.rs index de86b0a66c..29bf6e7575 100644 --- a/core/src/mast/node/basic_block_node/arbitrary.rs +++ b/core/src/mast/node/basic_block_node/arbitrary.rs @@ -93,7 +93,7 @@ pub fn op_no_imm_strategy() -> impl Strategy { // Strategy for operations with immediate values pub fn op_with_imm_strategy() -> impl Strategy { - prop_oneof![any::().prop_map(Felt::new).prop_map(Operation::Push)] + prop_oneof![any::().prop_map(Felt::new_unchecked).prop_map(Operation::Push)] } // Strategy for all non-control flow operations @@ -318,10 +318,7 @@ impl Arbitrary for MastForest { // Generate nodes in a way that respects topological ordering ( // Generate basic blocks first (they have no dependencies) - prop::collection::vec( - any_with::(bb_params.clone()), - 1..=*params.blocks.end(), - ), + prop::collection::vec(any_with::(bb_params), 1..=*params.blocks.end()), // Generate decorators prop::collection::vec( any::(), @@ -431,10 +428,10 @@ impl Arbitrary for MastForest { .into_iter() .map(|[a, b, c, d]| { Word::from([ - Felt::new(a), - Felt::new(b), - Felt::new(c), - Felt::new(d), + Felt::new_unchecked(a), + Felt::new_unchecked(b), + Felt::new_unchecked(c), + Felt::new_unchecked(d), ]) }) .collect::>() @@ -650,16 +647,16 @@ impl Arbitrary for AdviceMap { let word_strategy = prop_oneof![ Just(Word::default()), any::<[u64; 4]>().prop_map(|[a, b, c, d]| Word::new([ - Felt::new(a), - Felt::new(b), - Felt::new(c), - Felt::new(d) + Felt::new_unchecked(a), + Felt::new_unchecked(b), + Felt::new_unchecked(c), + Felt::new_unchecked(d) ])), ]; // Strategy for generating Arc<[Felt]> values let felt_array_strategy = prop::collection::vec(any::(), 1..=4).prop_map(|vals| { - let felts: Arc<[Felt]> = vals.into_iter().map(Felt::new).collect(); + let felts: Arc<[Felt]> = vals.into_iter().map(Felt::new_unchecked).collect(); felts }); @@ -735,7 +732,12 @@ impl Arbitrary for Kernel { fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { // Strategy for generating Word vectors let word_strategy = any::<[u64; 4]>().prop_map(|[a, b, c, d]| { - Word::new([Felt::new(a), Felt::new(b), Felt::new(c), Felt::new(d)]) + Word::new([ + Felt::new_unchecked(a), + Felt::new_unchecked(b), + Felt::new_unchecked(c), + Felt::new_unchecked(d), + ]) }); // Strategy for generating kernel (0 to 3 words to avoid hitting MAX_NUM_PROCEDURES limit) diff --git a/core/src/mast/node/basic_block_node/mod.rs b/core/src/mast/node/basic_block_node/mod.rs index 95bacde701..2d33b8d421 100644 --- a/core/src/mast/node/basic_block_node/mod.rs +++ b/core/src/mast/node/basic_block_node/mod.rs @@ -115,7 +115,7 @@ impl BasicBlockNode { #[cfg(debug_assertions)] validate_decorators(operations.len(), &decorators); - let (op_batches, digest) = batch_and_hash_ops(operations); + let (op_batches, digest) = batch_and_hash_ops(&operations); // the prior line may have inserted some padding Noops in the op_batches // the decorator mapping should still point to the correct operation when that happens let reflowed_decorators = BasicBlockNode::adjust_decorators(decorators, &op_batches); @@ -364,13 +364,13 @@ impl BasicBlockNode { /// Returns an iterator over the operations in the order in which they appear in the program. pub fn operations(&self) -> impl Iterator { - self.op_batches.iter().flat_map(|batch| batch.ops()) + self.op_batches.iter().flat_map(OpBatch::ops) } /// Returns an iterator over the un-padded operations in the order in which they /// appear in the program. pub fn raw_operations(&self) -> impl Iterator { - self.op_batches.iter().flat_map(|batch| batch.raw_ops()) + self.op_batches.iter().flat_map(OpBatch::raw_ops) } /// Returns the total number of operations and decorators in this basic block. @@ -498,15 +498,11 @@ impl BasicBlockNode { if batch_idx + 1 < self.op_batches.len() { if num_groups != BATCH_SIZE { return Err(format!( - "Batch {}: {} groups is not full batch size {}", - batch_idx, num_groups, BATCH_SIZE + "Batch {batch_idx}: {num_groups} groups is not full batch size {BATCH_SIZE}" )); } } else if !num_groups.is_power_of_two() { - return Err(format!( - "Batch {}: {} groups is not power of two", - batch_idx, num_groups - )); + return Err(format!("Batch {batch_idx}: {num_groups} groups is not power of two")); } } Ok(()) @@ -542,8 +538,7 @@ impl BasicBlockNode { for (op_idx, op) in group_ops.iter().enumerate() { if op.imm_value().is_some() { return Err(format!( - "Batch {}, group {}: operation at index {} requires immediate value, but this is the last group in batch", - batch_idx, group_idx, op_idx + "Batch {batch_idx}, group {group_idx}: operation at index {op_idx} requires immediate value, but this is the last group in batch" )); } } @@ -553,8 +548,7 @@ impl BasicBlockNode { && last_op.imm_value().is_some() { return Err(format!( - "Batch {}, group {}: ends with operation requiring immediate value", - batch_idx, group_idx + "Batch {batch_idx}, group {group_idx}: ends with operation requiring immediate value" )); } } @@ -617,8 +611,7 @@ impl BasicBlockNode { if group_size > GROUP_SIZE { return Err(format!( - "Batch {}, group {}: contains {} operations, exceeds maximum {}", - batch_idx, group_idx, group_size, GROUP_SIZE + "Batch {batch_idx}, group {group_idx}: contains {group_size} operations, exceeds maximum {GROUP_SIZE}" )); } } @@ -654,10 +647,9 @@ impl BasicBlockNode { let opcode = op.op_code() as u64; group_value |= opcode << (Operation::OP_BITS * local_op_idx); } - if groups[group_idx] != Felt::new(group_value) { + if groups[group_idx] != Felt::new_unchecked(group_value) { return Err(format!( - "Batch {}, group {}: committed opcode group does not match operations", - batch_idx, group_idx + "Batch {batch_idx}, group {group_idx}: committed opcode group does not match operations" )); } @@ -668,13 +660,12 @@ impl BasicBlockNode { BATCH_SIZE, Some(num_groups), ) - .map_err(|err| format!("Batch {}: {}", batch_idx, err))?; + .map_err(|err| format!("Batch {batch_idx}: {err}"))?; for (imm_group_idx, imm_value) in placements { if groups[imm_group_idx] != imm_value { return Err(format!( - "Batch {}: push immediate value mismatch at index {}", - batch_idx, imm_group_idx + "Batch {batch_idx}: push immediate value mismatch at index {imm_group_idx}" )); } immediate_slots[imm_group_idx] = true; @@ -687,8 +678,7 @@ impl BasicBlockNode { && groups[group_idx] != ZERO { return Err(format!( - "Batch {}, group {}: empty group must be zero", - batch_idx, group_idx + "Batch {batch_idx}, group {group_idx}: empty group must be zero" )); } } @@ -704,7 +694,7 @@ impl BasicBlockNode { for (batch_idx, batch) in self.op_batches.iter().enumerate() { batch .validate_padding_semantics() - .map_err(|err| format!("Batch {}: {}", batch_idx, err))?; + .map_err(|err| format!("Batch {batch_idx}: {err}"))?; } Ok(()) @@ -825,13 +815,12 @@ impl MastNodeExt for BasicBlockNode { let forest_node = &forest.nodes[*id]; let forest_node_ptr = match forest_node { MastNode::Block(block_node) => block_node as *const BasicBlockNode as *const (), - _ => panic!("Node type mismatch at {:?}", id), + _ => panic!("Node type mismatch at {id:?}"), }; let self_as_void = self_ptr as *const (); debug_assert_eq!( self_as_void, forest_node_ptr, - "Node pointer mismatch: expected node at {:?} to be self", - id + "Node pointer mismatch: expected node at {id:?} to be self" ); } } @@ -857,7 +846,7 @@ impl PrettyPrint for BasicBlockNodePrettyPrint<'_> { OperationOrDecorator::Operation(op) => op.render(), OperationOrDecorator::Decorator(decorator_id) => { self.mast_forest.decorator_by_id(decorator_id) - .map(|decorator| decorator.render()) + .map(PrettyPrint::render) .unwrap_or_else(|| const_text("")) }, }) @@ -885,7 +874,7 @@ impl PrettyPrint for BasicBlockNodePrettyPrint<'_> { OperationOrDecorator::Operation(op) => op.render(), OperationOrDecorator::Decorator(decorator_id) => { self.mast_forest.decorator_by_id(decorator_id) - .map(|decorator| decorator.render()) + .map(PrettyPrint::render) .unwrap_or_else(|| const_text("")) }, }) @@ -1360,7 +1349,7 @@ impl core::ops::Index for PaddedToRawPrefix { } /// Groups the provided operations into batches and computes the hash of the block. -fn batch_and_hash_ops(ops: Vec) -> (Vec, Word) { +fn batch_and_hash_ops(ops: &[Operation]) -> (Vec, Word) { // Group the operations into batches. let batches = batch_ops(ops); @@ -1373,11 +1362,11 @@ fn batch_and_hash_ops(ops: Vec) -> (Vec, Word) { /// Groups the provided operations into batches as described in the docs for this module (i.e., up /// to 9 operations per group, and 8 groups per batch). -fn batch_ops(ops: Vec) -> Vec { +fn batch_ops(ops: &[Operation]) -> Vec { let mut batches = Vec::::new(); let mut batch_acc = OpBatchAccumulator::new(); - for op in ops { + for op in ops.iter().copied() { // If the operation cannot be accepted into the current accumulator, add the contents of // the accumulator to the list of batches and start a new accumulator. if !batch_acc.can_accept_op(op) { @@ -1474,7 +1463,7 @@ impl BasicBlockNodeBuilder { #[cfg(debug_assertions)] validate_decorators(operations.len(), &decorators); - let (op_batches, computed_digest) = batch_and_hash_ops(operations); + let (op_batches, computed_digest) = batch_and_hash_ops(&operations); // Batch operations (adds padding NOOPs) // Adjust decorators from raw to padded indices let padded_decorators = BasicBlockNode::adjust_decorators(decorators, &op_batches); @@ -1536,7 +1525,7 @@ impl BasicBlockNodeBuilder { } // Batch operations (adds padding NOOPs) - let (op_batches, computed_digest) = batch_and_hash_ops(operations); + let (op_batches, computed_digest) = batch_and_hash_ops(&operations); // Use the forced digest if provided, otherwise use the computed digest let digest = self.digest.unwrap_or(computed_digest); @@ -1587,7 +1576,7 @@ impl MastForestContributor for BasicBlockNodeBuilder { validate_decorators(operations.len(), &decorators); // Batch operations (adds padding NOOPs) - let (op_batches, computed_digest) = batch_and_hash_ops(operations); + let (op_batches, computed_digest) = batch_and_hash_ops(&operations); // Use the forced digest if provided, otherwise use the computed digest let digest = self.digest.unwrap_or(computed_digest); @@ -1643,7 +1632,7 @@ impl MastForestContributor for BasicBlockNodeBuilder { let (op_batches, digest, raw_decorators) = match &self.operation_data { OperationData::Raw { operations, decorators } => { // Compute digest - use forced digest if available, otherwise compute normally - let (op_batches, computed_digest) = batch_and_hash_ops(operations.clone()); + let (op_batches, computed_digest) = batch_and_hash_ops(operations); let digest = self.digest.unwrap_or(computed_digest); // Decorators are already in raw form - no conversion needed @@ -1694,7 +1683,7 @@ impl MastForestContributor for BasicBlockNodeBuilder { // Collect assert operation data let mut assert_data = Vec::new(); - for (op_idx, op) in op_batches.iter().flat_map(|batch| batch.ops()).enumerate() { + for (op_idx, op) in op_batches.iter().flat_map(OpBatch::ops).enumerate() { if let Operation::U32assert2(inner_value) | Operation::Assert(inner_value) | Operation::MpVerify(inner_value) = op @@ -1716,9 +1705,9 @@ impl MastForestContributor for BasicBlockNodeBuilder { // Create iterator of slices from all collected data let decorator_bytes_iter = before_enter_bytes .iter() - .map(|bytes| bytes.as_slice()) + .map(<[u8; 32]>::as_slice) .chain(core::iter::once(op_decorator_data.as_slice())) - .chain(after_exit_bytes.iter().map(|bytes| bytes.as_slice())) + .chain(after_exit_bytes.iter().map(<[u8; 32]>::as_slice)) .chain(core::iter::once(assert_data.as_slice())); if self.before_enter.is_empty() @@ -1764,7 +1753,7 @@ impl MastForestContributor for BasicBlockNodeBuilder { #[cfg(any(test, feature = "arbitrary"))] impl proptest::prelude::Arbitrary for BasicBlockNodeBuilder { - type Parameters = super::arbitrary::BasicBlockNodeParams; + type Parameters = arbitrary::BasicBlockNodeParams; type Strategy = proptest::strategy::BoxedStrategy; fn arbitrary_with(params: Self::Parameters) -> Self::Strategy { diff --git a/core/src/mast/node/basic_block_node/op_batch.rs b/core/src/mast/node/basic_block_node/op_batch.rs index dfe88b424c..3ab9762bc6 100644 --- a/core/src/mast/node/basic_block_node/op_batch.rs +++ b/core/src/mast/node/basic_block_node/op_batch.rs @@ -53,7 +53,7 @@ impl OpBatch { /// of operations in the batch may be larger than the number of operations reported by this /// method. pub fn raw_ops(&self) -> impl Iterator { - debug_assert!(self.num_groups == 0 || self.indptr[self.num_groups] != 0, "{:?}", self); + debug_assert!(self.num_groups == 0 || self.indptr[self.num_groups] != 0, "{self:?}"); (0..self.num_groups).flat_map(|group_idx| { let padded = self.padding[group_idx]; let start_idx = self.indptr[group_idx]; @@ -131,7 +131,7 @@ impl OpBatch { let is_padded = *self .padding .get(group_idx) - .ok_or_else(|| format!("group {}: missing padding metadata", group_idx))?; + .ok_or_else(|| format!("group {group_idx}: missing padding metadata"))?; if !is_padded { continue; } @@ -139,27 +139,27 @@ impl OpBatch { let group_start = *self .indptr .get(group_idx) - .ok_or_else(|| format!("group {}: missing indptr start", group_idx))?; + .ok_or_else(|| format!("group {group_idx}: missing indptr start"))?; let group_end = *self .indptr .get(group_idx + 1) - .ok_or_else(|| format!("group {}: missing indptr end", group_idx))?; + .ok_or_else(|| format!("group {group_idx}: missing indptr end"))?; if group_start == group_end { - return Err(format!("group {}: empty group cannot be marked as padded", group_idx)); + return Err(format!("group {group_idx}: empty group cannot be marked as padded")); } if group_start > group_end { - return Err(format!("group {}: invalid group bounds", group_idx)); + return Err(format!("group {group_idx}: invalid group bounds")); } let last_op_idx = group_end - 1; let last_op = self .ops .get(last_op_idx) - .ok_or_else(|| format!("group {}: invalid group bounds", group_idx))?; + .ok_or_else(|| format!("group {group_idx}: invalid group bounds"))?; if *last_op != Operation::Noop { - return Err(format!("group {}: padded group must end with NOOP", group_idx)); + return Err(format!("group {group_idx}: padded group must end with NOOP")); } } @@ -336,14 +336,12 @@ pub(crate) fn collect_immediate_placements( && next_group_idx >= num_groups { return Err(format!( - "push immediate index {} exceeds num_groups {}", - next_group_idx, num_groups + "push immediate index {next_group_idx} exceeds num_groups {num_groups}" )); } if indptr[next_group_idx] != indptr[next_group_idx + 1] { return Err(format!( - "push immediate overlaps operation group at index {}", - next_group_idx + "push immediate overlaps operation group at index {next_group_idx}" )); } placements.push((next_group_idx, imm)); @@ -472,7 +470,7 @@ impl OpBatchAccumulator { // make sure the last group gets added to the group array; we also check the op_idx to // handle the case when a group contains a single NOOP operation. if self.group != 0 || self.op_idx != 0 { - self.groups[self.group_idx] = Felt::new(self.group); + self.groups[self.group_idx] = Felt::new_unchecked(self.group); } self.pad_if_needed(); self.finalize_indptr(); @@ -508,7 +506,7 @@ impl OpBatchAccumulator { // we pad if we are looking at an empty group, or one finishing in an op carrying an // immediate self.pad_if_needed(); - self.groups[self.group_idx] = Felt::new(self.group); + self.groups[self.group_idx] = Felt::new_unchecked(self.group); self.finalize_indptr(); self.group_idx = self.next_group_idx; @@ -638,9 +636,9 @@ mod op_batch_tests { let batch = { let mut acc = OpBatchAccumulator::new(); // group 0 - acc.add_op(Operation::Push(Felt::new(2))); - acc.add_op(Operation::Push(Felt::new(3))); - acc.add_op(Operation::Push(Felt::new(4))); + acc.add_op(Operation::Push(Felt::new_unchecked(2))); + acc.add_op(Operation::Push(Felt::new_unchecked(3))); + acc.add_op(Operation::Push(Felt::new_unchecked(4))); acc.add_op(Operation::Swap); acc.add_op(Operation::Swap); acc.add_op(Operation::Swap); @@ -659,7 +657,7 @@ mod op_batch_tests { acc.add_op(Operation::Swap); // group 5 - acc.add_op(Operation::Push(Felt::new(5))); + acc.add_op(Operation::Push(Felt::new_unchecked(5))); acc.add_op(Operation::Swap); acc.add_op(Operation::Swap); acc.add_op(Operation::Swap); @@ -696,9 +694,9 @@ mod op_batch_tests { let batch = { let mut acc = OpBatchAccumulator::new(); // group 0 - acc.add_op(Operation::Push(Felt::new(2))); - acc.add_op(Operation::Push(Felt::new(3))); - acc.add_op(Operation::Push(Felt::new(4))); + acc.add_op(Operation::Push(Felt::new_unchecked(2))); + acc.add_op(Operation::Push(Felt::new_unchecked(3))); + acc.add_op(Operation::Push(Felt::new_unchecked(4))); acc.add_op(Operation::Swap); acc.add_op(Operation::Swap); acc.add_op(Operation::Swap); @@ -717,7 +715,7 @@ mod op_batch_tests { acc.add_op(Operation::Swap); // group 5 - acc.add_op(Operation::Push(Felt::new(5))); + acc.add_op(Operation::Push(Felt::new_unchecked(5))); acc.add_op(Operation::Swap); acc.add_op(Operation::Swap); acc.add_op(Operation::Swap); diff --git a/core/src/mast/node/basic_block_node/tests.rs b/core/src/mast/node/basic_block_node/tests.rs index dd0962a8cb..24c0a47191 100644 --- a/core/src/mast/node/basic_block_node/tests.rs +++ b/core/src/mast/node/basic_block_node/tests.rs @@ -14,7 +14,7 @@ use crate::{ fn batch_ops_1() { // --- one operation ---------------------------------------------------------------------- let ops = vec![Operation::Add]; - let (batches, hash) = super::batch_and_hash_ops(ops.clone()); + let (batches, hash) = batch_and_hash_ops(&ops); insta::assert_debug_snapshot!(batches); insta::assert_debug_snapshot!(build_group_chunks(&batches).collect::>()); @@ -28,7 +28,7 @@ fn batch_ops_1() { fn batch_ops_2() { // --- two operations --------------------------------------------------------------------- let ops = vec![Operation::Add, Operation::Mul]; - let (batches, hash) = super::batch_and_hash_ops(ops.clone()); + let (batches, hash) = batch_and_hash_ops(&ops); insta::assert_debug_snapshot!(batches); insta::assert_debug_snapshot!(build_group_chunks(&batches).collect::>()); @@ -41,14 +41,14 @@ fn batch_ops_2() { #[test] fn batch_ops_3() { // --- one group with one immediate value ------------------------------------------------- - let ops = vec![Operation::Add, Operation::Push(Felt::new(12345678))]; - let (batches, hash) = super::batch_and_hash_ops(ops.clone()); + let ops = vec![Operation::Add, Operation::Push(Felt::new_unchecked(12345678))]; + let (batches, hash) = batch_and_hash_ops(&ops); insta::assert_debug_snapshot!(batches); insta::assert_debug_snapshot!(build_group_chunks(&batches).collect::>()); let mut batch_groups = [ZERO; BATCH_SIZE]; batch_groups[0] = build_group(&ops); - batch_groups[1] = Felt::new(12345678); + batch_groups[1] = Felt::new_unchecked(12345678); assert_eq!(hasher::hash_elements(&batch_groups), hash); } @@ -58,27 +58,27 @@ fn batch_ops_4() { // --- one group with 7 immediate values -------------------------------------------------- let ops = vec![ Operation::Push(ONE), - Operation::Push(Felt::new(2)), - Operation::Push(Felt::new(3)), - Operation::Push(Felt::new(4)), - Operation::Push(Felt::new(5)), - Operation::Push(Felt::new(6)), - Operation::Push(Felt::new(7)), + Operation::Push(Felt::new_unchecked(2)), + Operation::Push(Felt::new_unchecked(3)), + Operation::Push(Felt::new_unchecked(4)), + Operation::Push(Felt::new_unchecked(5)), + Operation::Push(Felt::new_unchecked(6)), + Operation::Push(Felt::new_unchecked(7)), Operation::Add, ]; - let (batches, hash) = super::batch_and_hash_ops(ops.clone()); + let (batches, hash) = batch_and_hash_ops(&ops); insta::assert_debug_snapshot!(batches); insta::assert_debug_snapshot!(build_group_chunks(&batches).collect::>()); let batch_groups = [ build_group(&ops), ONE, - Felt::new(2), - Felt::new(3), - Felt::new(4), - Felt::new(5), - Felt::new(6), - Felt::new(7), + Felt::new_unchecked(2), + Felt::new_unchecked(3), + Felt::new_unchecked(4), + Felt::new_unchecked(5), + Felt::new_unchecked(6), + Felt::new_unchecked(7), ]; assert_eq!(hasher::hash_elements(&batch_groups), hash); @@ -91,31 +91,31 @@ fn batch_ops_5() { Operation::Add, Operation::Mul, Operation::Push(ONE), - Operation::Push(Felt::new(2)), - Operation::Push(Felt::new(3)), - Operation::Push(Felt::new(4)), - Operation::Push(Felt::new(5)), - Operation::Push(Felt::new(6)), + Operation::Push(Felt::new_unchecked(2)), + Operation::Push(Felt::new_unchecked(3)), + Operation::Push(Felt::new_unchecked(4)), + Operation::Push(Felt::new_unchecked(5)), + Operation::Push(Felt::new_unchecked(6)), Operation::Add, - Operation::Push(Felt::new(7)), + Operation::Push(Felt::new_unchecked(7)), ]; - let (batches, hash) = super::batch_and_hash_ops(ops.clone()); + let (batches, hash) = batch_and_hash_ops(&ops); insta::assert_debug_snapshot!(batches); insta::assert_debug_snapshot!(build_group_chunks(&batches).collect::>()); let batch0_groups = [ build_group(&ops[..9]), ONE, - Felt::new(2), - Felt::new(3), - Felt::new(4), - Felt::new(5), - Felt::new(6), + Felt::new_unchecked(2), + Felt::new_unchecked(3), + Felt::new_unchecked(4), + Felt::new_unchecked(5), + Felt::new_unchecked(6), ZERO, ]; let mut batch1_groups = [ZERO; BATCH_SIZE]; batch1_groups[0] = build_group(&[ops[9]]); - batch1_groups[1] = Felt::new(7); + batch1_groups[1] = Felt::new_unchecked(7); let all_groups = [batch0_groups, batch1_groups].concat(); assert_eq!(hasher::hash_elements(&all_groups), hash); @@ -128,23 +128,23 @@ fn batch_ops_6() { Operation::Add, Operation::Mul, Operation::Add, - Operation::Push(Felt::new(7)), + Operation::Push(Felt::new_unchecked(7)), Operation::Add, Operation::Add, - Operation::Push(Felt::new(11)), + Operation::Push(Felt::new_unchecked(11)), Operation::Mul, Operation::Mul, Operation::Add, ]; - let (batches, hash) = super::batch_and_hash_ops(ops.clone()); + let (batches, hash) = batch_and_hash_ops(&ops); insta::assert_debug_snapshot!(batches); insta::assert_debug_snapshot!(build_group_chunks(&batches).collect::>()); let batch_groups = [ build_group(&ops[..9]), - Felt::new(7), - Felt::new(11), + Felt::new_unchecked(7), + Felt::new_unchecked(11), build_group(&ops[9..]), ZERO, ZERO, @@ -167,16 +167,16 @@ fn batch_ops_7() { Operation::Mul, Operation::Mul, Operation::Add, - Operation::Push(Felt::new(11)), + Operation::Push(Felt::new_unchecked(11)), ]; - let (batches, hash) = super::batch_and_hash_ops(ops.clone()); + let (batches, hash) = batch_and_hash_ops(&ops); insta::assert_debug_snapshot!(batches); insta::assert_debug_snapshot!(build_group_chunks(&batches).collect::>()); let batch_groups = [ build_group(&ops[..8]), build_group(&[ops[8]]), - Felt::new(11), + Felt::new_unchecked(11), ZERO, ZERO, ZERO, @@ -199,9 +199,9 @@ fn batch_ops_8() { Operation::Mul, Operation::Mul, Operation::Push(ONE), - Operation::Push(Felt::new(2)), + Operation::Push(Felt::new_unchecked(2)), ]; - let (batches, hash) = super::batch_and_hash_ops(ops.clone()); + let (batches, hash) = batch_and_hash_ops(&ops); insta::assert_debug_snapshot!(batches); insta::assert_debug_snapshot!(build_group_chunks(&batches).collect::>()); @@ -209,7 +209,7 @@ fn batch_ops_8() { build_group(&ops[..8]), ONE, build_group(&[ops[8]]), - Felt::new(2), + Felt::new_unchecked(2), ZERO, ZERO, ZERO, @@ -226,10 +226,10 @@ fn batch_ops_9() { Operation::Add, Operation::Mul, Operation::Push(ONE), - Operation::Push(Felt::new(2)), - Operation::Push(Felt::new(3)), - Operation::Push(Felt::new(4)), - Operation::Push(Felt::new(5)), + Operation::Push(Felt::new_unchecked(2)), + Operation::Push(Felt::new_unchecked(3)), + Operation::Push(Felt::new_unchecked(4)), + Operation::Push(Felt::new_unchecked(5)), Operation::Add, Operation::Mul, Operation::Add, @@ -240,26 +240,35 @@ fn batch_ops_9() { Operation::Mul, Operation::Add, Operation::Mul, - Operation::Push(Felt::new(6)), + Operation::Push(Felt::new_unchecked(6)), Operation::Pad, ]; - let (batches, hash) = super::batch_and_hash_ops(ops.clone()); + let (batches, hash) = batch_and_hash_ops(&ops); insta::assert_debug_snapshot!(batches); insta::assert_debug_snapshot!(build_group_chunks(&batches).collect::>()); let batch0_groups = [ build_group(&ops[..9]), ONE, - Felt::new(2), - Felt::new(3), - Felt::new(4), - Felt::new(5), + Felt::new_unchecked(2), + Felt::new_unchecked(3), + Felt::new_unchecked(4), + Felt::new_unchecked(5), build_group(&ops[9..17]), ZERO, ]; - let batch1_groups = [build_group(&ops[17..]), Felt::new(6), ZERO, ZERO, ZERO, ZERO, ZERO, ZERO]; + let batch1_groups = [ + build_group(&ops[17..]), + Felt::new_unchecked(6), + ZERO, + ZERO, + ZERO, + ZERO, + ZERO, + ZERO, + ]; let all_groups = [batch0_groups, batch1_groups].concat(); assert_eq!(hasher::hash_elements(&all_groups), hash); @@ -280,13 +289,14 @@ fn operation_or_decorator_iterator() { ]; // Convert raw decorators to decorator list by adding them to the forest first - let decorator_list: Vec<(usize, crate::mast::DecoratorId)> = decorators + let decorator_list: Vec<(usize, DecoratorId)> = decorators .into_iter() - .map(|(idx, decorator)| -> Result<(usize, crate::mast::DecoratorId), crate::mast::MastForestError> { + .map(|(idx, decorator)| -> Result<(usize, DecoratorId), MastForestError> { let decorator_id = mast_forest.add_decorator(decorator)?; Ok((idx, decorator_id)) }) - .collect::, _>>().unwrap(); + .collect::, _>>() + .unwrap(); let node_id = BasicBlockNodeBuilder::new(operations, decorator_list) .add_to_forest(&mut mast_forest) @@ -322,11 +332,11 @@ fn build_group(ops: &[Operation]) -> Felt { for (i, op) in ops.iter().enumerate() { group |= (op.op_code() as u64) << (Operation::OP_BITS * i); } - Felt::new(group) + Felt::new_unchecked(group) } fn build_group_chunks(batches: &[OpBatch]) -> impl Iterator { - batches.iter().flat_map(|opbatch| opbatch.group_chunks()) + batches.iter().flat_map(OpBatch::group_chunks) } fn basic_block_from_batch(batch: OpBatch) -> BasicBlockNode { @@ -359,7 +369,7 @@ proptest! { /// - Operations are correctly distributed across batches and groups. #[test] fn test_batch_creation_invariants(ops in op_non_control_sequence_strategy(50)) { - let (batches, _) = super::batch_and_hash_ops(ops.clone()); + let (batches, _) = batch_and_hash_ops(&ops); // A basic block contains one or more batches assert!(!batches.is_empty(), "There should be at least one batch"); @@ -387,8 +397,7 @@ proptest! { for chunk in batch.group_chunks() { let count = chunk.len(); assert!(chunk.len() <= GROUP_SIZE, - "Group {:?} in batch has {} operations, which exceeds the maximum of {}", - chunk, count, GROUP_SIZE); + "Group {chunk:?} in batch has {count} operations, which exceeds the maximum of {GROUP_SIZE}"); } } } @@ -399,7 +408,7 @@ proptest! { /// - If no groups available, both operation and immediate move to next batch #[test] fn test_immediate_value_placement(ops in op_non_control_sequence_strategy(50)) { - let (batches, _) = super::batch_and_hash_ops(ops.clone()); + let (batches, _) = batch_and_hash_ops(&ops); for batch in batches { let mut op_idx_in_group = 0; @@ -451,12 +460,12 @@ fn test_validate_immediate_commitment_rejects_opcode_group_mismatch() { #[test] fn test_validate_immediate_commitment_rejects_immediate_value_mismatch() { - let imm = Felt::new(1); + let imm = Felt::new_unchecked(1); let ops = vec![Operation::Push(imm), Operation::Add]; let indptr = [0usize, 2, 2, 2, 2, 2, 2, 2, 2]; let mut groups = [ZERO; BATCH_SIZE]; groups[0] = build_group(&ops); - groups[1] = Felt::new(2); + groups[1] = Felt::new_unchecked(2); let batch = OpBatch::new_from_parts(ops, indptr, [false; BATCH_SIZE], groups, 2); let node = basic_block_from_batch(batch); @@ -484,7 +493,7 @@ fn test_validate_immediate_commitment_rejects_nonzero_empty_group() { let indptr = [0usize, 1, 1, 1, 1, 1, 1, 1, 1]; let mut groups = [ZERO; BATCH_SIZE]; groups[0] = build_group(&ops); - groups[1] = Felt::new(9); + groups[1] = Felt::new_unchecked(9); let batch = OpBatch::new_from_parts(ops, indptr, [false; BATCH_SIZE], groups, 2); let node = basic_block_from_batch(batch); @@ -629,12 +638,12 @@ proptest! { let mut dummy_forest = MastForest::new(); // Convert decorators to use forest's decorator IDs - let forest_decorators: Vec<(usize, crate::mast::DecoratorId)> = decs + let forest_decorators: Vec<(usize, DecoratorId)> = decs .iter() .map(|(idx, decorator_id)| (*idx, *decorator_id)) .collect(); - let node_id = BasicBlockNodeBuilder::new(ops.clone(), forest_decorators) + let node_id = BasicBlockNodeBuilder::new(ops, forest_decorators) .add_to_forest(&mut dummy_forest) .unwrap(); let block = dummy_forest.get_node_by_id(node_id).unwrap().unwrap_basic_block(); @@ -661,9 +670,9 @@ fn test_mast_node_error_context_decorators_iterates_all_decorators() { let op_deco = Decorator::Trace(2); let after_exit_deco = Decorator::Trace(3); - let before_enter_id = forest.add_decorator(before_enter_deco.clone()).unwrap(); - let op_id = forest.add_decorator(op_deco.clone()).unwrap(); - let after_exit_id = forest.add_decorator(after_exit_deco.clone()).unwrap(); + let before_enter_id = forest.add_decorator(before_enter_deco).unwrap(); + let op_id = forest.add_decorator(op_deco).unwrap(); + let after_exit_id = forest.add_decorator(after_exit_deco).unwrap(); // Create a basic block with all types of decorators using add_to_forest let node_id = BasicBlockNodeBuilder::new(operations, vec![(1, op_id)]) @@ -700,10 +709,10 @@ fn test_indexed_decorator_iter_excludes_before_enter_after_exit() { let op_deco2 = Decorator::Trace(3); let after_exit_deco = Decorator::Trace(4); - let before_enter_id = forest.add_decorator(before_enter_deco.clone()).unwrap(); - let op_id1 = forest.add_decorator(op_deco1.clone()).unwrap(); - let op_id2 = forest.add_decorator(op_deco2.clone()).unwrap(); - let after_exit_id = forest.add_decorator(after_exit_deco.clone()).unwrap(); + let before_enter_id = forest.add_decorator(before_enter_deco).unwrap(); + let op_id1 = forest.add_decorator(op_deco1).unwrap(); + let op_id2 = forest.add_decorator(op_deco2).unwrap(); + let after_exit_id = forest.add_decorator(after_exit_deco).unwrap(); // Create a basic block with all types of decorators using add_to_forest let node_id = BasicBlockNodeBuilder::new(operations, vec![(0, op_id1), (1, op_id2)]) @@ -743,25 +752,24 @@ fn test_decorator_positions() { let trace_deco = Decorator::Trace(42); let debug_deco = Decorator::Trace(999); - let trace_id = forest.add_decorator(trace_deco.clone()).unwrap(); - let debug_id = forest.add_decorator(debug_deco.clone()).unwrap(); + let trace_id = forest.add_decorator(trace_deco).unwrap(); + let debug_id = forest.add_decorator(debug_deco).unwrap(); // Create a basic block with complex operations let operations = vec![ - Operation::Push(Felt::new(1)), - Operation::Push(Felt::new(2)), + Operation::Push(Felt::new_unchecked(1)), + Operation::Push(Felt::new_unchecked(2)), Operation::Add, - Operation::Push(Felt::new(3)), + Operation::Push(Felt::new_unchecked(3)), Operation::Mul, ]; // Create a basic block with complex operations using add_to_forest - let node_id = - BasicBlockNodeBuilder::new(operations.clone(), vec![(2, trace_id), (4, debug_id)]) - .with_before_enter(vec![trace_id, debug_id]) - .with_after_exit(vec![trace_id]) - .add_to_forest(&mut forest) - .unwrap(); + let node_id = BasicBlockNodeBuilder::new(operations, vec![(2, trace_id), (4, debug_id)]) + .with_before_enter(vec![trace_id, debug_id]) + .with_after_exit(vec![trace_id]) + .add_to_forest(&mut forest) + .unwrap(); let block = forest.get_node_by_id(node_id).unwrap().unwrap_basic_block(); @@ -807,7 +815,7 @@ proptest! { // Build BasicBlockNode using linked storage (this applies padding) let mut forest = MastForest::new(); // Convert decorators to use forest's decorator IDs - let forest_decorators: Vec<(usize, crate::mast::DecoratorId)> = decorators + let forest_decorators: Vec<(usize, DecoratorId)> = decorators .iter() .map(|(idx, decorator_id)| (*idx, *decorator_id)) .collect(); @@ -815,7 +823,7 @@ proptest! { .add_to_forest(&mut forest) .unwrap(); let block = forest.get_node_by_id(node_id).unwrap().unwrap_basic_block(); - let padded_ops = block.op_batches().iter().flat_map(|batch| batch.ops()).collect::>(); + let padded_ops = block.op_batches().iter().flat_map(OpBatch::ops).collect::>(); // Build both prefix arrays let raw2pad = RawToPaddedPrefix::new(block.op_batches()); @@ -874,7 +882,7 @@ proptest! { // Build BasicBlockNode using linked storage let mut forest = MastForest::new(); // Convert decorators to use forest's decorator IDs - let forest_decorators: Vec<(usize, crate::mast::DecoratorId)> = decorators + let forest_decorators: Vec<(usize, DecoratorId)> = decorators .iter() .map(|(idx, decorator_id)| (*idx, *decorator_id)) .collect(); @@ -917,7 +925,12 @@ fn test_basic_block_node_digest_forcing() { let normal_digest = node1.digest(); // Build with forced digest - let forced_digest = Word::new([Felt::new(1), Felt::new(2), Felt::new(3), Felt::new(4)]); + let forced_digest = Word::new([ + Felt::new_unchecked(1), + Felt::new_unchecked(2), + Felt::new_unchecked(3), + Felt::new_unchecked(4), + ]); let builder2 = BasicBlockNodeBuilder::new(operations, vec![]).with_digest(forced_digest); let node_id2 = builder2 .add_to_forest(&mut forest) @@ -934,7 +947,12 @@ fn test_basic_block_digest_forcing_with_decorators() { let decorator_id = forest.add_decorator(Decorator::Trace(42)).expect("Failed to add decorator"); let operations = vec![Operation::Add]; - let forced_digest = Word::new([Felt::new(13), Felt::new(14), Felt::new(15), Felt::new(16)]); + let forced_digest = Word::new([ + Felt::new_unchecked(13), + Felt::new_unchecked(14), + Felt::new_unchecked(15), + Felt::new_unchecked(16), + ]); let node_id = BasicBlockNodeBuilder::new(operations, vec![]) .with_before_enter(vec![decorator_id]) @@ -964,7 +982,12 @@ fn test_basic_block_fingerprint_uses_forced_digest() { let decorator_id = forest.add_decorator(Decorator::Trace(99)).expect("Failed to add decorator"); let operations = vec![Operation::Mul]; - let forced_digest = Word::new([Felt::new(17), Felt::new(18), Felt::new(19), Felt::new(20)]); + let forced_digest = Word::new([ + Felt::new_unchecked(17), + Felt::new_unchecked(18), + Felt::new_unchecked(19), + Felt::new_unchecked(20), + ]); let builder1 = BasicBlockNodeBuilder::new(operations.clone(), vec![]) .with_before_enter(vec![decorator_id]); @@ -989,8 +1012,8 @@ fn test_basic_block_fingerprint_uses_forced_digest() { #[test] fn test_to_builder_identity() { let ops = vec![ - Operation::Push(Felt::new(1)), - Operation::Push(Felt::new(2)), + Operation::Push(Felt::new_unchecked(1)), + Operation::Push(Felt::new_unchecked(2)), Operation::Add, Operation::Mul, ]; diff --git a/core/src/mast/node/call_node.rs b/core/src/mast/node/call_node.rs index 7c7b515875..5070922f15 100644 --- a/core/src/mast/node/call_node.rs +++ b/core/src/mast/node/call_node.rs @@ -44,9 +44,9 @@ pub struct CallNode { /// Constants impl CallNode { /// The domain of the call block (used for control block hashing). - pub const CALL_DOMAIN: Felt = Felt::new(opcodes::CALL as u64); + pub const CALL_DOMAIN: Felt = Felt::new_unchecked(opcodes::CALL as u64); /// The domain of the syscall block (used for control block hashing). - pub const SYSCALL_DOMAIN: Felt = Felt::new(opcodes::SYSCALL as u64); + pub const SYSCALL_DOMAIN: Felt = Felt::new_unchecked(opcodes::SYSCALL as u64); } //------------------------------------------------------------------------------------------------- @@ -276,13 +276,12 @@ impl MastNodeExt for CallNode { let forest_node = &forest.nodes[id]; let forest_node_ptr = match forest_node { MastNode::Call(call_node) => call_node as *const CallNode as *const (), - _ => panic!("Node type mismatch at {:?}", id), + _ => panic!("Node type mismatch at {id:?}"), }; let self_as_void = self_ptr as *const (); debug_assert_eq!( self_as_void, forest_node_ptr, - "Node pointer mismatch: expected node at {:?} to be self", - id + "Node pointer mismatch: expected node at {id:?} to be self" ); } } @@ -304,7 +303,7 @@ impl proptest::prelude::Arbitrary for CallNode { (any::(), any::<[u64; 4]>(), any::()) .prop_map(|(callee, digest_array, is_syscall)| { // Generate a random digest - let digest = Word::from(digest_array.map(Felt::new)); + let digest = Word::from(digest_array.map(Felt::new_unchecked)); // Construct directly to avoid MastForest validation for arbitrary data CallNode { callee, @@ -453,10 +452,7 @@ impl MastForestContributor for CallNodeBuilder { CallNode::CALL_DOMAIN }; - crate::chiplets::hasher::merge_in_domain( - &[callee_digest, miden_crypto::Word::default()], - domain, - ) + hasher::merge_in_domain(&[callee_digest, Word::default()], domain) }, ) } @@ -489,7 +485,7 @@ impl MastForestContributor for CallNodeBuilder { self.after_exit.extend(decorators); } - fn with_digest(mut self, digest: crate::Word) -> Self { + fn with_digest(mut self, digest: Word) -> Self { self.digest = Some(digest); self } diff --git a/core/src/mast/node/dyn_node.rs b/core/src/mast/node/dyn_node.rs index 25482f6ede..0351e60e8b 100644 --- a/core/src/mast/node/dyn_node.rs +++ b/core/src/mast/node/dyn_node.rs @@ -33,28 +33,28 @@ pub struct DynNode { /// Constants impl DynNode { /// The domain of the Dyn block (used for control block hashing). - pub const DYN_DOMAIN: Felt = Felt::new(opcodes::DYN as u64); + pub const DYN_DOMAIN: Felt = Felt::new_unchecked(opcodes::DYN as u64); /// The domain of the Dyncall block (used for control block hashing). - pub const DYNCALL_DOMAIN: Felt = Felt::new(opcodes::DYNCALL as u64); + pub const DYNCALL_DOMAIN: Felt = Felt::new_unchecked(opcodes::DYNCALL as u64); } /// Default digest constants impl DynNode { /// The default digest for a DynNode representing a dyncall operation. pub const DYNCALL_DEFAULT_DIGEST: Word = Word::new([ - Felt::new(14319792288905293245), - Felt::new(11465345153771181037), - Felt::new(16104169334207009019), - Felt::new(2750797734633655770), + Felt::new_unchecked(16830415514927835337), + Felt::new_unchecked(12164645914672292987), + Felt::new_unchecked(13192574193032437705), + Felt::new_unchecked(4604554596675732269), ]); /// The default digest for a DynNode representing a dynexec operation. pub const DYN_DEFAULT_DIGEST: Word = Word::new([ - Felt::new(13210061556570014836), - Felt::new(16003296542960478536), - Felt::new(6732564319544917702), - Felt::new(16687523027086140644), + Felt::new_unchecked(16952228088962355159), + Felt::new_unchecked(5793482471479538911), + Felt::new_unchecked(14446299416172848527), + Felt::new_unchecked(13522295374716441620), ]); } @@ -143,8 +143,8 @@ impl DynNodePrettyPrint<'_> { } } -impl crate::prettier::PrettyPrint for DynNodePrettyPrint<'_> { - fn render(&self) -> crate::prettier::Document { +impl PrettyPrint for DynNodePrettyPrint<'_> { + fn render(&self) -> Document { let dyn_text = if self.node.is_dyncall() { const_text("dyncall") } else { @@ -254,13 +254,12 @@ impl MastNodeExt for DynNode { let forest_node = &forest.nodes[id]; let forest_node_ptr = match forest_node { MastNode::Dyn(dyn_node) => dyn_node as *const DynNode as *const (), - _ => panic!("Node type mismatch at {:?}", id), + _ => panic!("Node type mismatch at {id:?}"), }; let self_as_void = self_ptr as *const (); debug_assert_eq!( self_as_void, forest_node_ptr, - "Node pointer mismatch: expected node at {:?} to be self", - id + "Node pointer mismatch: expected node at {id:?} to be self" ); } } @@ -426,7 +425,7 @@ impl MastForestContributor for DynNodeBuilder { self.after_exit.extend(decorators); } - fn with_digest(mut self, digest: crate::Word) -> Self { + fn with_digest(mut self, digest: Word) -> Self { self.digest = Some(digest); self } diff --git a/core/src/mast/node/external.rs b/core/src/mast/node/external.rs index 71b91409c8..c1b1c8b06d 100644 --- a/core/src/mast/node/external.rs +++ b/core/src/mast/node/external.rs @@ -104,8 +104,8 @@ impl ExternalNodePrettyPrint<'_> { } } -impl crate::prettier::PrettyPrint for ExternalNodePrettyPrint<'_> { - fn render(&self) -> crate::prettier::Document { +impl PrettyPrint for ExternalNodePrettyPrint<'_> { + fn render(&self) -> Document { let external = const_text("external") + const_text(".") + text(self.node.digest.as_bytes().to_hex_with_prefix()); @@ -208,13 +208,12 @@ impl MastNodeExt for ExternalNode { crate::mast::MastNode::External(external) => { external as *const ExternalNode as *const () }, - _ => panic!("Node type mismatch at {:?}", id), + _ => panic!("Node type mismatch at {id:?}"), }; let self_as_void = self_ptr as *const (); debug_assert_eq!( self_as_void, forest_node_ptr, - "Node pointer mismatch: expected node at {:?} to be self", - id + "Node pointer mismatch: expected node at {id:?} to be self" ); } } @@ -235,7 +234,7 @@ impl proptest::prelude::Arbitrary for ExternalNode { // Generate a random Word to use as the procedure hash/digest any::<[u64; 4]>() .prop_map(|[a, b, c, d]| { - let word = Word::from([Felt::new(a), Felt::new(b), Felt::new(c), Felt::new(d)]); + let word = Word::from([Felt::new_unchecked(a), Felt::new_unchecked(b), Felt::new_unchecked(c), Felt::new_unchecked(d)]); ExternalNodeBuilder::new(word).build() }) .no_shrink() // Pure random values, no meaningful shrinking pattern @@ -340,7 +339,7 @@ impl MastForestContributor for ExternalNodeBuilder { self.after_exit.extend(decorators); } - fn with_digest(mut self, digest: crate::Word) -> Self { + fn with_digest(mut self, digest: Word) -> Self { self.digest = digest; self } @@ -390,11 +389,11 @@ impl proptest::prelude::Arbitrary for ExternalNodeBuilder { ( any::<[u64; 4]>().prop_map(|[a, b, c, d]| { - miden_crypto::Word::new([ - miden_crypto::Felt::new(a), - miden_crypto::Felt::new(b), - miden_crypto::Felt::new(c), - miden_crypto::Felt::new(d), + Word::new([ + Felt::new_unchecked(a), + Felt::new_unchecked(b), + Felt::new_unchecked(c), + Felt::new_unchecked(d), ]) }), proptest::collection::vec( diff --git a/core/src/mast/node/join_node.rs b/core/src/mast/node/join_node.rs index ea87623c72..c39655f60c 100644 --- a/core/src/mast/node/join_node.rs +++ b/core/src/mast/node/join_node.rs @@ -35,7 +35,7 @@ pub struct JoinNode { /// Constants impl JoinNode { /// The domain of the join block (used for control block hashing). - pub const DOMAIN: Felt = Felt::new(opcodes::JOIN as u64); + pub const DOMAIN: Felt = Felt::new_unchecked(opcodes::JOIN as u64); } /// Public accessors @@ -260,13 +260,12 @@ impl MastNodeExt for JoinNode { let forest_node = &forest.nodes[id]; let forest_node_ptr = match forest_node { MastNode::Join(join_node) => join_node as *const JoinNode as *const (), - _ => panic!("Node type mismatch at {:?}", id), + _ => panic!("Node type mismatch at {id:?}"), }; let self_as_void = self_ptr as *const (); debug_assert_eq!( self_as_void, forest_node_ptr, - "Node pointer mismatch: expected node at {:?} to be self", - id + "Node pointer mismatch: expected node at {id:?} to be self" ); } } @@ -288,7 +287,7 @@ impl proptest::prelude::Arbitrary for JoinNode { (any::(), any::(), any::<[u64; 4]>()) .prop_map(|(first_child, second_child, digest_array)| { // Generate a random digest - let digest = Word::from(digest_array.map(Felt::new)); + let digest = Word::from(digest_array.map(Felt::new_unchecked)); // Construct directly to avoid MastForest validation for arbitrary data JoinNode { children: [first_child, second_child], @@ -416,10 +415,7 @@ impl MastForestContributor for JoinNodeBuilder { let left_child_hash = forest[self.children[0]].digest(); let right_child_hash = forest[self.children[1]].digest(); - crate::chiplets::hasher::merge_in_domain( - &[left_child_hash, right_child_hash], - JoinNode::DOMAIN, - ) + hasher::merge_in_domain(&[left_child_hash, right_child_hash], JoinNode::DOMAIN) }, ) } @@ -454,7 +450,7 @@ impl MastForestContributor for JoinNodeBuilder { self.after_exit.extend(decorators); } - fn with_digest(mut self, digest: crate::Word) -> Self { + fn with_digest(mut self, digest: Word) -> Self { self.digest = Some(digest); self } diff --git a/core/src/mast/node/loop_node.rs b/core/src/mast/node/loop_node.rs index 71f475a164..6934d15ce5 100644 --- a/core/src/mast/node/loop_node.rs +++ b/core/src/mast/node/loop_node.rs @@ -39,7 +39,7 @@ pub struct LoopNode { /// Constants impl LoopNode { /// The domain of the loop node (used for control block hashing). - pub const DOMAIN: Felt = Felt::new(opcodes::LOOP as u64); + pub const DOMAIN: Felt = Felt::new_unchecked(opcodes::LOOP as u64); } impl LoopNode { @@ -70,7 +70,7 @@ struct LoopNodePrettyPrint<'a> { mast_forest: &'a MastForest, } -impl crate::prettier::PrettyPrint for LoopNodePrettyPrint<'_> { +impl PrettyPrint for LoopNodePrettyPrint<'_> { fn render(&self) -> crate::prettier::Document { use crate::prettier::*; @@ -209,13 +209,12 @@ impl MastNodeExt for LoopNode { let forest_node = &forest.nodes[id]; let forest_node_ptr = match forest_node { MastNode::Loop(loop_node) => loop_node as *const LoopNode as *const (), - _ => panic!("Node type mismatch at {:?}", id), + _ => panic!("Node type mismatch at {id:?}"), }; let self_as_void = self_ptr as *const (); debug_assert_eq!( self_as_void, forest_node_ptr, - "Node pointer mismatch: expected node at {:?} to be self", - id + "Node pointer mismatch: expected node at {id:?} to be self" ); } } @@ -237,7 +236,7 @@ impl proptest::prelude::Arbitrary for LoopNode { (any::(), any::<[u64; 4]>()) .prop_map(|(body, digest_array)| { // Generate a random digest - let digest = Word::from(digest_array.map(Felt::new)); + let digest = Word::from(digest_array.map(Felt::new_unchecked)); // Construct directly to avoid MastForest validation for arbitrary data LoopNode { body, @@ -353,10 +352,7 @@ impl MastForestContributor for LoopNodeBuilder { } else { let body_hash = forest[self.body].digest(); - crate::chiplets::hasher::merge_in_domain( - &[body_hash, miden_crypto::Word::default()], - LoopNode::DOMAIN, - ) + hasher::merge_in_domain(&[body_hash, Word::default()], LoopNode::DOMAIN) }, ) } @@ -388,7 +384,7 @@ impl MastForestContributor for LoopNodeBuilder { self.after_exit.extend(decorators); } - fn with_digest(mut self, digest: crate::Word) -> Self { + fn with_digest(mut self, digest: Word) -> Self { self.digest = Some(digest); self } diff --git a/core/src/mast/node/mast_forest_contributor.rs b/core/src/mast/node/mast_forest_contributor.rs index 252d3d54d2..e34544eab5 100644 --- a/core/src/mast/node/mast_forest_contributor.rs +++ b/core/src/mast/node/mast_forest_contributor.rs @@ -201,7 +201,7 @@ mod fingerprint_invariant_tests { #[test] fn basic_block_fingerprint_different_assert_opcodes_no_decorators() { let forest = MastForest::new(); - let error_code = Felt::new(42); + let error_code = Felt::new_unchecked(42); // Create three basic blocks with different assert opcodes but no decorators using builders let builder_assert = @@ -235,8 +235,8 @@ mod fingerprint_invariant_tests { #[test] fn basic_block_fingerprint_different_assert_values_no_decorators() { let forest = MastForest::new(); - let error_code_1 = Felt::new(42); - let error_code_2 = Felt::new(123); + let error_code_1 = Felt::new_unchecked(42); + let error_code_2 = Felt::new_unchecked(123); // Create basic blocks with same assert opcode but different inner values, no decorators let builder_assert_1 = @@ -340,8 +340,8 @@ mod fingerprint_invariant_tests { prop_assume!(error_code_1 != error_code_2); // Ensure different error codes let forest = MastForest::new(); - let felt_1 = Felt::new(error_code_1); - let felt_2 = Felt::new(error_code_2); + let felt_1 = Felt::new_unchecked(error_code_1); + let felt_2 = Felt::new_unchecked(error_code_2); let builder_assert_1 = BasicBlockNodeBuilder::new(vec![Operation::Assert(felt_1)], Vec::new()); let builder_assert_2 = BasicBlockNodeBuilder::new(vec![Operation::Assert(felt_2)], Vec::new()); @@ -395,8 +395,12 @@ mod round_trip_tests { } // Test digest forcing - let forced_join_digest = - Word::new([Felt::new(5), Felt::new(6), Felt::new(7), Felt::new(8)]); + let forced_join_digest = Word::new([ + Felt::new_unchecked(5), + Felt::new_unchecked(6), + Felt::new_unchecked(7), + Felt::new_unchecked(8), + ]); let join_builder2 = JoinNodeBuilder::new([child1, child2]).with_digest(forced_join_digest); let join_node_id2 = join_builder2 .add_to_forest(&mut forest) @@ -415,7 +419,7 @@ mod round_trip_tests { let mut forest = MastForest::new(); let mast_builder1 = MastNodeBuilder::BasicBlock(BasicBlockNodeBuilder::new( - vec![Operation::Push(Felt::new(10))], + vec![Operation::Push(Felt::new_unchecked(10))], vec![], )); let mast_node_id1 = mast_builder1 @@ -424,10 +428,14 @@ mod round_trip_tests { let mast_node1 = forest.get_node_by_id(mast_node_id1).unwrap().unwrap_basic_block(); let mast_normal_digest = mast_node1.digest(); - let forced_mast_digest = - Word::new([Felt::new(9), Felt::new(10), Felt::new(11), Felt::new(12)]); + let forced_mast_digest = Word::new([ + Felt::new_unchecked(9), + Felt::new_unchecked(10), + Felt::new_unchecked(11), + Felt::new_unchecked(12), + ]); let mast_builder2 = MastNodeBuilder::BasicBlock( - BasicBlockNodeBuilder::new(vec![Operation::Push(Felt::new(10))], vec![]) + BasicBlockNodeBuilder::new(vec![Operation::Push(Felt::new_unchecked(10))], vec![]) .with_digest(forced_mast_digest), ); let mast_node_id2 = mast_builder2 diff --git a/core/src/mast/node/split_node.rs b/core/src/mast/node/split_node.rs index 64fba8188b..b3f2a85d6d 100644 --- a/core/src/mast/node/split_node.rs +++ b/core/src/mast/node/split_node.rs @@ -39,7 +39,7 @@ pub struct SplitNode { /// Constants impl SplitNode { /// The domain of the split node (used for control block hashing). - pub const DOMAIN: Felt = Felt::new(opcodes::SPLIT as u64); + pub const DOMAIN: Felt = Felt::new_unchecked(opcodes::SPLIT as u64); } /// Public accessors @@ -220,13 +220,12 @@ impl MastNodeExt for SplitNode { let forest_node = &forest.nodes[id]; let forest_node_ptr = match forest_node { MastNode::Split(split_node) => split_node as *const SplitNode as *const (), - _ => panic!("Node type mismatch at {:?}", id), + _ => panic!("Node type mismatch at {id:?}"), }; let self_as_void = self_ptr as *const (); debug_assert_eq!( self_as_void, forest_node_ptr, - "Node pointer mismatch: expected node at {:?} to be self", - id + "Node pointer mismatch: expected node at {id:?} to be self" ); } } @@ -248,7 +247,7 @@ impl proptest::prelude::Arbitrary for SplitNode { (any::(), any::(), any::<[u64; 4]>()) .prop_map(|(true_branch, false_branch, digest_array)| { // Generate a random digest - let digest = Word::from(digest_array.map(Felt::new)); + let digest = Word::from(digest_array.map(Felt::new_unchecked)); // Construct directly to avoid MastForest validation for arbitrary data SplitNode { branches: [true_branch, false_branch], @@ -376,10 +375,7 @@ impl MastForestContributor for SplitNodeBuilder { let if_branch_hash = forest[self.branches[0]].digest(); let else_branch_hash = forest[self.branches[1]].digest(); - crate::chiplets::hasher::merge_in_domain( - &[if_branch_hash, else_branch_hash], - SplitNode::DOMAIN, - ) + hasher::merge_in_domain(&[if_branch_hash, else_branch_hash], SplitNode::DOMAIN) }, ) } @@ -414,7 +410,7 @@ impl MastForestContributor for SplitNodeBuilder { self.after_exit.extend(decorators); } - fn with_digest(mut self, digest: crate::Word) -> Self { + fn with_digest(mut self, digest: Word) -> Self { self.digest = Some(digest); self } diff --git a/core/src/mast/node_fingerprint.rs b/core/src/mast/node_fingerprint.rs index 38ed198c2c..12e3c634c9 100644 --- a/core/src/mast/node_fingerprint.rs +++ b/core/src/mast/node_fingerprint.rs @@ -115,9 +115,9 @@ pub fn fingerprint_from_parts( } else { let decorator_bytes_iter = pre_decorator_hash_bytes .iter() - .map(|bytes| bytes.as_slice()) - .chain(post_decorator_hash_bytes.iter().map(|bytes| bytes.as_slice())) - .chain(children_decorator_roots.iter().map(|bytes| bytes.as_slice())); + .map(<[u8; 32]>::as_slice) + .chain(post_decorator_hash_bytes.iter().map(<[u8; 32]>::as_slice)) + .chain(children_decorator_roots.iter().map(<[u8; 32]>::as_slice)); let decorator_root = Blake3_256::hash_iter(decorator_bytes_iter); Ok(MastNodeFingerprint::with_decorator_root(node_digest, decorator_root)) diff --git a/core/src/mast/serialization/asm_op.rs b/core/src/mast/serialization/asm_op.rs index 78a6e66c16..9bee0e7d93 100644 --- a/core/src/mast/serialization/asm_op.rs +++ b/core/src/mast/serialization/asm_op.rs @@ -199,8 +199,7 @@ mod tests { fn test_asm_op_roundtrip_with_location() { let location = Location::new(Uri::new("test://file.masm"), ByteIndex::new(10), ByteIndex::new(20)); - let asm_op = - AssemblyOp::new(Some(location.clone()), "my_proc".to_string(), 3, "mul".to_string()); + let asm_op = AssemblyOp::new(Some(location), "my_proc".to_string(), 3, "mul".to_string()); let mut builder = AsmOpDataBuilder::new(); builder.add_asm_op(&asm_op); @@ -237,9 +236,9 @@ mod tests { // Verify all restore correctly for (i, (info, original)) in infos.iter().zip([&asm_op1, &asm_op2, &asm_op3]).enumerate() { let restored = info.try_into_asm_op(&string_table, &data).unwrap(); - assert_eq!(restored.context_name(), original.context_name(), "asm_op {}", i); - assert_eq!(restored.op(), original.op(), "asm_op {}", i); - assert_eq!(restored.num_cycles(), original.num_cycles(), "asm_op {}", i); + assert_eq!(restored.context_name(), original.context_name(), "asm_op {i}"); + assert_eq!(restored.op(), original.op(), "asm_op {i}"); + assert_eq!(restored.num_cycles(), original.num_cycles(), "asm_op {i}"); } } diff --git a/core/src/mast/serialization/basic_blocks.rs b/core/src/mast/serialization/basic_blocks.rs index de63ab7e48..8f6866e884 100644 --- a/core/src/mast/serialization/basic_blocks.rs +++ b/core/src/mast/serialization/basic_blocks.rs @@ -1,13 +1,19 @@ -//! Basic block serialization format. +//! Basic block serialization for the MAST wire format. //! -//! ## Wire Format +//! Basic blocks are the variable-size part of the format. Node entries only store an offset into +//! this section. //! -//! - Padded operations (variable size) -//! - Batch count (4 bytes) -//! - Delta-encoded indptr per batch (4 bytes each: 8 deltas × 4 bits, packed) -//! - Padding flags per batch (1 byte each, bit-packed) +//! The wire layout for one basic block is: +//! - Encoded operations vector (`Vec`) +//! - Batch count (`u32`) +//! - Delta-encoded `indptr` arrays for each batch (`4 * num_batches` bytes) +//! - Padding flags for each batch (`1 * num_batches` bytes) //! -//! **Total**: `ops_size + 4 + (5 * num_batches)` bytes +//! The total encoded size is: +//! `encoded_operations_len + size_of::() + (5 * num_batches)`. +//! +//! This matches [`basic_block_data_len`], which is used for size accounting in stripped and +//! hashless serialization. use alloc::vec::Vec; @@ -34,6 +40,22 @@ impl BasicBlockDataBuilder { } } +/// Returns the serialized size of a basic block in the node data section. +pub(super) fn basic_block_data_len(basic_block: &BasicBlockNode) -> usize { + let mut op_count = 0usize; + let mut ops_size = 0usize; + for op in basic_block.operations() { + op_count += 1; + ops_size += op.encoded_size(); + } + + let num_batches = basic_block.num_op_batches(); + let mut size = op_count.get_size_hint() + ops_size; + size += size_of::(); + size += 5 * num_batches; + size +} + /// Mutators impl BasicBlockDataBuilder { /// Encodes a [`BasicBlockNode`]'s operations into the serialized [`crate::mast::MastForest`] @@ -96,7 +118,7 @@ fn pack_indptr_deltas(indptr: &[usize; 9]) -> [u8; 4] { let mut packed = [0u8; 4]; for i in 0..8 { let delta = indptr[i + 1] - indptr[i]; - debug_assert!(delta <= 9, "delta {} exceeds maximum of 9", delta); + debug_assert!(delta <= 9, "delta {delta} exceeds maximum of 9"); let byte_idx = i / 2; let nibble_shift = (i % 2) * 4; @@ -113,7 +135,7 @@ fn pack_indptr_deltas(indptr: &[usize; 9]) -> [u8; 4] { /// # Errors /// /// Returns `DeserializationError::InvalidValue` if any delta exceeds GROUP_SIZE. -fn unpack_indptr_deltas(packed: &[u8; 4]) -> Result<[usize; 9], DeserializationError> { +fn unpack_indptr_deltas(packed: [u8; 4]) -> Result<[usize; 9], DeserializationError> { let mut indptr = [0usize; 9]; for i in 0..8 { @@ -123,8 +145,7 @@ fn unpack_indptr_deltas(packed: &[u8; 4]) -> Result<[usize; 9], DeserializationE if delta > OP_GROUP_SIZE { return Err(DeserializationError::InvalidValue(format!( - "indptr delta {} exceeds maximum of {} at position {} (operation groups comprise at most {} ops)", - delta, OP_GROUP_SIZE, i, OP_GROUP_SIZE + "indptr delta {delta} exceeds maximum of {OP_GROUP_SIZE} at position {i} (operation groups comprise at most {OP_GROUP_SIZE} ops)" ))); } @@ -185,8 +206,7 @@ impl BasicBlockDataDecoder<'_> { let max_batches = ops_data_reader.max_alloc(BATCH_METADATA_BYTES_PER_BATCH); if num_batches > max_batches { return Err(DeserializationError::InvalidValue(format!( - "batch count {} exceeds remaining data capacity {}", - num_batches, max_batches + "batch count {num_batches} exceeds remaining data capacity {max_batches}" ))); } @@ -194,7 +214,7 @@ impl BasicBlockDataDecoder<'_> { let mut batch_indptrs: Vec<[usize; 9]> = Vec::with_capacity(num_batches); for _ in 0..num_batches { let packed: [u8; 4] = ops_data_reader.read()?; - let indptr = unpack_indptr_deltas(&packed)?; + let indptr = unpack_indptr_deltas(packed)?; batch_indptrs.push(indptr); } @@ -234,7 +254,7 @@ impl BasicBlockDataDecoder<'_> { // Reconstruct the groups array and calculate num_groups // num_groups is the next available slot after all operation groups and immediate values - let mut groups = [Felt::new(0); 8]; + let mut groups = [Felt::new_unchecked(0); 8]; let mut next_group_idx = 0; for array_idx in 0..highest_op_group { @@ -248,7 +268,7 @@ impl BasicBlockDataDecoder<'_> { let opcode = op.op_code() as u64; group_value |= opcode << (Operation::OP_BITS * local_op_idx); } - groups[array_idx] = Felt::new(group_value); + groups[array_idx] = Felt::new_unchecked(group_value); let (placements, next_group_idx_after) = collect_immediate_placements( &batch_ops, @@ -274,7 +294,7 @@ impl BasicBlockDataDecoder<'_> { batch_ops, *indptr, padding, groups, num_groups, ); op_batch.validate_padding_semantics().map_err(|err| { - DeserializationError::InvalidValue(format!("batch {}: {}", batch_idx, err)) + DeserializationError::InvalidValue(format!("batch {batch_idx}: {err}")) })?; op_batches.push(op_batch); @@ -306,7 +326,7 @@ mod tests { #[case::some_zero_deltas([0, 0, 5, 5, 10, 10, 15, 15, 20])] fn test_pack_unpack_indptr_roundtrip(#[case] indptr: [usize; 9]) { let packed = pack_indptr_deltas(&indptr); - let unpacked = unpack_indptr_deltas(&packed).unwrap(); + let unpacked = unpack_indptr_deltas(packed).unwrap(); assert_eq!(indptr, unpacked); } @@ -317,7 +337,7 @@ mod tests { #[case::delta_11_position_3([0x00, 0xb0, 0x00, 0x00], "delta 11 exceeds maximum of 9")] #[case::delta_14_position_7([0x00, 0x00, 0x00, 0x0e], "delta 14 exceeds maximum of 9")] fn test_unpack_invalid_delta(#[case] packed: [u8; 4], #[case] expected_msg: &str) { - let result = unpack_indptr_deltas(&packed); + let result = unpack_indptr_deltas(packed); assert!(result.is_err()); let err_msg = result.unwrap_err().to_string(); assert!(err_msg.contains(expected_msg)); @@ -377,7 +397,7 @@ mod tests { #[test] fn test_decode_operations_rejects_push_immediate_group_overflow() { - let operations = vec![Operation::Push(Felt::new(1))]; + let operations = vec![Operation::Push(Felt::new_unchecked(1))]; let mut bytes = Vec::new(); operations.write_into(&mut bytes); diff --git a/core/src/mast/serialization/info.rs b/core/src/mast/serialization/info.rs index 8a17146d7d..29faf860e2 100644 --- a/core/src/mast/serialization/info.rs +++ b/core/src/mast/serialization/info.rs @@ -1,134 +1,14 @@ use alloc::vec::Vec; use super::{NodeDataOffset, basic_blocks::BasicBlockDataDecoder}; +#[cfg(test)] +use crate::mast::node::MastNodeExt; use crate::{ - mast::{ - MastForestContributor, MastNode, MastNodeId, Word, - node::{MastNodeBuilder, MastNodeExt}, - }, + mast::{MastForestContributor, MastNode, MastNodeId, Word, node::MastNodeBuilder}, serde::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable}, }; -// MAST NODE INFO -// ================================================================================================ - -/// Represents a serialized [`MastNode`], with some data inlined in its [`MastNodeType`]. -/// -/// The serialized representation of [`MastNodeInfo`] is guaranteed to be fixed width, so that the -/// nodes stored in the `nodes` table of the serialized [`MastForest`] can be accessed quickly by -/// index. -#[derive(Debug)] -pub struct MastNodeInfo { - ty: MastNodeType, - digest: Word, -} - -impl MastNodeInfo { - /// Constructs a new [`MastNodeInfo`] from a [`MastNode`], along with an `ops_offset` - /// - /// For non-basic block nodes, `ops_offset` is ignored, and should be set to 0. - pub fn new(mast_node: &MastNode, ops_offset: NodeDataOffset) -> Self { - if !matches!(mast_node, &MastNode::Block(_)) { - debug_assert_eq!(ops_offset, 0); - } - - let ty = MastNodeType::new(mast_node, ops_offset); - - Self { ty, digest: mast_node.digest() } - } - - /// Attempts to convert this [`MastNodeInfo`] into a [`MastNodeBuilder`]. - /// - /// The `node_count` is the total expected number of nodes in the [`MastForest`] **after - /// deserialization**. - pub fn try_into_mast_node_builder( - self, - node_count: usize, - basic_block_data_decoder: &BasicBlockDataDecoder, - ) -> Result { - match self.ty { - MastNodeType::Block { ops_offset } => { - let op_batches = basic_block_data_decoder.decode_operations(ops_offset)?; - let builder = crate::mast::node::BasicBlockNodeBuilder::from_op_batches( - op_batches, - Vec::new(), // decorators set later - self.digest, - ); - Ok(MastNodeBuilder::BasicBlock(builder)) - }, - MastNodeType::Join { left_child_id, right_child_id } => { - let left_child = MastNodeId::from_u32_with_node_count(left_child_id, node_count)?; - let right_child = MastNodeId::from_u32_with_node_count(right_child_id, node_count)?; - let builder = crate::mast::node::JoinNodeBuilder::new([left_child, right_child]) - .with_digest(self.digest); - Ok(MastNodeBuilder::Join(builder)) - }, - MastNodeType::Split { if_branch_id, else_branch_id } => { - let if_branch = MastNodeId::from_u32_with_node_count(if_branch_id, node_count)?; - let else_branch = MastNodeId::from_u32_with_node_count(else_branch_id, node_count)?; - let builder = crate::mast::node::SplitNodeBuilder::new([if_branch, else_branch]) - .with_digest(self.digest); - Ok(MastNodeBuilder::Split(builder)) - }, - MastNodeType::Loop { body_id } => { - let body_id = MastNodeId::from_u32_with_node_count(body_id, node_count)?; - let builder = - crate::mast::node::LoopNodeBuilder::new(body_id).with_digest(self.digest); - Ok(MastNodeBuilder::Loop(builder)) - }, - MastNodeType::Call { callee_id } => { - let callee_id = MastNodeId::from_u32_with_node_count(callee_id, node_count)?; - let builder = - crate::mast::node::CallNodeBuilder::new(callee_id).with_digest(self.digest); - Ok(MastNodeBuilder::Call(builder)) - }, - MastNodeType::SysCall { callee_id } => { - let callee_id = MastNodeId::from_u32_with_node_count(callee_id, node_count)?; - let builder = crate::mast::node::CallNodeBuilder::new_syscall(callee_id) - .with_digest(self.digest); - Ok(MastNodeBuilder::Call(builder)) - }, - MastNodeType::Dyn => { - let builder = crate::mast::node::DynNodeBuilder::new_dyn().with_digest(self.digest); - Ok(MastNodeBuilder::Dyn(builder)) - }, - MastNodeType::Dyncall => { - let builder = - crate::mast::node::DynNodeBuilder::new_dyncall().with_digest(self.digest); - Ok(MastNodeBuilder::Dyn(builder)) - }, - MastNodeType::External => { - let builder = crate::mast::node::ExternalNodeBuilder::new(self.digest); - Ok(MastNodeBuilder::External(builder)) - }, - } - } -} - -impl Serializable for MastNodeInfo { - fn write_into(&self, target: &mut W) { - let Self { ty, digest } = self; - - ty.write_into(target); - digest.write_into(target); - } -} - -impl Deserializable for MastNodeInfo { - fn read_from(source: &mut R) -> Result { - let ty = Deserializable::read_from(source)?; - let digest = Word::read_from(source)?; - - Ok(Self { ty, digest }) - } - - /// Returns the minimum serialized size: 8 bytes for MastNodeType + 32 bytes for Word digest. - fn min_serialized_size() -> usize { - 40 - } -} - -// MAST NODE TYPE +// CONSTANTS // ================================================================================================ const JOIN: u8 = 0; @@ -141,15 +21,22 @@ const DYN: u8 = 6; const DYNCALL: u8 = 7; const EXTERNAL: u8 = 8; -/// Represents the variant of a [`MastNode`], as well as any additional data. For example, for more -/// efficient decoding, and because of the frequency with which these node types appear, we directly -/// represent the child indices for `Join`, `Split`, and `Loop`, `Call` and `SysCall` inline. +// MAST NODE ENTRIES +// ================================================================================================ + +/// Fixed-width structural metadata for a serialized [`MastNode`]. +/// +/// This is the random-access portion of the node table. Digests are intentionally modeled +/// separately so the wire format can move them into dedicated sections. /// -/// The serialized representation of the MAST node type is guaranteed to be 8 bytes, so that -/// [`MastNodeInfo`] (which contains it) can be of fixed width. +/// Child indices for `Join`, `Split`, `Loop`, `Call`, and `SysCall` are stored inline so random +/// access does not need any extra pointer chasing. +/// +/// The serialized representation is always 8 bytes, which keeps the node-entry table fixed-width +/// on the wire. #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(u8)] -pub enum MastNodeType { +pub enum MastNodeEntry { Join { left_child_id: u32, right_child_id: u32, @@ -177,13 +64,20 @@ pub enum MastNodeType { } /// Constructors -impl MastNodeType { - /// Constructs a new [`MastNodeType`] from a [`MastNode`]. +impl MastNodeEntry { + /// Serialized byte size of one fixed-width MAST node entry. + pub const SERIALIZED_SIZE: usize = 8; + + /// Constructs a new [`MastNodeEntry`] from a [`MastNode`]. pub fn new(mast_node: &MastNode, ops_offset: NodeDataOffset) -> Self { use MastNode::*; + if !matches!(mast_node, &Block(_)) { + debug_assert_eq!(ops_offset, 0); + } + match mast_node { - Block(_block_node) => Self::Block { ops_offset }, + Block(_) => Self::Block { ops_offset }, Join(join_node) => Self::Join { left_child_id: join_node.first().0, right_child_id: join_node.second().0, @@ -210,29 +104,90 @@ impl MastNodeType { External(_) => Self::External, } } + + /// Attempts to convert this [`MastNodeEntry`] into a [`MastNodeBuilder`]. + /// + /// The `node_count` is the total expected number of nodes in the + /// [`crate::mast::MastForest`] **after deserialization**. + pub fn try_into_mast_node_builder( + self, + node_count: usize, + basic_block_data_decoder: &BasicBlockDataDecoder, + digest: Word, + ) -> Result { + match self { + Self::Block { ops_offset } => { + let op_batches = basic_block_data_decoder.decode_operations(ops_offset)?; + let builder = crate::mast::node::BasicBlockNodeBuilder::from_op_batches( + op_batches, + Vec::new(), // decorators set later + digest, + ); + Ok(MastNodeBuilder::BasicBlock(builder)) + }, + Self::Join { left_child_id, right_child_id } => { + let left_child = MastNodeId::from_u32_with_node_count(left_child_id, node_count)?; + let right_child = MastNodeId::from_u32_with_node_count(right_child_id, node_count)?; + let builder = crate::mast::node::JoinNodeBuilder::new([left_child, right_child]) + .with_digest(digest); + Ok(MastNodeBuilder::Join(builder)) + }, + Self::Split { if_branch_id, else_branch_id } => { + let if_branch = MastNodeId::from_u32_with_node_count(if_branch_id, node_count)?; + let else_branch = MastNodeId::from_u32_with_node_count(else_branch_id, node_count)?; + let builder = crate::mast::node::SplitNodeBuilder::new([if_branch, else_branch]) + .with_digest(digest); + Ok(MastNodeBuilder::Split(builder)) + }, + Self::Loop { body_id } => { + let body_id = MastNodeId::from_u32_with_node_count(body_id, node_count)?; + let builder = crate::mast::node::LoopNodeBuilder::new(body_id).with_digest(digest); + Ok(MastNodeBuilder::Loop(builder)) + }, + Self::Call { callee_id } => { + let callee_id = MastNodeId::from_u32_with_node_count(callee_id, node_count)?; + let builder = + crate::mast::node::CallNodeBuilder::new(callee_id).with_digest(digest); + Ok(MastNodeBuilder::Call(builder)) + }, + Self::SysCall { callee_id } => { + let callee_id = MastNodeId::from_u32_with_node_count(callee_id, node_count)?; + let builder = + crate::mast::node::CallNodeBuilder::new_syscall(callee_id).with_digest(digest); + Ok(MastNodeBuilder::Call(builder)) + }, + Self::Dyn => Ok(MastNodeBuilder::Dyn( + crate::mast::node::DynNodeBuilder::new_dyn().with_digest(digest), + )), + Self::Dyncall => Ok(MastNodeBuilder::Dyn( + crate::mast::node::DynNodeBuilder::new_dyncall().with_digest(digest), + )), + Self::External => { + Ok(MastNodeBuilder::External(crate::mast::node::ExternalNodeBuilder::new(digest))) + }, + } + } } -impl Serializable for MastNodeType { +impl Serializable for MastNodeEntry { fn write_into(&self, target: &mut W) { let discriminant = self.discriminant() as u64; assert!(discriminant <= 0b1111); let payload = match *self { - MastNodeType::Join { + Self::Join { left_child_id: left, right_child_id: right, } => Self::encode_u32_pair(left, right), - MastNodeType::Split { + Self::Split { if_branch_id: if_branch, else_branch_id: else_branch, } => Self::encode_u32_pair(if_branch, else_branch), - MastNodeType::Loop { body_id: body } => Self::encode_u32_payload(body), - MastNodeType::Block { ops_offset } => Self::encode_u32_payload(ops_offset), - MastNodeType::Call { callee_id } => Self::encode_u32_payload(callee_id), - MastNodeType::SysCall { callee_id } => Self::encode_u32_payload(callee_id), - MastNodeType::Dyn => 0, - MastNodeType::Dyncall => 0, - MastNodeType::External => 0, + Self::Loop { body_id: body } => Self::encode_u32_payload(body), + Self::Block { ops_offset } => Self::encode_u32_payload(ops_offset), + Self::Call { callee_id } => Self::encode_u32_payload(callee_id), + Self::SysCall { callee_id } => Self::encode_u32_payload(callee_id), + Self::Dyn | Self::Dyncall | Self::External => 0, }; let value = (discriminant << 60) | payload; @@ -240,47 +195,12 @@ impl Serializable for MastNodeType { } } -/// Serialization helpers -impl MastNodeType { - fn discriminant(&self) -> u8 { - // SAFETY: This is safe because we have given this enum a primitive representation with - // #[repr(u8)], with the first field of the underlying union-of-structs the discriminant. - // - // See the section on "accessing the numeric value of the discriminant" - // here: https://doc.rust-lang.org/std/mem/fn.discriminant.html - unsafe { *<*const _>::from(self).cast::() } - } - - /// Encodes two u32 numbers in the first 60 bits of a `u64`. - /// - /// # Panics - /// - Panics if either `left_value` or `right_value` doesn't fit in 30 bits. - fn encode_u32_pair(left_value: u32, right_value: u32) -> u64 { - assert!( - left_value.leading_zeros() >= 2, - "MastNodeType::encode_u32_pair: left value doesn't fit in 30 bits: {left_value}", - ); - assert!( - right_value.leading_zeros() >= 2, - "MastNodeType::encode_u32_pair: right value doesn't fit in 30 bits: {right_value}", - ); - - ((left_value as u64) << 30) | (right_value as u64) - } - - fn encode_u32_payload(payload: u32) -> u64 { - payload as u64 - } -} - -impl Deserializable for MastNodeType { +impl Deserializable for MastNodeEntry { fn read_from(source: &mut R) -> Result { let (discriminant, payload) = { let value = source.read_u64()?; - // 4 bits let discriminant = (value >> 60) as u8; - // 60 bits let payload = value & 0x0f_ff_ff_ff_ff_ff_ff_ff; (discriminant, payload) @@ -322,12 +242,45 @@ impl Deserializable for MastNodeType { /// Returns the fixed serialized size: always 8 bytes (u64). fn min_serialized_size() -> usize { - 8 + Self::SERIALIZED_SIZE + } +} + +/// Serialization helpers +impl MastNodeEntry { + fn discriminant(&self) -> u8 { + // SAFETY: This is safe because we have given this enum a primitive representation with + // #[repr(u8)], with the first field of the underlying union-of-structs the discriminant. + // + // See the section on "accessing the numeric value of the discriminant" + // here: https://doc.rust-lang.org/std/mem/fn.discriminant.html + unsafe { *<*const _>::from(self).cast::() } + } + + /// Encodes two u32 numbers in the first 60 bits of a `u64`. + /// + /// # Panics + /// - Panics if either `left_value` or `right_value` doesn't fit in 30 bits. + fn encode_u32_pair(left_value: u32, right_value: u32) -> u64 { + assert!( + left_value.leading_zeros() >= 2, + "MastNodeEntry::encode_u32_pair: left value doesn't fit in 30 bits: {left_value}", + ); + assert!( + right_value.leading_zeros() >= 2, + "MastNodeEntry::encode_u32_pair: right value doesn't fit in 30 bits: {right_value}", + ); + + ((left_value as u64) << 30) | (right_value as u64) + } + + fn encode_u32_payload(payload: u32) -> u64 { + payload as u64 } } /// Deserialization helpers -impl MastNodeType { +impl MastNodeEntry { /// Decodes two `u32` numbers from a 60-bit payload. fn decode_u32_pair(payload: u64) -> (u32, u32) { let left_value = (payload >> 30) as u32; @@ -348,6 +301,83 @@ impl MastNodeType { } } +// MAST NODE INFO +// ================================================================================================ + +/// Logical node metadata combining fixed-width structure and a digest value. +/// +/// This is a convenience type for APIs that want both pieces together. The wire format does not +/// require `MastNodeInfo` to appear as one contiguous fixed-width section. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct MastNodeInfo { + entry: MastNodeEntry, + digest: Word, +} + +impl MastNodeInfo { + /// Constructs a new [`MastNodeInfo`] from a [`MastNode`], along with an `ops_offset` + /// + /// For non-basic block nodes, `ops_offset` is ignored, and should be set to 0. + #[cfg(test)] + pub fn new(mast_node: &MastNode, ops_offset: NodeDataOffset) -> Self { + Self { + entry: MastNodeEntry::new(mast_node, ops_offset), + digest: mast_node.digest(), + } + } + + /// Attempts to convert this [`MastNodeInfo`] into a [`MastNodeBuilder`]. + #[cfg(test)] + pub fn try_into_mast_node_builder( + self, + node_count: usize, + basic_block_data_decoder: &BasicBlockDataDecoder, + ) -> Result { + self.entry + .try_into_mast_node_builder(node_count, basic_block_data_decoder, self.digest) + } + + /// Returns the fixed-width structural node entry. + pub fn node_entry(&self) -> MastNodeEntry { + self.entry + } + + /// Returns the stored node digest. + pub fn digest(&self) -> Word { + self.digest + } + + /// Builds node metadata directly from serialized components. + pub(crate) fn from_entry(entry: MastNodeEntry, digest: Word) -> Self { + Self { entry, digest } + } +} + +#[cfg(test)] +impl Serializable for MastNodeInfo { + fn write_into(&self, target: &mut W) { + self.entry.write_into(target); + self.digest.write_into(target); + } +} + +#[cfg(test)] +impl Deserializable for MastNodeInfo { + fn read_from(source: &mut R) -> Result { + let entry = MastNodeEntry::read_from(source)?; + let digest = Word::read_from(source)?; + Ok(Self { entry, digest }) + } + + /// Returns the minimum serialized size: 8 bytes for `MastNodeEntry` + 32 bytes for `Word`. + fn min_serialized_size() -> usize { + MastNodeEntry::min_serialized_size() + Word::min_serialized_size() + } +} + +// TESTS +// ================================================================================================ + #[cfg(test)] mod tests { use alloc::vec::Vec; @@ -357,41 +387,41 @@ mod tests { #[test] fn serialize_deserialize_60_bit_payload() { // each child needs 30 bits - let mast_node_type = MastNodeType::Join { + let mast_node_entry = MastNodeEntry::Join { left_child_id: 0x3f_ff_ff_ff, right_child_id: 0x3f_ff_ff_ff, }; - let serialized = mast_node_type.to_bytes(); - let deserialized = MastNodeType::read_from_bytes(&serialized).unwrap(); + let serialized = mast_node_entry.to_bytes(); + let deserialized = MastNodeEntry::read_from_bytes(&serialized).unwrap(); - assert_eq!(mast_node_type, deserialized); + assert_eq!(mast_node_entry, deserialized); } #[test] #[should_panic] fn serialize_large_payloads_fails_1() { // left child needs 31 bits - let mast_node_type = MastNodeType::Join { + let mast_node_entry = MastNodeEntry::Join { left_child_id: 0x4f_ff_ff_ff, right_child_id: 0x0, }; // must panic - let _serialized = mast_node_type.to_bytes(); + let _serialized = mast_node_entry.to_bytes(); } #[test] #[should_panic] fn serialize_large_payloads_fails_2() { // right child needs 31 bits - let mast_node_type = MastNodeType::Join { + let mast_node_entry = MastNodeEntry::Join { left_child_id: 0x0, right_child_id: 0x4f_ff_ff_ff, }; // must panic - let _serialized = mast_node_type.to_bytes(); + let _serialized = mast_node_entry.to_bytes(); } #[test] @@ -406,7 +436,7 @@ mod tests { serialized_buffer }; - let deserialized_result = MastNodeType::read_from_bytes(&serialized); + let deserialized_result = MastNodeEntry::read_from_bytes(&serialized); assert_matches!(deserialized_result, Err(DeserializationError::InvalidValue(_))); } diff --git a/core/src/mast/serialization/layout.rs b/core/src/mast/serialization/layout.rs new file mode 100644 index 0000000000..952be4ed74 --- /dev/null +++ b/core/src/mast/serialization/layout.rs @@ -0,0 +1,416 @@ +use alloc::{format, string::ToString, vec::Vec}; + +use super::{ + FLAG_HASHLESS, FLAG_STRIPPED, FLAGS_RESERVED_MASK, MAGIC, MastForest, MastNodeEntry, VERSION, +}; +use crate::{ + mast::MastNodeId, + serde::{ByteReader, Deserializable, DeserializationError, SliceReader}, +}; + +// FOREST LAYOUT +// ================================================================================================ + +/// Fixed offsets and counts for the structural sections of a serialized MAST forest. +/// +/// This is the shared substrate used by both serialized random-access views and the reader-based +/// deserialization paths. All offsets are absolute byte offsets into the full serialized blob. +/// `ForestLayout` itself is not a trust marker; it only says the structural sections fit within +/// the scanned byte slice. +/// +/// The scanner validates section sizes immediately. For budgeted readers, it also bounds wire +/// counts via [`ByteReader::max_alloc`] before those counts are used to size fixed-width sections. +/// Plain [`SliceReader`] leaves `max_alloc` unconstrained, so trusted inspection paths keep their +/// previous behavior. Full untrusted validation lives above this layer in +/// [`crate::mast::UntrustedMastForest`]. +#[derive(Debug, Clone, Copy)] +pub(crate) struct ForestLayout { + pub(super) node_count: usize, + pub(super) roots_count: usize, + pub(super) roots_offset: usize, + pub(super) basic_block_offset: usize, + pub(super) basic_block_len: usize, + pub(super) node_entry_offset: usize, + pub(super) external_digest_offset: usize, + #[cfg(test)] + pub(super) external_digest_count: usize, + pub(super) node_hash_offset: Option, + #[cfg(test)] + pub(super) node_hash_count: usize, +} + +/// Raw wire flags from the MAST header. +/// +/// These flags describe which optional sections are present in the payload. Trust policy lives in +/// the caller that reads the payload, not in the flags themselves. +#[derive(Debug, Clone, Copy)] +pub(super) struct WireFlags(u8); + +impl ForestLayout { + pub(crate) fn is_hashless(&self) -> bool { + self.node_hash_offset.is_none() + } + + pub(super) fn read_procedure_root_at( + &self, + bytes: &[u8], + index: usize, + ) -> Result { + if index >= self.roots_count { + return Err(DeserializationError::InvalidValue(format!( + "root index {} out of bounds for {} roots", + index, self.roots_count + ))); + } + + let mut raw = [0u8; size_of::()]; + raw.copy_from_slice(read_fixed_section_entry( + bytes, + self.roots_offset, + size_of::(), + index, + "root", + )?); + MastNodeId::from_u32_with_node_count(u32::from_le_bytes(raw), self.node_count) + } + + pub(super) fn read_node_entry_at( + &self, + bytes: &[u8], + index: usize, + ) -> Result { + if index >= self.node_count { + return Err(DeserializationError::InvalidValue(format!( + "node index {} out of bounds for {} nodes", + index, self.node_count + ))); + } + + let mut reader = SliceReader::new(read_fixed_section_entry( + bytes, + self.node_entry_offset, + MastNodeEntry::SERIALIZED_SIZE, + index, + "node entry", + )?); + MastNodeEntry::read_from(&mut reader) + } + + #[cfg(test)] + pub(super) fn advice_map_offset( + &self, + bytes_len: usize, + ) -> Result { + let digest_section_end = if let Some(node_hash_offset) = self.node_hash_offset { + node_hash_offset + .checked_add(self.node_hash_count * crate::Word::min_serialized_size()) + .ok_or_else(|| { + DeserializationError::InvalidValue("node hash section overflow".to_string()) + })? + } else { + self.external_digest_offset + .checked_add(self.external_digest_count * crate::Word::min_serialized_size()) + .ok_or_else(|| { + DeserializationError::InvalidValue( + "external digest section overflow".to_string(), + ) + })? + }; + + if digest_section_end > bytes_len { + return Err(DeserializationError::UnexpectedEOF); + } + + Ok(digest_section_end) + } +} + +// WIRE FLAGS +// ================================================================================================ + +impl WireFlags { + pub(super) fn new(bits: u8) -> Result { + let flags = Self(bits); + if flags.is_hashless() && !flags.is_stripped() { + return Err(DeserializationError::InvalidValue( + "HASHLESS flag requires STRIPPED flag to be set".to_string(), + )); + } + + Ok(flags) + } + + pub(super) fn bits(self) -> u8 { + self.0 + } + + pub(super) fn is_stripped(self) -> bool { + self.0 & FLAG_STRIPPED != 0 + } + + pub(super) fn is_hashless(self) -> bool { + self.0 & FLAG_HASHLESS != 0 + } +} + +// LAYOUT SCANNING +// ================================================================================================ + +pub(super) fn read_header_and_scan_layout( + source: &mut R, + allow_hashless: bool, +) -> Result<(WireFlags, ForestLayout), DeserializationError> { + // This scanner always enforces syntactic layout validity. Reader choice determines the trust + // policy for counts: e.g. `SliceReader` for trusted inspection versus `BudgetedReader` for the + // untrusted deserialization path. + let (raw_flags, _version) = read_and_validate_header(source)?; + let flags = WireFlags::new(raw_flags)?; + if flags.is_hashless() && !allow_hashless { + return Err(DeserializationError::InvalidValue( + "HASHLESS flag is set; use UntrustedMastForest for untrusted input".to_string(), + )); + } + let layout = scan_layout_sections(source, flags.is_hashless())?; + + Ok((flags, layout)) +} + +pub(super) trait OffsetTrackingReader: ByteReader { + fn offset(&self) -> usize; +} + +pub(super) struct TrackingReader<'a, R> { + inner: &'a mut R, + offset: usize, + recorded: Option>, +} + +impl<'a, R> TrackingReader<'a, R> { + pub(super) fn new(inner: &'a mut R) -> Self { + Self { inner, offset: 0, recorded: None } + } + + pub(super) fn new_recording(inner: &'a mut R) -> Self { + Self { + inner, + offset: 0, + recorded: Some(Vec::new()), + } + } + + pub(super) fn into_recorded(self) -> Vec { + self.recorded.unwrap_or_default() + } + + fn advance_offset(&mut self, len: usize) -> Result<(), DeserializationError> { + self.offset = self + .offset + .checked_add(len) + .ok_or_else(|| DeserializationError::InvalidValue("offset overflow".to_string()))?; + Ok(()) + } + + fn record_slice(&mut self, slice: &[u8]) { + if let Some(recorded) = &mut self.recorded { + recorded.extend_from_slice(slice); + } + } +} + +impl ByteReader for TrackingReader<'_, R> { + fn read_u8(&mut self) -> Result { + let byte = self.inner.read_u8()?; + self.advance_offset(1)?; + self.record_slice(&[byte]); + Ok(byte) + } + + fn peek_u8(&self) -> Result { + self.inner.peek_u8() + } + + fn read_slice(&mut self, len: usize) -> Result<&[u8], DeserializationError> { + let slice = self.inner.read_slice(len)?; + self.offset = self + .offset + .checked_add(len) + .ok_or_else(|| DeserializationError::InvalidValue("offset overflow".to_string()))?; + if let Some(recorded) = &mut self.recorded { + recorded.extend_from_slice(slice); + } + Ok(slice) + } + + fn read_array(&mut self) -> Result<[u8; N], DeserializationError> { + let array = self.inner.read_array::()?; + self.advance_offset(N)?; + self.record_slice(&array); + Ok(array) + } + + fn check_eor(&self, num_bytes: usize) -> Result<(), DeserializationError> { + self.inner.check_eor(num_bytes) + } + + fn has_more_bytes(&self) -> bool { + self.inner.has_more_bytes() + } + + fn max_alloc(&self, element_size: usize) -> usize { + self.inner.max_alloc(element_size) + } +} + +impl OffsetTrackingReader for TrackingReader<'_, R> { + fn offset(&self) -> usize { + self.offset + } +} + +fn scan_layout_sections( + source: &mut R, + is_hashless: bool, +) -> Result { + let node_count = source.read_usize()?; + if node_count > MastForest::MAX_NODES { + return Err(DeserializationError::InvalidValue(format!( + "node count {} exceeds maximum allowed {}", + node_count, + MastForest::MAX_NODES + ))); + } + validate_budgeted_count(source, node_count, MastNodeEntry::SERIALIZED_SIZE, "node count")?; + + let roots_count = source.read_usize()?; + validate_budgeted_count(source, roots_count, size_of::(), "root count")?; + let roots_offset = source.offset(); + let roots_len_bytes = roots_count + .checked_mul(size_of::()) + .ok_or_else(|| DeserializationError::InvalidValue("roots length overflow".to_string()))?; + let _roots_data = source.read_slice(roots_len_bytes)?; + + let basic_block_len = source.read_usize()?; + let basic_block_offset = source.offset(); + let _basic_block_data = source.read_slice(basic_block_len)?; + + let node_entry_offset = source.offset(); + let mut external_digest_count = 0usize; + for _ in 0..node_count { + let node_entry = MastNodeEntry::read_from(source)?; + if matches!(node_entry, MastNodeEntry::External) { + external_digest_count = external_digest_count.checked_add(1).ok_or_else(|| { + DeserializationError::InvalidValue("external digest count overflow".to_string()) + })?; + } + } + + let external_digest_offset = source.offset(); + let external_digests_len = external_digest_count + .checked_mul(crate::Word::min_serialized_size()) + .ok_or_else(|| { + DeserializationError::InvalidValue("external digest length overflow".to_string()) + })?; + let _external_digests = source.read_slice(external_digests_len)?; + + let node_hash_count = node_count.checked_sub(external_digest_count).ok_or_else(|| { + DeserializationError::InvalidValue("node hash count underflow".to_string()) + })?; + let node_hash_offset = if is_hashless { + None + } else { + let offset = source.offset(); + let node_hash_len = + node_hash_count.checked_mul(crate::Word::min_serialized_size()).ok_or_else(|| { + DeserializationError::InvalidValue("node hash length overflow".to_string()) + })?; + let _node_hashes = source.read_slice(node_hash_len)?; + Some(offset) + }; + + Ok(ForestLayout { + node_count, + roots_count, + roots_offset, + basic_block_offset, + basic_block_len, + node_entry_offset, + external_digest_offset, + #[cfg(test)] + external_digest_count, + node_hash_offset, + #[cfg(test)] + node_hash_count, + }) +} + +fn validate_budgeted_count( + source: &R, + count: usize, + element_size: usize, + label: &str, +) -> Result<(), DeserializationError> { + let max_count = source.max_alloc(element_size); + if count > max_count { + return Err(DeserializationError::InvalidValue(format!( + "{label} {count} exceeds reader allocation bound {max_count} for {element_size}-byte elements", + ))); + } + + Ok(()) +} + +fn read_and_validate_header( + source: &mut R, +) -> Result<(u8, [u8; 3]), DeserializationError> { + let magic: [u8; 4] = source.read_array()?; + if magic != *MAGIC { + return Err(DeserializationError::InvalidValue(format!( + "Invalid magic bytes. Expected '{:?}', got '{:?}'", + *MAGIC, magic + ))); + } + + let flags: u8 = source.read_u8()?; + + let version: [u8; 3] = source.read_array()?; + if version != VERSION { + return Err(DeserializationError::InvalidValue(format!( + "Unsupported version. Got '{version:?}', but only '{VERSION:?}' is supported", + ))); + } + + if flags & FLAGS_RESERVED_MASK != 0 { + return Err(DeserializationError::InvalidValue(format!( + "Unknown flags set in MAST header: {:#04x}. Reserved bits must be zero.", + flags & FLAGS_RESERVED_MASK + ))); + } + + Ok((flags, version)) +} + +// HELPERS +// ================================================================================================ + +pub(super) fn read_fixed_section_entry<'a>( + bytes: &'a [u8], + section_offset: usize, + entry_size: usize, + index: usize, + section_name: &str, +) -> Result<&'a [u8], DeserializationError> { + let entry_offset = index + .checked_mul(entry_size) + .and_then(|delta| section_offset.checked_add(delta)) + .ok_or_else(|| { + DeserializationError::InvalidValue(format!("{section_name} offset overflow")) + })?; + let entry_end = entry_offset.checked_add(entry_size).ok_or_else(|| { + DeserializationError::InvalidValue(format!("{section_name} length overflow")) + })?; + if entry_end > bytes.len() { + return Err(DeserializationError::UnexpectedEOF); + } + + Ok(&bytes[entry_offset..entry_end]) +} diff --git a/core/src/mast/serialization/mod.rs b/core/src/mast/serialization/mod.rs index 6fdd0c91d7..d49fcf74a4 100644 --- a/core/src/mast/serialization/mod.rs +++ b/core/src/mast/serialization/mod.rs @@ -1,11 +1,44 @@ -//! The serialization format of MastForest is as follows: +//! MAST forest serialization keeps one fixed structural layout for full, stripped, and hashless +//! payloads. +//! +//! The main goal is to keep random access cheap in stripped and hashless modes. Node structure +//! stays in one fixed-width section. Variable-size data lives in separate sections. Internal node +//! digests also live in a separate section so hashless payloads can omit them without changing the +//! structural layout. +//! +//! Wire flags describe serializer intent, not reader trust policy. Trusted [`MastForest`] reads +//! reject hashless payloads. [`crate::mast::UntrustedMastForest`] accepts them and rebuilds +//! non-external digests before use. If a non-hashless payload is sent down the untrusted path, +//! validation recomputes those digests and requires them to match the serialized values. +//! Budgeted untrusted reads always bound wire counts during layout scanning via +//! [`ByteReader::max_alloc`]. Callers that opt into validation budgeting also get a second check: +//! - later stripped/hashless helper allocations are charged against an explicit validation budget +//! before the corresponding `Vec` or CSR scaffolding is created +//! - the default convenience path uses a coarse validation budget derived from the input size; this +//! is intentionally a simple bound for common callers, not an exact peak-memory formula +//! +//! The main layers fit together like this: +//! +//! ```text +//! wire bytes +//! | +//! +--> ForestLayout -----------> SerializedMastForest --+ +//! | absolute offsets structural view | +//! | v +//! +--> UntrustedMastForest ----validate----> ResolvedSerializedForest ---> MastForest +//! bytes + parsed state digest-backed view trusted runtime +//! +//! MastForestView is the shared random-access API implemented by SerializedMastForest and +//! MastForest. +//! ``` +//! +//! The format is: //! //! (Metadata) //! - MAGIC (4 bytes) + FLAGS (1 byte) + VERSION (3 bytes) //! //! (Counts) //! - nodes count (`usize`) -//! - decorators count (`usize`) - 0 if stripped, reserved for future use in lazy loading (#2504) //! //! (Procedure roots section) //! - procedure roots (`Vec` as MastNodeId values) @@ -13,8 +46,17 @@ //! (Basic block data section) //! - basic block data (padded operations + batch metadata) //! -//! (Node info section) -//! - MAST node infos (`Vec`) +//! (Node entries section) +//! - fixed-width structural node entries (`Vec`) +//! - `Block` entries store offsets into the basic-block section above +//! +//! (External digest section) +//! - digests for `External` nodes only (`Vec`, ordered by node index) +//! - lookup is dense-by-kind: the Nth external node uses slot N in this section +//! +//! (Node hash section - omitted if FLAGS bit 1 is set) +//! - digests for all non-external nodes (`Vec`, ordered by node index) +//! - lookup is also dense-by-kind: the Nth non-external node uses slot N in this section //! //! (Advice map section) //! - Advice map (`AdviceMap`) @@ -28,28 +70,62 @@ //! - NodeToDecoratorIds CSR (before_enter and after_exit decorators, dense representation) //! - Procedure names map (`BTreeMap`) //! -//! # Stripped Format +//! In stripped format, the `DebugInfo` section is omitted and readers materialize an empty +//! `DebugInfo`. +//! +//! In hashless format, the internal node-hash section is omitted and `HASHLESS` also implies +//! `STRIPPED`. External node digests still stay on the wire because they cannot be rebuilt from +//! local structure. This keeps hashless focused on the untrusted-validation use case: trusted +//! reads reject `HASHLESS`, and the untrusted path rebuilds the data it actually trusts before +//! use, so supporting a separate "hashless but with debug info" mode would add another wire mode +//! without changing the validation semantics. //! -//! When serializing with [`MastForest::write_stripped`], the FLAGS byte has bit 0 set -//! and the entire DebugInfo section is omitted. Deserialization auto-detects the format -//! and creates an empty `DebugInfo` with valid CSR structures when reading stripped files. +//! Readers recover per-node digest lookup by scanning node entries once and building a compact +//! "slot by node index" table. This preserves random access without forcing all digests into the +//! same contiguous array on the wire. +//! +//! Public entry points adopt these policies: +//! - [`MastForest::read_from_bytes`]: trusted full payload, no hashless support. +//! - [`SerializedMastForest::new`]: structural inspection for local tooling, including hashless +//! payloads; not an untrusted-validation entry point. +//! - [`crate::mast::UntrustedMastForest::read_from_bytes`] / +//! [`crate::mast::UntrustedMastForest::read_from_bytes_with_budgets`]: untrusted parsing plus +//! later validation before use. + +#[cfg(test)] +use alloc::string::ToString; +use alloc::{format, vec::Vec}; -use alloc::vec::Vec; +use miden_utils_sync::OnceLockCompat; use super::{MastForest, MastNode, MastNodeId}; use crate::{ advice::AdviceMap, - serde::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable}, + mast::node::MastNodeExt, + serde::{ + BudgetedReader, ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable, + SliceReader, + }, }; pub(crate) mod asm_op; pub(crate) mod decorator; mod info; -use info::MastNodeInfo; +pub use info::{MastNodeEntry, MastNodeInfo}; + +mod view; +pub use view::MastForestView; + +mod layout; +pub(super) use layout::ForestLayout; +use layout::{TrackingReader, WireFlags, read_header_and_scan_layout}; + +mod resolved; +use resolved::{ResolvedSerializedForest, basic_block_offset_for_node_index}; mod basic_blocks; -use basic_blocks::{BasicBlockDataBuilder, BasicBlockDataDecoder}; +use basic_blocks::{BasicBlockDataBuilder, basic_block_data_len}; pub(crate) mod string_table; pub(crate) use string_table::StringTable; @@ -75,30 +151,60 @@ type StringDataOffset = usize; /// Specifies an offset into the strings table of an encoded [`MastForest`]. type StringIndex = usize; +/// Default multiplier for the untrusted validation allocation budget. +/// +/// The budgeted byte reader limits wire-driven parsing. Hashless and stripped validation also +/// needs transient per-node allocations for the slot table, empty debug-info scaffolding, and +/// rebuilt digest table. The generic untrusted path also retains a recorded copy of the consumed +/// serialized payload for deferred validation. +/// +/// This convenience multiplier is therefore a coarse "wire bytes plus worst-case helper +/// headroom" bound: +/// - `* 6` covers the helper-allocation model introduced with explicit validation budgeting +/// - `+ 1 * bytes_len` covers the retained serialized copy recorded during untrusted reads +/// +/// It is deliberately conservative and exists to make the default +/// [`crate::mast::UntrustedMastForest::read_from_bytes`] path usable without forcing callers to +/// size each helper allocation themselves. Callers with stricter limits should use +/// [`crate::mast::UntrustedMastForest::read_from_bytes_with_budgets`] and choose explicit parsing +/// and validation budgets. +const DEFAULT_UNTRUSTED_ALLOCATION_BUDGET_MULTIPLIER: usize = 7; + +/// Byte-read budget multiplier for trusted full deserialization from a byte slice. +/// +/// The budget is intentionally finite to reject malicious length prefixes, but larger than the +/// source length because collection deserialization uses conservative per-element size estimates. +const TRUSTED_BYTE_READ_BUDGET_MULTIPLIER: usize = 64; + // CONSTANTS // ================================================================================================ /// Magic bytes for detecting that a file is binary-encoded MAST. /// -/// The format uses 4 bytes for identification followed by a flags byte: -/// - Bytes 0-3: `b"MAST"` - Magic identifier -/// - Byte 4: Flags byte (see [`FLAG_STRIPPED`] and [`FLAGS_RESERVED_MASK`] constants) +/// The header is `b"MAST"` + flags byte + version bytes. /// -/// This design repurposes the original null terminator (`b"MAST\0"`) as a flags byte, -/// maintaining backward compatibility: old files have flags=0x00 (the null byte), -/// which means "debug info present". +/// This repurposes the old `b"MAST\0"` terminator as the flags byte, so legacy payloads still +/// decode as "debug info present". const MAGIC: &[u8; 4] = b"MAST"; -/// Flag indicating debug info is stripped from the serialized MastForest. +/// Flag indicating that the `DebugInfo` section is omitted from the wire payload. /// -/// When this bit is set in the flags byte, the DebugInfo section is omitted entirely. -/// The deserializer will create an empty `DebugInfo` with valid CSR structures. +/// Readers treat this as serializer intent about the wire layout, not as a trust decision. const FLAG_STRIPPED: u8 = 0x01; +/// Flag indicating that the internal node-hash section is omitted from the wire payload. +/// +/// External digests still remain serialized in their own section because they cannot be rebuilt +/// from local structure. This flag implies [`FLAG_STRIPPED`] because no supported consumer treats +/// wire `DebugInfo` as trusted in hashless mode: [`crate::mast::MastForest`] rejects `HASHLESS`, +/// [`SerializedMastForest::new`] accepts it only for structural inspection, and the untrusted path +/// rebuilds the data it actually trusts before use. +pub(super) const FLAG_HASHLESS: u8 = 0x02; + /// Mask for reserved flag bits that must be zero. /// -/// Bits 1-7 are reserved for future use. If any are set, deserialization fails. -const FLAGS_RESERVED_MASK: u8 = 0xfe; +/// Bits 2-7 are reserved for future use. If any are set, deserialization fails. +const FLAGS_RESERVED_MASK: u8 = 0xfc; /// The format version. /// @@ -115,14 +221,19 @@ const FLAGS_RESERVED_MASK: u8 = 0xfe; /// - [0, 0, 2]: Removed AssemblyOp from Decorator enum serialization. AssemblyOps are now stored /// separately in DebugInfo. Removed `should_break` field from AssemblyOp serialization (#2646). /// Removed `breakpoint` instruction (#2655). -const VERSION: [u8; 3] = [0, 0, 2]; +/// - [0, 0, 3]: Added HASHLESS flag (bit 1). HASHLESS implies STRIPPED. Trusted deserialization +/// rejects HASHLESS. Split fixed-width node entries from digest storage. External digests moved +/// to a dedicated section. Hashless serialization omits the general node-hash section entirely. +/// Dropped the serialized decorator-count field because it was not used by the wire layout or +/// deserializers. +const VERSION: [u8; 3] = [0, 0, 3]; // MAST FOREST SERIALIZATION/DESERIALIZATION // ================================================================================================ impl Serializable for MastForest { fn write_into(&self, target: &mut W) { - self.write_into_with_options(target, false); + self.write_into_with_options(target, false, false); } } @@ -131,46 +242,64 @@ impl MastForest { /// /// When `stripped` is true, the DebugInfo section is omitted and the FLAGS byte /// has bit 0 set. - fn write_into_with_options(&self, target: &mut W, stripped: bool) { + fn write_into_with_options( + &self, + target: &mut W, + stripped: bool, + hashless: bool, + ) { let mut basic_block_data_builder = BasicBlockDataBuilder::new(); // magic & flags target.write_bytes(MAGIC); - target.write_u8(if stripped { FLAG_STRIPPED } else { 0x00 }); + let flags = if stripped || hashless { FLAG_STRIPPED } else { 0 } + | if hashless { FLAG_HASHLESS } else { 0 }; + target.write_u8(flags); // version target.write_bytes(&VERSION); - // node & decorator counts + // node count target.write_usize(self.nodes.len()); - target.write_usize(if stripped { 0 } else { self.debug_info.num_decorators() }); // roots let roots: Vec = self.roots.iter().copied().map(u32::from).collect(); roots.write_into(target); - // Prepare MAST node infos, but don't store them yet. We store them at the end to make - // deserialization more efficient. - let mast_node_infos: Vec = self - .nodes - .iter() - .map(|mast_node| { - let ops_offset = if let MastNode::Block(basic_block) = mast_node { - basic_block_data_builder.encode_basic_block(basic_block) - } else { - 0 - }; - - MastNodeInfo::new(mast_node, ops_offset) - }) - .collect(); + let mut mast_node_entries = Vec::with_capacity(self.nodes.len()); + let mut external_digests = Vec::new(); + let mut node_hashes = Vec::new(); + + for mast_node in self.nodes.iter() { + let ops_offset = if let MastNode::Block(basic_block) = mast_node { + basic_block_data_builder.encode_basic_block(basic_block) + } else { + 0 + }; + + mast_node_entries.push(MastNodeEntry::new(mast_node, ops_offset)); + if mast_node.is_external() { + external_digests.push(mast_node.digest()); + } else if !hashless { + node_hashes.push(mast_node.digest()); + } + } let basic_block_data = basic_block_data_builder.finalize(); basic_block_data.write_into(target); - // Write node infos - for mast_node_info in mast_node_infos { - mast_node_info.write_into(target); + for mast_node_entry in mast_node_entries { + mast_node_entry.write_into(target); + } + + for digest in external_digests { + digest.write_into(target); + } + + if !hashless { + for digest in node_hashes { + digest.write_into(target); + } } self.advice_map.write_into(target); @@ -182,134 +311,524 @@ impl MastForest { } } -impl Deserializable for MastForest { - fn read_from(source: &mut R) -> Result { - let flags = read_and_validate_header(source)?; - let is_stripped = flags & FLAG_STRIPPED != 0; - - // Reading sections metadata - let node_count = source.read_usize()?; - if node_count > MastForest::MAX_NODES { - return Err(DeserializationError::InvalidValue(format!( - "node count {} exceeds maximum allowed {}", - node_count, - MastForest::MAX_NODES - ))); +pub(super) fn write_stripped_into(forest: &MastForest, target: &mut W) { + forest.write_into_with_options(target, true, false); +} + +pub(super) fn write_hashless_into(forest: &MastForest, target: &mut W) { + forest.write_into_with_options(target, true, true); +} + +pub(super) fn stripped_size_hint(forest: &MastForest) -> usize { + serialized_size_hint(forest, true, false) +} + +fn serialized_size_hint(forest: &MastForest, stripped: bool, hashless: bool) -> usize { + let node_count = forest.nodes.len(); + let external_count = forest.nodes.iter().filter(|node| node.is_external()).count(); + let non_external_count = node_count - external_count; + + let mut size = MAGIC.len() + 1 + VERSION.len(); + size += node_count.get_size_hint(); + + let roots_len = forest.roots.len(); + size += roots_len.get_size_hint(); + size += roots_len * size_of::(); + + let mut basic_block_len = 0usize; + for node in forest.nodes.iter() { + if let MastNode::Block(block) = node { + basic_block_len += basic_block_data_len(block); } - let _decorator_count = source.read_usize()?; // Read for wire format compatibility + } + size += basic_block_len.get_size_hint() + basic_block_len; + + size += node_count * MastNodeEntry::SERIALIZED_SIZE; + size += external_count * crate::Word::min_serialized_size(); + if !hashless { + size += non_external_count * crate::Word::min_serialized_size(); + } + size += forest.advice_map.serialized_size_hint(); + if !stripped { + size += forest.debug_info.get_size_hint(); + } + + size +} - // Reading procedure roots - let roots: Vec = Deserializable::read_from(source)?; +/// A zero-copy structural view over serialized MAST forest bytes. +/// +/// This view accepts full, stripped, and hashless payloads. It validates the header and the +/// fixed-width structural sections needed for random access, but it does not fully materialize the +/// forest. +/// +/// Use this when callers need random access to roots or node metadata without deserializing the +/// full forest. For strict trusted deserialization, use +/// [`crate::mast::MastForest::read_from_bytes`]. +/// +/// # Examples +/// +/// ``` +/// use miden_core::{ +/// mast::{BasicBlockNodeBuilder, MastForest, MastForestContributor, SerializedMastForest}, +/// operations::Operation, +/// }; +/// +/// let mut forest = MastForest::new(); +/// let block_id = BasicBlockNodeBuilder::new(vec![Operation::Add], Vec::new()) +/// .add_to_forest(&mut forest) +/// .unwrap(); +/// forest.make_root(block_id); +/// +/// let mut bytes = Vec::new(); +/// forest.write_stripped(&mut bytes); +/// +/// let view = SerializedMastForest::new(&bytes).unwrap(); +/// assert_eq!(view.node_count(), forest.nodes().len()); +/// assert!(view.node_info_at(0).is_ok()); +/// ``` +#[derive(Debug)] +pub struct SerializedMastForest<'a> { + bytes: &'a [u8], + flags: WireFlags, + layout: ForestLayout, + resolved: OnceLockCompat, DeserializationError>>, +} - // Reading nodes - let basic_block_data: Vec = Deserializable::read_from(source)?; - let mast_node_infos: Vec = node_infos_iter(source, node_count) - .collect::, DeserializationError>>()?; +impl<'a> SerializedMastForest<'a> { + /// Creates a new view from serialized bytes. + /// + /// The input may be full, stripped, or hashless format. + /// Structural parsing is delegated to the same single-pass scanner used by reader-based + /// deserialization paths. + /// + /// This constructor is layout-oriented: it validates the header and sections needed for + /// node/roots/random-access metadata only. It does not validate or fully parse trailing + /// `AdviceMap` / `DebugInfo` payloads. + /// + /// Treat this as a trusted inspection API, not as an untrusted-validation entry point. It is + /// appropriate for local tools that need random access over serialized structure, but callers + /// handling adversarial bytes should use [`crate::mast::UntrustedMastForest`] instead. + /// + /// In particular, this constructor does **not** protect callers from untrusted-input concerns + /// that are enforced by [`crate::mast::UntrustedMastForest::validate`]. It does not: + /// - verify that serialized non-external digests match the structure they describe + /// - check topological ordering / forward-reference constraints + /// - validate basic-block batch invariants or procedure-name-root consistency + /// - fully parse or validate trailing `AdviceMap` / `DebugInfo` payloads + /// - provide a bounded-work guarantee for hashless digest-backed inspection + /// + /// For strict full-payload validation, use + /// [`crate::mast::MastForest::read_from_bytes`]. + /// + /// Wire flags describe serializer intent, not trust policy. This constructor accepts + /// hashless payloads for inspection even though trusted [`crate::mast::MastForest`] + /// deserialization rejects them. + /// + /// Digest lookup follows the wire layout: + /// - If the internal-hash section is present, non-external node digests are read from it. + /// - If the internal-hash section is absent, the first digest-backed access rebuilds all + /// non-external node digests from structure and caches them. + /// - External node digests are always read from the external-digest section. + /// + /// # Examples + /// + /// ``` + /// use miden_core::{ + /// mast::{BasicBlockNodeBuilder, MastForest, MastForestContributor, SerializedMastForest}, + /// operations::Operation, + /// }; + /// + /// let mut forest = MastForest::new(); + /// let block_id = BasicBlockNodeBuilder::new(vec![Operation::Add], Vec::new()) + /// .add_to_forest(&mut forest) + /// .unwrap(); + /// forest.make_root(block_id); + /// + /// let mut bytes = Vec::new(); + /// forest.write_stripped(&mut bytes); + /// + /// let view = SerializedMastForest::new(&bytes).unwrap(); + /// assert_eq!(view.node_count(), 1); + /// ``` + pub fn new(bytes: &'a [u8]) -> Result { + let mut reader = SliceReader::new(bytes); + let mut scanner = TrackingReader::new(&mut reader); + let (flags, layout) = read_header_and_scan_layout(&mut scanner, true)?; + + Ok(Self { + bytes, + flags, + layout, + resolved: OnceLockCompat::new(), + }) + } - let advice_map = AdviceMap::read_from(source)?; + /// Returns the number of nodes in the serialized forest. + pub fn node_count(&self) -> usize { + self.layout.node_count + } - // Deserialize DebugInfo or create empty one if stripped - let debug_info = if is_stripped { - super::DebugInfo::empty_for_nodes(node_count) + /// Returns `true` when the wire header says that the internal-hash section is omitted. + pub fn is_hashless(&self) -> bool { + self.flags.is_hashless() + } + + /// Returns `true` when the wire header says that the `DebugInfo` section is omitted. + pub fn is_stripped(&self) -> bool { + self.flags.is_stripped() + } + + /// Returns the number of procedure roots in the serialized forest. + pub fn procedure_root_count(&self) -> usize { + self.layout.roots_count + } + + /// Returns the procedure root id at the specified index. + /// + /// Returns an error if `index >= self.procedure_root_count()`. + pub fn procedure_root_at(&self, index: usize) -> Result { + self.layout.read_procedure_root_at(self.bytes, index) + } + + /// Returns the `MastNodeInfo` at the specified index. + /// + /// On hashless payloads, this may trigger the first digest-backed access and therefore the + /// one-time rebuild of the non-external digest table described in [`Self::node_digest_at`]. + /// + /// Returns an error if `index >= self.node_count()`. + /// + /// # Examples + /// + /// ``` + /// use miden_core::{ + /// mast::{BasicBlockNodeBuilder, MastForest, MastForestContributor, SerializedMastForest}, + /// operations::Operation, + /// }; + /// + /// let mut forest = MastForest::new(); + /// let block_id = BasicBlockNodeBuilder::new(vec![Operation::Add], Vec::new()) + /// .add_to_forest(&mut forest) + /// .unwrap(); + /// forest.make_root(block_id); + /// + /// let mut bytes = Vec::new(); + /// forest.write_stripped(&mut bytes); + /// + /// let view = SerializedMastForest::new(&bytes).unwrap(); + /// assert!(view.node_info_at(0).is_ok()); + /// ``` + pub fn node_info_at(&self, index: usize) -> Result { + Ok(MastNodeInfo::from_entry( + self.node_entry_at(index)?, + self.node_digest_at(index)?, + )) + } + + /// Returns the fixed-width structural node entry at the specified index. + /// + /// Returns an error if `index >= self.node_count()`. + pub fn node_entry_at(&self, index: usize) -> Result { + self.layout.read_node_entry_at(self.bytes, index) + } + + /// Returns the digest for the node at the specified index. + /// + /// This resolves digests lazily. If the internal-hash section is absent, the first + /// digest-backed access rebuilds all non-external node digests and caches them. + /// + /// This means the hashless cost model is: + /// - `node_count()`, `node_entry_at()`, and `procedure_root_at()` stay cheap and structural + /// - the first `node_digest_at()` / `node_info_at()` call does `O(node_count)` digest rebuild + /// work and allocates the cached digest table + /// - later digest lookups reuse that cache + /// + /// Returns an error if `index >= self.node_count()`. + pub fn node_digest_at(&self, index: usize) -> Result { + self.resolved()?.node_digest_at(index) + } + + fn resolved(&self) -> Result<&ResolvedSerializedForest<'a>, DeserializationError> { + self.resolved + .get_or_init(|| ResolvedSerializedForest::new(self.bytes, self.layout)) + .as_ref() + .map_err(Clone::clone) + } +} + +impl MastForestView for SerializedMastForest<'_> { + fn node_count(&self) -> usize { + SerializedMastForest::node_count(self) + } + + fn node_entry_at(&self, index: usize) -> Result { + SerializedMastForest::node_entry_at(self, index) + } + + fn node_digest_at(&self, index: usize) -> Result { + SerializedMastForest::node_digest_at(self, index) + } + + fn procedure_root_count(&self) -> usize { + SerializedMastForest::procedure_root_count(self) + } + + fn procedure_root_at(&self, index: usize) -> Result { + SerializedMastForest::procedure_root_at(self, index) + } +} + +impl MastForestView for MastForest { + fn node_count(&self) -> usize { + self.nodes.len() + } + + fn node_entry_at(&self, index: usize) -> Result { + let node = self.nodes.as_slice().get(index).ok_or_else(|| { + DeserializationError::InvalidValue(format!("node index {index} out of bounds")) + })?; + let ops_offset = if matches!(node, MastNode::Block(_)) { + basic_block_offset_for_node_index(self.nodes.as_slice(), index)? } else { - super::DebugInfo::read_from(source)? + 0 }; - // Constructing MastForest - let mast_forest = { - let mut mast_forest = MastForest::new(); - - // Set the fully deserialized debug_info - it already contains all mappings - mast_forest.debug_info = debug_info; - - // Convert node infos to builders - let basic_block_data_decoder = BasicBlockDataDecoder::new(&basic_block_data); - let mast_builders = mast_node_infos - .into_iter() - .map(|node_info| { - node_info.try_into_mast_node_builder(node_count, &basic_block_data_decoder) - }) - .collect::, _>>()?; - - // Add all builders to forest using relaxed validation - for mast_node_builder in mast_builders { - mast_node_builder.add_to_forest_relaxed(&mut mast_forest).map_err(|e| { - DeserializationError::InvalidValue(format!( - "failed to add node to MAST forest while deserializing: {e}", - )) - })?; - } + Ok(MastNodeEntry::new(node, ops_offset)) + } - // roots - for root in roots { - // make sure the root is valid in the context of the MAST forest - let root = MastNodeId::from_u32_safe(root, &mast_forest)?; - mast_forest.make_root(root); - } + fn node_digest_at(&self, index: usize) -> Result { + self.nodes.as_slice().get(index).map(MastNode::digest).ok_or_else(|| { + DeserializationError::InvalidValue(format!("node index {index} out of bounds")) + }) + } - mast_forest.advice_map = advice_map; + fn procedure_root_count(&self) -> usize { + self.roots.len() + } - mast_forest - }; + fn procedure_root_at(&self, index: usize) -> Result { + self.roots.get(index).copied().ok_or_else(|| { + DeserializationError::InvalidValue(format!( + "root index {} out of bounds for {} roots", + index, + self.roots.len() + )) + }) + } +} + +// TEST HELPERS +// ================================================================================================ + +#[cfg(test)] +impl SerializedMastForest<'_> { + fn advice_map_offset(&self) -> Result { + self.layout.advice_map_offset(self.bytes.len()) + } + + fn node_entry_offset(&self) -> usize { + self.layout.node_entry_offset + } - // Note: Full validation of deserialized MastForests (e.g., checking that procedure name - // digests correspond to procedure roots) is intentionally not performed here. - // The serialized format is expected to come from a trusted source (e.g., the assembler - // or a verified package). Callers should use MastForest::validate() if validation of - // untrusted input is needed. + fn node_hash_offset(&self) -> Option { + self.layout.node_hash_offset + } - Ok(mast_forest) + fn digest_slot_at(&self, index: usize) -> usize { + self.resolved() + .expect("digest slots should be readable for a valid serialized view") + .digest_slot_at(index) } } -/// Reads and validates the MAST header (magic, flags, version). -/// -/// Returns the flags byte on success. -fn read_and_validate_header(source: &mut R) -> Result { - // Read magic - let magic: [u8; 4] = source.read_array()?; - if magic != *MAGIC { - return Err(DeserializationError::InvalidValue(format!( - "Invalid magic bytes. Expected '{:?}', got '{:?}'", - *MAGIC, magic - ))); +#[cfg(test)] +fn read_u8_at(bytes: &[u8], offset: &mut usize) -> Result { + read_slice_at(bytes, offset, 1).map(|slice| slice[0]) +} + +#[cfg(test)] +fn read_array_at( + bytes: &[u8], + offset: &mut usize, +) -> Result<[u8; N], DeserializationError> { + let slice = read_slice_at(bytes, offset, N)?; + let mut result = [0u8; N]; + result.copy_from_slice(slice); + Ok(result) +} + +#[cfg(test)] +fn read_slice_at<'a>( + bytes: &'a [u8], + offset: &mut usize, + len: usize, +) -> Result<&'a [u8], DeserializationError> { + let end = offset + .checked_add(len) + .ok_or_else(|| DeserializationError::InvalidValue("offset overflow".to_string()))?; + if end > bytes.len() { + return Err(DeserializationError::UnexpectedEOF); } + let slice = &bytes[*offset..end]; + *offset = end; + Ok(slice) +} - // Read and validate flags - let flags: u8 = source.read_u8()?; - if flags & FLAGS_RESERVED_MASK != 0 { +// NOTE: Mirrors ByteReader::read_usize (vint64) decoding to preserve wire compatibility. +#[cfg(test)] +fn read_usize_at(bytes: &[u8], offset: &mut usize) -> Result { + if *offset >= bytes.len() { + return Err(DeserializationError::UnexpectedEOF); + } + let first_byte = bytes[*offset]; + let length = first_byte.trailing_zeros() as usize + 1; + + let result = if length == 9 { + let _marker = read_u8_at(bytes, offset)?; + let value = read_array_at::<8>(bytes, offset)?; + u64::from_le_bytes(value) + } else { + let mut encoded = [0u8; 8]; + let value = read_slice_at(bytes, offset, length)?; + encoded[..length].copy_from_slice(value); + u64::from_le_bytes(encoded) >> length + }; + + if result > usize::MAX as u64 { return Err(DeserializationError::InvalidValue(format!( - "Unknown flags set in MAST header: {:#04x}. Reserved bits must be zero.", - flags & FLAGS_RESERVED_MASK + "Encoded value must be less than {}, but {} was provided", + usize::MAX, + result ))); } - // Read and validate version - let version: [u8; 3] = source.read_array()?; - if version != VERSION { + Ok(result as usize) +} + +impl Deserializable for MastForest { + fn read_from(source: &mut R) -> Result { + let (_flags, forest) = decode_from_reader(source, false)?; + forest.into_materialized() + } + + fn read_from_bytes(bytes: &[u8]) -> Result { + let budget = bytes.len().saturating_mul(TRUSTED_BYTE_READ_BUDGET_MULTIPLIER); + let mut reader = BudgetedReader::new(SliceReader::new(bytes), budget); + Self::read_from(&mut reader) + } +} + +impl super::UntrustedMastForest { + pub(super) fn into_materialized(self) -> Result { + let resolved = if let Some(allocation_budget) = self.remaining_allocation_budget { + ResolvedSerializedForest::new_with_allocation_budget( + &self.bytes, + self.layout, + allocation_budget, + )? + } else { + ResolvedSerializedForest::new(&self.bytes, self.layout)? + }; + + resolved.materialize(self.advice_map, self.debug_info) + } +} + +pub(super) fn read_untrusted_with_flags( + source: &mut R, +) -> Result<(super::UntrustedMastForest, u8), DeserializationError> { + let (flags, forest) = decode_from_reader(source, true)?; + log_untrusted_overspecification(flags); + Ok((forest, flags.bits())) +} + +pub(super) fn read_untrusted_with_flags_and_allocation_budget( + source: &mut R, + allocation_budget: usize, +) -> Result<(super::UntrustedMastForest, u8), DeserializationError> { + let (flags, forest) = decode_from_reader_inner(source, true, Some(allocation_budget))?; + log_untrusted_overspecification(flags); + Ok((forest, flags.bits())) +} + +fn log_untrusted_overspecification(flags: WireFlags) { + if !flags.is_hashless() { + log::error!( + "UntrustedMastForest expected HASHLESS input; supplied artifact includes wire node hashes, and validation will recompute them and require them to match" + ); + } + + if !flags.is_stripped() { + log::error!( + "UntrustedMastForest expected STRIPPED input; supplied artifact includes DebugInfo and other optional payloads over the wire" + ); + } +} + +fn decode_from_reader( + source: &mut R, + allow_hashless: bool, +) -> Result<(WireFlags, super::UntrustedMastForest), DeserializationError> { + decode_from_reader_inner(source, allow_hashless, None) +} + +fn decode_from_reader_inner( + source: &mut R, + allow_hashless: bool, + mut remaining_allocation_budget: Option, +) -> Result<(WireFlags, super::UntrustedMastForest), DeserializationError> { + let mut recording = TrackingReader::new_recording(source); + let (flags, layout) = read_header_and_scan_layout(&mut recording, allow_hashless)?; + + let advice_map = AdviceMap::read_from(&mut recording)?; + let debug_info = if flags.is_stripped() { + if let Some(allocation_budget) = &mut remaining_allocation_budget { + reserve_allocation::( + allocation_budget, + layout.node_count.checked_add(1).ok_or_else(|| { + DeserializationError::InvalidValue("debug-info node count overflow".into()) + })?, + "empty debug-info scaffolding", + )?; + } + super::DebugInfo::empty_for_nodes(layout.node_count) + } else { + super::DebugInfo::read_from(&mut recording)? + }; + + Ok(( + flags, + super::UntrustedMastForest { + bytes: recording.into_recorded(), + layout, + advice_map, + debug_info, + remaining_allocation_budget, + }, + )) +} + +pub(super) fn reserve_allocation( + remaining_budget: &mut usize, + count: usize, + label: &str, +) -> Result<(), DeserializationError> { + let bytes_needed = count + .checked_mul(size_of::()) + .ok_or_else(|| DeserializationError::InvalidValue(format!("{label} size overflow")))?; + if bytes_needed > *remaining_budget { return Err(DeserializationError::InvalidValue(format!( - "Unsupported version. Got '{version:?}', but only '{VERSION:?}' is supported", + "{label} requires {bytes_needed} bytes, exceeding the remaining untrusted allocation budget of {} bytes", + *remaining_budget ))); } - Ok(flags) + *remaining_budget -= bytes_needed; + Ok(()) } -fn node_infos_iter<'a, R>( - source: &'a mut R, - node_count: usize, -) -> impl Iterator> + 'a -where - R: ByteReader + 'a, -{ - let mut remaining = node_count; - core::iter::from_fn(move || { - if remaining == 0 { - return None; - } - remaining -= 1; - Some(MastNodeInfo::read_from(source)) - }) +pub(super) fn default_untrusted_allocation_budget(bytes_len: usize) -> usize { + bytes_len.saturating_mul(DEFAULT_UNTRUSTED_ALLOCATION_BUDGET_MULTIPLIER) } // UNTRUSTED DESERIALIZATION @@ -325,14 +844,13 @@ impl Deserializable for super::UntrustedMastForest { /// to verify structural integrity and recompute all node hashes before using /// the forest. fn read_from(source: &mut R) -> Result { - let forest = MastForest::read_from(source)?; - Ok(super::UntrustedMastForest(forest)) + read_untrusted_with_flags(source).map(|(forest, _flags)| forest) } /// Deserializes an [`super::UntrustedMastForest`] from bytes using budgeted deserialization. /// - /// This method uses a [`crate::serde::BudgetedReader`] with a budget equal to the input size - /// to protect against denial-of-service attacks from malicious input. + /// This method uses the default untrusted wire/validation budget from + /// [`super::UntrustedMastForest::read_from_bytes`]. /// /// After deserialization, callers should use [`super::UntrustedMastForest::validate()`] /// to verify structural integrity and recompute all node hashes before using @@ -341,22 +859,3 @@ impl Deserializable for super::UntrustedMastForest { super::UntrustedMastForest::read_from_bytes(bytes) } } - -// STRIPPED SERIALIZATION -// ================================================================================================ - -/// Wrapper for serializing a [`MastForest`] without debug information. -/// -/// This newtype enables an alternative serialization format that omits the DebugInfo section, -/// producing smaller output files suitable for production deployment where debug info is not -/// needed. -/// -/// The resulting bytes can be deserialized with the standard [`Deserializable`] impl for -/// [`MastForest`], which auto-detects the format via the flags byte in the header. -pub(super) struct StrippedMastForest<'a>(pub(super) &'a MastForest); - -impl Serializable for StrippedMastForest<'_> { - fn write_into(&self, target: &mut W) { - self.0.write_into_with_options(target, true); - } -} diff --git a/core/src/mast/serialization/resolved.rs b/core/src/mast/serialization/resolved.rs new file mode 100644 index 0000000000..dd1ca83e41 --- /dev/null +++ b/core/src/mast/serialization/resolved.rs @@ -0,0 +1,408 @@ +use alloc::{format, string::ToString, vec::Vec}; + +use super::{ + AdviceMap, ForestLayout, MastForest, MastNodeEntry, MastNodeId, basic_block_data_len, + reserve_allocation, +}; +use crate::{ + Felt, + chiplets::hasher, + mast::{ + CallNode, DebugInfo, DynNode, JoinNode, LoopNode, SplitNode, + serialization::{basic_blocks::BasicBlockDataDecoder, layout::read_fixed_section_entry}, + }, + serde::{Deserializable, DeserializationError, SliceReader}, +}; + +/// Digest sources for a parsed serialized forest. +/// +/// Non-external nodes either read from the internal-hash section or from a rebuilt in-memory hash +/// table. External nodes always read from the external-digest section. +#[derive(Debug, Clone)] +struct ForestDigests { + /// Dense slot index for each node within its digest section. + /// + /// External nodes index into the external-digest section. All other nodes index into the + /// general node-hash section or the rebuilt hash table. + slot_by_node: Vec, + /// Source of non-external digests. + /// + /// `None` means the serialized bytes still contain the internal node-hash section, so + /// lookups read directly from the wire. `Some(...)` means the payload was hashless and the + /// non-external digests have been recomputed once into this cache. + hash_table: Option>, +} + +/// A serialized forest whose digest source has been resolved. +/// +/// This is the elaborated layer between raw wire layout and a fully materialized [`MastForest`]. +/// It combines structural access from [`ForestLayout`] with digest access from either wire sections +/// or a rebuilt in-memory hash table. +#[derive(Debug, Clone)] +pub(super) struct ResolvedSerializedForest<'a> { + bytes: &'a [u8], + layout: ForestLayout, + digests: ForestDigests, +} + +impl ForestDigests { + /// Resolves how later digest lookups will be served for a parsed serialized forest. + /// + /// `bytes` and `layout` provide the already-scanned structural wire view. When + /// `remaining_allocation_budget` is `Some`, helper allocations needed for untrusted validation + /// such as the slot table and rebuilt hash table are charged against that budget. Trusted + /// structural views pass `None` here, which keeps the previous unbudgeted inspection behavior. + fn new( + bytes: &[u8], + layout: &ForestLayout, + mut remaining_allocation_budget: Option<&mut usize>, + ) -> Result { + let slot_by_node = + build_digest_slot_by_node(bytes, layout, remaining_allocation_budget.as_deref_mut())?; + // If the internal-hash section is absent, rebuild all non-external digests once and cache + // them for later lookups. + let hash_table = if layout.node_hash_offset.is_none() { + Some(recompute_hash_table(bytes, layout, remaining_allocation_budget)?) + } else { + None + }; + + Ok(Self { slot_by_node, hash_table }) + } + + fn digest_at( + &self, + bytes: &[u8], + layout: &ForestLayout, + index: usize, + entry: MastNodeEntry, + ) -> Result { + let digest_slot = self.slot_by_node.get(index).copied().ok_or_else(|| { + DeserializationError::InvalidValue(format!( + "node index {} out of bounds for {} digest slots", + index, + self.slot_by_node.len() + )) + })? as usize; + + if matches!(entry, MastNodeEntry::External) { + return read_digest_entry(bytes, layout.external_digest_offset, digest_slot); + } + + if let Some(hash_table) = &self.hash_table { + return hash_table.get(index).copied().ok_or_else(|| { + DeserializationError::InvalidValue(format!( + "node index {} out of bounds for {} rebuilt digests", + index, + hash_table.len() + )) + }); + } + + let node_hash_offset = layout.node_hash_offset.ok_or_else(|| { + DeserializationError::InvalidValue( + "hash-backed digest lookup requested but node hash section is absent".to_string(), + ) + })?; + read_digest_entry(bytes, node_hash_offset, digest_slot) + } +} + +impl<'a> ResolvedSerializedForest<'a> { + /// Resolves digest access for a parsed serialized forest. + pub(super) fn new(bytes: &'a [u8], layout: ForestLayout) -> Result { + let digests = ForestDigests::new(bytes, &layout, None)?; + Ok(Self { bytes, layout, digests }) + } + + /// Resolves digest access for a parsed serialized forest while charging helper allocations + /// against an explicit untrusted validation budget. + pub(super) fn new_with_allocation_budget( + bytes: &'a [u8], + layout: ForestLayout, + mut allocation_budget: usize, + ) -> Result { + let digests = ForestDigests::new(bytes, &layout, Some(&mut allocation_budget))?; + Ok(Self { bytes, layout, digests }) + } + + /// Materializes a full [`MastForest`] from the serialized structure and resolved digests. + pub(super) fn materialize( + &self, + advice_map: AdviceMap, + debug_info: DebugInfo, + ) -> Result { + let basic_block_data_decoder = BasicBlockDataDecoder::new(basic_block_data( + self.bytes, + self.layout.basic_block_offset, + self.layout.basic_block_len, + )?); + let mut mast_forest = MastForest::new(); + mast_forest.debug_info = debug_info; + + for index in 0..self.node_count() { + let entry = self.node_entry_at(index)?; + let digest = self.node_digest_for_entry(index, entry)?; + + let mast_node_builder = entry.try_into_mast_node_builder( + self.node_count(), + &basic_block_data_decoder, + digest, + )?; + mast_node_builder.add_to_forest_relaxed(&mut mast_forest).map_err(|e| { + DeserializationError::InvalidValue(format!( + "failed to add node to MAST forest while deserializing: {e}", + )) + })?; + } + + for index in 0..self.procedure_root_count() { + mast_forest.make_root(self.procedure_root_at(index)?); + } + + mast_forest.advice_map = advice_map; + Ok(mast_forest) + } + + pub(super) fn node_count(&self) -> usize { + self.layout.node_count + } + + pub(super) fn procedure_root_count(&self) -> usize { + self.layout.roots_count + } + + pub(super) fn procedure_root_at( + &self, + index: usize, + ) -> Result { + self.layout.read_procedure_root_at(self.bytes, index) + } + + pub(super) fn node_entry_at( + &self, + index: usize, + ) -> Result { + self.layout.read_node_entry_at(self.bytes, index) + } + + /// Returns the digest for the node at `index`. + /// + /// The caller-supplied index is checked via [`Self::node_entry_at`] before the digest lookup + /// reaches the internal slot table. + pub(super) fn node_digest_at(&self, index: usize) -> Result { + let entry = self.node_entry_at(index)?; + self.node_digest_for_entry(index, entry) + } + + /// Returns the digest for a node whose entry was already read and bounds-checked by the caller. + fn node_digest_for_entry( + &self, + index: usize, + entry: MastNodeEntry, + ) -> Result { + self.digests.digest_at(self.bytes, &self.layout, index, entry) + } + + #[cfg(test)] + pub(super) fn digest_slot_at(&self, index: usize) -> usize { + self.digests.slot_by_node[index] as usize + } +} + +fn read_digest_entry( + bytes: &[u8], + digest_section_offset: usize, + index: usize, +) -> Result { + let mut reader = SliceReader::new(read_fixed_section_entry( + bytes, + digest_section_offset, + crate::Word::min_serialized_size(), + index, + "digest", + )?); + crate::Word::read_from(&mut reader) +} + +fn basic_block_data( + bytes: &[u8], + basic_block_offset: usize, + basic_block_len: usize, +) -> Result<&[u8], DeserializationError> { + // Layout scanning already established the coarse section boundaries. This helper keeps the + // consumer-side slice extraction explicit and local to the basic-block decoder path. + let end = basic_block_offset.checked_add(basic_block_len).ok_or_else(|| { + DeserializationError::InvalidValue("basic-block data overflow".to_string()) + })?; + if end > bytes.len() { + return Err(DeserializationError::UnexpectedEOF); + } + Ok(&bytes[basic_block_offset..end]) +} + +fn build_digest_slot_by_node( + bytes: &[u8], + layout: &ForestLayout, + remaining_allocation_budget: Option<&mut usize>, +) -> Result, DeserializationError> { + // Digest sections are packed densely by node kind rather than by absolute node index. + // This scan records, for each node index, which slot to read from in the corresponding digest + // source. + let mut slots = Vec::new(); + reserve_node_capacity( + &mut slots, + layout.node_count, + "digest slot table", + remaining_allocation_budget, + )?; + let mut external_slot = 0u32; + let mut node_hash_slot = 0u32; + + for index in 0..layout.node_count { + let entry = layout.read_node_entry_at(bytes, index)?; + if matches!(entry, MastNodeEntry::External) { + slots.push(external_slot); + external_slot = external_slot.checked_add(1).ok_or_else(|| { + DeserializationError::InvalidValue("external digest slot overflow".to_string()) + })?; + } else { + slots.push(node_hash_slot); + node_hash_slot = node_hash_slot.checked_add(1).ok_or_else(|| { + DeserializationError::InvalidValue("node hash slot overflow".to_string()) + })?; + } + } + + Ok(slots) +} + +fn recompute_hash_table( + bytes: &[u8], + layout: &ForestLayout, + remaining_allocation_budget: Option<&mut usize>, +) -> Result, DeserializationError> { + let basic_block_data_decoder = BasicBlockDataDecoder::new(basic_block_data( + bytes, + layout.basic_block_offset, + layout.basic_block_len, + )?); + + let mut digests = Vec::new(); + reserve_node_capacity( + &mut digests, + layout.node_count, + "hash table", + remaining_allocation_budget, + )?; + let mut external_digest_index = 0usize; + + for index in 0..layout.node_count { + let entry = layout.read_node_entry_at(bytes, index)?; + let computed = match entry { + MastNodeEntry::Block { ops_offset } => { + let op_batches = basic_block_data_decoder.decode_operations(ops_offset)?; + let op_groups: Vec = + op_batches.iter().flat_map(|batch| *batch.groups()).collect(); + hasher::hash_elements(&op_groups) + }, + MastNodeEntry::Join { left_child_id, right_child_id } => { + let left = checked_child_index(index, left_child_id, layout.node_count)?; + let right = checked_child_index(index, right_child_id, layout.node_count)?; + hasher::merge_in_domain(&[digests[left], digests[right]], JoinNode::DOMAIN) + }, + MastNodeEntry::Split { if_branch_id, else_branch_id } => { + let on_true = checked_child_index(index, if_branch_id, layout.node_count)?; + let on_false = checked_child_index(index, else_branch_id, layout.node_count)?; + hasher::merge_in_domain(&[digests[on_true], digests[on_false]], SplitNode::DOMAIN) + }, + MastNodeEntry::Loop { body_id } => { + let body = checked_child_index(index, body_id, layout.node_count)?; + hasher::merge_in_domain(&[digests[body], crate::Word::default()], LoopNode::DOMAIN) + }, + MastNodeEntry::Call { callee_id } => { + let callee = checked_child_index(index, callee_id, layout.node_count)?; + hasher::merge_in_domain( + &[digests[callee], crate::Word::default()], + CallNode::CALL_DOMAIN, + ) + }, + MastNodeEntry::SysCall { callee_id } => { + let callee = checked_child_index(index, callee_id, layout.node_count)?; + hasher::merge_in_domain( + &[digests[callee], crate::Word::default()], + CallNode::SYSCALL_DOMAIN, + ) + }, + MastNodeEntry::Dyn => DynNode::DYN_DEFAULT_DIGEST, + MastNodeEntry::Dyncall => DynNode::DYNCALL_DEFAULT_DIGEST, + MastNodeEntry::External => { + let digest = + read_digest_entry(bytes, layout.external_digest_offset, external_digest_index)?; + external_digest_index = external_digest_index.checked_add(1).ok_or_else(|| { + DeserializationError::InvalidValue("external digest index overflow".to_string()) + })?; + digest + }, + }; + + digests.push(computed); + } + + Ok(digests) +} + +fn reserve_node_capacity( + values: &mut Vec, + node_count: usize, + label: &str, + remaining_allocation_budget: Option<&mut usize>, +) -> Result<(), DeserializationError> { + if let Some(allocation_budget) = remaining_allocation_budget { + reserve_allocation::(allocation_budget, node_count, label)?; + } + values.try_reserve_exact(node_count).map_err(|err| { + DeserializationError::InvalidValue(format!( + "failed to reserve {label} for {node_count} nodes: {err}", + )) + }) +} + +fn checked_child_index( + parent_index: usize, + child_id: u32, + node_count: usize, +) -> Result { + let child_index = child_id as usize; + if child_index >= node_count { + return Err(DeserializationError::InvalidValue(format!( + "child id {child_id} out of bounds for {node_count} nodes" + ))); + } + if child_index >= parent_index { + return Err(DeserializationError::InvalidValue(format!( + "forward reference from node {parent_index} to {child_id} (child index must be less than parent)" + ))); + } + Ok(child_index) +} + +pub(super) fn basic_block_offset_for_node_index( + nodes: &[super::MastNode], + node_index: usize, +) -> Result { + let mut offset = 0usize; + for node in nodes.iter().take(node_index) { + if let super::MastNode::Block(block) = node { + offset = offset.checked_add(basic_block_data_len(block)).ok_or_else(|| { + DeserializationError::InvalidValue("basic-block data offset overflow".to_string()) + })?; + } + } + + offset.try_into().map_err(|_| { + DeserializationError::InvalidValue( + "basic-block data offset does not fit in u32".to_string(), + ) + }) +} diff --git a/core/src/mast/serialization/seed_gen.rs b/core/src/mast/serialization/seed_gen.rs index 5f468fa9c1..a8a145e5bc 100644 --- a/core/src/mast/serialization/seed_gen.rs +++ b/core/src/mast/serialization/seed_gen.rs @@ -14,7 +14,7 @@ use crate::{ precompile::PrecompileRequest, program::{Kernel, Program, StackInputs, StackOutputs}, proof::{ExecutionProof, HashFunction}, - serde::Serializable, + serde::{ByteWriter, Serializable}, }; /// Generates seed corpus files for fuzzing. @@ -22,6 +22,12 @@ use crate::{ #[test] #[ignore = "run manually to generate fuzz seeds"] fn generate_fuzz_seeds() { + fn write_mast_seed(targets: &[&str], name: &str, bytes: &[u8]) { + for target in targets { + write_seed(target, name, bytes); + } + } + fn write_seed(target: &str, name: &str, bytes: &[u8]) { let corpus_dir = std::path::Path::new("../miden-core-fuzz/corpus").join(target); std::fs::create_dir_all(&corpus_dir).expect("Failed to create corpus directory"); @@ -38,7 +44,18 @@ fn generate_fuzz_seeds() { forest.make_root(block_id); let bytes = forest.to_bytes(); - write_seed("mast_forest_deserialize", "minimal_block.bin", &bytes); + write_mast_seed( + &[ + "mast_forest_deserialize", + "mast_forest_validate", + "mast_node_info", + "serialized_mast_forest_new", + "basic_block_data", + "debug_info", + ], + "minimal_block.bin", + &bytes, + ); } // Seed 2: Forest with join node @@ -54,7 +71,18 @@ fn generate_fuzz_seeds() { forest.make_root(join); let bytes = forest.to_bytes(); - write_seed("mast_forest_deserialize", "join_node.bin", &bytes); + write_mast_seed( + &[ + "mast_forest_deserialize", + "mast_forest_validate", + "mast_node_info", + "serialized_mast_forest_new", + "basic_block_data", + "debug_info", + ], + "join_node.bin", + &bytes, + ); } // Seed 3: Stripped forest (no debug info) @@ -67,19 +95,64 @@ fn generate_fuzz_seeds() { let mut bytes = Vec::new(); forest.write_stripped(&mut bytes); - write_seed("mast_forest_deserialize", "stripped.bin", &bytes); + write_mast_seed( + &[ + "mast_forest_deserialize", + "mast_forest_validate", + "mast_node_info", + "serialized_mast_forest_new", + "basic_block_data", + ], + "stripped.bin", + &bytes, + ); + } + + // Seed 4: Hashless forest (no internal hash section, no debug info) + { + let mut forest = MastForest::new(); + let block_id = BasicBlockNodeBuilder::new(vec![Operation::Add], Vec::new()) + .add_to_forest(&mut forest) + .unwrap(); + forest.make_root(block_id); + + let mut bytes = Vec::new(); + forest.write_hashless(&mut bytes); + write_mast_seed( + &["mast_forest_validate", "mast_node_info", "serialized_mast_forest_new"], + "hashless.bin", + &bytes, + ); } - // Seed 4: Empty header (just magic + flags + version + minimal counts) + // Seed 5: Empty header (just magic + flags + version + minimal counts) { let bytes: &[u8] = b"MAST\x00\x00\x00\x01"; - write_seed("mast_forest_deserialize", "header_only.bin", bytes); + write_mast_seed( + &[ + "mast_forest_deserialize", + "mast_forest_validate", + "mast_node_info", + "serialized_mast_forest_new", + ], + "header_only.bin", + bytes, + ); } - // Seed 5: Invalid magic + // Seed 6: Invalid magic { let bytes: &[u8] = b"XXXX\x00\x00\x00\x01"; - write_seed("mast_forest_deserialize", "invalid_magic.bin", bytes); + write_mast_seed( + &[ + "mast_forest_deserialize", + "mast_forest_validate", + "mast_node_info", + "serialized_mast_forest_new", + ], + "invalid_magic.bin", + bytes, + ); } // Program seed @@ -101,7 +174,13 @@ fn generate_fuzz_seeds() { .unwrap(); forest.make_root(block_id); - let a: Word = [Felt::new(9), Felt::new(10), Felt::new(11), Felt::new(12)].into(); + let a: Word = [ + Felt::new_unchecked(9), + Felt::new_unchecked(10), + Felt::new_unchecked(11), + Felt::new_unchecked(12), + ] + .into(); let kernel = Kernel::from_hashes_unchecked(vec![a, a]); let program = Program::with_kernel(Arc::new(forest), block_id, kernel); @@ -113,14 +192,34 @@ fn generate_fuzz_seeds() { let kernel = Kernel::default(); write_seed("kernel_deserialize", "empty_kernel.bin", &kernel.to_bytes()); - let a: Word = [Felt::new(1), Felt::new(2), Felt::new(3), Felt::new(4)].into(); - let b: Word = [Felt::new(5), Felt::new(6), Felt::new(7), Felt::new(8)].into(); + let a: Word = [ + Felt::new_unchecked(1), + Felt::new_unchecked(2), + Felt::new_unchecked(3), + Felt::new_unchecked(4), + ] + .into(); + let b: Word = [ + Felt::new_unchecked(5), + Felt::new_unchecked(6), + Felt::new_unchecked(7), + Felt::new_unchecked(8), + ] + .into(); let non_empty = Kernel::new(&[a]).expect("failed to build non-empty kernel"); write_seed("kernel_deserialize", "single_kernel.bin", &non_empty.to_bytes()); let max_kernel: Vec = (0u64..=254) - .map(|n| [Felt::new(n), Felt::new(n + 1), Felt::new(n + 2), Felt::new(n + 3)].into()) + .map(|n| { + [ + Felt::new_unchecked(n), + Felt::new_unchecked(n + 1), + Felt::new_unchecked(n + 2), + Felt::new_unchecked(n + 3), + ] + .into() + }) .collect(); let max_kernel = Kernel::new(&max_kernel).expect("failed to build max-size kernel"); write_seed("kernel_deserialize", "max_kernel_255.bin", &max_kernel.to_bytes()); @@ -141,8 +240,8 @@ fn generate_fuzz_seeds() { // Stack IO seeds { - let inputs = StackInputs::new(&[Felt::new(1), Felt::new(2)]).unwrap(); - let outputs = StackOutputs::new(&[Felt::new(3), Felt::new(4)]).unwrap(); + let inputs = StackInputs::new(&[Felt::new_unchecked(1), Felt::new_unchecked(2)]).unwrap(); + let outputs = StackOutputs::new(&[Felt::new_unchecked(3), Felt::new_unchecked(4)]).unwrap(); write_seed("stack_io_deserialize", "stack_inputs.bin", &inputs.to_bytes()); write_seed("stack_io_deserialize", "stack_outputs.bin", &outputs.to_bytes()); } @@ -174,5 +273,35 @@ fn generate_fuzz_seeds() { write_seed("execution_proof_deserialize", "minimal_proof.bin", &proof.to_bytes()); } + // Execution proof seeds for malicious length-prefix deserialization. + { + let mut oversized_proof_len = Vec::new(); + oversized_proof_len.write_usize(usize::MAX); + write_seed("execution_proof_deserialize", "oversized_proof_len.bin", &oversized_proof_len); + + let mut oversized_pc_requests_len = Vec::new(); + oversized_pc_requests_len.write_usize(0); + oversized_pc_requests_len.write_u8(HashFunction::Blake3_256 as u8); + oversized_pc_requests_len.write_usize(usize::MAX); + write_seed( + "execution_proof_deserialize", + "oversized_pc_requests_len.bin", + &oversized_pc_requests_len, + ); + } + + // Execution proof seed with many small precompile requests. + { + let pc_requests = (0..64) + .map(|event_id| PrecompileRequest::new(EventId::from_u64(event_id), Vec::new())) + .collect(); + let proof = ExecutionProof::new(vec![1, 2, 3], HashFunction::Blake3_256, pc_requests); + write_seed( + "execution_proof_deserialize", + "many_minimal_precompile_requests.bin", + &proof.to_bytes(), + ); + } + println!("\nSeed corpus generated in ../miden-core-fuzz/corpus"); } diff --git a/core/src/mast/serialization/tests.rs b/core/src/mast/serialization/tests.rs index 99786866e8..44242aa55c 100644 --- a/core/src/mast/serialization/tests.rs +++ b/core/src/mast/serialization/tests.rs @@ -1,19 +1,57 @@ -use std::string::ToString; +use std::{ + string::{String, ToString}, + sync::{Mutex, Once}, +}; use super::*; use crate::{ Felt, ONE, Word, chiplets::hasher, mast::{ - BasicBlockNodeBuilder, CallNodeBuilder, DynNodeBuilder, ExternalNodeBuilder, - JoinNodeBuilder, LoopNodeBuilder, MastForestContributor, MastForestError, MastNodeExt, - MastNodeId, OP_BATCH_SIZE, OpBatch, SplitNodeBuilder, UntrustedMastForest, + BasicBlockNodeBuilder, CallNodeBuilder, DebugInfo, DynNodeBuilder, ExternalNodeBuilder, + JoinNodeBuilder, LoopNodeBuilder, MastForestContributor, MastForestError, MastForestView, + MastNodeExt, MastNodeId, OP_BATCH_SIZE, OpBatch, SplitNodeBuilder, UntrustedMastForest, }, operations::{DebugOptions, Decorator, Operation}, - serde::{ByteReader, DeserializationError, SliceReader}, + serde::{ByteReader, Deserializable, DeserializationError, Serializable, SliceReader}, utils::Idx, }; +struct TestLogger { + messages: Mutex>, +} + +impl log::Log for TestLogger { + fn enabled(&self, metadata: &log::Metadata<'_>) -> bool { + metadata.level() <= log::Level::Error + } + + fn log(&self, record: &log::Record<'_>) { + if self.enabled(record.metadata()) { + self.messages.lock().unwrap().push(record.args().to_string()); + } + } + + fn flush(&self) {} +} + +static TEST_LOGGER: TestLogger = TestLogger { messages: Mutex::new(Vec::new()) }; +static TEST_LOGGER_INIT: Once = Once::new(); +static TEST_LOGGER_GUARD: Mutex<()> = Mutex::new(()); + +fn with_captured_error_logs(f: impl FnOnce() -> T) -> (T, Vec) { + TEST_LOGGER_INIT.call_once(|| { + log::set_logger(&TEST_LOGGER).expect("test logger should be installed once"); + log::set_max_level(log::LevelFilter::Error); + }); + + let _guard = TEST_LOGGER_GUARD.lock().unwrap(); + TEST_LOGGER.messages.lock().unwrap().clear(); + let result = f(); + let messages = TEST_LOGGER.messages.lock().unwrap().clone(); + (result, messages) +} + /// If this test fails to compile, it means that `Operation` or `Decorator` was changed. Make sure /// that all tests in this file are updated accordingly. For example, if a new `Operation` variant /// was added, make sure that you add it in the vector of operations in @@ -118,91 +156,190 @@ fn confirm_operation_and_decorator_structure() { }; } +/// Returns all currently supported basic-block [`Operation`] variants. +/// +/// Control-flow instructions (e.g. `join`, `split`, `loop`, `call`) are represented as +/// [`MastNode`] variants, not as basic-block [`Operation`] values. +fn sample_basic_block_operations_all_variants() -> Vec { + vec![ + Operation::Noop, + Operation::Assert(Felt::from_u32(42)), + Operation::SDepth, + Operation::Caller, + Operation::Clk, + Operation::Add, + Operation::Neg, + Operation::Mul, + Operation::Inv, + Operation::Incr, + Operation::And, + Operation::Or, + Operation::Not, + Operation::Eq, + Operation::Eqz, + Operation::Expacc, + Operation::Ext2Mul, + Operation::U32split, + Operation::U32add, + Operation::U32assert2(Felt::from_u32(222)), + Operation::U32add3, + Operation::U32sub, + Operation::U32mul, + Operation::U32madd, + Operation::U32div, + Operation::U32and, + Operation::U32xor, + Operation::Pad, + Operation::Drop, + Operation::Dup0, + Operation::Dup1, + Operation::Dup2, + Operation::Dup3, + Operation::Dup4, + Operation::Dup5, + Operation::Dup6, + Operation::Dup7, + Operation::Dup9, + Operation::Dup11, + Operation::Dup13, + Operation::Dup15, + Operation::Swap, + Operation::SwapW, + Operation::SwapW2, + Operation::SwapW3, + Operation::SwapDW, + Operation::MovUp2, + Operation::MovUp3, + Operation::MovUp4, + Operation::MovUp5, + Operation::MovUp6, + Operation::MovUp7, + Operation::MovUp8, + Operation::MovDn2, + Operation::MovDn3, + Operation::MovDn4, + Operation::MovDn5, + Operation::MovDn6, + Operation::MovDn7, + Operation::MovDn8, + Operation::CSwap, + Operation::CSwapW, + Operation::Push(Felt::new_unchecked(45)), + Operation::AdvPop, + Operation::AdvPopW, + Operation::MLoadW, + Operation::MStoreW, + Operation::MLoad, + Operation::MStore, + Operation::MStream, + Operation::Pipe, + Operation::CryptoStream, + Operation::HPerm, + Operation::MpVerify(Felt::from_u32(1022)), + Operation::MrUpdate, + Operation::FriE2F4, + Operation::HornerBase, + Operation::HornerExt, + Operation::EvalCircuit, + Operation::Emit, + Operation::LogPrecompile, + ] +} + +fn assert_operation_encoded_size_matches_serialized_len(operation: Operation) { + match operation { + operation @ (Operation::Noop + | Operation::Assert(_) + | Operation::SDepth + | Operation::Caller + | Operation::Clk + | Operation::Add + | Operation::Neg + | Operation::Mul + | Operation::Inv + | Operation::Incr + | Operation::And + | Operation::Or + | Operation::Not + | Operation::Eq + | Operation::Eqz + | Operation::Expacc + | Operation::Ext2Mul + | Operation::U32split + | Operation::U32add + | Operation::U32assert2(_) + | Operation::U32add3 + | Operation::U32sub + | Operation::U32mul + | Operation::U32madd + | Operation::U32div + | Operation::U32and + | Operation::U32xor + | Operation::Pad + | Operation::Drop + | Operation::Dup0 + | Operation::Dup1 + | Operation::Dup2 + | Operation::Dup3 + | Operation::Dup4 + | Operation::Dup5 + | Operation::Dup6 + | Operation::Dup7 + | Operation::Dup9 + | Operation::Dup11 + | Operation::Dup13 + | Operation::Dup15 + | Operation::Swap + | Operation::SwapW + | Operation::SwapW2 + | Operation::SwapW3 + | Operation::SwapDW + | Operation::MovUp2 + | Operation::MovUp3 + | Operation::MovUp4 + | Operation::MovUp5 + | Operation::MovUp6 + | Operation::MovUp7 + | Operation::MovUp8 + | Operation::MovDn2 + | Operation::MovDn3 + | Operation::MovDn4 + | Operation::MovDn5 + | Operation::MovDn6 + | Operation::MovDn7 + | Operation::MovDn8 + | Operation::CSwap + | Operation::CSwapW + | Operation::Push(_) + | Operation::AdvPop + | Operation::AdvPopW + | Operation::MLoadW + | Operation::MStoreW + | Operation::MLoad + | Operation::MStore + | Operation::MStream + | Operation::Pipe + | Operation::CryptoStream + | Operation::HPerm + | Operation::MpVerify(_) + | Operation::MrUpdate + | Operation::FriE2F4 + | Operation::HornerBase + | Operation::HornerExt + | Operation::EvalCircuit + | Operation::Emit + | Operation::LogPrecompile) => { + assert_eq!(operation.encoded_size(), operation.to_bytes().len()); + }, + } +} + #[test] fn serialize_deserialize_all_nodes() { let mut mast_forest = MastForest::new(); let basic_block_id = { - let operations = vec![ - Operation::Noop, - Operation::Assert(Felt::from_u32(42)), - Operation::SDepth, - Operation::Caller, - Operation::Clk, - Operation::Add, - Operation::Neg, - Operation::Mul, - Operation::Inv, - Operation::Incr, - Operation::And, - Operation::Or, - Operation::Not, - Operation::Eq, - Operation::Eqz, - Operation::Expacc, - Operation::Ext2Mul, - Operation::U32split, - Operation::U32add, - Operation::U32assert2(Felt::from_u32(222)), - Operation::U32add3, - Operation::U32sub, - Operation::U32mul, - Operation::U32madd, - Operation::U32div, - Operation::U32and, - Operation::U32xor, - Operation::Pad, - Operation::Drop, - Operation::Dup0, - Operation::Dup1, - Operation::Dup2, - Operation::Dup3, - Operation::Dup4, - Operation::Dup5, - Operation::Dup6, - Operation::Dup7, - Operation::Dup9, - Operation::Dup11, - Operation::Dup13, - Operation::Dup15, - Operation::Swap, - Operation::SwapW, - Operation::SwapW2, - Operation::SwapW3, - Operation::SwapDW, - Operation::MovUp2, - Operation::MovUp3, - Operation::MovUp4, - Operation::MovUp5, - Operation::MovUp6, - Operation::MovUp7, - Operation::MovUp8, - Operation::MovDn2, - Operation::MovDn3, - Operation::MovDn4, - Operation::MovDn5, - Operation::MovDn6, - Operation::MovDn7, - Operation::MovDn8, - Operation::CSwap, - Operation::CSwapW, - Operation::Push(Felt::new(45)), - Operation::AdvPop, - Operation::AdvPopW, - Operation::MLoadW, - Operation::MStoreW, - Operation::MLoad, - Operation::MStore, - Operation::MStream, - Operation::Pipe, - Operation::HPerm, - Operation::MpVerify(Felt::from_u32(1022)), - Operation::MrUpdate, - Operation::FriE2F4, - Operation::HornerBase, - Operation::HornerExt, - Operation::Emit, - ]; + let operations = sample_basic_block_operations_all_variants(); let num_operations = operations.len(); @@ -218,21 +355,18 @@ fn serialize_deserialize_all_nodes() { (num_operations, Decorator::Trace(55)), ]; - { - // Convert raw decorators to decorator list by adding them to the forest first - let decorator_list: Vec<(usize, crate::mast::DecoratorId)> = decorators + // Convert raw decorators to decorator list by adding them to the forest first + let decorator_list: Vec<(usize, crate::mast::DecoratorId)> = decorators .into_iter() - .map(|(idx, decorator)| -> Result<(usize, crate::mast::DecoratorId), MastForestError> { - let decorator_id = mast_forest.add_decorator(decorator)?; - Ok((idx, decorator_id)) + .map(|(idx, decorator)| { + mast_forest.add_decorator(decorator).map(|decorator_id| (idx, decorator_id)) }) .collect::, MastForestError>>() .unwrap(); - BasicBlockNodeBuilder::new(operations, decorator_list) - .add_to_forest(&mut mast_forest) - .unwrap() - } + BasicBlockNodeBuilder::new(operations, decorator_list) + .add_to_forest(&mut mast_forest) + .unwrap() }; // Decorators to add to following nodes @@ -309,6 +443,236 @@ fn serialize_deserialize_all_nodes() { assert_eq!(mast_forest, deserialized_mast_forest); } +#[test] +fn test_operation_encoded_size_matches_serialized_len() { + for operation in sample_basic_block_operations_all_variants() { + assert_operation_encoded_size_matches_serialized_len(operation); + } +} + +#[test] +fn test_operation_encoded_size_push_varint_boundaries() { + for value in [ + 127u64, + 128, + 16_383, + 16_384, + 2_097_151, + 2_097_152, + 268_435_455, + 268_435_456, + 72_057_594_037_927_935, + 72_057_594_037_927_936, + ] { + assert_operation_encoded_size_matches_serialized_len(Operation::Push(Felt::new_unchecked( + value, + ))); + } +} + +fn assert_serialized_view_matches_forest(forest: &MastForest) { + let mut bytes = Vec::new(); + forest.write_stripped(&mut bytes); + + let view = SerializedMastForest::new(&bytes).unwrap(); + assert_eq!(view.node_count(), forest.nodes().len()); + + let mut bb_builder = BasicBlockDataBuilder::new(); + for (idx, node) in forest.nodes().iter().enumerate() { + let ops_offset = if let MastNode::Block(block) = node { + bb_builder.encode_basic_block(block) + } else { + 0 + }; + let expected = MastNodeInfo::new(node, ops_offset); + let actual = view.node_info_at(idx).unwrap(); + assert_eq!(expected.to_bytes(), actual.to_bytes()); + } +} + +#[test] +fn test_mast_forest_view_trait_matches_serialized_view() { + let mut forest = MastForest::new(); + + let block1 = BasicBlockNodeBuilder::new( + vec![Operation::Push(Felt::new_unchecked(7)), Operation::Add, Operation::Mul], + Vec::new(), + ) + .add_to_forest(&mut forest) + .unwrap(); + let block2 = BasicBlockNodeBuilder::new(vec![Operation::U32div], Vec::new()) + .add_to_forest(&mut forest) + .unwrap(); + let join = JoinNodeBuilder::new([block1, block2]).add_to_forest(&mut forest).unwrap(); + forest.make_root(join); + + let mut bytes = Vec::new(); + forest.write_stripped(&mut bytes); + let serialized = SerializedMastForest::new(&bytes).unwrap(); + + let in_memory: &dyn MastForestView = &forest; + let serialized_view: &dyn MastForestView = &serialized; + + assert!(!in_memory.is_empty()); + assert!(in_memory.has_node(0)); + assert!(!in_memory.has_node(in_memory.node_count())); + + assert_eq!(in_memory.node_count(), serialized_view.node_count()); + for index in 0..in_memory.node_count() { + assert_eq!( + in_memory.node_info_at(index).unwrap().to_bytes(), + serialized_view.node_info_at(index).unwrap().to_bytes() + ); + assert_eq!( + in_memory.node_digest_at(index).unwrap(), + serialized_view.node_digest_at(index).unwrap() + ); + } + + assert_eq!(in_memory.procedure_root_count(), serialized_view.procedure_root_count()); + assert_eq!(in_memory.procedure_roots().unwrap(), serialized_view.procedure_roots().unwrap()); + + let in_memory_infos = in_memory.all_node_infos().unwrap(); + let serialized_infos = serialized_view.all_node_infos().unwrap(); + assert_eq!(in_memory_infos.len(), serialized_infos.len()); + for (lhs, rhs) in in_memory_infos.iter().zip(serialized_infos.iter()) { + assert_eq!(lhs.to_bytes(), rhs.to_bytes()); + } +} + +#[test] +fn test_serialized_mast_forest_random_access_all_node_types() { + let mut forest = MastForest::new(); + + let block_id = BasicBlockNodeBuilder::new(vec![Operation::Add], Vec::new()) + .add_to_forest(&mut forest) + .unwrap(); + let call_id = CallNodeBuilder::new(block_id).add_to_forest(&mut forest).unwrap(); + let syscall_id = CallNodeBuilder::new_syscall(block_id).add_to_forest(&mut forest).unwrap(); + let loop_id = LoopNodeBuilder::new(block_id).add_to_forest(&mut forest).unwrap(); + let join_id = JoinNodeBuilder::new([block_id, call_id]).add_to_forest(&mut forest).unwrap(); + let split_id = SplitNodeBuilder::new([block_id, call_id]).add_to_forest(&mut forest).unwrap(); + let dyn_id = DynNodeBuilder::new_dyn().add_to_forest(&mut forest).unwrap(); + let dyncall_id = DynNodeBuilder::new_dyncall().add_to_forest(&mut forest).unwrap(); + let external_id = ExternalNodeBuilder::new(Word::default()).add_to_forest(&mut forest).unwrap(); + + forest.make_root(join_id); + forest.make_root(syscall_id); + forest.make_root(loop_id); + forest.make_root(split_id); + forest.make_root(dyn_id); + forest.make_root(dyncall_id); + forest.make_root(external_id); + + assert_serialized_view_matches_forest(&forest); +} + +#[test] +fn test_serialized_mast_forest_large_counts() { + let mut forest = MastForest::new(); + let mut roots = Vec::new(); + + for _ in 0..300 { + let block_id = BasicBlockNodeBuilder::new(vec![Operation::Add], Vec::new()) + .add_to_forest(&mut forest) + .unwrap(); + roots.push(block_id); + } + + for root in roots.iter().take(200) { + forest.make_root(*root); + } + + assert_serialized_view_matches_forest(&forest); +} + +fn debug_info_offset_after_advice_map(bytes: &[u8]) -> usize { + let view = SerializedMastForest::new(bytes).unwrap(); + let mut offset = view.advice_map_offset().unwrap(); + let entry_count = read_usize_at(bytes, &mut offset).unwrap(); + for _ in 0..entry_count { + for _ in 0..4 { + let _ = read_array_at::<8>(bytes, &mut offset).unwrap(); + } + let values_len = read_usize_at(bytes, &mut offset).unwrap(); + for _ in 0..values_len { + let _ = read_array_at::<8>(bytes, &mut offset).unwrap(); + } + } + offset +} + +fn node_hash_digest_offset(view: &SerializedMastForest<'_>, node_index: usize) -> usize { + let digest_slot = view.digest_slot_at(node_index); + view.node_hash_offset().unwrap() + digest_slot * Word::min_serialized_size() +} + +fn rewrite_debug_info_procedure_name_digest( + bytes: &[u8], + from_digest: Word, + to_digest: Word, +) -> Vec { + let debug_info_offset = debug_info_offset_after_advice_map(bytes); + let mut reader = SliceReader::new(&bytes[debug_info_offset..]); + let mut debug_info = DebugInfo::read_from(&mut reader).unwrap(); + + let procedure_names: Vec<_> = debug_info + .procedure_names() + .map(|(digest, name)| { + let remapped_digest = if digest == from_digest { to_digest } else { digest }; + (remapped_digest, name.to_string().into()) + }) + .collect(); + + debug_info.clear_procedure_names(); + debug_info.extend_procedure_names(procedure_names); + + let mut rewritten = bytes[..debug_info_offset].to_vec(); + debug_info.write_into(&mut rewritten); + rewritten +} + +#[test] +fn test_serialized_mast_forest_hashless_omits_hash_section_and_recomputes_digests() { + let mut forest = MastForest::new(); + let block1 = BasicBlockNodeBuilder::new(vec![Operation::Add, Operation::Mul], Vec::new()) + .add_to_forest(&mut forest) + .unwrap(); + let block2 = BasicBlockNodeBuilder::new(vec![Operation::U32div], Vec::new()) + .add_to_forest(&mut forest) + .unwrap(); + let join = JoinNodeBuilder::new([block1, block2]).add_to_forest(&mut forest).unwrap(); + forest.make_root(join); + + let mut bytes = Vec::new(); + forest.write_hashless(&mut bytes); + let view = SerializedMastForest::new(&bytes).unwrap(); + assert!(view.node_hash_offset().is_none()); + for index in 0..view.node_count() { + assert_eq!(forest.nodes()[index].digest(), view.node_info_at(index).unwrap().digest()); + } +} + +#[test] +fn test_serialized_mast_forest_hashless_accepts_external_nodes_parse_only() { + let mut forest = MastForest::new(); + let external_digest = Word::new([ + Felt::new_unchecked(1), + Felt::new_unchecked(2), + Felt::new_unchecked(3), + Felt::new_unchecked(4), + ]); + let external_id = ExternalNodeBuilder::new(external_digest).add_to_forest(&mut forest).unwrap(); + forest.make_root(external_id); + + let mut bytes = Vec::new(); + forest.write_hashless(&mut bytes); + let view = SerializedMastForest::new(&bytes).unwrap(); + assert_eq!(view.node_count(), 1); + assert!(view.node_info_at(0).is_ok()); + assert_eq!(view.node_digest_at(0).unwrap(), external_digest); +} + /// Test that a forest with a node whose child ids are larger than its own id serializes and /// deserializes successfully. #[test] @@ -480,12 +844,11 @@ fn mast_forest_basic_block_serialization_no_decorator_duplication() { // Get the deserialized block let deserialized_root_id = deserialized.procedure_roots()[0]; - let deserialized_block = - if let crate::mast::MastNode::Block(block) = &deserialized[deserialized_root_id] { - block - } else { - panic!("Expected a block node"); - }; + let deserialized_block = if let MastNode::Block(block) = &deserialized[deserialized_root_id] { + block + } else { + panic!("Expected a block node"); + }; // Verify that each decorator appears exactly once in the deserialized structure assert_eq!( @@ -533,26 +896,58 @@ fn mast_forest_deserialize_invalid_ops_offset_fails() { let _: [u8; 8] = reader.read_array().unwrap(); // magic (4) + flags (1) + version (3) let _node_count: usize = reader.read().unwrap(); - let _decorator_count: usize = reader.read().unwrap(); let _roots: Vec = Deserializable::read_from(&mut reader).unwrap(); - let basic_block_data: Vec = Deserializable::read_from(&mut reader).unwrap(); + let _basic_block_data: Vec = Deserializable::read_from(&mut reader).unwrap(); - // Calculate offset to MastNodeInfo: - // magic (4) + flags (1) + version (3) + node_count (8) + decorator_count (8) + - // roots_len (8) + 1 root (4) + bb_data_len (8) + bb_data - let node_info_offset = 4 + 1 + 3 + 8 + 8 + 8 + 4 + 8 + basic_block_data.len(); + let view = SerializedMastForest::new(&serialized).unwrap(); + let node_entry_offset = view.node_entry_offset(); // Corrupt the ops_offset field with an out-of-bounds value let block_discriminant: u64 = 3; let corrupted_value = (block_discriminant << 60) | u32::MAX as u64; let mut corrupted = serialized; - corrupted_value.write_into(&mut &mut corrupted[node_info_offset..node_info_offset + 8]); + corrupted_value.write_into(&mut &mut corrupted[node_entry_offset..node_entry_offset + 8]); let result = MastForest::read_from_bytes(&corrupted); assert_matches!(result, Err(DeserializationError::InvalidValue(_))); } +#[test] +fn mast_forest_read_from_bytes_rejects_fuzzed_overflow_payload() { + // This fuzz payload contains length fields that make deserialization read far past the input + // size. If this starts succeeding, the byte-slice path may no longer be enforcing its budget. + let payload = [ + 0x4d, 0x41, 0x53, 0x54, 0x00, 0x00, 0x00, 0x03, 0x07, 0x03, 0x0b, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x30, 0x01, + 0x3b, 0x0b, 0x00, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0x53, 0x4a, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0x21, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xad, 0xad, 0xad, 0xad, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x84, 0x81, 0xc3, 0xbc, 0x72, 0x7f, + 0x15, 0x30, + ]; + + let result = MastForest::read_from_bytes(&payload); + assert!(result.is_err()); + + // Wrapped fuzz inputs must use the generic budgeted entry point; otherwise the outer + // collection length can drive unbounded work before the inner forest fails. + let mut vec_payload = vec![0]; + vec_payload.extend_from_slice(&1000u64.to_le_bytes()); + let budget = vec_payload.len().saturating_mul(TRUSTED_BYTE_READ_BUDGET_MULTIPLIER); + let result = Vec::::read_from_bytes_with_budget(&vec_payload, budget); + assert!(result.is_err()); + + let mut option_payload = vec![1]; + option_payload.extend_from_slice(&payload); + let budget = option_payload.len().saturating_mul(TRUSTED_BYTE_READ_BUDGET_MULTIPLIER); + let result = Option::::read_from_bytes_with_budget(&option_payload, budget); + assert!(result.is_err()); +} + #[test] fn mast_forest_serialize_deserialize_procedure_names() { let mut forest = MastForest::new(); @@ -625,8 +1020,8 @@ fn test_opbatch_roundtrip_preservation() { let operations = vec![ Operation::Add, - Operation::Push(Felt::new(100)), - Operation::Push(Felt::new(200)), + Operation::Push(Felt::new_unchecked(100)), + Operation::Push(Felt::new_unchecked(200)), Operation::Mul, ]; @@ -645,7 +1040,7 @@ fn test_opbatch_roundtrip_preservation() { #[test] fn test_multi_batch_roundtrip() { let mut forest = MastForest::new(); - let operations: Vec<_> = (0..80).map(|i| Operation::Push(Felt::new(i))).collect(); + let operations: Vec<_> = (0..80).map(|i| Operation::Push(Felt::new_unchecked(i))).collect(); let block_id = BasicBlockNodeBuilder::new(operations, Vec::new()) .add_to_forest(&mut forest) @@ -670,14 +1065,14 @@ fn test_decorator_indices_preserved_with_padding() { let operations = vec![ Operation::Add, Operation::Mul, - Operation::Push(Felt::new(100)), // Will cause padding + Operation::Push(Felt::new_unchecked(100)), // Will cause padding Operation::Drop, ]; // Add decorator at operation index 2 (the PUSH) let decorators = vec![(2, decorator_id)]; - let block_id = BasicBlockNodeBuilder::new(operations.clone(), decorators) + let block_id = BasicBlockNodeBuilder::new(operations, decorators) .add_to_forest(&mut forest) .unwrap(); @@ -723,13 +1118,17 @@ fn test_raw_vs_batched_construction_equivalence() { let mut forest2 = MastForest::new(); let decorator_id1 = forest1.add_decorator(Decorator::Trace(1)).unwrap(); - let _decorator_id2 = forest2.add_decorator(Decorator::Trace(1)).unwrap(); + let _ = forest2.add_decorator(Decorator::Trace(1)).unwrap(); - let operations = - vec![Operation::Add, Operation::Mul, Operation::Push(Felt::new(100)), Operation::Drop]; + let operations = vec![ + Operation::Add, + Operation::Mul, + Operation::Push(Felt::new_unchecked(100)), + Operation::Drop, + ]; // Path 1: Raw construction - let block_id1 = BasicBlockNodeBuilder::new(operations.clone(), vec![(2, decorator_id1)]) + let block_id1 = BasicBlockNodeBuilder::new(operations, vec![(2, decorator_id1)]) .add_to_forest(&mut forest1) .unwrap(); @@ -774,14 +1173,14 @@ fn test_raw_batched_digest_equivalence() { let operations = vec![ Operation::Add, Operation::Mul, - Operation::Push(Felt::new(42)), + Operation::Push(Felt::new_unchecked(42)), Operation::Drop, Operation::Dup0, ]; // Construct via Raw path let mut forest1 = MastForest::new(); - let block_id1 = BasicBlockNodeBuilder::new(operations.clone(), Vec::new()) + let block_id1 = BasicBlockNodeBuilder::new(operations, Vec::new()) .add_to_forest(&mut forest1) .unwrap(); let digest1 = forest1[block_id1].unwrap_basic_block().digest(); @@ -804,8 +1203,8 @@ fn test_batched_construction_preserves_structure() { let operations = vec![ Operation::Add, Operation::Mul, - Operation::Push(Felt::new(100)), - Operation::Push(Felt::new(200)), + Operation::Push(Felt::new_unchecked(100)), + Operation::Push(Felt::new_unchecked(200)), ]; let block_id = BasicBlockNodeBuilder::new(operations, Vec::new()) @@ -839,111 +1238,165 @@ fn test_batched_construction_preserves_structure() { // PROPTEST-BASED ROUND-TRIP SERIALIZATION TESTS // ================================================================================================ -/// Test that the new header format uses flags=0x00 for full serialization. +fn assert_header_flags(bytes: &[u8], expected_flags: u8) { + assert_eq!(&bytes[0..4], b"MAST", "Magic should be MAST"); + assert_eq!(bytes[4], expected_flags, "unexpected serialization flags"); + assert_eq!(&bytes[5..8], &[0, 0, 3], "Version should be [0, 0, 3]"); +} + #[test] -fn test_header_backward_compatible() { +fn test_header_flags_for_all_serialization_modes() { let mut forest = MastForest::new(); let block_id = BasicBlockNodeBuilder::new(vec![Operation::Add], Vec::new()) .add_to_forest(&mut forest) .unwrap(); forest.make_root(block_id); - let bytes = forest.to_bytes(); + assert_header_flags(&forest.to_bytes(), 0x00); - // Check header structure: MAST (4 bytes) + flags (1 byte) + version (3 bytes) - assert_eq!(&bytes[0..4], b"MAST", "Magic should be MAST"); - assert_eq!(bytes[4], 0x00, "Flags should be 0x00 for full serialization"); - // Version [0, 0, 2] includes: AssemblyOp removed from Decorator enum serialization - assert_eq!(&bytes[5..8], &[0, 0, 2], "Version should be [0, 0, 2]"); + let mut stripped_bytes = Vec::new(); + forest.write_stripped(&mut stripped_bytes); + assert_header_flags(&stripped_bytes, 0x01); + + let mut hashless_bytes = Vec::new(); + forest.write_hashless(&mut hashless_bytes); + assert_header_flags(&hashless_bytes, 0x03); } -/// Test that stripped serialization produces smaller output than full serialization. +/// Test that legacy version headers are rejected. #[test] -fn test_stripped_serialization_smaller_than_full() { +fn test_legacy_version_is_rejected() { let mut forest = MastForest::new(); - - // Add decorators - let decorator_id = forest.add_decorator(Decorator::Trace(42)).unwrap(); - - let operations = vec![Operation::Add, Operation::Mul, Operation::Drop]; - let block_id = BasicBlockNodeBuilder::new(operations, vec![(0, decorator_id)]) + let block_id = BasicBlockNodeBuilder::new(vec![Operation::Add], Vec::new()) .add_to_forest(&mut forest) .unwrap(); forest.make_root(block_id); - // Add procedure name for more debug info - let digest = forest[block_id].digest(); - forest.insert_procedure_name(digest, "test_proc".into()); - - let full_bytes = forest.to_bytes(); - - let mut stripped_bytes = Vec::new(); - forest.write_stripped(&mut stripped_bytes); + let mut bytes = forest.to_bytes(); + bytes[5..8].copy_from_slice(&[0, 0, 2]); - assert!( - stripped_bytes.len() < full_bytes.len(), - "Stripped ({} bytes) should be smaller than full ({} bytes)", - stripped_bytes.len(), - full_bytes.len() + let result = MastForest::read_from_bytes(&bytes); + assert_matches!( + result, + Err(DeserializationError::InvalidValue(msg)) if msg.contains("Unsupported version") ); } -/// Test that stripped serialization round-trips correctly with empty DebugInfo. +/// Test that stripping and hashless serialization reduce wire size monotonically. #[test] -fn test_stripped_serialization_roundtrip() { +fn test_serialization_sizes_shrink_from_full_to_stripped_to_hashless() { let mut forest = MastForest::new(); - // Add decorators let decorator_id = forest.add_decorator(Decorator::Trace(42)).unwrap(); - let operations = vec![Operation::Add, Operation::Mul, Operation::Drop]; let block_id = BasicBlockNodeBuilder::new(operations, vec![(0, decorator_id)]) .add_to_forest(&mut forest) .unwrap(); forest.make_root(block_id); - // Add procedure name and error code let digest = forest[block_id].digest(); forest.insert_procedure_name(digest, "test_proc".into()); - let _ = forest.register_error("test error".into()); - // Serialize stripped + let full_bytes = forest.to_bytes(); + let mut stripped_bytes = Vec::new(); forest.write_stripped(&mut stripped_bytes); - // Deserialize - let restored = MastForest::read_from_bytes(&stripped_bytes).unwrap(); + let mut hashless_bytes = Vec::new(); + forest.write_hashless(&mut hashless_bytes); - // Verify structure is preserved - assert_eq!(forest.num_nodes(), restored.num_nodes()); - assert_eq!(forest.procedure_roots().len(), restored.procedure_roots().len()); + let full_view = SerializedMastForest::new(&full_bytes).unwrap(); + assert!(!full_view.is_stripped()); + assert!(!full_view.is_hashless()); + assert_eq!(full_view.node_count(), forest.num_nodes() as usize); + assert_eq!(full_view.procedure_root_count(), 1); + assert!(full_view.node_info_at(0).is_ok()); - // Verify debug info is empty assert!( - restored.debug_info.is_empty(), - "DebugInfo should be empty after stripped roundtrip" + stripped_bytes.len() < full_bytes.len(), + "Stripped ({} bytes) should be smaller than full ({} bytes)", + stripped_bytes.len(), + full_bytes.len() + ); + assert!( + hashless_bytes.len() < stripped_bytes.len(), + "Hashless ({} bytes) should be smaller than stripped ({} bytes)", + hashless_bytes.len(), + stripped_bytes.len() ); - assert_eq!(restored.decorators().len(), 0); - assert_eq!(restored.procedure_name(&digest), None); + + let stripped_view = SerializedMastForest::new(&stripped_bytes).unwrap(); + let hashless_view = SerializedMastForest::new(&hashless_bytes).unwrap(); + assert!(stripped_view.node_hash_offset().is_some()); + assert!(hashless_view.node_hash_offset().is_none()); } -/// Test that stripped serialization sets the correct header flags. +fn assert_stripped_size_hint_matches_serialized_len(forest: &MastForest) { + let mut bytes = Vec::new(); + forest.write_stripped(&mut bytes); + assert_eq!(forest.stripped_size_hint(), bytes.len()); +} + +/// Test that stripped size hints stay exact for both compact and large forests. #[test] -fn test_stripped_header_flags() { +fn test_stripped_size_hint_matches_serialized_len() { + let mut small_forest = MastForest::new(); + + let block1 = BasicBlockNodeBuilder::new( + vec![Operation::Add, Operation::Push(Felt::new_unchecked(3))], + Vec::new(), + ) + .add_to_forest(&mut small_forest) + .unwrap(); + let block2 = BasicBlockNodeBuilder::new( + vec![Operation::U32div, Operation::Assert(Felt::new_unchecked(1))], + Vec::new(), + ) + .add_to_forest(&mut small_forest) + .unwrap(); + let join = JoinNodeBuilder::new([block1, block2]).add_to_forest(&mut small_forest).unwrap(); + small_forest.make_root(join); + small_forest + .advice_map_mut() + .insert(Word::default(), vec![ONE, Felt::new_unchecked(2)]); + assert_stripped_size_hint_matches_serialized_len(&small_forest); + let mut forest = MastForest::new(); - let block_id = BasicBlockNodeBuilder::new(vec![Operation::Add], Vec::new()) + + let mut operations = Vec::with_capacity(304); + for _ in 0..300 { + operations.push(Operation::Add); + } + operations.push(Operation::Push(Felt::new_unchecked(7))); + operations.push(Operation::Assert(Felt::new_unchecked(9))); + operations.push(Operation::U32assert2(Felt::new_unchecked(11))); + operations.push(Operation::MpVerify(Felt::new_unchecked(13))); + + let block_id = BasicBlockNodeBuilder::new(operations, Vec::new()) .add_to_forest(&mut forest) .unwrap(); forest.make_root(block_id); - let mut stripped_bytes = Vec::new(); - forest.write_stripped(&mut stripped_bytes); - - // Check header structure - assert_eq!(&stripped_bytes[0..4], b"MAST", "Magic should be MAST"); - assert_eq!(stripped_bytes[4], 0x01, "Flags should be 0x01 for stripped serialization"); - // Version [0, 0, 2] includes: AssemblyOp removed from Decorator enum serialization - assert_eq!(&stripped_bytes[5..8], &[0, 0, 2], "Version should be [0, 0, 2]"); + let key_a = Word::new([ + Felt::new_unchecked(1), + Felt::new_unchecked(2), + Felt::new_unchecked(3), + Felt::new_unchecked(4), + ]); + let key_b = Word::new([ + Felt::new_unchecked(5), + Felt::new_unchecked(6), + Felt::new_unchecked(7), + Felt::new_unchecked(8), + ]); + + let values_a: Vec = (0..200).map(|i| Felt::new_unchecked(i as u64)).collect(); + let values_b: Vec = (0..5).map(|i| Felt::new_unchecked((i + 10) as u64)).collect(); + + forest.advice_map_mut().insert(key_a, values_a); + forest.advice_map_mut().insert(key_b, values_b); + + assert_stripped_size_hint_matches_serialized_len(&forest); } /// Test that node digests are preserved in stripped serialization. @@ -963,7 +1416,7 @@ fn test_stripped_preserves_digests() { forest.make_root(join_id); // Capture original digests - let original_digests: Vec<_> = forest.nodes().iter().map(|n| n.digest()).collect(); + let original_digests: Vec<_> = forest.nodes().iter().map(MastNodeExt::digest).collect(); // Stripped roundtrip let mut stripped_bytes = Vec::new(); @@ -971,7 +1424,7 @@ fn test_stripped_preserves_digests() { let restored = MastForest::read_from_bytes(&stripped_bytes).unwrap(); // Verify digests match - let restored_digests: Vec<_> = restored.nodes().iter().map(|n| n.digest()).collect(); + let restored_digests: Vec<_> = restored.nodes().iter().map(MastNodeExt::digest).collect(); assert_eq!(original_digests, restored_digests, "Node digests should be preserved"); } @@ -986,8 +1439,8 @@ fn test_deserialize_rejects_unknown_flags() { let mut bytes = forest.to_bytes(); - // Set an unknown flag (bit 1) - bytes[4] = 0x02; + // Set an unknown flag (bit 2) + bytes[4] = 0x04; let result = MastForest::read_from_bytes(&bytes); assert_matches!( @@ -996,6 +1449,175 @@ fn test_deserialize_rejects_unknown_flags() { ); } +/// Test that trusted deserialization rejects hashless inputs. +#[test] +fn test_trusted_rejects_hashless() { + let mut forest = MastForest::new(); + let block_id = BasicBlockNodeBuilder::new(vec![Operation::Add], Vec::new()) + .add_to_forest(&mut forest) + .unwrap(); + forest.make_root(block_id); + + let mut hashless_bytes = Vec::new(); + forest.write_hashless(&mut hashless_bytes); + + let result = MastForest::read_from_bytes(&hashless_bytes); + assert_matches!( + result, + Err(DeserializationError::InvalidValue(msg)) if msg.contains("HASHLESS") + ); +} + +#[test] +fn test_trusted_rejects_truncated_hashless_before_layout_scan() { + let mut forest = MastForest::new(); + let block_id = BasicBlockNodeBuilder::new(vec![Operation::Add], Vec::new()) + .add_to_forest(&mut forest) + .unwrap(); + forest.make_root(block_id); + + let mut hashless_bytes = Vec::new(); + forest.write_hashless(&mut hashless_bytes); + hashless_bytes.truncate(8); + + let result = MastForest::read_from_bytes(&hashless_bytes); + assert_matches!( + result, + Err(DeserializationError::InvalidValue(msg)) if msg.contains("HASHLESS") + ); +} + +/// Test that hashless without stripped is rejected. +#[test] +fn test_hashless_requires_stripped() { + let mut forest = MastForest::new(); + let block_id = BasicBlockNodeBuilder::new(vec![Operation::Add], Vec::new()) + .add_to_forest(&mut forest) + .unwrap(); + forest.make_root(block_id); + + let mut bytes = forest.to_bytes(); + // Set HASHLESS without STRIPPED + bytes[4] = 0x02; + + let result = UntrustedMastForest::read_from_bytes(&bytes); + assert_matches!( + result, + Err(DeserializationError::InvalidValue(msg)) if msg.contains("HASHLESS") && msg.contains("STRIPPED") + ); +} + +fn assert_untrusted_overspec_logging( + bytes: &[u8], + expected_flags: u8, + expected_nodes: u32, + expected_log_fragments: &[&str], +) { + let (result, logs) = + with_captured_error_logs(|| UntrustedMastForest::read_from_bytes_with_flags(bytes)); + + let (untrusted, flags) = result.unwrap(); + assert_eq!(flags, expected_flags); + assert_eq!(logs.len(), expected_log_fragments.len()); + for expected in expected_log_fragments { + assert!(logs.iter().any(|msg| msg.contains(expected))); + } + assert_eq!(untrusted.validate().unwrap().num_nodes(), expected_nodes); + + let (budgeted, budgeted_flags) = UntrustedMastForest::read_from_bytes_with_budgets_and_flags( + bytes, + bytes.len(), + default_untrusted_allocation_budget(bytes.len()), + ) + .unwrap(); + assert_eq!(budgeted_flags, expected_flags); + assert_eq!(budgeted.validate().unwrap().num_nodes(), expected_nodes); +} + +#[test] +fn test_untrusted_overspecification_logging_matches_wire_mode() { + let mut forest = MastForest::new(); + let block_id = BasicBlockNodeBuilder::new(vec![Operation::Add], Vec::new()) + .add_to_forest(&mut forest) + .unwrap(); + forest.make_root(block_id); + + let mut hashless_bytes = Vec::new(); + forest.write_hashless(&mut hashless_bytes); + assert_untrusted_overspec_logging(&hashless_bytes, 0x03, forest.num_nodes(), &[]); + + let mut stripped_bytes = Vec::new(); + forest.write_stripped(&mut stripped_bytes); + assert_untrusted_overspec_logging( + &stripped_bytes, + 0x01, + forest.num_nodes(), + &["wire node hashes"], + ); + + forest.insert_procedure_name(forest[block_id].digest(), "test".into()); + let bytes = forest.to_bytes(); + assert_untrusted_overspec_logging( + &bytes, + 0x00, + forest.num_nodes(), + &["wire node hashes", "DebugInfo"], + ); +} + +/// Test that untrusted validation in hashless mode recomputes non-external digests without any +/// general wire hash section. +#[test] +fn test_untrusted_hashless_validate_recomputes_without_wire_hash_section() { + let mut forest = MastForest::new(); + let block1 = BasicBlockNodeBuilder::new(vec![Operation::Add, Operation::Mul], Vec::new()) + .add_to_forest(&mut forest) + .unwrap(); + let block2 = BasicBlockNodeBuilder::new(vec![Operation::U32div], Vec::new()) + .add_to_forest(&mut forest) + .unwrap(); + let join = JoinNodeBuilder::new([block1, block2]).add_to_forest(&mut forest).unwrap(); + forest.make_root(join); + + let expected_digests: Vec<_> = + forest.nodes().iter().map(super::super::node::MastNodeExt::digest).collect(); + + let mut hashless_bytes = Vec::new(); + forest.write_hashless(&mut hashless_bytes); + + let (untrusted, flags) = + UntrustedMastForest::read_from_bytes_with_flags(&hashless_bytes).unwrap(); + assert_eq!(flags, 0x03); + + let validated = untrusted.validate().unwrap(); + let validated_digests: Vec<_> = + validated.nodes().iter().map(super::super::node::MastNodeExt::digest).collect(); + assert_eq!(validated_digests, expected_digests); +} + +/// Test that untrusted hashless deserialization accepts external nodes at parse time. +#[test] +fn test_untrusted_hashless_external_parse_and_validate() { + let mut forest = MastForest::new(); + let external = ExternalNodeBuilder::new(Word::new([ + Felt::new_unchecked(10), + Felt::new_unchecked(11), + Felt::new_unchecked(12), + Felt::new_unchecked(13), + ])) + .add_to_forest(&mut forest) + .unwrap(); + forest.make_root(external); + + let mut hashless_bytes = Vec::new(); + forest.write_hashless(&mut hashless_bytes); + + let (untrusted, flags) = + UntrustedMastForest::read_from_bytes_with_flags(&hashless_bytes).unwrap(); + assert_eq!(flags, 0x03, "hashless untrusted path should preserve wire mode"); + assert_eq!(untrusted.validate().unwrap().num_nodes(), 1); +} + mod proptests { use proptest::{prelude::*, strategy::Just}; @@ -1037,7 +1659,7 @@ mod proptests { // Verify all nodes match for (idx, original) in forest.nodes().iter().enumerate() { - let node_id = crate::mast::MastNodeId::new_unchecked(idx as u32); + let node_id = MastNodeId::new_unchecked(idx as u32); let deserialized_node = &deserialized[node_id]; // Check digests match @@ -1090,7 +1712,7 @@ mod proptests { prop::sample::select(vec![ Operation::Add, Operation::Mul, - Operation::Push(crate::Felt::new(42)), + Operation::Push(Felt::new_unchecked(42)), Operation::Drop, Operation::Dup0, Operation::Swap, @@ -1166,7 +1788,7 @@ mod proptests { prop::sample::select(vec![ Operation::Add, Operation::Mul, - Operation::Push(Felt::new(99)), + Operation::Push(Felt::new_unchecked(99)), Operation::Drop, Operation::Dup0, ]), @@ -1271,7 +1893,7 @@ mod proptests { // Verify all node digests match for (idx, original) in forest.nodes().iter().enumerate() { - let node_id = crate::mast::MastNodeId::new_unchecked(idx as u32); + let node_id = MastNodeId::new_unchecked(idx as u32); let restored_node = &restored[node_id]; prop_assert_eq!( @@ -1344,11 +1966,11 @@ fn test_debuginfo_serialization_sparse() { // Verify decorators are at correct nodes for i in 0..10 { - let node_id = crate::mast::MastNodeId::new_unchecked(i); + let node_id = MastNodeId::new_unchecked(i); let orig_decorators = forest.decorator_indices_for_op(node_id, 0); let deser_decorators = deserialized.decorator_indices_for_op(node_id, 0); - assert_eq!(orig_decorators, deser_decorators, "Decorators at node {} should match", i); + assert_eq!(orig_decorators, deser_decorators, "Decorators at node {i} should match"); } } @@ -1382,28 +2004,26 @@ fn test_debuginfo_serialization_dense() { // Verify decorators are at correct nodes for i in 0..10 { - let node_id = crate::mast::MastNodeId::new_unchecked(i); + let node_id = MastNodeId::new_unchecked(i); let orig_decorators = forest.decorator_indices_for_op(node_id, 0); let deser_decorators = deserialized.decorator_indices_for_op(node_id, 0); - assert_eq!(orig_decorators, deser_decorators, "Decorators at node {} should match", i); + assert_eq!(orig_decorators, deser_decorators, "Decorators at node {i} should match"); // Verify expected decorator presence if i < 8 { - assert_eq!(orig_decorators.len(), 1, "Node {} should have 1 decorator", i); + assert_eq!(orig_decorators.len(), 1, "Node {i} should have 1 decorator"); assert_eq!( deser_decorators.len(), 1, - "Node {} should have 1 decorator after deserialization", - i + "Node {i} should have 1 decorator after deserialization" ); } else { - assert_eq!(orig_decorators.len(), 0, "Node {} should have no decorators", i); + assert_eq!(orig_decorators.len(), 0, "Node {i} should have no decorators"); assert_eq!( deser_decorators.len(), 0, - "Node {} should have no decorators after deserialization", - i + "Node {i} should have no decorators after deserialization" ); } } @@ -1412,30 +2032,6 @@ fn test_debuginfo_serialization_dense() { // UNTRUSTED MAST FOREST VALIDATION TESTS // ================================================================================================ -/// Test that UntrustedMastForest::validate succeeds for a valid forest. -#[test] -fn test_untrusted_forest_valid_roundtrip() { - let mut forest = MastForest::new(); - - let block1_id = BasicBlockNodeBuilder::new(vec![Operation::Add], Vec::new()) - .add_to_forest(&mut forest) - .unwrap(); - let block2_id = BasicBlockNodeBuilder::new(vec![Operation::Mul], Vec::new()) - .add_to_forest(&mut forest) - .unwrap(); - let join_id = JoinNodeBuilder::new([block1_id, block2_id]).add_to_forest(&mut forest).unwrap(); - forest.make_root(join_id); - - // Serialize - let bytes = forest.to_bytes(); - - // Deserialize as untrusted and validate - let untrusted = UntrustedMastForest::read_from_bytes(&bytes).unwrap(); - let validated = untrusted.validate().unwrap(); - - assert_eq!(forest, validated); -} - /// Test that UntrustedMastForest::validate detects forward references. #[test] fn test_untrusted_forest_detects_forward_reference() { @@ -1467,42 +2063,109 @@ fn test_untrusted_forest_detects_forward_reference() { assert_matches!(result, Err(MastForestError::ForwardReference(_, _))); } -/// Test that UntrustedMastForest::validate detects hash mismatches. #[test] -fn test_untrusted_forest_detects_hash_mismatch() { +fn test_untrusted_forest_rejects_mismatched_wire_root_hash() { let mut forest = MastForest::new(); let block_id = BasicBlockNodeBuilder::new(vec![Operation::Add], Vec::new()) .add_to_forest(&mut forest) .unwrap(); forest.make_root(block_id); + let expected_digest = forest[block_id].digest(); + forest.insert_procedure_name(expected_digest, "proc".into()); let bytes = forest.to_bytes(); + let view = SerializedMastForest::new(&bytes).unwrap(); + let digest_offset = node_hash_digest_offset(&view, block_id.to_usize()); + let bogus_digest: Word = [ + Felt::new_unchecked(9), + Felt::new_unchecked(8), + Felt::new_unchecked(7), + Felt::new_unchecked(6), + ] + .into(); + + let mut corrupted = + rewrite_debug_info_procedure_name_digest(&bytes, expected_digest, bogus_digest); + bogus_digest.write_into( + &mut &mut corrupted[digest_offset..digest_offset + Word::min_serialized_size()], + ); - // Corrupt the digest of the node by modifying bytes in the node info section - // Format: magic (4) + flags (1) + version (3) + node_count (8) + decorator_count (8) + - // roots_len (8) + 1 root (4) + bb_data_len (8) + bb_data + node_info - // - // First, determine where the node info section starts - let mut reader = SliceReader::new(&bytes); - let _header: [u8; 8] = reader.read_array().unwrap(); - let _node_count: usize = reader.read().unwrap(); - let _decorator_count: usize = reader.read().unwrap(); - let _roots: Vec = Deserializable::read_from(&mut reader).unwrap(); - let basic_block_data: Vec = Deserializable::read_from(&mut reader).unwrap(); + let untrusted = UntrustedMastForest::read_from_bytes(&corrupted).unwrap(); + let result = untrusted.validate(); - // Node info starts after: 4 + 1 + 3 + 8 + 8 + 8 + 4 + 8 + bb_data.len() - let node_info_offset = 4 + 1 + 3 + 8 + 8 + 8 + 4 + 8 + basic_block_data.len(); + assert_matches!( + result, + Err(MastForestError::HashMismatch { + node_id, + expected, + computed, + }) if node_id == block_id && expected == bogus_digest && computed == expected_digest + ); +} + +#[test] +fn test_untrusted_forest_rejects_invalid_procedure_name_digest_without_remapping() { + let mut forest = MastForest::new(); + let block_id = BasicBlockNodeBuilder::new(vec![Operation::Add], Vec::new()) + .add_to_forest(&mut forest) + .unwrap(); + forest.make_root(block_id); + let expected_digest = forest[block_id].digest(); + forest.insert_procedure_name(expected_digest, "proc".into()); + + let bytes = forest.to_bytes(); + let bogus_digest: Word = [ + Felt::new_unchecked(9), + Felt::new_unchecked(8), + Felt::new_unchecked(7), + Felt::new_unchecked(6), + ] + .into(); + + let corrupted = rewrite_debug_info_procedure_name_digest(&bytes, expected_digest, bogus_digest); + + let untrusted = UntrustedMastForest::read_from_bytes(&corrupted).unwrap(); + let result = untrusted.validate(); + + assert_matches!(result, Err(MastForestError::InvalidProcedureNameDigest(digest)) if digest == bogus_digest); +} + +#[test] +fn test_untrusted_forest_rejects_digest_collision_in_wire_hashes() { + let mut forest = MastForest::new(); + let left_root = BasicBlockNodeBuilder::new(vec![Operation::Add], Vec::new()) + .add_to_forest(&mut forest) + .unwrap(); + let right_root = BasicBlockNodeBuilder::new(vec![Operation::Mul], Vec::new()) + .add_to_forest(&mut forest) + .unwrap(); + forest.make_root(left_root); + forest.make_root(right_root); + + let left_digest = forest[left_root].digest(); + let right_digest = forest[right_root].digest(); + forest.insert_procedure_name(right_digest, "right".into()); + + let bytes = forest.to_bytes(); + let view = SerializedMastForest::new(&bytes).unwrap(); + let left_digest_offset = node_hash_digest_offset(&view, left_root.to_usize()); - // Node info format: type (8 bytes) + digest (32 bytes = 4 x 8 bytes) - // Corrupt one byte in the digest (byte 8-15 of node info) let mut corrupted = bytes.clone(); - corrupted[node_info_offset + 8] ^= 0xff; // Flip bits in first word of digest + right_digest.write_into( + &mut &mut corrupted[left_digest_offset..left_digest_offset + Word::min_serialized_size()], + ); - // Deserialize as untrusted and try to validate let untrusted = UntrustedMastForest::read_from_bytes(&corrupted).unwrap(); let result = untrusted.validate(); - assert_matches!(result, Err(MastForestError::HashMismatch { .. })); + assert_matches!( + result, + Err(MastForestError::HashMismatch { + node_id, + expected, + computed, + }) if node_id == left_root && expected == right_digest && computed == left_digest + ); } // UNTRUSTED VALIDATION TEST HELPERS @@ -1514,7 +2177,7 @@ fn build_group(ops: &[Operation]) -> Felt { for (i, op) in ops.iter().enumerate() { group |= (op.op_code() as u64) << (Operation::OP_BITS * i); } - Felt::new(group) + Felt::new_unchecked(group) } fn make_batch(num_groups: usize, op: Operation) -> OpBatch { @@ -1533,7 +2196,7 @@ fn make_batch(num_groups: usize, op: Operation) -> OpBatch { for pad in padding.iter_mut().skip(num_groups) { *pad = true; } - let mut groups = [Felt::new(0); OP_BATCH_SIZE]; + let mut groups = [Felt::new_unchecked(0); OP_BATCH_SIZE]; for group in groups.iter_mut().take(num_groups) { *group = build_group(&[op]); } @@ -1574,8 +2237,8 @@ fn build_malicious_single_block_forest_bytes(push_imm: Felt) -> Vec { bytes[indptr_offset..indptr_offset + 4].copy_from_slice(&malicious_packed_indptr); - // Recompute the correct digest for the now-malformed decoding and patch it into node info, so - // that `UntrustedMastForest::validate()` will accept it if the issue exists. + // Recompute the correct digest for the now-malformed decoding and patch it into the node-hash + // section, so that `UntrustedMastForest::validate()` will accept it if the issue exists. if let Some(digest) = compute_single_block_digest_from_decoded_groups(&bytes) { bytes[digest_offset..digest_offset + 32].copy_from_slice(&digest.to_bytes()); } @@ -1649,20 +2312,18 @@ fn locate_single_block_indptr_and_digest_offsets(bytes: &[u8]) -> (usize, usize) let node_count: usize = cursor.read().unwrap(); assert_eq!(node_count, 1); - let _decorator_count: usize = cursor.read().unwrap(); let _roots: Vec = Deserializable::read_from(&mut cursor).unwrap(); // basic block data section: Vec let bb_data_len: usize = cursor.read().unwrap(); let bb_payload_start = cursor.position(); let bb_payload_end = bb_payload_start + bb_data_len; + let view = SerializedMastForest::new(bytes).unwrap(); + let node_entries_start = view.node_entry_offset(); - // node infos start immediately after basic block data payload - let node_infos_start = bb_payload_end; - - // node info: MastNodeType (8 bytes) + digest Word (32 bytes) + // node entry: MastNodeEntry (8 bytes) let node_type_u64 = u64::from_le_bytes( - bytes[node_infos_start..node_infos_start + 8] + bytes[node_entries_start..node_entries_start + 8] .try_into() .expect("node type bytes"), ); @@ -1673,7 +2334,7 @@ fn locate_single_block_indptr_and_digest_offsets(bytes: &[u8]) -> (usize, usize) assert!(payload <= u32::MAX as u64, "Block ops_offset payload must fit in u32"); let ops_offset = payload as usize; - let digest_offset = node_infos_start + 8; + let digest_offset = view.node_hash_offset().unwrap(); // Locate the start of the packed indptr for the first (and only) batch. let block_start = bb_payload_start + ops_offset; @@ -1706,8 +2367,7 @@ fn compute_single_block_digest_from_decoded_groups(bytes: &[u8]) -> Option fn test_untrusted_forest_rejects_non_full_prefix_batch() { let op_batches = vec![make_batch(4, Operation::Add), make_batch(2, Operation::Mul)]; - let op_groups: Vec = - op_batches.iter().flat_map(|batch| batch.groups()).copied().collect(); + let op_groups: Vec = op_batches.iter().flat_map(OpBatch::groups).copied().collect(); let digest = hasher::hash_elements(&op_groups); let mut forest = MastForest::new(); @@ -1728,8 +2388,7 @@ fn test_untrusted_forest_rejects_non_full_prefix_batch() { fn test_untrusted_forest_accepts_full_prefix_batch() { let op_batches = vec![make_batch(OP_BATCH_SIZE, Operation::Add), make_batch(4, Operation::Mul)]; - let op_groups: Vec = - op_batches.iter().flat_map(|batch| batch.groups()).copied().collect(); + let op_groups: Vec = op_batches.iter().flat_map(OpBatch::groups).copied().collect(); let digest = hasher::hash_elements(&op_groups); let mut forest = MastForest::new(); @@ -1749,8 +2408,8 @@ fn test_untrusted_forest_accepts_full_prefix_batch() { fn test_untrusted_forest_rejects_basic_block_indptr_that_breaks_push_immediate_commitment() { // Two distinct immediates. Using large values reduces the chance of accidental equality with a // packed opcode group value. - let imm_a = Felt::new(0xdead_beef_dead_beef); - let imm_b = Felt::new(0xfeed_face_feed_face); + let imm_a = Felt::new_unchecked(0xdead_beef_dead_beef); + let imm_b = Felt::new_unchecked(0xfeed_face_feed_face); let bytes_a = build_malicious_single_block_forest_bytes(imm_a); let bytes_b = build_malicious_single_block_forest_bytes(imm_b); @@ -1774,23 +2433,22 @@ fn test_untrusted_forest_rejects_basic_block_indptr_that_breaks_push_immediate_c // A fix may choose to reject this encoding at validation time. Either (or both) being `Err` // is an acceptable outcome: it prevents the commitment gap. + let assert_expected_rejection = |result: Result| match result { + Err(MastForestError::InvalidBatchPadding(_, msg)) => { + assert!(msg.contains("push immediate")); + }, + Err(MastForestError::Deserialization(DeserializationError::InvalidValue(msg))) => { + assert!(msg.contains("push immediate")); + }, + Err(err) => panic!("unexpected validation error: {err:?}"), + Ok(_) => {}, + }; + let (forest_a, forest_b) = match (validated_a, validated_b) { (Ok(forest_a), Ok(forest_b)) => (forest_a, forest_b), (validated_a, validated_b) => { - match validated_a { - Err(MastForestError::InvalidBatchPadding(_, msg)) => { - assert!(msg.contains("push immediate")); - }, - Err(err) => panic!("unexpected validation error: {err:?}"), - Ok(_) => {}, - } - match validated_b { - Err(MastForestError::InvalidBatchPadding(_, msg)) => { - assert!(msg.contains("push immediate")); - }, - Err(err) => panic!("unexpected validation error: {err:?}"), - Ok(_) => {}, - } + assert_expected_rejection(validated_a); + assert_expected_rejection(validated_b); return; }, }; @@ -1919,17 +2577,14 @@ fn test_deserialization_rejects_excessive_node_count() { let mut bytes = Vec::new(); // Write valid header - super::MAGIC.write_into(&mut bytes); + MAGIC.write_into(&mut bytes); bytes.write_u8(0); // flags - super::VERSION.write_into(&mut bytes); + VERSION.write_into(&mut bytes); // Write excessive node count (MAX_NODES + 1) let excessive_count: usize = MastForest::MAX_NODES + 1; excessive_count.write_into(&mut bytes); - // Write decorator count - 0usize.write_into(&mut bytes); - // Attempt to deserialize - should fail before any large allocation let result = MastForest::read_from_bytes(&bytes); assert!(result.is_err()); @@ -1939,3 +2594,81 @@ fn test_deserialization_rejects_excessive_node_count() { "Expected error about exceeding maximum, got: {err}" ); } + +/// Test that untrusted deserialization rejects node counts that exceed the reader allocation +/// bound before they can drive later allocations. +#[test] +fn test_untrusted_deserialization_rejects_node_count_above_budget_bound() { + let mut bytes = Vec::new(); + + MAGIC.write_into(&mut bytes); + bytes.write_u8(FLAG_STRIPPED | FLAG_HASHLESS); + VERSION.write_into(&mut bytes); + + 2usize.write_into(&mut bytes); + + let result = UntrustedMastForest::read_from_bytes_with_budget(&bytes, bytes.len()); + assert!(result.is_err()); + let err = result.unwrap_err(); + assert!( + err.to_string().contains("node count 2 exceeds reader allocation bound"), + "Expected budget-bound node count error, got: {err}" + ); +} + +/// Test that custom untrusted budgets also apply to later hashless validation allocations. +#[test] +fn test_untrusted_hashless_validation_respects_custom_allocation_budget() { + let mut forest = MastForest::new(); + let left = BasicBlockNodeBuilder::new(vec![Operation::Add], Vec::new()) + .add_to_forest(&mut forest) + .unwrap(); + let right = BasicBlockNodeBuilder::new(vec![Operation::Mul], Vec::new()) + .add_to_forest(&mut forest) + .unwrap(); + let root = JoinNodeBuilder::new([left, right]).add_to_forest(&mut forest).unwrap(); + forest.make_root(root); + + let mut bytes = Vec::new(); + forest.write_hashless(&mut bytes); + + let untrusted = + UntrustedMastForest::read_from_bytes_with_budgets(&bytes, bytes.len(), bytes.len()) + .unwrap(); + let result = untrusted.validate(); + assert!(result.is_err()); + let err = result.unwrap_err(); + assert!( + err.to_string().contains("remaining untrusted allocation budget"), + "Expected validation-allocation budget error, got: {err}" + ); +} + +/// Test that stripped payloads charge empty debug-info scaffolding with the target pointer width. +#[cfg(target_pointer_width = "64")] +#[test] +fn test_untrusted_stripped_debug_info_budget_uses_usize_slots() { + let mut forest = MastForest::new(); + let left = BasicBlockNodeBuilder::new(vec![Operation::Add], Vec::new()) + .add_to_forest(&mut forest) + .unwrap(); + let right = BasicBlockNodeBuilder::new(vec![Operation::Mul], Vec::new()) + .add_to_forest(&mut forest) + .unwrap(); + let root = JoinNodeBuilder::new([left, right]).add_to_forest(&mut forest).unwrap(); + forest.make_root(root); + + let mut bytes = Vec::new(); + forest.write_stripped(&mut bytes); + + let validation_budget = + (usize::try_from(forest.num_nodes()).unwrap() + 1) * size_of::() - 1; + let result = + UntrustedMastForest::read_from_bytes_with_budgets(&bytes, bytes.len(), validation_budget); + assert!(result.is_err()); + let err = result.unwrap_err(); + assert!( + err.to_string().contains("empty debug-info scaffolding"), + "Expected stripped debug-info budget error, got: {err}" + ); +} diff --git a/core/src/mast/serialization/view.rs b/core/src/mast/serialization/view.rs new file mode 100644 index 0000000000..a0eb574b5f --- /dev/null +++ b/core/src/mast/serialization/view.rs @@ -0,0 +1,64 @@ +use alloc::vec::Vec; + +use super::{MastNodeEntry, MastNodeInfo}; +use crate::{Word, mast::MastNodeId, serde::DeserializationError}; + +/// Read-only view over serialization-oriented MAST node metadata. +/// +/// This trait lives alongside [`super::SerializedMastForest`] because its surface is defined in +/// terms of serialized-equivalent node entries and digests, even though both +/// [`super::SerializedMastForest`] and in-memory [`crate::mast::MastForest`] implement it. +pub trait MastForestView { + /// Returns the number of nodes in the forest. + fn node_count(&self) -> usize; + + /// Returns fixed-width structural metadata for a node at the specified index. + /// + /// Returns an error if `index >= self.node_count()`. + fn node_entry_at(&self, index: usize) -> Result; + + /// Returns the digest of the node at the specified index. + /// + /// Returns an error if `index >= self.node_count()`. + fn node_digest_at(&self, index: usize) -> Result; + + /// Returns serialized-equivalent metadata for a node at the specified index. + /// + /// Returns an error if `index >= self.node_count()`. + fn node_info_at(&self, index: usize) -> Result { + Ok(MastNodeInfo::from_entry( + self.node_entry_at(index)?, + self.node_digest_at(index)?, + )) + } + + /// Returns the number of procedure roots in the forest. + fn procedure_root_count(&self) -> usize; + + /// Returns the procedure root id at the specified index. + /// + /// Returns an error if `index >= self.procedure_root_count()`. + fn procedure_root_at(&self, index: usize) -> Result; + + /// Returns true when the forest contains no nodes. + fn is_empty(&self) -> bool { + self.node_count() == 0 + } + + /// Returns true when `index` is a valid node index. + fn has_node(&self, index: usize) -> bool { + index < self.node_count() + } + + /// Returns all node infos in index order. + fn all_node_infos(&self) -> Result, DeserializationError> { + (0..self.node_count()).map(|index| self.node_info_at(index)).collect() + } + + /// Returns all procedure roots in index order. + fn procedure_roots(&self) -> Result, DeserializationError> { + (0..self.procedure_root_count()) + .map(|index| self.procedure_root_at(index)) + .collect() + } +} diff --git a/core/src/mast/tests.rs b/core/src/mast/tests.rs index 665368b520..45e1ef648c 100644 --- a/core/src/mast/tests.rs +++ b/core/src/mast/tests.rs @@ -1,10 +1,10 @@ use alloc::vec::Vec; -use miden_crypto::{WORD_SIZE, rand::test_utils::prng_array}; +use miden_crypto::rand::test_utils::prng_array; use proptest::prelude::*; use crate::{ - Felt, Word, + Felt, WORD_SIZE, Word, chiplets::hasher, mast::{ BasicBlockNodeBuilder, CallNodeBuilder, DynNode, DynNodeBuilder, JoinNodeBuilder, @@ -58,9 +58,9 @@ fn test_decorator_storage_consistency_with_block_iterator() { // Create operations let operations = vec![ - Operation::Push(Felt::new(1)), + Operation::Push(Felt::new_unchecked(1)), Operation::Add, - Operation::Push(Felt::new(2)), + Operation::Push(Felt::new_unchecked(2)), Operation::Mul, ]; @@ -72,7 +72,7 @@ fn test_decorator_storage_consistency_with_block_iterator() { ]; // Add block to forest using BasicBlockNodeBuilder - let block_id = BasicBlockNodeBuilder::new(operations.clone(), decorators.clone()) + let block_id = BasicBlockNodeBuilder::new(operations, decorators.clone()) .add_to_forest(&mut forest) .unwrap(); @@ -112,12 +112,11 @@ fn test_decorator_storage_consistency_with_block_iterator() { .map(|(_, id)| id) .collect(); - assert_eq!(forest_decos, block_decos, "Decorators for operation {} should match", op_idx); + assert_eq!(forest_decos, block_decos, "Decorators for operation {op_idx} should match"); assert_eq!( forest_decos, &[*expected_decorator_id], - "Should have correct decorator for operation {}", - op_idx + "Should have correct decorator for operation {op_idx}" ); } @@ -135,8 +134,8 @@ fn test_decorator_storage_consistency_with_block_iterator() { .map(|(_, id)| id) .collect(); - assert_eq!(forest_decos, [], "Operation {} should have no decorators", op_idx); - assert_eq!(block_decos, [], "Operation {} should have no decorators", op_idx); + assert_eq!(forest_decos, [], "Operation {op_idx} should have no decorators"); + assert_eq!(block_decos, [], "Operation {op_idx} should have no decorators"); } } @@ -145,10 +144,10 @@ fn test_decorator_storage_consistency_with_empty_block() { let mut forest = MastForest::new(); // Create operations without decorators - let operations = vec![Operation::Push(Felt::new(1)), Operation::Add]; + let operations = vec![Operation::Push(Felt::new_unchecked(1)), Operation::Add]; // Add block to forest using BasicBlockNodeBuilder with no decorators - let block_id = BasicBlockNodeBuilder::new(operations.clone(), vec![]) + let block_id = BasicBlockNodeBuilder::new(operations, vec![]) .add_to_forest(&mut forest) .unwrap(); @@ -182,7 +181,7 @@ fn test_decorator_storage_consistency_with_multiple_blocks() { let deco2 = forest.add_decorator(Decorator::Trace(2)).unwrap(); // Create first block - let operations1 = vec![Operation::Push(Felt::new(1)), Operation::Add]; + let operations1 = vec![Operation::Push(Felt::new_unchecked(1)), Operation::Add]; let decorators1 = vec![(0, deco1), (1, deco2)]; let block_id1 = BasicBlockNodeBuilder::new(operations1, decorators1) .add_to_forest(&mut forest) @@ -192,7 +191,7 @@ fn test_decorator_storage_consistency_with_multiple_blocks() { let deco3 = forest.add_decorator(Decorator::Debug(DebugOptions::StackTop(99))).unwrap(); // Create second block - let operations2 = vec![Operation::Push(Felt::new(2)), Operation::Mul]; + let operations2 = vec![Operation::Push(Felt::new_unchecked(2)), Operation::Mul]; let decorators2 = vec![(0, deco3)]; let block_id2 = BasicBlockNodeBuilder::new(operations2, decorators2) .add_to_forest(&mut forest) @@ -244,7 +243,7 @@ fn test_decorator_storage_after_clear_debug_info() { let deco1 = forest.add_decorator(Decorator::Trace(1)).unwrap(); let deco2 = forest.add_decorator(Decorator::Trace(2)).unwrap(); - let operations = vec![Operation::Push(Felt::new(1)), Operation::Add]; + let operations = vec![Operation::Push(Felt::new_unchecked(1)), Operation::Add]; let block_id = BasicBlockNodeBuilder::new(operations, vec![(0, deco1), (1, deco2)]) .add_to_forest(&mut forest) .unwrap(); @@ -268,7 +267,7 @@ fn test_clear_debug_info_edge_cases() { assert_eq!(forest.debug_info.op_decorator_storage().num_nodes(), 0); // Idempotent: clearing twice should be safe - let operations = vec![Operation::Push(Felt::new(1)), Operation::Add]; + let operations = vec![Operation::Push(Felt::new_unchecked(1)), Operation::Add]; let block_id = BasicBlockNodeBuilder::new(operations, vec![]) .add_to_forest(&mut forest) .unwrap(); @@ -284,7 +283,7 @@ fn test_clear_debug_info_multiple_node_types() { let mut forest = MastForest::new(); let deco = forest.add_decorator(Decorator::Trace(1)).unwrap(); let block_id = BasicBlockNodeBuilder::new( - vec![Operation::Push(Felt::new(1)), Operation::Add], + vec![Operation::Push(Felt::new_unchecked(1)), Operation::Add], vec![(0, deco)], ) .add_to_forest(&mut forest) @@ -299,6 +298,31 @@ fn test_clear_debug_info_multiple_node_types() { assert!(forest.decorator_links_for_node(block_id).unwrap().into_iter().next().is_none()); } +#[test] +fn test_compact_after_clear_debug_info_does_not_materialize_empty_node_decorators() { + let mut forest = MastForest::new(); + let decorator = forest.add_decorator(Decorator::Trace(1)).unwrap(); + let block_id = BasicBlockNodeBuilder::new( + vec![Operation::Push(Felt::new_unchecked(1)), Operation::Add], + vec![(0, decorator)], + ) + .with_before_enter(vec![decorator]) + .add_to_forest(&mut forest) + .unwrap(); + let call_id = CallNodeBuilder::new(block_id).add_to_forest(&mut forest).unwrap(); + forest.make_root(call_id); + + forest.clear_debug_info(); + let (compacted, _) = forest.compact(); + + assert!(compacted.debug_info.node_decorator_storage().is_empty()); + for node_idx in 0..compacted.nodes().len() { + let node_id = crate::mast::MastNodeId::new_unchecked(node_idx as u32); + assert!(compacted.before_enter_decorators(node_id).is_empty()); + assert!(compacted.after_exit_decorators(node_id).is_empty()); + } +} + #[test] fn test_mast_forest_roundtrip_with_basic_blocks_and_decorators() { use crate::mast::MastNode; @@ -324,8 +348,8 @@ fn test_mast_forest_roundtrip_with_basic_blocks_and_decorators() { // Block 2: Complex block with multiple decorators at same operation index let operations2 = vec![ - Operation::Push(Felt::new(1)), - Operation::Push(Felt::new(2)), + Operation::Push(Felt::new_unchecked(1)), + Operation::Push(Felt::new_unchecked(2)), Operation::Mul, Operation::Drop, ]; @@ -433,7 +457,7 @@ fn test_mast_forest_roundtrip_with_basic_blocks_and_decorators() { match op_idx { 0 => op0_decorators.push(decorator_id), 3 => op3_decorators.push(decorator_id), - _ => panic!("Unexpected decorator at operation index {}", op_idx), + _ => panic!("Unexpected decorator at operation index {op_idx}"), } } assert_eq!(op0_decorators.len(), 2); @@ -450,12 +474,15 @@ fn test_mast_forest_serde_converts_linked_to_owned_decorators() { let deco2 = forest.add_decorator(Decorator::Trace(2)).unwrap(); // Create operations with decorators - let operations = - vec![Operation::Push(Felt::new(1)), Operation::Add, Operation::Push(Felt::new(2))]; + let operations = vec![ + Operation::Push(Felt::new_unchecked(1)), + Operation::Add, + Operation::Push(Felt::new_unchecked(2)), + ]; let decorators = vec![(0, deco1), (2, deco2)]; // Add block to forest - this will create Linked decorators - let block_id = BasicBlockNodeBuilder::new(operations.clone(), decorators.clone()) + let block_id = BasicBlockNodeBuilder::new(operations, decorators) .add_to_forest(&mut forest) .unwrap(); @@ -537,12 +564,15 @@ fn test_mast_forest_serializable_converts_linked_to_owned_decorators() { let deco2 = forest.add_decorator(Decorator::Trace(2)).unwrap(); // Create operations with decorators - let operations = - vec![Operation::Push(Felt::new(1)), Operation::Add, Operation::Push(Felt::new(2))]; + let operations = vec![ + Operation::Push(Felt::new_unchecked(1)), + Operation::Add, + Operation::Push(Felt::new_unchecked(2)), + ]; let decorators = vec![(0, deco1), (2, deco2)]; // Add block to forest - this will create Linked decorators - let block_id = BasicBlockNodeBuilder::new(operations.clone(), decorators.clone()) + let block_id = BasicBlockNodeBuilder::new(operations, decorators) .add_to_forest(&mut forest) .unwrap(); @@ -673,9 +703,8 @@ fn test_forest_borrowing_decorator_access() { assert_eq!(forest_borrowed_iter, expected_from_forest); // Test 6: Raw decorator iterator with forest borrowing - let raw_forest_iter: Vec<_> = block_node.raw_decorator_iter(&forest).collect(); // Should include before_enter, op-indexed, and after_exit in order - assert_eq!(raw_forest_iter.len(), 3); // Only op-indexed decorators in this case + assert_eq!(block_node.raw_decorator_iter(&forest).count(), 3); // Only op-indexed decorators in this case // Test 7: Raw op indexed decorators with forest borrowing let raw_op_decorators = block_node.raw_op_indexed_decorators(&forest); @@ -730,16 +759,16 @@ fn test_mast_forest_compaction_comprehensive() { forest.make_root(bb_with_op_deco); // === Join nodes with before-enter decorators === - let child1 = BasicBlockNodeBuilder::new(vec![Operation::Push(Felt::new(1))], Vec::new()) - .add_to_forest(&mut forest) - .unwrap(); - let child2 = BasicBlockNodeBuilder::new(vec![Operation::Push(Felt::new(2))], Vec::new()) - .add_to_forest(&mut forest) - .unwrap(); - let join_no_deco = crate::mast::JoinNodeBuilder::new([child1, child2]) - .add_to_forest(&mut forest) - .unwrap(); - let join_with_before_deco = crate::mast::JoinNodeBuilder::new([child1, child2]) + let child1 = + BasicBlockNodeBuilder::new(vec![Operation::Push(Felt::new_unchecked(1))], Vec::new()) + .add_to_forest(&mut forest) + .unwrap(); + let child2 = + BasicBlockNodeBuilder::new(vec![Operation::Push(Felt::new_unchecked(2))], Vec::new()) + .add_to_forest(&mut forest) + .unwrap(); + let join_no_deco = JoinNodeBuilder::new([child1, child2]).add_to_forest(&mut forest).unwrap(); + let join_with_before_deco = JoinNodeBuilder::new([child1, child2]) .with_before_enter(vec![debug_deco]) .add_to_forest(&mut forest) .unwrap(); @@ -751,13 +780,13 @@ fn test_mast_forest_compaction_comprehensive() { .add_to_forest(&mut forest) .unwrap(); let split_child2 = - BasicBlockNodeBuilder::new(vec![Operation::Assert(Felt::new(1))], Vec::new()) + BasicBlockNodeBuilder::new(vec![Operation::Assert(Felt::new_unchecked(1))], Vec::new()) .add_to_forest(&mut forest) .unwrap(); - let split_no_deco = crate::mast::SplitNodeBuilder::new([split_child1, split_child2]) + let split_no_deco = SplitNodeBuilder::new([split_child1, split_child2]) .add_to_forest(&mut forest) .unwrap(); - let split_with_after_deco = crate::mast::SplitNodeBuilder::new([split_child1, split_child2]) + let split_with_after_deco = SplitNodeBuilder::new([split_child1, split_child2]) .with_after_exit(vec![trace_deco]) .add_to_forest(&mut forest) .unwrap(); @@ -781,10 +810,8 @@ fn test_mast_forest_compaction_comprehensive() { let call_target = BasicBlockNodeBuilder::new(vec![Operation::Mul], Vec::new()) .add_to_forest(&mut forest) .unwrap(); - let call_no_deco = crate::mast::CallNodeBuilder::new(call_target) - .add_to_forest(&mut forest) - .unwrap(); - let call_with_after_deco = crate::mast::CallNodeBuilder::new(call_target) + let call_no_deco = CallNodeBuilder::new(call_target).add_to_forest(&mut forest).unwrap(); + let call_with_after_deco = CallNodeBuilder::new(call_target) .with_after_exit(vec![trace_deco]) .add_to_forest(&mut forest) .unwrap(); @@ -792,8 +819,8 @@ fn test_mast_forest_compaction_comprehensive() { forest.make_root(call_with_after_deco); // === Dyn nodes with before-enter decorators === - let dyn_no_deco = crate::mast::DynNodeBuilder::new_dyn().add_to_forest(&mut forest).unwrap(); - let dyn_with_before_deco = crate::mast::DynNodeBuilder::new_dyn() + let dyn_no_deco = DynNodeBuilder::new_dyn().add_to_forest(&mut forest).unwrap(); + let dyn_with_before_deco = DynNodeBuilder::new_dyn() .with_before_enter(vec![debug_deco]) .add_to_forest(&mut forest) .unwrap(); @@ -843,7 +870,7 @@ fn test_mast_forest_get_assembly_op_basic_block() { let asm_op_id = forest.debug_info.add_asm_op(assembly_op.clone()).unwrap(); // Add a basic block node - let operations = vec![Operation::Push(Felt::new(1)), Operation::Add]; + let operations = vec![Operation::Push(Felt::new_unchecked(1)), Operation::Add]; let node_id = BasicBlockNodeBuilder::new(operations, vec![]) .add_to_forest(&mut forest) .unwrap(); @@ -872,8 +899,8 @@ fn test_mast_forest_get_assembly_op_with_target_index() { // Add a basic block node with 5 operations let operations = vec![ - Operation::Push(Felt::new(1)), - Operation::Push(Felt::new(2)), + Operation::Push(Felt::new_unchecked(1)), + Operation::Push(Felt::new_unchecked(2)), Operation::Mul, Operation::Add, Operation::Drop, @@ -927,8 +954,8 @@ fn test_mast_forest_get_assembly_op_all_node_types() { let asm_op_id = forest.debug_info.add_asm_op(assembly_op.clone()).unwrap(); // Create a basic block with an AssemblyOp registered for its operations - let operations = vec![Operation::Push(Felt::new(1)), Operation::Add]; - let bb_node_id = BasicBlockNodeBuilder::new(operations.clone(), vec![]) + let operations = vec![Operation::Push(Felt::new_unchecked(1)), Operation::Add]; + let bb_node_id = BasicBlockNodeBuilder::new(operations, vec![]) .add_to_forest(&mut forest) .unwrap(); @@ -942,9 +969,10 @@ fn test_mast_forest_get_assembly_op_all_node_types() { // Create some control flow nodes using this basic block let call_node = CallNodeBuilder::new(bb_node_id).add_to_forest(&mut forest).unwrap(); - let join_child2 = BasicBlockNodeBuilder::new(vec![Operation::Push(Felt::new(2))], vec![]) - .add_to_forest(&mut forest) - .unwrap(); + let join_child2 = + BasicBlockNodeBuilder::new(vec![Operation::Push(Felt::new_unchecked(2))], vec![]) + .add_to_forest(&mut forest) + .unwrap(); let _join_node = JoinNodeBuilder::new([bb_node_id, join_child2]) .add_to_forest(&mut forest) .unwrap(); @@ -968,7 +996,7 @@ fn test_mast_forest_get_assembly_comprehensive_edge_cases() { let mut forest = MastForest::new(); // Test 1: Node with no AssemblyOps registered should return None - let operations = vec![Operation::Push(Felt::new(1)), Operation::Add]; + let operations = vec![Operation::Push(Felt::new_unchecked(1)), Operation::Add]; let node_id = BasicBlockNodeBuilder::new(operations.clone(), vec![]) .add_to_forest(&mut forest) .unwrap(); @@ -980,7 +1008,7 @@ fn test_mast_forest_get_assembly_comprehensive_edge_cases() { let asm_op1 = AssemblyOp::new(None, "context1".into(), 1, "op1".into()); let asm_op_id1 = forest.debug_info.add_asm_op(asm_op1.clone()).unwrap(); - let node_id2 = BasicBlockNodeBuilder::new(operations.clone(), vec![]) + let node_id2 = BasicBlockNodeBuilder::new(operations, vec![]) .add_to_forest(&mut forest) .unwrap(); forest.debug_info.register_asm_ops(node_id2, 2, vec![(0, asm_op_id1)]).unwrap(); @@ -995,7 +1023,7 @@ fn test_mast_forest_get_assembly_comprehensive_edge_cases() { let asm_op_id2 = forest.debug_info.add_asm_op(asm_op2.clone()).unwrap(); let asm_op_id3 = forest.debug_info.add_asm_op(asm_op3.clone()).unwrap(); - let ops_multi = vec![Operation::Push(Felt::new(1)), Operation::Add, Operation::Mul]; + let ops_multi = vec![Operation::Push(Felt::new_unchecked(1)), Operation::Add, Operation::Mul]; let node_id3 = BasicBlockNodeBuilder::new(ops_multi, vec![]) .add_to_forest(&mut forest) .unwrap(); @@ -1032,7 +1060,12 @@ fn test_mast_forest_get_assembly_comprehensive_edge_cases() { let asm_op_multi = AssemblyOp::new(None, "multi_cycle".into(), 3, "multi_op".into()); let asm_op_id_multi = forest.debug_info.add_asm_op(asm_op_multi.clone()).unwrap(); - let ops4 = vec![Operation::Push(Felt::new(1)), Operation::Add, Operation::Mul, Operation::Neg]; + let ops4 = vec![ + Operation::Push(Felt::new_unchecked(1)), + Operation::Add, + Operation::Mul, + Operation::Neg, + ]; let node_id4 = BasicBlockNodeBuilder::new(ops4, vec![]).add_to_forest(&mut forest).unwrap(); forest .debug_info @@ -1046,7 +1079,7 @@ fn test_mast_forest_get_assembly_comprehensive_edge_cases() { // All three indices should return the same AssemblyOp for idx in 1..=3 { let result = forest.get_assembly_op(node_id4, Some(idx)); - assert!(result.is_some(), "Should find AssemblyOp at index {}", idx); + assert!(result.is_some(), "Should find AssemblyOp at index {idx}"); assert_eq!(result.unwrap(), &asm_op_multi); } @@ -1172,7 +1205,7 @@ fn digest_from_seed(seed: [u8; 32]) -> Word { digest.iter_mut().enumerate().for_each(|(i, d)| { *d = <[u8; 8]>::try_from(&seed[i * 8..(i + 1) * 8]) .map(u64::from_le_bytes) - .map(Felt::new) + .map(Felt::new_unchecked) .unwrap() }); digest.into() diff --git a/core/src/operations/decorators/debug_var.rs b/core/src/operations/decorators/debug_var.rs index 7023fd27bb..bc12723969 100644 --- a/core/src/operations/decorators/debug_var.rs +++ b/core/src/operations/decorators/debug_var.rs @@ -117,13 +117,13 @@ impl fmt::Display for DebugVarInfo { write!(f, "var.{}", self.name)?; if let Some(arg_index) = self.arg_index { - write!(f, "[arg{}]", arg_index)?; + write!(f, "[arg{arg_index}]")?; } write!(f, " = {}", self.value_location)?; if let Some(loc) = &self.location { - write!(f, " {}", loc)?; + write!(f, " {loc}")?; } Ok(()) @@ -174,12 +174,12 @@ pub enum DebugVarLocation { impl fmt::Display for DebugVarLocation { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - Self::Stack(pos) => write!(f, "stack[{}]", pos), - Self::Memory(addr) => write!(f, "mem[{}]", addr), + Self::Stack(pos) => write!(f, "stack[{pos}]"), + Self::Memory(addr) => write!(f, "mem[{addr}]"), Self::Const(val) => write!(f, "const({})", val.as_canonical_u64()), - Self::Local(offset) => write!(f, "FMP{:+}", offset), + Self::Local(offset) => write!(f, "FMP{offset:+}"), Self::FrameBase { global_index, byte_offset } => { - write!(f, "global[{}]{:+}", global_index, byte_offset) + write!(f, "global[{global_index}]{byte_offset:+}") }, Self::Expression(bytes) => { write!(f, "expr(")?; @@ -187,7 +187,7 @@ impl fmt::Display for DebugVarLocation { if i > 0 { write!(f, " ")?; } - write!(f, "{:02x}", byte)?; + write!(f, "{byte:02x}")?; } write!(f, ")") }, @@ -238,7 +238,7 @@ impl Deserializable for DebugVarLocation { 1 => Ok(Self::Memory(source.read_u32()?)), 2 => { let value = source.read_u64()?; - Ok(Self::Const(Felt::new(value))) + Ok(Self::Const(Felt::new_unchecked(value))) }, 3 => { let bytes = source.read_array::<2>()?; @@ -266,7 +266,7 @@ impl Serializable for DebugVarInfo { (*self.name).write_into(target); self.value_location.write_into(target); self.type_id.write_into(target); - self.arg_index.map(|n| n.get()).write_into(target); + self.arg_index.map(core::num::NonZero::get).write_into(target); self.location.write_into(target); } } @@ -332,7 +332,7 @@ mod tests { fn debug_var_location_display() { assert_eq!(DebugVarLocation::Stack(0).to_string(), "stack[0]"); assert_eq!(DebugVarLocation::Memory(256).to_string(), "mem[256]"); - assert_eq!(DebugVarLocation::Const(Felt::new(42)).to_string(), "const(42)"); + assert_eq!(DebugVarLocation::Const(Felt::new_unchecked(42)).to_string(), "const(42)"); assert_eq!(DebugVarLocation::Local(-3).to_string(), "FMP-3"); assert_eq!( DebugVarLocation::Expression(vec![0x10, 0x20, 0x30]).to_string(), @@ -345,7 +345,7 @@ mod tests { let locations = [ DebugVarLocation::Stack(7), DebugVarLocation::Memory(0xdead_beef), - DebugVarLocation::Const(Felt::new(999)), + DebugVarLocation::Const(Felt::new_unchecked(999)), DebugVarLocation::Local(-3), DebugVarLocation::FrameBase { global_index: 20, byte_offset: -12 }, DebugVarLocation::Expression(vec![0x10, 0x20, 0x30]), diff --git a/core/src/operations/mod.rs b/core/src/operations/mod.rs index eb15be822d..9ea21ca3c5 100644 --- a/core/src/operations/mod.rs +++ b/core/src/operations/mod.rs @@ -904,6 +904,101 @@ impl Serializable for Operation { } } +impl Operation { + /// Returns the serialized size of this operation in bytes. + pub(crate) fn encoded_size(&self) -> usize { + let mut size = size_of::(); + match self { + Operation::Assert(err_code) + | Operation::MpVerify(err_code) + | Operation::U32assert2(err_code) => { + size += err_code.get_size_hint(); + }, + Operation::Push(value) => { + size += value.as_canonical_u64().get_size_hint(); + }, + Operation::Noop + | Operation::SDepth + | Operation::Caller + | Operation::Clk + | Operation::Add + | Operation::Neg + | Operation::Mul + | Operation::Inv + | Operation::Incr + | Operation::And + | Operation::Or + | Operation::Not + | Operation::Eq + | Operation::Eqz + | Operation::Expacc + | Operation::Ext2Mul + | Operation::U32split + | Operation::U32add + | Operation::U32add3 + | Operation::U32sub + | Operation::U32mul + | Operation::U32madd + | Operation::U32div + | Operation::U32and + | Operation::U32xor + | Operation::Pad + | Operation::Drop + | Operation::Dup0 + | Operation::Dup1 + | Operation::Dup2 + | Operation::Dup3 + | Operation::Dup4 + | Operation::Dup5 + | Operation::Dup6 + | Operation::Dup7 + | Operation::Dup9 + | Operation::Dup11 + | Operation::Dup13 + | Operation::Dup15 + | Operation::Swap + | Operation::SwapW + | Operation::SwapW2 + | Operation::SwapW3 + | Operation::SwapDW + | Operation::Emit + | Operation::MovUp2 + | Operation::MovUp3 + | Operation::MovUp4 + | Operation::MovUp5 + | Operation::MovUp6 + | Operation::MovUp7 + | Operation::MovUp8 + | Operation::MovDn2 + | Operation::MovDn3 + | Operation::MovDn4 + | Operation::MovDn5 + | Operation::MovDn6 + | Operation::MovDn7 + | Operation::MovDn8 + | Operation::CSwap + | Operation::CSwapW + | Operation::AdvPop + | Operation::AdvPopW + | Operation::MLoadW + | Operation::MStoreW + | Operation::MLoad + | Operation::MStore + | Operation::MStream + | Operation::Pipe + | Operation::CryptoStream + | Operation::HPerm + | Operation::MrUpdate + | Operation::FriE2F4 + | Operation::HornerBase + | Operation::HornerExt + | Operation::EvalCircuit + | Operation::LogPrecompile => (), + } + size + } +} + impl Deserializable for Operation { fn read_from(source: &mut R) -> Result { let op_code = source.read_u8()?; diff --git a/core/src/precompile.rs b/core/src/precompile.rs index c7384d9bc0..fb140d1046 100644 --- a/core/src/precompile.rs +++ b/core/src/precompile.rs @@ -118,6 +118,10 @@ impl Deserializable for PrecompileRequest { let calldata = Vec::::read_from(source)?; Ok(Self { event_id, calldata }) } + + fn min_serialized_size() -> usize { + EventId::min_serialized_size() + Vec::::min_serialized_size() + } } // PRECOMPILE TRANSCRIPT TYPES diff --git a/core/src/program/kernel.rs b/core/src/program/kernel.rs index 0e7fe01eb8..4ce42077da 100644 --- a/core/src/program/kernel.rs +++ b/core/src/program/kernel.rs @@ -53,7 +53,7 @@ impl Kernel { // Canonical ordering is a separate kernel invariant (not just a dedup side effect), so // we sort first and then validate uniqueness over the canonical representation. - hashes.sort_by_key(|v| v.as_bytes()); // ensure consistent order + hashes.sort_by_key(Word::as_bytes); // ensure consistent order let duplicated = hashes.windows(2).any(|data| data[0] == data[1]); if duplicated { @@ -142,8 +142,20 @@ mod tests { #[test] fn kernel_read_from_rejects_duplicate_procedure_hashes() { - let a: Word = [Felt::new(1), Felt::new(2), Felt::new(3), Felt::new(4)].into(); - let b: Word = [Felt::new(5), Felt::new(6), Felt::new(7), Felt::new(8)].into(); + let a: Word = [ + Felt::new_unchecked(1), + Felt::new_unchecked(2), + Felt::new_unchecked(3), + Felt::new_unchecked(4), + ] + .into(); + let b: Word = [ + Felt::new_unchecked(5), + Felt::new_unchecked(6), + Felt::new_unchecked(7), + Felt::new_unchecked(8), + ] + .into(); assert!( Kernel::new(&[a, a]).is_err(), @@ -170,7 +182,13 @@ mod tests { #[cfg(feature = "serde")] #[test] fn kernel_serde_deserialisation_rejects_duplicate_procedure_hashes() { - let a: Word = [Felt::new(1), Felt::new(2), Felt::new(3), Felt::new(4)].into(); + let a: Word = [ + Felt::new_unchecked(1), + Felt::new_unchecked(2), + Felt::new_unchecked(3), + Felt::new_unchecked(4), + ] + .into(); assert!( Kernel::new(&[a, a]).is_err(), @@ -190,7 +208,15 @@ mod tests { #[test] fn kernel_serde_deserialisation_rejects_too_many_procedure_hashes() { let proc_hashes: Vec = (0u64..=255) - .map(|n| [Felt::new(n), Felt::new(n + 1), Felt::new(n + 2), Felt::new(n + 3)].into()) + .map(|n| { + [ + Felt::new_unchecked(n), + Felt::new_unchecked(n + 1), + Felt::new_unchecked(n + 2), + Felt::new_unchecked(n + 3), + ] + .into() + }) .collect(); let json = serde_json::to_string(&proc_hashes).unwrap(); diff --git a/core/src/program/mod.rs b/core/src/program/mod.rs index f9a9d0b79e..2108ff4d03 100644 --- a/core/src/program/mod.rs +++ b/core/src/program/mod.rs @@ -155,13 +155,10 @@ impl Program { }, Err(err) => Err(err), }) - .map_err(|p| { - match p.downcast::() { - // SAFETY: It is guaranteed to be safe to read Box - Ok(err) => unsafe { core::ptr::read(&*err) }, - // Propagate unknown panics - Err(err) => std::panic::resume_unwind(err), - } + .map_err(|p| match p.downcast::() { + Ok(err) => *err, + // Propagate unknown panics + Err(err) => std::panic::resume_unwind(err), })? } } diff --git a/core/src/program/stack/inputs.rs b/core/src/program/stack/inputs.rs index 7903e928d5..6ab66788ff 100644 --- a/core/src/program/stack/inputs.rs +++ b/core/src/program/stack/inputs.rs @@ -13,7 +13,7 @@ use crate::{ /// Defines the initial state of the VM's operand stack. /// /// The first element is at position 0 (top of stack). -#[derive(Clone, Copy, Debug, Default)] +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] pub struct StackInputs { elements: [Felt; MIN_STACK_DEPTH], } diff --git a/core/src/program/stack/tests.rs b/core/src/program/stack/tests.rs index 6fcbb322e8..fff0e32a33 100644 --- a/core/src/program/stack/tests.rs +++ b/core/src/program/stack/tests.rs @@ -140,17 +140,17 @@ fn test_get_stack_word() { // For idx=0, we expect [1, 2, 3, 4] (elements at positions 0-3, in order) let word_0 = outputs.get_word(0).unwrap(); - assert_eq!(word_0[0], Felt::new(1), "word[0] element 0"); - assert_eq!(word_0[1], Felt::new(2), "word[0] element 1"); - assert_eq!(word_0[2], Felt::new(3), "word[0] element 2"); - assert_eq!(word_0[3], Felt::new(4), "word[0] element 3"); + assert_eq!(word_0[0], Felt::new_unchecked(1), "word[0] element 0"); + assert_eq!(word_0[1], Felt::new_unchecked(2), "word[0] element 1"); + assert_eq!(word_0[2], Felt::new_unchecked(3), "word[0] element 2"); + assert_eq!(word_0[3], Felt::new_unchecked(4), "word[0] element 3"); // For idx=4, we expect [5, 6, 7, 8] let word_4 = outputs.get_word(4).unwrap(); - assert_eq!(word_4[0], Felt::new(5), "word[4] element 0"); - assert_eq!(word_4[1], Felt::new(6), "word[4] element 1"); - assert_eq!(word_4[2], Felt::new(7), "word[4] element 2"); - assert_eq!(word_4[3], Felt::new(8), "word[4] element 3"); + assert_eq!(word_4[0], Felt::new_unchecked(5), "word[4] element 0"); + assert_eq!(word_4[1], Felt::new_unchecked(6), "word[4] element 1"); + assert_eq!(word_4[2], Felt::new_unchecked(7), "word[4] element 2"); + assert_eq!(word_4[3], Felt::new_unchecked(8), "word[4] element 3"); // Test bounds checking - should return None for out of bounds access assert!(outputs.get_word(13).is_none(), "Should return None for out of bounds"); diff --git a/core/src/proof.rs b/core/src/proof.rs index a978db0bc3..fbb6e3dd9d 100644 --- a/core/src/proof.rs +++ b/core/src/proof.rs @@ -3,6 +3,8 @@ use alloc::{ vec::Vec, }; +#[cfg(feature = "arbitrary")] +use proptest::prelude::*; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; @@ -10,7 +12,8 @@ use crate::{ crypto::hash::{Blake3_256, Poseidon2, Rpo256, Rpx256}, precompile::PrecompileRequest, serde::{ - ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable, SliceReader, + BudgetedReader, ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable, + SliceReader, }, }; @@ -87,8 +90,7 @@ impl ExecutionProof { /// /// The serialization layout matches the [`Serializable`] implementation of [`ExecutionProof`]. pub fn from_bytes(source: &[u8]) -> Result { - let mut reader = SliceReader::new(source); - Self::read_from(&mut reader) + ::read_from_bytes(source) } // DESTRUCTOR @@ -106,6 +108,10 @@ impl ExecutionProof { /// A hash function used during STARK proof generation. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr( + all(feature = "arbitrary", test), + miden_test_serde_macros::serde_test(binary_serde(true)) +)] #[repr(u8)] pub enum HashFunction { /// BLAKE3 hash function with 256-bit output. @@ -165,6 +171,24 @@ impl TryFrom<&str> for HashFunction { } } +#[cfg(feature = "arbitrary")] +impl Arbitrary for HashFunction { + type Parameters = (); + type Strategy = BoxedStrategy; + + fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { + any::() + .prop_map(|tag| match tag % 5 { + 0 => Self::Blake3_256, + 1 => Self::Rpo256, + 2 => Self::Rpx256, + 3 => Self::Poseidon2, + _ => Self::Keccak, + }) + .boxed() + } +} + // SERIALIZATION // ================================================================================================ @@ -196,6 +220,11 @@ impl Deserializable for ExecutionProof { Ok(ExecutionProof { proof, hash_fn, pc_requests }) } + + fn read_from_bytes(bytes: &[u8]) -> Result { + let mut reader = BudgetedReader::new(SliceReader::new(bytes), bytes.len()); + Self::read_from(&mut reader) + } } // HASH FUNCTION ERROR @@ -230,7 +259,48 @@ impl ExecutionProof { #[cfg(test)] mod tests { use super::*; - use crate::serde::{BudgetedReader, ByteWriter, DeserializationError, SliceReader}; + use crate::{ + events::EventId, + serde::{BudgetedReader, ByteWriter, DeserializationError, SliceReader}, + }; + + #[test] + fn execution_proof_from_bytes_rejects_unbounded_proof_len() { + let mut bytes = Vec::new(); + bytes.write_usize(usize::MAX); + + let err = ExecutionProof::from_bytes(&bytes).unwrap_err(); + let DeserializationError::InvalidValue(message) = err else { + panic!("expected InvalidValue error"); + }; + assert!(message.contains("requested")); + assert!(message.contains("reader can provide at most")); + } + + #[test] + fn execution_proof_read_from_bytes_rejects_unbounded_proof_len() { + let mut bytes = Vec::new(); + bytes.write_usize(usize::MAX); + + let err = ExecutionProof::read_from_bytes(&bytes).unwrap_err(); + let DeserializationError::InvalidValue(message) = err else { + panic!("expected InvalidValue error"); + }; + assert!(message.contains("requested")); + assert!(message.contains("reader can provide at most")); + } + + #[test] + fn execution_proof_from_bytes_accepts_many_minimal_precompile_requests() { + let pc_requests = (0..64) + .map(|event_id| PrecompileRequest::new(EventId::from_u64(event_id), Vec::new())) + .collect(); + let proof = ExecutionProof::new(vec![1, 2, 3], HashFunction::Blake3_256, pc_requests); + + let decoded = ExecutionProof::from_bytes(&proof.to_bytes()).unwrap(); + + assert_eq!(decoded, proof); + } #[test] fn execution_proof_rejects_over_budget_proof_len() { diff --git a/core/src/utils/col_matrix.rs b/core/src/utils/col_matrix.rs index 80da16cba5..ef67f7c363 100644 --- a/core/src/utils/col_matrix.rs +++ b/core/src/utils/col_matrix.rs @@ -60,7 +60,7 @@ impl ColMatrix { /// Returns an iterator over all columns in this matrix. pub fn columns(&self) -> impl Iterator { - self.columns.iter().map(|col| col.as_slice()) + self.columns.iter().map(Vec::as_slice) } /// Copies values of all columns at the specified row into the specified row slice. diff --git a/core/src/utils/mod.rs b/core/src/utils/mod.rs index 2f0287b092..5571cb9362 100644 --- a/core/src/utils/mod.rs +++ b/core/src/utils/mod.rs @@ -50,10 +50,10 @@ impl ToElements for Vec { pub fn hash_string_to_word<'a>(value: impl Into<&'a str>) -> Word { let digest_bytes: [u8; 32] = Blake3_256::hash(value.into().as_bytes()).into(); [ - Felt::new(u64::from_le_bytes(digest_bytes[0..8].try_into().unwrap())), - Felt::new(u64::from_le_bytes(digest_bytes[8..16].try_into().unwrap())), - Felt::new(u64::from_le_bytes(digest_bytes[16..24].try_into().unwrap())), - Felt::new(u64::from_le_bytes(digest_bytes[24..32].try_into().unwrap())), + Felt::new_unchecked(u64::from_le_bytes(digest_bytes[0..8].try_into().unwrap())), + Felt::new_unchecked(u64::from_le_bytes(digest_bytes[8..16].try_into().unwrap())), + Felt::new_unchecked(u64::from_le_bytes(digest_bytes[16..24].try_into().unwrap())), + Felt::new_unchecked(u64::from_le_bytes(digest_bytes[24..32].try_into().unwrap())), ] .into() } @@ -110,7 +110,7 @@ where /// Number of bytes packed into each u32 field element. /// /// Used for converting between byte arrays and u32-packed field elements in memory. -const BYTES_PER_U32: usize = core::mem::size_of::(); +const BYTES_PER_U32: usize = size_of::(); /// Converts bytes to field elements using u32 packing in little-endian format. /// diff --git a/crates/ace-codegen/Cargo.toml b/crates/ace-codegen/Cargo.toml index 26507f4a06..c63ea80fbf 100644 --- a/crates/ace-codegen/Cargo.toml +++ b/crates/ace-codegen/Cargo.toml @@ -13,11 +13,13 @@ repository.workspace = true rust-version.workspace = true edition.workspace = true +[features] +testing = [] + [dependencies] miden-core = { workspace = true } miden-crypto = { workspace = true } thiserror = { workspace = true } [dev-dependencies] -miden-air = { workspace = true, features = ["std"] } miden-core = { workspace = true, features = ["std"] } diff --git a/crates/ace-codegen/src/circuit.rs b/crates/ace-codegen/src/circuit.rs index 49b0867533..900b6c52f0 100644 --- a/crates/ace-codegen/src/circuit.rs +++ b/crates/ace-codegen/src/circuit.rs @@ -89,22 +89,21 @@ impl AceCircuit { } /// Emit an ACE circuit from the DAG and input layout. -pub(crate) fn emit_circuit( - dag: &AceDag, - layout: InputLayout, -) -> Result, AceError> +pub fn emit_circuit(dag: &AceDag, layout: InputLayout) -> Result, AceError> where EF: Field, { let mut constants = Vec::new(); let mut constant_map = HashMap::::new(); let mut operations = Vec::new(); - let mut node_map: Vec> = vec![None; dag.nodes.len()]; + let mut node_map: Vec> = vec![None; dag.nodes().len()]; - for (idx, node) in dag.nodes.iter().enumerate() { + for (idx, node) in dag.nodes().iter().enumerate() { let ace_node = match node { NodeKind::Input(key) => { - let input_idx = layout.index(*key).expect("input key must be present in layout"); + let input_idx = layout.index(*key).ok_or_else(|| AceError::InvalidInputLayout { + message: format!("missing input key in layout: {key:?}"), + })?; AceNode::Input(input_idx) }, NodeKind::Constant(value) => { @@ -153,7 +152,7 @@ where node_map[idx] = Some(ace_node); } - let root = lookup_node(&node_map, dag.root); + let root = lookup_node(&node_map, dag.root()); Ok(AceCircuit { layout, constants, operations, root }) } diff --git a/crates/ace-codegen/src/dag/builder.rs b/crates/ace-codegen/src/dag/builder.rs index 25b9a8f0af..170de6685d 100644 --- a/crates/ace-codegen/src/dag/builder.rs +++ b/crates/ace-codegen/src/dag/builder.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; use miden_crypto::field::Field; -use super::ir::{NodeId, NodeKind}; +use super::ir::{DagId, DagSnapshot, NodeId, NodeKind}; use crate::layout::InputKey; /// A hash-consed DAG builder. @@ -11,8 +11,10 @@ use crate::layout::InputKey; /// compact and deterministic. #[derive(Debug)] pub struct DagBuilder { + dag_id: DagId, nodes: Vec>, cache: HashMap, NodeId>, + imported_dag: Option, } impl DagBuilder @@ -21,7 +23,59 @@ where { /// Create an empty, hash-consed DAG builder. pub fn new() -> Self { - Self { nodes: Vec::new(), cache: HashMap::new() } + Self { + dag_id: DagId::fresh(), + nodes: Vec::new(), + cache: HashMap::new(), + imported_dag: None, + } + } + + /// Resume building from existing nodes using the published 0.23.0 API shape. + /// + /// Imported node ids are rebased onto the new builder, and ids from the source DAG + /// are accepted only when that provenance is encoded in the node graph itself. + pub fn from_nodes(nodes: Vec>) -> Self { + let imported_dag = infer_dag_id(&nodes) + .map(|source_dag_id| ImportedDag { source_dag_id, imported_len: nodes.len() }); + let dag_id = DagId::fresh(); + let nodes = rebase_nodes(nodes, dag_id); + + Self::from_existing_nodes(dag_id, nodes, imported_dag) + } + + /// Resume building from an exported snapshot. + /// + /// This preserves the original DAG id even when the imported nodes are all leaves. + pub fn from_snapshot(snapshot: DagSnapshot) -> Self { + let (source_dag_id, nodes, _) = snapshot.into_parts(); + let dag_id = DagId::fresh(); + let imported_dag = Some(ImportedDag { source_dag_id, imported_len: nodes.len() }); + let nodes = rebase_nodes(nodes, dag_id); + + Self::from_existing_nodes(dag_id, nodes, imported_dag) + } + + /// Resume building from an existing DAG. + /// + /// Rebuilds the deduplication cache so that subsequent operations reuse + /// existing subexpressions. + pub fn from_dag(dag: super::AceDag) -> Self { + let dag_id = dag.dag_id(); + Self::from_existing_nodes(dag_id, dag.into_nodes(), None) + } + + fn from_existing_nodes( + dag_id: DagId, + nodes: Vec>, + imported_dag: Option, + ) -> Self { + let cache = nodes + .iter() + .enumerate() + .map(|(i, n)| (n.clone(), NodeId::in_dag(i, dag_id))) + .collect(); + Self { dag_id, nodes, cache, imported_dag } } /// Consume the builder and return its node list. @@ -29,6 +83,13 @@ where self.nodes } + /// Consume the builder and return a DAG with the provided root. + pub fn build(self, root: NodeId) -> super::AceDag { + let root = self.resolve_id(root, "DAG root must refer to a node built by this DagBuilder"); + + super::AceDag::from_parts(self.dag_id, self.nodes, root) + } + /// Add an input node. pub fn input(&mut self, key: InputKey) -> NodeId { self.intern(NodeKind::Input(key)) @@ -41,6 +102,8 @@ where /// Add an addition node (with constant folding). pub fn add(&mut self, a: NodeId, b: NodeId) -> NodeId { + let a = self.resolve_node(a); + let b = self.resolve_node(b); if let (Some(x), Some(y)) = (self.const_value(a), self.const_value(b)) { return self.constant(x + y); } @@ -56,6 +119,8 @@ where /// Add a subtraction node (with constant folding). pub fn sub(&mut self, a: NodeId, b: NodeId) -> NodeId { + let a = self.resolve_node(a); + let b = self.resolve_node(b); if let (Some(x), Some(y)) = (self.const_value(a), self.const_value(b)) { return self.constant(x - y); } @@ -67,6 +132,8 @@ where /// Add a multiplication node (with constant folding). pub fn mul(&mut self, a: NodeId, b: NodeId) -> NodeId { + let a = self.resolve_node(a); + let b = self.resolve_node(b); if let (Some(x), Some(y)) = (self.const_value(a), self.const_value(b)) { return self.constant(x * y); } @@ -85,6 +152,7 @@ where /// Add a negation node (with constant folding). pub fn neg(&mut self, a: NodeId) -> NodeId { + let a = self.resolve_node(a); if let Some(x) = self.const_value(a) { return self.constant(-x); } @@ -106,15 +174,69 @@ where self.const_value(id).is_some_and(|v| v == EF::ONE) } + fn resolve_node(&self, id: NodeId) -> NodeId { + self.resolve_id(id, "DAG node must come from this DagBuilder") + } + fn intern(&mut self, node: NodeKind) -> NodeId { if let Some(id) = self.cache.get(&node) { return *id; } - let id = NodeId(self.nodes.len()); + let id = NodeId::in_dag(self.nodes.len(), self.dag_id); self.nodes.push(node.clone()); self.cache.insert(node, id); id } + + fn resolve_id(&self, id: NodeId, message: &str) -> NodeId { + assert!(id.index() < self.nodes.len(), "{message}"); + + if id.dag_id == self.dag_id { + return id; + } + + if let Some(imported) = &self.imported_dag + && imported.source_dag_id == id.dag_id + && id.index() < imported.imported_len + { + return NodeId::in_dag(id.index(), self.dag_id); + } + + panic!("{message}"); + } +} + +fn infer_dag_id(nodes: &[NodeKind]) -> Option { + nodes.iter().find_map(|node| match node { + NodeKind::Add(a, _) | NodeKind::Sub(a, _) | NodeKind::Mul(a, _) | NodeKind::Neg(a) => { + Some(a.dag_id) + }, + NodeKind::Input(_) | NodeKind::Constant(_) => None, + }) +} + +fn rebase_nodes(nodes: Vec>, dag_id: DagId) -> Vec> { + nodes + .into_iter() + .map(|node| match node { + NodeKind::Input(key) => NodeKind::Input(key), + NodeKind::Constant(value) => NodeKind::Constant(value), + NodeKind::Add(a, b) => NodeKind::Add(rebase_node(a, dag_id), rebase_node(b, dag_id)), + NodeKind::Sub(a, b) => NodeKind::Sub(rebase_node(a, dag_id), rebase_node(b, dag_id)), + NodeKind::Mul(a, b) => NodeKind::Mul(rebase_node(a, dag_id), rebase_node(b, dag_id)), + NodeKind::Neg(a) => NodeKind::Neg(rebase_node(a, dag_id)), + }) + .collect() +} + +fn rebase_node(id: NodeId, dag_id: DagId) -> NodeId { + NodeId::in_dag(id.index(), dag_id) +} + +#[derive(Debug, Clone)] +struct ImportedDag { + source_dag_id: DagId, + imported_len: usize, } impl Default for DagBuilder @@ -125,3 +247,194 @@ where Self::new() } } + +#[cfg(test)] +mod tests { + use miden_core::{Felt, field::QuadFelt}; + + use super::DagBuilder; + use crate::layout::InputKey; + + fn felt(value: u64) -> QuadFelt { + QuadFelt::from(Felt::new_unchecked(value)) + } + + #[test] + #[should_panic(expected = "DAG root must refer to a node built by this DagBuilder")] + fn build_rejects_same_index_root_from_another_builder() { + let mut foreign_builder = DagBuilder::::new(); + let foreign_root = foreign_builder.constant(felt(1)); + + let mut builder = DagBuilder::::new(); + builder.constant(felt(1)); + + let _ = builder.build(foreign_root); + } + + #[test] + #[should_panic(expected = "DAG node must come from this DagBuilder")] + fn add_rejects_foreign_node() { + let mut foreign_builder = DagBuilder::::new(); + let foreign = foreign_builder.constant(felt(2)); + + let mut builder = DagBuilder::::new(); + let local = builder.constant(felt(1)); + + let _ = builder.add(local, foreign); + } + + #[test] + #[should_panic(expected = "DAG node must come from this DagBuilder")] + fn sub_rejects_foreign_node() { + let mut foreign_builder = DagBuilder::::new(); + let foreign = foreign_builder.constant(felt(2)); + + let mut builder = DagBuilder::::new(); + let local = builder.constant(felt(1)); + + let _ = builder.sub(local, foreign); + } + + #[test] + #[should_panic(expected = "DAG node must come from this DagBuilder")] + fn mul_rejects_foreign_node() { + let mut foreign_builder = DagBuilder::::new(); + let foreign = foreign_builder.constant(felt(2)); + + let mut builder = DagBuilder::::new(); + let local = builder.constant(felt(1)); + + let _ = builder.mul(local, foreign); + } + + #[test] + #[should_panic(expected = "DAG node must come from this DagBuilder")] + fn neg_rejects_foreign_node() { + let mut foreign_builder = DagBuilder::::new(); + let foreign = foreign_builder.constant(felt(2)); + + let mut builder = DagBuilder::::new(); + let _ = builder.constant(felt(1)); + + let _ = builder.neg(foreign); + } + + #[test] + fn from_dag_preserves_node_ownership() { + let mut builder = DagBuilder::::new(); + let a = builder.constant(felt(1)); + let dag = builder.build(a); + let root = dag.root(); + + let mut rebuilt = DagBuilder::from_dag(dag); + let b = rebuilt.constant(felt(2)); + let sum = rebuilt.add(root, b); + + let rebuilt_dag = rebuilt.build(sum); + assert_eq!(rebuilt_dag.root().index(), sum.index()); + } + + #[test] + fn from_nodes_accepts_published_root_shape() { + let mut builder = DagBuilder::::new(); + let a = builder.input(InputKey::Gamma); + let b = builder.constant(felt(2)); + let root = builder.add(a, b); + let dag = builder.build(root); + + let mut rebuilt = DagBuilder::from_nodes(dag.nodes.clone()); + let c = rebuilt.constant(felt(3)); + let sum = rebuilt.add(dag.root, c); + + let rebuilt_dag = rebuilt.build(sum); + assert_eq!(rebuilt_dag.root().index(), sum.index()); + } + + #[test] + fn from_nodes_accepts_leaf_only_root_shape() { + let mut builder = DagBuilder::::new(); + let a = builder.constant(felt(1)); + let dag = builder.build(a); + + let root = dag.root(); + let mut rebuilt = DagBuilder::from_snapshot(dag.into_snapshot()); + let b = rebuilt.constant(felt(2)); + let sum = rebuilt.add(root, b); + + let rebuilt_dag = rebuilt.build(sum); + assert_eq!(rebuilt_dag.root().index(), sum.index()); + } + + #[test] + fn from_snapshot_accepts_leaf_only_root_after_source_dag_is_dropped() { + let mut builder = DagBuilder::::new(); + let a = builder.constant(felt(1)); + let snapshot = builder.build(a).into_snapshot(); + let root = snapshot.root(); + + let mut rebuilt = DagBuilder::from_snapshot(snapshot); + let b = rebuilt.constant(felt(2)); + let sum = rebuilt.add(root, b); + + let rebuilt_dag = rebuilt.build(sum); + assert_eq!(rebuilt_dag.root().index(), sum.index()); + } + + #[test] + #[should_panic(expected = "DAG node must come from this DagBuilder")] + fn from_nodes_rejects_foreign_node_from_another_builder() { + let mut source_builder = DagBuilder::::new(); + let a = source_builder.input(InputKey::Gamma); + let b = source_builder.constant(felt(2)); + let root = source_builder.add(a, b); + let dag = source_builder.build(root); + + let mut rebuilt = DagBuilder::from_nodes(dag.nodes.clone()); + let mut foreign_builder = DagBuilder::::new(); + let foreign = foreign_builder.constant(felt(3)); + + let _ = rebuilt.add(dag.root, foreign); + } + + #[test] + #[should_panic(expected = "DAG root must refer to a node built by this DagBuilder")] + fn from_nodes_rejects_foreign_root_from_another_builder() { + let mut source_builder = DagBuilder::::new(); + let a = source_builder.input(InputKey::Gamma); + let b = source_builder.constant(felt(2)); + let root = source_builder.add(a, b); + let dag = source_builder.build(root); + + let rebuilt = DagBuilder::from_nodes(dag.nodes); + let mut foreign_builder = DagBuilder::::new(); + let foreign = foreign_builder.constant(felt(3)); + + let _ = rebuilt.build(foreign); + } + + #[test] + #[should_panic(expected = "DAG root must refer to a node built by this DagBuilder")] + fn from_nodes_leaf_only_rejects_foreign_root_before_any_imported_id() { + let mut source_builder = DagBuilder::::new(); + let source = source_builder.constant(felt(1)); + let dag = source_builder.build(source); + + let rebuilt = DagBuilder::from_nodes(dag.nodes.clone()); + let _ = rebuilt.build(dag.root); + } + + #[test] + #[should_panic(expected = "DAG root must refer to a node built by this DagBuilder")] + fn from_snapshot_leaf_only_rejects_foreign_root() { + let mut source_builder = DagBuilder::::new(); + let source = source_builder.constant(felt(1)); + let snapshot = source_builder.build(source).into_snapshot(); + + let mut foreign_builder = DagBuilder::::new(); + let foreign = foreign_builder.constant(felt(3)); + let foreign_dag = foreign_builder.build(foreign); + + let rebuilt = DagBuilder::from_snapshot(snapshot); + let _ = rebuilt.build(foreign_dag.root); + } +} diff --git a/crates/ace-codegen/src/dag/ir.rs b/crates/ace-codegen/src/dag/ir.rs index f261d9a196..9ad1f4aafd 100644 --- a/crates/ace-codegen/src/dag/ir.rs +++ b/crates/ace-codegen/src/dag/ir.rs @@ -1,3 +1,5 @@ +use core::sync::atomic::{AtomicUsize, Ordering}; + use miden_crypto::{ field::TwoAdicField, stark::dft::{NaiveDft, TwoAdicSubgroupDft}, @@ -5,14 +7,32 @@ use miden_crypto::{ use crate::layout::InputKey; +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub(crate) struct DagId(usize); + +impl DagId { + pub(crate) fn fresh() -> Self { + static NEXT_DAG_ID: AtomicUsize = AtomicUsize::new(0); + + Self(NEXT_DAG_ID.fetch_add(1, Ordering::Relaxed)) + } +} + /// Identifier for a node in the DAG. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub struct NodeId(pub(super) usize); +pub struct NodeId { + pub(super) dag_id: DagId, + pub(super) index: usize, +} impl NodeId { /// Return the underlying node index. pub const fn index(self) -> usize { - self.0 + self.index + } + + pub(super) const fn in_dag(index: usize, dag_id: DagId) -> Self { + Self { dag_id, index } } } @@ -77,7 +97,7 @@ impl PeriodicColumnData { /// Maximum periodic column length (used to align powers). pub fn max_period(&self) -> usize { - self.coeffs.iter().map(|c| c.len()).max().unwrap_or(0) + self.coeffs.iter().map(Vec::len).max().unwrap_or(0) } /// Iterate over the per-column coefficient vectors. @@ -89,8 +109,59 @@ impl PeriodicColumnData { /// A built DAG with a designated root. #[derive(Debug)] pub struct AceDag { + dag_id: DagId, /// Topologically ordered nodes. pub nodes: Vec>, /// Root node of the verifier equation. pub root: NodeId, } + +/// Exported DAG data that preserves the source DAG id across imports. +#[derive(Debug, Clone)] +pub struct DagSnapshot { + nodes: Vec>, + root: NodeId, + source_dag_id: DagId, +} + +impl AceDag { + pub(crate) fn from_parts(dag_id: DagId, nodes: Vec>, root: NodeId) -> Self { + Self { dag_id, nodes, root } + } + + pub(crate) fn nodes(&self) -> &[NodeKind] { + &self.nodes + } + + pub(crate) fn into_nodes(self) -> Vec> { + self.nodes + } + + pub(crate) fn dag_id(&self) -> DagId { + self.dag_id + } + + pub fn root(&self) -> NodeId { + self.root + } + + /// Consume the DAG and return an exported snapshot that can be re-imported later. + pub fn into_snapshot(self) -> DagSnapshot { + DagSnapshot { + nodes: self.nodes, + root: self.root, + source_dag_id: self.dag_id, + } + } +} + +impl DagSnapshot { + /// Root node of the verifier equation. + pub fn root(&self) -> NodeId { + self.root + } + + pub(super) fn into_parts(self) -> (DagId, Vec>, NodeId) { + (self.source_dag_id, self.nodes, self.root) + } +} diff --git a/crates/ace-codegen/src/dag/lower.rs b/crates/ace-codegen/src/dag/lower.rs index e5f43f9a38..f9e0d1f23e 100644 --- a/crates/ace-codegen/src/dag/lower.rs +++ b/crates/ace-codegen/src/dag/lower.rs @@ -1,3 +1,86 @@ +//! Lowering from symbolic AIR constraints to the verifier DAG. +//! +//! # Verifier expression +//! +//! The ACE circuit evaluates the STARK verifier's core check at a single +//! out-of-domain point `z`. The root expression is: +//! +//! ```text +//! root = acc - quotient_recomposition * (z^N - 1) +//! ``` +//! +//! The verifier accepts if and only if `root == 0`. +//! +//! ## Constraint folding +//! +//! Given N constraints `C_0, C_1, ..., C_{N-1}`, the folded accumulator `acc` +//! is built via Horner's method with the composition challenge `alpha`: +//! +//! ```text +//! acc = C_0 + alpha * (C_1 + alpha * (C_2 + ... )) +//! ``` +//! +//! Each constraint `C_i(z)` is a symbolic expression over trace openings, +//! public inputs, periodic columns, and selector polynomials (see below). +//! +//! +//! ## Selector polynomials +//! +//! Constraints may be multiplied by selector polynomials that restrict them +//! to specific rows. These selectors are precomputed by the MASM verifier +//! and supplied as circuit inputs: +//! +//! - `is_first = (z^N - 1) / (z - 1)` Active on the first row of the trace. +//! +//! - `is_last = (z^N - 1) / (z - g^{-1})` Active on the last row of the trace (g = trace domain +//! generator). +//! +//! - `is_transition = z - g^{-1}` Active on all rows except the last. +//! +//! ## Periodic columns +//! +//! Periodic columns are polynomials evaluated at `z_k = z^(N / max_cycle_len)`. +//! Each column's coefficients are Horner-evaluated at `z_k` (or a power of +//! `z_k` for columns whose period divides `max_cycle_len`). +//! +//! ## Quotient recomposition +//! +//! The quotient polynomial `Q(x)` is split into `k` chunks `Q_0, ..., Q_{k-1}`, +//! where chunk `Q_i` is evaluated on a coset shifted by `s_i`. To recover the +//! combined quotient at `z^N`, barycentric interpolation over the `k` coset +//! shifts is used: +//! +//! ```text +//! s_i = s0 * f^i (coset shifts) +//! delta_i = z^N - s_i (eval point minus each shift) +//! w_i = weight0 * f^i (barycentric weights) +//! zps_i = w_i * prod_{j != i} delta_j +//! +//! quotient_recomposition = sum_{i=0}^{k-1} zps_i * Q_i(z) +//! ``` +//! +//! where `s0 = offset^N`, `f = h^N` (h = LDE domain generator), +//! `weight0 = 1 / (k * s0^{k-1})`, and `Q_i(z)` is reconstructed from its +//! base-field coordinates evaluations. +//! +//! ## Stark variables summary +//! +//! Each stark variable and where it enters the expression: +//! +//! ```text +//! alpha Composition challenge. Horner accumulator for constraint folding. +//! z^N Trace-length power. Vanishing factor and delta base in quotient +//! recomposition. +//! z_k Periodic column evaluation point (z^(N / max_cycle_len)). +//! is_first Precomputed selector (z^N - 1) / (z - 1). +//! is_last Precomputed selector (z^N - 1) / (z - g^{-1}). +//! is_transition Precomputed selector z - g^{-1}. +//! gamma Batching challenge for auxiliary trace boundary checks. +//! weight0 First barycentric weight for quotient recomposition. +//! f Chunk shift ratio h^N. Generates coset shifts and weights. +//! s0 First coset shift offset^N. Base for shifted evaluation points. +//! ``` + use std::collections::HashMap; use miden_crypto::{ @@ -40,25 +123,9 @@ where panic!("preprocessed trace entries are not supported") }, }, - BaseLeaf::IsFirstRow => { - let z_pow_n = builder.input(InputKey::ZPowN); - let one = builder.constant(EF::ONE); - let numerator = builder.sub(z_pow_n, one); - let inv = builder.input(InputKey::InvZMinusOne); - builder.mul(numerator, inv) - }, - BaseLeaf::IsLastRow => { - let z_pow_n = builder.input(InputKey::ZPowN); - let one = builder.constant(EF::ONE); - let numerator = builder.sub(z_pow_n, one); - let inv = builder.input(InputKey::InvZMinusGInv); - builder.mul(numerator, inv) - }, - BaseLeaf::IsTransition => { - let z = builder.input(InputKey::Z); - let g_inv = builder.input(InputKey::GInv); - builder.sub(z, g_inv) - }, + BaseLeaf::IsFirstRow => builder.input(InputKey::IsFirst), + BaseLeaf::IsLastRow => builder.input(InputKey::IsLast), + BaseLeaf::IsTransition => builder.input(InputKey::IsTransition), BaseLeaf::Constant(c) => builder.constant(EF::from(*c)), }, SymbolicExpression::Add { x, y, .. } => { @@ -169,7 +236,6 @@ where None => Vec::new(), }; let alpha = builder.input(InputKey::Alpha); - let inv_vanishing = builder.input(InputKey::InvVanishing); // Merge base and extension constraints in evaluation order using the layout. let total = constraint_layout.base_indices.len() + constraint_layout.ext_indices.len(); @@ -192,12 +258,15 @@ where let acc_mul = builder.mul(acc, alpha); acc = builder.add(acc_mul, node); } - let folded = builder.mul(acc, inv_vanishing); let quotient = build_quotient_recomposition_dag::(&mut builder, layout); - let root = builder.sub(folded, quotient); + let z_pow_n = builder.input(InputKey::ZPowN); + let one = builder.constant(EF::ONE); + let vanishing = builder.sub(z_pow_n, one); + let q_times_v = builder.mul(quotient, vanishing); + let root = builder.sub(acc, q_times_v); - AceDag { nodes: builder.into_nodes(), root } + builder.build(root) } fn build_periodic_nodes( diff --git a/crates/ace-codegen/src/dag/mod.rs b/crates/ace-codegen/src/dag/mod.rs index 90485e3429..31c57dac86 100644 --- a/crates/ace-codegen/src/dag/mod.rs +++ b/crates/ace-codegen/src/dag/mod.rs @@ -11,5 +11,5 @@ mod ir; mod lower; pub use builder::DagBuilder; -pub use ir::{AceDag, NodeId, NodeKind, PeriodicColumnData}; +pub use ir::{AceDag, DagSnapshot, NodeId, NodeKind, PeriodicColumnData}; pub use lower::build_verifier_dag; diff --git a/crates/ace-codegen/src/encode.rs b/crates/ace-codegen/src/encode.rs index d9fc1b001b..a14bc9c757 100644 --- a/crates/ace-codegen/src/encode.rs +++ b/crates/ace-codegen/src/encode.rs @@ -172,7 +172,7 @@ where let lhs_id = node_id(op.lhs)?; let rhs_id = node_id(op.rhs)?; let tag = op_tag(op.op); - Ok(Felt::new(lhs_id + rhs_id * RHS_NODE_OFFSET + tag * OP_TAG_OFFSET)) + Ok(Felt::new_unchecked(lhs_id + rhs_id * RHS_NODE_OFFSET + tag * OP_TAG_OFFSET)) }; for op in &self.operations { diff --git a/crates/ace-codegen/src/layout/keys.rs b/crates/ace-codegen/src/layout/keys.rs index d1d7041db9..a8d93fd2ba 100644 --- a/crates/ace-codegen/src/layout/keys.rs +++ b/crates/ace-codegen/src/layout/keys.rs @@ -20,30 +20,29 @@ pub enum InputKey { }, /// Aux bus boundary value at the given index. AuxBusBoundary(usize), - /// Out-of-domain evaluation point `zeta`. - Z, + /// Variable-length public input reduction at the given group index. + VlpiReduction(usize), + /// Batching challenge gamma for combining the constraint evaluation with the + /// auxiliary trace boundary checks. + Gamma, /// Composition challenge used to fold constraints. Alpha, /// `zeta^N`, where `N` is the trace length. ZPowN, - /// `g^{-1}`, inverse trace domain generator. - GInv, - /// `g^{-2}`, squared inverse trace domain generator. - GInv2, /// `zeta^(N / max_cycle_len)` for periodic columns. ZK, + /// Precomputed first-row selector: `(z^N - 1) / (z - 1)`. + IsFirst, + /// Precomputed last-row selector: `(z^N - 1) / (z - g^{-1})`. + IsLast, + /// Precomputed transition selector: `z - g^{-1}`. + IsTransition, /// First barycentric weight for quotient recomposition. Weight0, - /// `g = h^N`, the chunk shift ratio. - G, + /// `f = h^N`, the chunk shift ratio between cosets. + F, /// `s0 = offset^N`, the first chunk shift. S0, - /// `1 / (zeta - g^{-1})` (selector denominator). - InvZMinusGInv, - /// `1 / (zeta - 1)` (selector denominator). - InvZMinusOne, - /// `1 / (zeta^N - 1)` (vanishing inverse). - InvVanishing, /// Base-field coordinate for a quotient chunk opening at `offset` /// (0 = zeta, 1 = g * zeta). QuotientChunkCoord { @@ -61,7 +60,7 @@ pub(crate) struct InputKeyMapper<'a> { impl InputKeyMapper<'_> { /// Return the input index for a key, if it exists in the layout. - pub(crate) fn index_of(&self, key: InputKey) -> Option { + pub(crate) fn index_of(self, key: InputKey) -> Option { let layout = self.layout; match key { InputKey::Public(i) => layout.regions.public_values.index(i), @@ -84,18 +83,22 @@ impl InputKeyMapper<'_> { } }, InputKey::AuxBusBoundary(i) => layout.regions.aux_bus_boundary.index(i), - InputKey::Z => Some(layout.stark.z), + InputKey::VlpiReduction(i) => { + let local = i * layout.vlpi_stride; + layout.regions.vlpi_reductions.index(local) + }, + // Extension-field stark vars. InputKey::Alpha => Some(layout.stark.alpha), - InputKey::GInv => Some(layout.stark.g_inv), InputKey::ZPowN => Some(layout.stark.z_pow_n), - InputKey::GInv2 => Some(layout.stark.g_inv2), InputKey::ZK => Some(layout.stark.z_k), + InputKey::IsFirst => Some(layout.stark.is_first), + InputKey::IsLast => Some(layout.stark.is_last), + InputKey::IsTransition => Some(layout.stark.is_transition), + InputKey::Gamma => Some(layout.stark.gamma), + // Base-field stark vars (stored as (val, 0) in the EF slot). InputKey::Weight0 => Some(layout.stark.weight0), - InputKey::G => Some(layout.stark.g), + InputKey::F => Some(layout.stark.f), InputKey::S0 => Some(layout.stark.s0), - InputKey::InvZMinusGInv => Some(layout.stark.inv_z_minus_g_inv), - InputKey::InvZMinusOne => Some(layout.stark.inv_z_minus_one), - InputKey::InvVanishing => Some(layout.stark.inv_vanishing), InputKey::QuotientChunkCoord { offset, chunk, coord } => { if chunk >= layout.counts.num_quotient_chunks || coord >= EXT_DEGREE { return None; diff --git a/crates/ace-codegen/src/layout/mod.rs b/crates/ace-codegen/src/layout/mod.rs index 9446978694..8504870c75 100644 --- a/crates/ace-codegen/src/layout/mod.rs +++ b/crates/ace-codegen/src/layout/mod.rs @@ -18,13 +18,11 @@ //! - Lagrange-kernel weights and shifts for quotient chunk recomposition. //! - Constraint folding with the composition challenge and final root check. //! -//! The current "stark vars" block is sufficient to derive both selector -//! polynomials and the Lagrange-kernel weights used in quotient chunk -//! recomposition: -//! - Selector evaluations: -//! - `inv_vanishing = 1 / (z^N - 1)` -//! - `is_first = (z^N - 1) * inv(z - 1)` -//! - `is_last = (z^N - 1) * inv(z - g^{-1})` +//! The current "stark vars" block provides precomputed selectors and the +//! Lagrange-kernel weights used in quotient chunk recomposition: +//! - Precomputed selectors (computed in MASM, supplied as inputs): +//! - `is_first = (z^N - 1) / (z - 1)` +//! - `is_last = (z^N - 1) / (z - g^{-1})` //! - `is_transition = z - g^{-1}` //! - Lagrange kernel inputs: //! - `s0 = offset^N` and `g = subgroup_gen^N` define the shifts `s_i = s0 * g^i`. @@ -47,8 +45,7 @@ //! Notes: //! - `quotient_next` is included in the READ layout and is mapped via //! `InputKey::QuotientChunkCoord` with `offset = 1`. -//! - `stark_vars` reserves at least 14 EF slots for the canonical verifier inputs. Extra slots are -//! left available for future aux inputs. +//! - `stark_vars` reserves 10 EF slots for the canonical verifier inputs. mod keys; mod plan; diff --git a/crates/ace-codegen/src/layout/plan.rs b/crates/ace-codegen/src/layout/plan.rs index 3b440b9fd7..b3db7ff347 100644 --- a/crates/ace-codegen/src/layout/plan.rs +++ b/crates/ace-codegen/src/layout/plan.rs @@ -22,14 +22,18 @@ pub struct InputCounts { pub width: usize, /// Width of the aux trace. pub aux_width: usize, + /// Number of committed boundary values (accumulator column finals). + pub num_aux_boundary: usize, /// Number of public inputs. pub num_public: usize, + /// Number of variable-length public input (VLPI) reduction slots (in EF elements). + /// This is derived from `AceConfig::num_vlpi_groups` by the layout policy: + /// MASM expands each group to 2 EF slots (word-aligned); Native uses 1 per group. + pub num_vlpi: usize, /// Number of randomness challenges used by the AIR. pub num_randomness: usize, /// Number of periodic columns. pub num_periodic: usize, - /// Number of auxiliary (stark var) inputs reserved. - pub num_aux_inputs: usize, /// Number of quotient chunks. pub num_quotient_chunks: usize, } @@ -39,6 +43,8 @@ pub struct InputCounts { pub(crate) struct LayoutRegions { /// Region containing fixed-length public values. pub public_values: InputRegion, + /// Region containing variable-length public input reductions. + pub vlpi_reductions: InputRegion, /// Region containing randomness inputs (alpha, beta). pub randomness: InputRegion, /// Main trace OOD values at `zeta`. @@ -60,32 +66,39 @@ pub(crate) struct LayoutRegions { } /// Indexes of canonical verifier scalars inside the stark-vars block. +/// +/// Every slot in the ACE input array is an extension-field (EF) element -- +/// the circuit operates entirely in the extension field. However, some of +/// these scalars are inherently base-field values that the MASM verifier +/// stores as `(val, 0)` in the EF slot. +/// +/// See the module documentation on [`super::super::dag::lower`] for how each +/// variable enters the verifier expression. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub(crate) struct StarkVarIndices { - /// Index of `zeta` in the stark-vars block. - pub z: usize, - /// Index of the composition challenge `alpha`. + // -- Extension-field values (slots 0-5) -- + /// Composition challenge `alpha` for folding constraints. pub alpha: usize, - /// Index of `g^{-1}`. - pub g_inv: usize, - /// Index of `zeta^N`. + /// `zeta^N` where N is the trace length. pub z_pow_n: usize, - /// Index of `g^{-2}`. - pub g_inv2: usize, - /// Index of `z_k`. + /// `zeta^(N / max_cycle_len)` for periodic column evaluation. pub z_k: usize, - /// Index of `weight0`. + /// Precomputed first-row selector: `(z^N - 1) / (z - 1)`. + pub is_first: usize, + /// Precomputed last-row selector: `(z^N - 1) / (z - g^{-1})`. + pub is_last: usize, + /// Precomputed transition selector: `z - g^{-1}`. + pub is_transition: usize, + /// Batching challenge `gamma` for reduced_aux_values. + pub gamma: usize, + + // -- Base-field values stored as (val, 0) in EF slots -- + /// First barycentric weight `1 / (k * s0^{k-1})`. pub weight0: usize, - /// Index of `g`. - pub g: usize, - /// Index of `s0`. + /// `f = h^N` (chunk shift ratio between cosets). + pub f: usize, + /// `s0 = offset^N` (first chunk shift). pub s0: usize, - /// Index of `1 / (zeta - g^{-1})`. - pub inv_z_minus_g_inv: usize, - /// Index of `1 / (zeta - 1)`. - pub inv_z_minus_one: usize, - /// Index of `1 / (zeta^N - 1)`. - pub inv_vanishing: usize, } /// ACE input layout for Plonky3-based verifier logic. @@ -100,6 +113,8 @@ pub struct InputLayout { pub(crate) aux_rand_alpha: usize, /// Input index for aux randomness beta. pub(crate) aux_rand_beta: usize, + /// Stride between logical VLPI groups (2 for MASM word-aligned, 1 for native). + pub(crate) vlpi_stride: usize, /// Indexes into the stark-vars region. pub(crate) stark: StarkVarIndices, /// Total number of inputs (length of the READ section). @@ -123,6 +138,7 @@ impl InputLayout { let mut max_end = 0usize; for region in [ self.regions.public_values, + self.regions.vlpi_reductions, self.regions.randomness, self.regions.main_curr, self.regions.aux_curr, @@ -152,30 +168,27 @@ impl InputLayout { "quotient_next width mismatch" ); assert_eq!( - self.regions.aux_bus_boundary.width, self.counts.aux_width, + self.regions.aux_bus_boundary.width, self.counts.num_aux_boundary, "aux bus boundary width mismatch" ); - let stark_end = self.regions.stark_vars.offset + self.regions.stark_vars.width; - for (name, idx) in [ - ("z", self.stark.z), - ("alpha", self.stark.alpha), - ("g_inv", self.stark.g_inv), - ("z_pow_n", self.stark.z_pow_n), - ("g_inv2", self.stark.g_inv2), - ("z_k", self.stark.z_k), - ("weight0", self.stark.weight0), - ("g", self.stark.g), - ("s0", self.stark.s0), - ("inv_z_minus_g_inv", self.stark.inv_z_minus_g_inv), - ("inv_z_minus_one", self.stark.inv_z_minus_one), - ("inv_vanishing", self.stark.inv_vanishing), - ] { - assert!( - idx >= self.regions.stark_vars.offset && idx < stark_end, - "stark var {name} out of range" - ); - } + let stark_start = self.regions.stark_vars.offset; + let stark_end = stark_start + self.regions.stark_vars.width; + let check = |name: &str, idx: usize| { + assert!(idx >= stark_start && idx < stark_end, "stark var {name} out of range"); + }; + // Extension-field slots. + check("alpha", self.stark.alpha); + check("z_pow_n", self.stark.z_pow_n); + check("z_k", self.stark.z_k); + check("is_first", self.stark.is_first); + check("is_last", self.stark.is_last); + check("is_transition", self.stark.is_transition); + check("gamma", self.stark.gamma); + // Base-field slots (stored as (val, 0) in the EF slot). + check("weight0", self.stark.weight0); + check("f", self.stark.f); + check("s0", self.stark.s0); let rand_start = self.regions.randomness.offset; let rand_end = rand_start + self.regions.randomness.width; diff --git a/crates/ace-codegen/src/layout/policy.rs b/crates/ace-codegen/src/layout/policy.rs index d5453b8479..3f6f3efae2 100644 --- a/crates/ace-codegen/src/layout/policy.rs +++ b/crates/ace-codegen/src/layout/policy.rs @@ -12,6 +12,8 @@ enum Alignment { #[derive(Clone, Copy)] struct LayoutPolicy { public_values: Alignment, + vlpi: Alignment, + vlpi_stride: usize, randomness: Alignment, main: Alignment, aux: Alignment, @@ -25,6 +27,8 @@ impl LayoutPolicy { fn native() -> Self { Self { public_values: Alignment::Unaligned, + vlpi: Alignment::Unaligned, + vlpi_stride: 1, randomness: Alignment::Unaligned, main: Alignment::Unaligned, aux: Alignment::Unaligned, @@ -38,6 +42,8 @@ impl LayoutPolicy { fn masm() -> Self { Self { public_values: Alignment::QuadWord, + vlpi: Alignment::Word, + vlpi_stride: 2, randomness: Alignment::Word, main: Alignment::DoubleWord, aux: Alignment::DoubleWord, @@ -82,12 +88,15 @@ impl InputLayout { } fn build_with_policy(counts: InputCounts, policy: LayoutPolicy) -> Self { - /// Minimum number of EF slots reserved for verifier "stark vars". - const STARK_BASE_VARS: usize = 14; + // Number of EF slots in the stark-vars block. Every ACE input slot is an + // extension-field element (QuadFelt). Some stark vars are base-field values + // embedded as (val, 0); see the slot table below for which is which. + const NUM_STARK_VARS: usize = 10; let mut builder = LayoutBuilder::new(); let public_values = builder.alloc(counts.num_public, policy.public_values); + let vlpi_reductions = builder.alloc(counts.num_vlpi, policy.vlpi); /// Number of randomness inputs (alpha + beta). const NUM_RANDOMNESS_INPUTS: usize = 2; let randomness = builder.alloc(NUM_RANDOMNESS_INPUTS, policy.randomness); @@ -99,26 +108,38 @@ impl InputLayout { let main_next = builder.alloc(counts.width, policy.main); let aux_next = builder.alloc(aux_coord_width, policy.aux); let quotient_next = builder.alloc(counts.num_quotient_chunks * EXT_DEGREE, policy.quotient); - let aux_bus_boundary = builder.alloc(counts.aux_width, policy.aux_bus_boundary); - - let stark_base_width = counts.num_aux_inputs.max(STARK_BASE_VARS); - let stark_vars = builder.alloc(stark_base_width, policy.stark_vars); - - // Matches utils::set_up_auxiliary_inputs_ace layout (EF slots): - // [z, alpha, g^-1, z^N, g^-2, z^k, weight0, g, s0, 0, - // inv(z-g^-1), inv(z-1), inv(z^N-1), 0] - let z = stark_vars.offset; - let alpha = stark_vars.offset + 1; - let g_inv = stark_vars.offset + 2; - let z_pow_n = stark_vars.offset + 3; - let g_inv2 = stark_vars.offset + 4; - let z_k = stark_vars.offset + 5; - let weight0 = stark_vars.offset + 6; - let g = stark_vars.offset + 7; - let s0 = stark_vars.offset + 8; - let inv_z_minus_g_inv = stark_vars.offset + 10; - let inv_z_minus_one = stark_vars.offset + 11; - let inv_vanishing = stark_vars.offset + 12; + let aux_bus_boundary = builder.alloc(counts.num_aux_boundary, policy.aux_bus_boundary); + + let stark_vars = builder.alloc(NUM_STARK_VARS, policy.stark_vars); + + // Matches utils::set_up_auxiliary_inputs_ace layout (EF slots). + // + // Extension-field values are grouped first (slots 0-6), then base-field + // values stored as (val, 0) in EF slots (slots 7-9). + // + // Slot Value Field + // ---- ------------------ ----- + // 0 alpha EF Composition challenge (Horner multiplier) + // 1 z^N EF Trace-length power (quotient deltas + vanishing + // 2 z_k EF Periodic column eval point + // 3 is_first EF Precomputed: (z^N - 1) / (z - 1) + // 4 is_last EF Precomputed: (z^N - 1) / (z - g^{-1}) + // 5 is_transition EF Precomputed: z - g^{-1} + // 6 gamma EF Batching challenge + // 7 weight0 base First barycentric weight + // 8 f base Chunk shift ratio h^N + // 9 s0 base First coset shift offset^N + let b = stark_vars.offset; + let alpha = b; + let z_pow_n = b + 1; + let z_k = b + 2; + let is_first = b + 3; + let is_last = b + 4; + let is_transition = b + 5; + let gamma = b + 6; + let weight0 = b + 7; + let f = b + 8; + let s0 = b + 9; if let Some(end_align) = policy.end_align { builder.align(end_align); @@ -127,6 +148,7 @@ impl InputLayout { Self { regions: LayoutRegions { public_values, + vlpi_reductions, randomness, main_curr, aux_curr, @@ -139,22 +161,73 @@ impl InputLayout { }, aux_rand_alpha, aux_rand_beta, + vlpi_stride: policy.vlpi_stride, stark: StarkVarIndices { - z, alpha, - g_inv, z_pow_n, - g_inv2, z_k, + is_first, + is_last, + is_transition, + gamma, weight0, - g, + f, s0, - inv_z_minus_g_inv, - inv_z_minus_one, - inv_vanishing, }, total_inputs: builder.offset, counts, } } } + +#[cfg(test)] +mod tests { + use super::super::{InputCounts, InputKey, InputLayout}; + + #[test] + fn masm_layout_vlpi_groups_use_word_stride() { + let counts = InputCounts { + width: 1, + aux_width: 1, + num_aux_boundary: 1, + num_public: 8, + // Two logical VLPI groups in MASM occupy four EF slots total: + // [group0, pad0, group1, pad1]. + num_vlpi: 4, + num_randomness: 2, + num_periodic: 0, + num_quotient_chunks: 1, + }; + let layout = InputLayout::new_masm(counts); + + let vlpi_base = layout.index(InputKey::VlpiReduction(0)).unwrap(); + assert_eq!(layout.index(InputKey::VlpiReduction(0)), Some(vlpi_base)); + assert_eq!( + layout.index(InputKey::VlpiReduction(1)), + Some(vlpi_base + 2), + "MASM VLPI groups should advance by a word-aligned stride" + ); + } + + #[test] + fn native_layout_vlpi_groups_use_unit_stride() { + let counts = InputCounts { + width: 1, + aux_width: 1, + num_aux_boundary: 1, + num_public: 8, + num_vlpi: 2, + num_randomness: 2, + num_periodic: 0, + num_quotient_chunks: 1, + }; + let layout = InputLayout::new(counts); + + let vlpi_base = layout.index(InputKey::VlpiReduction(0)).unwrap(); + assert_eq!( + layout.index(InputKey::VlpiReduction(1)), + Some(vlpi_base + 1), + "Native VLPI groups should advance by unit stride" + ); + } +} diff --git a/crates/ace-codegen/src/lib.rs b/crates/ace-codegen/src/lib.rs index 21c17a92c6..8302131a99 100644 --- a/crates/ace-codegen/src/lib.rs +++ b/crates/ace-codegen/src/lib.rs @@ -1,7 +1,7 @@ //! ACE circuit codegen for Plonky3-based Miden AIRs. //! //! The pipeline is: -//! 1. Capture AIR constraints via plonky3's `SymbolicAirBuilder`. +//! 1. Capture AIR constraints via the `SymbolicAirBuilder`. //! 2. Lower symbolic expressions into a DAG that mirrors verifier constraints evaluation. //! 3. Emit an ACE circuit plus an `InputLayout` describing the MASM ACE-READ section order. //! @@ -16,7 +16,7 @@ //! use miden_air::ProcessorAir; //! use miden_core::{Felt, field::QuadFelt}; //! -//! let config = AceConfig { num_quotient_chunks: 8, num_aux_inputs: 14, layout: LayoutKind::Masm }; +//! let config = AceConfig { num_quotient_chunks: 8, num_vlpi_groups: 1, layout: LayoutKind::Masm }; //! let circuit = build_ace_circuit_for_air::<_, Felt, QuadFelt>(&ProcessorAir, config)?; //! ``` //! @@ -59,9 +59,15 @@ pub enum AceError { InvalidInputLayout { message: String }, } +#[cfg(any(test, feature = "testing"))] +pub mod testing; + pub use crate::{ - circuit::AceCircuit, + circuit::{AceCircuit, emit_circuit}, + dag::{AceDag, DagBuilder, DagSnapshot, NodeId, NodeKind}, encode::EncodedCircuit, layout::{InputCounts, InputKey, InputLayout}, - pipeline::{AceConfig, LayoutKind, build_ace_circuit_for_air, build_layout_for_air}, + pipeline::{ + AceArtifacts, AceConfig, LayoutKind, build_ace_circuit_for_air, build_ace_dag_for_air, + }, }; diff --git a/crates/ace-codegen/src/pipeline.rs b/crates/ace-codegen/src/pipeline.rs index 5365dd5a70..4e1f24621a 100644 --- a/crates/ace-codegen/src/pipeline.rs +++ b/crates/ace-codegen/src/pipeline.rs @@ -38,15 +38,18 @@ pub enum LayoutKind { pub struct AceConfig { /// Number of quotient chunks used by the AIR. pub num_quotient_chunks: usize, - /// Number of auxiliary inputs reserved in the stark-vars block. - pub num_aux_inputs: usize, + /// Number of variable-length public input groups. + /// Each group produces one reduced extension field element. + /// The layout policy handles alignment (e.g., MASM word-aligns each group to + /// 2 EF slots; Native uses 1 EF slot per group). + pub num_vlpi_groups: usize, /// Layout policy (Native vs Masm). pub layout: LayoutKind, } /// Output of the ACE codegen pipeline (layout + DAG). #[derive(Debug)] -pub(crate) struct AceArtifacts { +pub struct AceArtifacts { /// Input layout describing the READ section order. pub layout: InputLayout, /// DAG that mirrors the verifier evaluation. @@ -55,8 +58,9 @@ pub(crate) struct AceArtifacts { /// Build a verifier-equivalent ACE circuit for the provided AIR. /// -/// This is the highest-level entry point: it builds the DAG, validates layout -/// invariants, and emits the off-VM circuit representation. +/// This builds the constraint-evaluation DAG, validates layout invariants, and +/// emits the off-VM circuit representation. The circuit performs the constraint +/// evaluation check at the out-of-domain point z. pub fn build_ace_circuit_for_air( air: &A, config: AceConfig, @@ -71,31 +75,8 @@ where emit_circuit(&artifacts.dag, artifacts.layout) } -/// Build the input layout for the provided AIR. -/// -/// The returned `InputLayout` is validated and ready for input assembly. -pub fn build_layout_for_air(air: &A, config: AceConfig) -> InputLayout -where - A: LiftedAir, - F: Field, - EF: ExtensionField, - SymbolicExpressionExt: Algebra, -{ - let num_periodic = air.periodic_columns().len(); - let counts = input_counts_for_air::(air, config, num_periodic); - let layout = match config.layout { - LayoutKind::Native => InputLayout::new(counts), - LayoutKind::Masm => InputLayout::new_masm(counts), - }; - layout.validate(); - layout -} - /// Build a verifier-equivalent DAG and layout for the provided AIR. -/// -/// This is useful when you need the DAG for off-VM checks and want to -/// assemble inputs separately. -pub(crate) fn build_ace_dag_for_air( +pub fn build_ace_dag_for_air( air: &A, config: AceConfig, ) -> Result, AceError> @@ -154,15 +135,27 @@ where ); let num_randomness = air.num_randomness(); - assert!(num_randomness > 0, "AIR must declare at least one randomness challenge"); + assert!( + num_randomness == 2, + "AIR must declare exactly 2 randomness challenges (alpha, beta), got {num_randomness}" + ); + + // Convert logical VLPI groups to EF slots based on layout policy. + // MASM word-aligns each group (4 base felts = 2 EF slots per group). + // Native uses 1 EF slot per group (no padding). + let num_vlpi = match config.layout { + LayoutKind::Masm => config.num_vlpi_groups * 2, + LayoutKind::Native => config.num_vlpi_groups, + }; InputCounts { width: air.width(), aux_width: air.aux_width(), + num_aux_boundary: air.num_aux_values(), num_public: air.num_public_values(), + num_vlpi, num_randomness, num_periodic, - num_aux_inputs: config.num_aux_inputs, num_quotient_chunks: config.num_quotient_chunks, } } diff --git a/crates/ace-codegen/src/quotient.rs b/crates/ace-codegen/src/quotient.rs index a28b14ffa8..2cc4d6c33b 100644 --- a/crates/ace-codegen/src/quotient.rs +++ b/crates/ace-codegen/src/quotient.rs @@ -6,102 +6,11 @@ use miden_crypto::field::{ExtensionField, Field}; -#[cfg(test)] -use crate::AceError; use crate::{ dag::{DagBuilder, NodeId}, layout::{InputKey, InputLayout}, }; -/// Evaluate the quotient recomposition at `zeta` using provided inputs. -#[cfg(test)] -pub fn eval_quotient(layout: &InputLayout, inputs: &[EF]) -> Result -where - F: Field, - EF: ExtensionField, -{ - if inputs.len() != layout.total_inputs { - return Err(AceError::InvalidInputLength { - expected: layout.total_inputs, - got: inputs.len(), - }); - } - - let k = layout.counts.num_quotient_chunks; - let z_pow_n = inputs[layout.index(InputKey::ZPowN).expect("ZPowN in layout")]; - let s0 = inputs[layout.index(InputKey::S0).expect("S0 in layout")]; - let g = inputs[layout.index(InputKey::G).expect("G in layout")]; - let weight0 = inputs[layout.index(InputKey::Weight0).expect("Weight0 in layout")]; - - let (deltas, weights) = { - let mut ops = FieldOps; - compute_deltas_and_weights(k, z_pow_n, s0, g, weight0, &mut ops) - }; - - let mut chunk_values = Vec::with_capacity(k); - for chunk in 0..k { - let mut value = EF::ZERO; - for coord in 0..EF::DIMENSION { - let basis = EF::ith_basis_element(coord).expect("basis index within extension degree"); - let coord_value = inputs[layout - .index(InputKey::QuotientChunkCoord { offset: 0, chunk, coord }) - .expect("quotient chunk coord in layout")]; - value += basis * coord_value; - } - chunk_values.push(value); - } - - let mut quotient = EF::ZERO; - for (i, &chunk_value) in chunk_values.iter().enumerate() { - let mut prod = EF::ONE; - for (j, delta) in deltas.iter().enumerate() { - if i != j { - prod *= *delta; - } - } - let zps = weights[i] * prod; - quotient += zps * chunk_value; - } - - Ok(quotient) -} - -/// Compute the barycentric kernel value (`zps`) for a single chunk. -#[cfg(test)] -pub fn zps_for_chunk(layout: &InputLayout, inputs: &[EF], chunk: usize) -> Result -where - EF: Field, -{ - if inputs.len() != layout.total_inputs { - return Err(AceError::InvalidInputLength { - expected: layout.total_inputs, - got: inputs.len(), - }); - } - - let k = layout.counts.num_quotient_chunks; - assert!(chunk < k, "quotient chunk {chunk} out of range (k={k})"); - - let z_pow_n = inputs[layout.index(InputKey::ZPowN).expect("ZPowN in layout")]; - let s0 = inputs[layout.index(InputKey::S0).expect("S0 in layout")]; - let g = inputs[layout.index(InputKey::G).expect("G in layout")]; - let weight0 = inputs[layout.index(InputKey::Weight0).expect("Weight0 in layout")]; - - let (deltas, weights) = { - let mut ops = FieldOps; - compute_deltas_and_weights(k, z_pow_n, s0, g, weight0, &mut ops) - }; - - let mut prod = EF::ONE; - for (j, delta) in deltas.iter().enumerate() { - if j != chunk { - prod *= *delta; - } - } - - Ok(weights[chunk] * prod) -} - /// Build DAG nodes that recombine quotient chunks. pub(crate) fn build_quotient_recomposition_dag( builder: &mut DagBuilder, @@ -114,12 +23,12 @@ where let k = layout.counts.num_quotient_chunks; let z_pow_n = builder.input(InputKey::ZPowN); let s0 = builder.input(InputKey::S0); - let g = builder.input(InputKey::G); + let f = builder.input(InputKey::F); let weight0 = builder.input(InputKey::Weight0); let (deltas, weights) = { let mut ops = DagOps { builder }; - compute_deltas_and_weights(k, z_pow_n, s0, g, weight0, &mut ops) + compute_deltas_and_weights(k, z_pow_n, s0, f, weight0, &mut ops) }; let mut chunk_values = Vec::with_capacity(k); @@ -152,23 +61,6 @@ where quotient } -#[cfg(test)] -struct FieldOps; - -#[cfg(test)] -impl Ops for FieldOps -where - EF: Field, -{ - fn sub(&mut self, a: EF, b: EF) -> EF { - a - b - } - - fn mul(&mut self, a: EF, b: EF) -> EF { - a * b - } -} - struct DagOps<'a, EF> { builder: &'a mut DagBuilder, } @@ -195,7 +87,7 @@ fn compute_deltas_and_weights( k: usize, z_pow_n: T, s0: T, - g: T, + f: T, weight0: T, ops: &mut impl Ops, ) -> (Vec, Vec) @@ -209,8 +101,8 @@ where for _ in 0..k { deltas.push(ops.sub(z_pow_n, shift)); weights.push(weight); - shift = ops.mul(shift, g); - weight = ops.mul(weight, g); + shift = ops.mul(shift, f); + weight = ops.mul(weight, f); } (deltas, weights) } diff --git a/crates/ace-codegen/src/randomness.rs b/crates/ace-codegen/src/randomness.rs index 45689a50e8..c1f6e70d45 100644 --- a/crates/ace-codegen/src/randomness.rs +++ b/crates/ace-codegen/src/randomness.rs @@ -22,10 +22,10 @@ pub(crate) fn aux_rand_indices(randomness: InputRegion) -> (usize, usize) { /// Lower a challenge index into DAG nodes. /// -/// Challenge indices map to: -/// - 0 → alpha -/// - 1 → 1 (beta^0) -/// - n → beta^(n-1) +/// The AIR's `Challenges::from_randomness` receives these two raw values and +/// internally expands beta into powers `[1, beta, beta^2, ...]` via symbolic +/// multiplication. This means the DAG will contain nodes for `beta^k` built +/// from `AuxRandBeta`, which is correct. pub(crate) fn lower_challenge( builder: &mut DagBuilder, layout: &InputLayout, @@ -37,16 +37,11 @@ where let num = layout.counts.num_randomness; assert!(index < num, "challenge index {index} out of range (num={num})"); - if index == 0 { - return builder.input(InputKey::AuxRandAlpha); + match index { + 0 => builder.input(InputKey::AuxRandAlpha), + 1 => builder.input(InputKey::AuxRandBeta), + _ => panic!( + "challenge index {index} exceeds the 2-element randomness convention (alpha, beta)" + ), } - if index == 1 { - return builder.constant(EF::ONE); - } - let beta_node = builder.input(InputKey::AuxRandBeta); - let mut power = beta_node; - for _ in 2..index { - power = builder.mul(power, beta_node); - } - power } diff --git a/crates/ace-codegen/src/testing.rs b/crates/ace-codegen/src/testing.rs new file mode 100644 index 0000000000..a268f30d30 --- /dev/null +++ b/crates/ace-codegen/src/testing.rs @@ -0,0 +1,340 @@ +//! Test helpers for ACE codegen, available under the `testing` feature or `#[cfg(test)]`. +//! +//! These provide reference evaluators for symbolic expressions, periodic columns, +//! constraint folding, quotient recomposition, and DAG evaluation, suitable for +//! validating the ACE pipeline from both within ace-codegen tests and from +//! downstream integration tests (e.g. in miden-air). + +use miden_core::{Felt, field::QuadFelt}; +use miden_crypto::{ + field::{ExtensionField, Field, TwoAdicField}, + stark::{ + air::symbolic::{ + BaseEntry, BaseLeaf, ConstraintLayout, ExtEntry, ExtLeaf, SymbolicExpression, + SymbolicExpressionExt, + }, + dft::{Radix2DitParallel, TwoAdicSubgroupDft}, + }, +}; + +use crate::{AceDag, AceError, InputKey, InputLayout}; + +/// Deterministic input filler for layout-sized buffers. +/// +/// Generates pseudo-random `QuadFelt` values using a simple LCG, suitable for +/// testing against hand-computed reference values. +pub fn fill_inputs(layout: &InputLayout) -> Vec { + let mut values = Vec::with_capacity(layout.total_inputs); + let mut state = 0x9e37_79b9_7f4a_7c15u64; + for _ in 0..layout.total_inputs { + state = state.wrapping_mul(6364136223846793005).wrapping_add(1); + let lo = Felt::new_unchecked(state); + state = state.wrapping_mul(6364136223846793005).wrapping_add(1); + let hi = Felt::new_unchecked(state); + values.push(QuadFelt::new([lo, hi])); + } + values +} + +/// Evaluate periodic columns at a point by computing the polynomial in +/// coefficient form via inverse DFT, then evaluating with Horner's method. +pub fn eval_periodic_values(periodic_columns: &[Vec], z_k: EF) -> Vec +where + F: TwoAdicField + Ord, + EF: ExtensionField, +{ + if periodic_columns.is_empty() { + return Vec::new(); + } + let max_len = periodic_columns.iter().map(Vec::len).max().unwrap_or(0); + let dft = Radix2DitParallel::::default(); + + periodic_columns + .iter() + .map(|col| { + if col.is_empty() { + return EF::ZERO; + } + let coeffs = dft.idft(col.clone()); + let ratio = max_len / col.len(); + let log_pow = ratio.ilog2() as usize; + let mut z_col = z_k; + for _ in 0..log_pow { + z_col *= z_col; + } + let mut acc = EF::ZERO; + for coeff in coeffs.iter().rev() { + acc = acc * z_col + EF::from(*coeff); + } + acc + }) + .collect() +} + +/// Evaluate a base-field symbolic expression at concrete inputs. +pub fn eval_base_expr( + expr: &SymbolicExpression, + inputs: &[EF], + layout: &InputLayout, + periodic_values: &[EF], +) -> EF +where + F: Field, + EF: ExtensionField, +{ + match expr { + SymbolicExpression::Leaf(leaf) => match leaf { + BaseLeaf::Variable(v) => match v.entry { + BaseEntry::Main { offset } => { + let key = InputKey::Main { offset, index: v.index }; + inputs[layout.index(key).unwrap()] + }, + BaseEntry::Public => { + let key = InputKey::Public(v.index); + inputs[layout.index(key).unwrap()] + }, + BaseEntry::Periodic => periodic_values[v.index], + BaseEntry::Preprocessed { .. } => panic!("preprocessed not supported in test"), + }, + BaseLeaf::IsFirstRow => inputs[layout.index(InputKey::IsFirst).unwrap()], + BaseLeaf::IsLastRow => inputs[layout.index(InputKey::IsLast).unwrap()], + BaseLeaf::IsTransition => inputs[layout.index(InputKey::IsTransition).unwrap()], + BaseLeaf::Constant(c) => EF::from(*c), + }, + SymbolicExpression::Add { x, y, .. } => { + eval_base_expr::(x, inputs, layout, periodic_values) + + eval_base_expr::(y, inputs, layout, periodic_values) + }, + SymbolicExpression::Sub { x, y, .. } => { + eval_base_expr::(x, inputs, layout, periodic_values) + - eval_base_expr::(y, inputs, layout, periodic_values) + }, + SymbolicExpression::Mul { x, y, .. } => { + eval_base_expr::(x, inputs, layout, periodic_values) + * eval_base_expr::(y, inputs, layout, periodic_values) + }, + SymbolicExpression::Neg { x, .. } => { + -eval_base_expr::(x, inputs, layout, periodic_values) + }, + } +} + +/// Evaluate an extension-field symbolic expression at concrete inputs. +pub fn eval_ext_expr( + expr: &SymbolicExpressionExt, + inputs: &[EF], + layout: &InputLayout, + periodic_values: &[EF], +) -> EF +where + F: Field, + EF: ExtensionField, +{ + match expr { + SymbolicExpressionExt::Leaf(leaf) => match leaf { + ExtLeaf::Base(base_expr) => { + eval_base_expr::(base_expr, inputs, layout, periodic_values) + }, + ExtLeaf::ExtVariable(v) => match v.entry { + ExtEntry::Permutation { offset } => { + let mut acc = EF::ZERO; + for coord in 0..EF::DIMENSION { + let basis = EF::ith_basis_element(coord).unwrap(); + let key = InputKey::AuxCoord { offset, index: v.index, coord }; + let value = inputs[layout.index(key).unwrap()]; + acc += basis * value; + } + acc + }, + ExtEntry::Challenge => { + let alpha = inputs[layout.index(InputKey::AuxRandAlpha).unwrap()]; + let beta = inputs[layout.index(InputKey::AuxRandBeta).unwrap()]; + match v.index { + 0 => alpha, + 1 => beta, + _ => panic!( + "challenge index {} exceeds the 2-element randomness convention", + v.index + ), + } + }, + ExtEntry::PermutationValue => { + let key = InputKey::AuxBusBoundary(v.index); + inputs[layout.index(key).unwrap()] + }, + }, + ExtLeaf::ExtConstant(c) => *c, + }, + SymbolicExpressionExt::Add { x, y, .. } => { + eval_ext_expr::(x, inputs, layout, periodic_values) + + eval_ext_expr::(y, inputs, layout, periodic_values) + }, + SymbolicExpressionExt::Sub { x, y, .. } => { + eval_ext_expr::(x, inputs, layout, periodic_values) + - eval_ext_expr::(y, inputs, layout, periodic_values) + }, + SymbolicExpressionExt::Mul { x, y, .. } => { + eval_ext_expr::(x, inputs, layout, periodic_values) + * eval_ext_expr::(y, inputs, layout, periodic_values) + }, + SymbolicExpressionExt::Neg { x, .. } => { + -eval_ext_expr::(x, inputs, layout, periodic_values) + }, + } +} + +/// Evaluate the folded constraint accumulator from symbolic constraints. +/// +/// Merges base and extension constraints in evaluation order (using the +/// `ConstraintLayout`), then folds them via Horner with `alpha`. +pub fn eval_folded_constraints( + base_constraints: &[SymbolicExpression], + ext_constraints: &[SymbolicExpressionExt], + constraint_layout: &ConstraintLayout, + inputs: &[EF], + layout: &InputLayout, + periodic_values: &[EF], +) -> EF +where + F: Field, + EF: ExtensionField, +{ + let alpha = inputs[layout.index(InputKey::Alpha).unwrap()]; + + let total = constraint_layout.base_indices.len() + constraint_layout.ext_indices.len(); + let mut ordered: Vec<(usize, bool, usize)> = Vec::with_capacity(total); + for (i, &pos) in constraint_layout.base_indices.iter().enumerate() { + ordered.push((pos, false, i)); + } + for (i, &pos) in constraint_layout.ext_indices.iter().enumerate() { + ordered.push((pos, true, i)); + } + ordered.sort_by_key(|(pos, ..)| *pos); + + let mut acc = EF::ZERO; + for &(_, is_ext, idx) in &ordered { + let val = if is_ext { + eval_ext_expr::(&ext_constraints[idx], inputs, layout, periodic_values) + } else { + eval_base_expr::(&base_constraints[idx], inputs, layout, periodic_values) + }; + acc = acc * alpha + val; + } + acc +} + +/// Evaluate the quotient recomposition at `zeta` using provided inputs. +pub fn eval_quotient(layout: &InputLayout, inputs: &[EF]) -> EF +where + F: Field, + EF: ExtensionField, +{ + let k = layout.counts.num_quotient_chunks; + let z_pow_n = inputs[layout.index(InputKey::ZPowN).expect("ZPowN in layout")]; + let s0 = inputs[layout.index(InputKey::S0).expect("S0 in layout")]; + let f = inputs[layout.index(InputKey::F).expect("F in layout")]; + let weight0 = inputs[layout.index(InputKey::Weight0).expect("Weight0 in layout")]; + + let (deltas, weights) = compute_deltas_and_weights(k, z_pow_n, s0, f, weight0); + + let mut quotient = EF::ZERO; + for chunk in 0..k { + let mut chunk_value = EF::ZERO; + for coord in 0..EF::DIMENSION { + let basis = EF::ith_basis_element(coord).expect("basis index within extension degree"); + let coord_value = inputs[layout + .index(InputKey::QuotientChunkCoord { offset: 0, chunk, coord }) + .expect("quotient chunk coord in layout")]; + chunk_value += basis * coord_value; + } + + let mut prod = EF::ONE; + for (j, delta) in deltas.iter().enumerate() { + if j != chunk { + prod *= *delta; + } + } + quotient += weights[chunk] * prod * chunk_value; + } + + quotient +} + +/// Compute the barycentric kernel value (`zps`) for a single quotient chunk. +pub fn zps_for_chunk(layout: &InputLayout, inputs: &[EF], chunk: usize) -> EF +where + F: Field, + EF: ExtensionField, +{ + let k = layout.counts.num_quotient_chunks; + assert!(chunk < k, "quotient chunk {chunk} out of range (k={k})"); + + let z_pow_n = inputs[layout.index(InputKey::ZPowN).expect("ZPowN in layout")]; + let s0 = inputs[layout.index(InputKey::S0).expect("S0 in layout")]; + let f = inputs[layout.index(InputKey::F).expect("F in layout")]; + let weight0 = inputs[layout.index(InputKey::Weight0).expect("Weight0 in layout")]; + + let (deltas, weights) = compute_deltas_and_weights(k, z_pow_n, s0, f, weight0); + + let mut prod = EF::ONE; + for (j, delta) in deltas.iter().enumerate() { + if j != chunk { + prod *= *delta; + } + } + + weights[chunk] * prod +} + +/// Evaluate a lowered DAG against concrete inputs. +pub fn eval_dag(dag: &AceDag, inputs: &[EF], layout: &InputLayout) -> Result +where + EF: Field, +{ + if inputs.len() != layout.total_inputs { + return Err(AceError::InvalidInputLength { + expected: layout.total_inputs, + got: inputs.len(), + }); + } + + let mut values: Vec = vec![EF::ZERO; dag.nodes().len()]; + for (idx, node) in dag.nodes().iter().enumerate() { + let value = match node { + crate::dag::NodeKind::Input(key) => { + let input_idx = layout.index(*key).ok_or_else(|| AceError::InvalidInputLayout { + message: format!("missing input key in layout: {key:?}"), + })?; + inputs[input_idx] + }, + crate::dag::NodeKind::Constant(c) => *c, + crate::dag::NodeKind::Add(a, b) => values[a.index()] + values[b.index()], + crate::dag::NodeKind::Sub(a, b) => values[a.index()] - values[b.index()], + crate::dag::NodeKind::Mul(a, b) => values[a.index()] * values[b.index()], + crate::dag::NodeKind::Neg(a) => -values[a.index()], + }; + values[idx] = value; + } + + Ok(values[dag.root().index()]) +} + +fn compute_deltas_and_weights( + k: usize, + z_pow_n: EF, + s0: EF, + f: EF, + weight0: EF, +) -> (Vec, Vec) { + let mut deltas = Vec::with_capacity(k); + let mut weights = Vec::with_capacity(k); + let mut shift = s0; + let mut weight = weight0; + for _ in 0..k { + deltas.push(z_pow_n - shift); + weights.push(weight); + shift *= f; + weight *= f; + } + (deltas, weights) +} diff --git a/crates/ace-codegen/src/tests/basic.rs b/crates/ace-codegen/src/tests/basic.rs index 3d8dbd102b..6df99484b4 100644 --- a/crates/ace-codegen/src/tests/basic.rs +++ b/crates/ace-codegen/src/tests/basic.rs @@ -35,7 +35,7 @@ impl LiftedAir for MockAir { } fn num_randomness(&self) -> usize { - 1 + 2 } fn aux_width(&self) -> usize { @@ -70,7 +70,7 @@ impl LiftedAir for MockAir { } fn ef(x: u64) -> EF { - EF::from(F::new(x)) + EF::from(F::new_unchecked(x)) } fn build_inputs(layout: &InputLayout) -> Vec { @@ -89,18 +89,16 @@ fn build_inputs(layout: &InputLayout) -> Vec { set(InputKey::AuxCoord { offset: 0, index: 0, coord: 1 }, ef(101)); set(InputKey::AuxCoord { offset: 1, index: 0, coord: 0 }, ef(12)); set(InputKey::AuxCoord { offset: 1, index: 0, coord: 1 }, ef(102)); - set(InputKey::Z, ef(2)); set(InputKey::Alpha, ef(17)); - set(InputKey::GInv, ef(3)); set(InputKey::ZPowN, ef(19)); - set(InputKey::GInv2, ef(5)); set(InputKey::ZK, ef(23)); + set(InputKey::IsFirst, ef(47)); + set(InputKey::IsLast, ef(43)); + set(InputKey::IsTransition, ef(2) - ef(3)); + set(InputKey::Gamma, ef(53)); set(InputKey::Weight0, ef(31)); - set(InputKey::G, ef(37)); + set(InputKey::F, ef(37)); set(InputKey::S0, ef(41)); - set(InputKey::InvZMinusGInv, ef(43)); - set(InputKey::InvZMinusOne, ef(47)); - set(InputKey::InvVanishing, ef(2)); set(InputKey::QuotientChunkCoord { offset: 0, chunk: 0, coord: 0 }, ef(2)); set(InputKey::QuotientChunkCoord { offset: 0, chunk: 0, coord: 1 }, ef(3)); @@ -115,7 +113,7 @@ fn test_verifier_dag_matches_manual_eval() { let air = MockAir; let config = AceConfig { num_quotient_chunks: 2, - num_aux_inputs: 14, + num_vlpi_groups: 0, layout: LayoutKind::Native, }; let artifacts = build_ace_dag_for_air::<_, F, EF>(&air, config).unwrap(); @@ -135,28 +133,20 @@ fn test_verifier_dag_matches_manual_eval() { }; let mut builder = SymbolicAirBuilder::::new(air_layout); air.eval(&mut builder); - let constraint_layout = builder.constraint_layout(); - let base_constraints = builder.base_constraints(); - let ext_constraints = builder.extension_constraints(); - let dag = artifacts.dag; - - let alpha = inputs[layout.index(InputKey::Alpha).unwrap()]; - let inv_vanishing = inputs[layout.index(InputKey::InvVanishing).unwrap()]; - - let acc = eval_folded_constraints::( - &base_constraints, - &ext_constraints, - &constraint_layout, - alpha, + + let acc = eval_folded_constraints( + &builder.base_constraints(), + &builder.extension_constraints(), + &builder.constraint_layout(), &inputs, &layout, &periodic_values, ); - let folded = acc * inv_vanishing; - let quotient = eval_quotient(&layout, &inputs); - let expected = folded - quotient; + let z_pow_n = inputs[layout.index(InputKey::ZPowN).unwrap()]; + let vanishing = z_pow_n - EF::ONE; + let expected = acc - eval_quotient(&layout, &inputs) * vanishing; - let actual = eval_dag(&dag.nodes, dag.root, &inputs, &layout); + let actual = eval_dag(artifacts.dag.nodes(), artifacts.dag.root(), &inputs, &layout); assert_eq!(actual, expected); } @@ -165,7 +155,7 @@ fn test_emitted_circuit_matches_dag_eval() { let air = MockAir; let config = AceConfig { num_quotient_chunks: 2, - num_aux_inputs: 14, + num_vlpi_groups: 0, layout: LayoutKind::Native, }; let artifacts = build_ace_dag_for_air::<_, F, EF>(&air, config).unwrap(); @@ -173,7 +163,7 @@ fn test_emitted_circuit_matches_dag_eval() { let inputs = build_inputs(&layout); let circuit = emit_circuit(&artifacts.dag, layout.clone()).unwrap(); - let dag_value = eval_dag(&artifacts.dag.nodes, artifacts.dag.root, &inputs, &layout); + let dag_value = eval_dag(artifacts.dag.nodes(), artifacts.dag.root(), &inputs, &layout); let circuit_value = circuit.eval(&inputs).expect("circuit eval"); assert_eq!(circuit_value, dag_value); } @@ -183,7 +173,7 @@ fn test_encoded_circuit_structure() { let air = MockAir; let config = AceConfig { num_quotient_chunks: 2, - num_aux_inputs: 14, + num_vlpi_groups: 0, layout: LayoutKind::Native, }; let artifacts = build_ace_dag_for_air::<_, F, EF>(&air, config).unwrap(); diff --git a/crates/ace-codegen/src/tests/common.rs b/crates/ace-codegen/src/tests/common.rs index 431196ea6e..06ce2d4f31 100644 --- a/crates/ace-codegen/src/tests/common.rs +++ b/crates/ace-codegen/src/tests/common.rs @@ -1,227 +1,14 @@ use miden_core::{Felt, field::QuadFelt}; -use miden_crypto::{ - field::{ExtensionField, Field, PrimeCharacteristicRing}, - stark::{ - air::symbolic::{ - BaseEntry, BaseLeaf, ConstraintLayout, ExtEntry, ExtLeaf, SymbolicExpression, - SymbolicExpressionExt, - }, - dft::{Radix2DitParallel, TwoAdicSubgroupDft}, - }, -}; +use miden_crypto::field::PrimeCharacteristicRing; +pub use crate::testing::eval_folded_constraints; use crate::{ - InputKey, InputLayout, + InputLayout, dag::{NodeId, NodeKind}, - quotient, }; -/// Deterministic input filler for layout-sized buffers. -pub fn fill_inputs(layout: &InputLayout) -> Vec { - let mut values = Vec::with_capacity(layout.total_inputs); - let mut state = 0x9e37_79b9_7f4a_7c15u64; - for _ in 0..layout.total_inputs { - state = state.wrapping_mul(6364136223846793005).wrapping_add(1); - let lo = Felt::new(state); - state = state.wrapping_mul(6364136223846793005).wrapping_add(1); - let hi = Felt::new(state); - values.push(QuadFelt::new([lo, hi])); - } - values -} - pub fn eval_periodic_values(periodic_columns: &[Vec], z_k: QuadFelt) -> Vec { - if periodic_columns.is_empty() { - return Vec::new(); - } - let max_len = periodic_columns.iter().map(|col| col.len()).max().unwrap_or(0); - let dft = Radix2DitParallel::::default(); - - periodic_columns - .iter() - .map(|col| { - if col.is_empty() { - return QuadFelt::ZERO; - } - let coeffs = dft.idft(col.clone()); - let ratio = max_len / col.len(); - let log_pow = ratio.ilog2() as usize; - let mut z_col = z_k; - for _ in 0..log_pow { - z_col *= z_col; - } - let mut acc = QuadFelt::ZERO; - for coeff in coeffs.iter().rev() { - acc = acc * z_col + QuadFelt::from(*coeff); - } - acc - }) - .collect() -} - -/// Evaluate a base-field symbolic expression at concrete inputs. -pub fn eval_base_expr( - expr: &SymbolicExpression, - inputs: &[EF], - layout: &InputLayout, - periodic_values: &[EF], -) -> EF -where - F: Field, - EF: ExtensionField, -{ - match expr { - SymbolicExpression::Leaf(leaf) => match leaf { - BaseLeaf::Variable(v) => match v.entry { - BaseEntry::Main { offset } => { - let key = InputKey::Main { offset, index: v.index }; - inputs[layout.index(key).unwrap()] - }, - BaseEntry::Public => { - let key = InputKey::Public(v.index); - inputs[layout.index(key).unwrap()] - }, - BaseEntry::Periodic => periodic_values[v.index], - BaseEntry::Preprocessed { .. } => { - panic!("preprocessed not supported in test") - }, - }, - BaseLeaf::IsFirstRow => { - let z_pow_n = inputs[layout.index(InputKey::ZPowN).unwrap()]; - let inv = inputs[layout.index(InputKey::InvZMinusOne).unwrap()]; - (z_pow_n - EF::ONE) * inv - }, - BaseLeaf::IsLastRow => { - let z_pow_n = inputs[layout.index(InputKey::ZPowN).unwrap()]; - let inv = inputs[layout.index(InputKey::InvZMinusGInv).unwrap()]; - (z_pow_n - EF::ONE) * inv - }, - BaseLeaf::IsTransition => { - let z = inputs[layout.index(InputKey::Z).unwrap()]; - let g_inv = inputs[layout.index(InputKey::GInv).unwrap()]; - z - g_inv - }, - BaseLeaf::Constant(c) => EF::from(*c), - }, - SymbolicExpression::Add { x, y, .. } => { - eval_base_expr::(x, inputs, layout, periodic_values) - + eval_base_expr::(y, inputs, layout, periodic_values) - }, - SymbolicExpression::Sub { x, y, .. } => { - eval_base_expr::(x, inputs, layout, periodic_values) - - eval_base_expr::(y, inputs, layout, periodic_values) - }, - SymbolicExpression::Mul { x, y, .. } => { - eval_base_expr::(x, inputs, layout, periodic_values) - * eval_base_expr::(y, inputs, layout, periodic_values) - }, - SymbolicExpression::Neg { x, .. } => { - -eval_base_expr::(x, inputs, layout, periodic_values) - }, - } -} - -/// Evaluate an extension-field symbolic expression at concrete inputs. -pub fn eval_ext_expr( - expr: &SymbolicExpressionExt, - inputs: &[EF], - layout: &InputLayout, - periodic_values: &[EF], -) -> EF -where - F: Field, - EF: ExtensionField, -{ - match expr { - SymbolicExpressionExt::Leaf(leaf) => match leaf { - ExtLeaf::Base(base_expr) => { - eval_base_expr::(base_expr, inputs, layout, periodic_values) - }, - ExtLeaf::ExtVariable(v) => match v.entry { - ExtEntry::Permutation { offset } => { - let mut acc = EF::ZERO; - for coord in 0..EF::DIMENSION { - let basis = EF::ith_basis_element(coord).unwrap(); - let key = InputKey::AuxCoord { offset, index: v.index, coord }; - let value = inputs[layout.index(key).unwrap()]; - acc += basis * value; - } - acc - }, - ExtEntry::Challenge => { - let alpha = inputs[layout.index(InputKey::AuxRandAlpha).unwrap()]; - let beta = inputs[layout.index(InputKey::AuxRandBeta).unwrap()]; - match v.index { - 0 => alpha, - 1 => EF::ONE, - _ => { - let mut power = beta; - for _ in 2..v.index { - power *= beta; - } - power - }, - } - }, - ExtEntry::PermutationValue => { - let key = InputKey::AuxBusBoundary(v.index); - inputs[layout.index(key).unwrap()] - }, - }, - ExtLeaf::ExtConstant(c) => *c, - }, - SymbolicExpressionExt::Add { x, y, .. } => { - eval_ext_expr::(x, inputs, layout, periodic_values) - + eval_ext_expr::(y, inputs, layout, periodic_values) - }, - SymbolicExpressionExt::Sub { x, y, .. } => { - eval_ext_expr::(x, inputs, layout, periodic_values) - - eval_ext_expr::(y, inputs, layout, periodic_values) - }, - SymbolicExpressionExt::Mul { x, y, .. } => { - eval_ext_expr::(x, inputs, layout, periodic_values) - * eval_ext_expr::(y, inputs, layout, periodic_values) - }, - SymbolicExpressionExt::Neg { x, .. } => { - -eval_ext_expr::(x, inputs, layout, periodic_values) - }, - } -} - -/// Evaluate all constraints (base + extension) folded with alpha in evaluation order. -pub fn eval_folded_constraints( - base_constraints: &[SymbolicExpression], - ext_constraints: &[SymbolicExpressionExt], - constraint_layout: &ConstraintLayout, - alpha: EF, - inputs: &[EF], - layout: &InputLayout, - periodic_values: &[EF], -) -> EF -where - F: Field, - EF: ExtensionField, -{ - let total = constraint_layout.base_indices.len() + constraint_layout.ext_indices.len(); - let mut ordered: Vec<(usize, bool, usize)> = Vec::with_capacity(total); - for (i, &pos) in constraint_layout.base_indices.iter().enumerate() { - ordered.push((pos, false, i)); - } - for (i, &pos) in constraint_layout.ext_indices.iter().enumerate() { - ordered.push((pos, true, i)); - } - ordered.sort_by_key(|(pos, ..)| *pos); - - let mut acc = EF::ZERO; - for &(_, is_ext, idx) in &ordered { - let val = if is_ext { - eval_ext_expr::(&ext_constraints[idx], inputs, layout, periodic_values) - } else { - eval_base_expr::(&base_constraints[idx], inputs, layout, periodic_values) - }; - acc = acc * alpha + val; - } - acc + crate::testing::eval_periodic_values::(periodic_columns, z_k) } pub fn eval_dag( @@ -246,9 +33,5 @@ pub fn eval_dag( } pub fn eval_quotient(layout: &InputLayout, inputs: &[QuadFelt]) -> QuadFelt { - quotient::eval_quotient::(layout, inputs).expect("quotient evaluation") -} - -pub fn zps_for_chunk(layout: &InputLayout, inputs: &[QuadFelt], chunk: usize) -> QuadFelt { - quotient::zps_for_chunk(layout, inputs, chunk).expect("quotient zps") + crate::testing::eval_quotient::(layout, inputs) } diff --git a/crates/ace-codegen/src/tests/layout_masm.rs b/crates/ace-codegen/src/tests/layout_masm.rs index ad073a4e78..4fcea57141 100644 --- a/crates/ace-codegen/src/tests/layout_masm.rs +++ b/crates/ace-codegen/src/tests/layout_masm.rs @@ -5,10 +5,13 @@ fn masm_layout_aligns_and_maps_aux_inputs() { let counts = InputCounts { width: 3, aux_width: 2, + // TODO(#3032): 2 boundary values, but only the first is real (col 0 accumulator). + // The second is always zero. Reduce to 1 once trace splitting lands. + num_aux_boundary: 2, num_public: 5, + num_vlpi: 0, num_randomness: 16, num_periodic: 1, - num_aux_inputs: 14, num_quotient_chunks: 2, }; let layout = InputLayout::new_masm(counts); @@ -35,24 +38,24 @@ fn masm_layout_aligns_and_maps_aux_inputs() { assert_eq!(quotient_next_base % 4, 0); let aux_bus_base = layout.index(InputKey::AuxBusBoundary(0)).unwrap(); assert_eq!(aux_bus_base % 2, 0); - let stark_base = layout.index(InputKey::Z).unwrap(); + let stark_base = layout.index(InputKey::Alpha).unwrap(); assert_eq!(stark_base % 2, 0); assert_eq!(layout.index(InputKey::AuxRandBeta), Some(rand_base)); assert_eq!(layout.index(InputKey::AuxRandAlpha), Some(rand_base + 1)); - let base = layout.index(InputKey::Z).unwrap(); - assert_eq!(layout.index(InputKey::Z), Some(base)); - assert_eq!(layout.index(InputKey::Alpha), Some(base + 1)); - assert_eq!(layout.index(InputKey::GInv), Some(base + 2)); - assert_eq!(layout.index(InputKey::ZPowN), Some(base + 3)); - assert_eq!(layout.index(InputKey::GInv2), Some(base + 4)); - assert_eq!(layout.index(InputKey::ZK), Some(base + 5)); - assert_eq!(layout.index(InputKey::Weight0), Some(base + 6)); - assert_eq!(layout.index(InputKey::G), Some(base + 7)); - assert_eq!(layout.index(InputKey::S0), Some(base + 8)); - assert_eq!(layout.index(InputKey::InvZMinusGInv), Some(base + 10)); - assert_eq!(layout.index(InputKey::InvZMinusOne), Some(base + 11)); - assert_eq!(layout.index(InputKey::InvVanishing), Some(base + 12)); + // EF values: slots 0-6 + let base = layout.index(InputKey::Alpha).unwrap(); + assert_eq!(layout.index(InputKey::Alpha), Some(base)); + assert_eq!(layout.index(InputKey::ZPowN), Some(base + 1)); + assert_eq!(layout.index(InputKey::ZK), Some(base + 2)); + assert_eq!(layout.index(InputKey::IsFirst), Some(base + 3)); + assert_eq!(layout.index(InputKey::IsLast), Some(base + 4)); + assert_eq!(layout.index(InputKey::IsTransition), Some(base + 5)); + assert_eq!(layout.index(InputKey::Gamma), Some(base + 6)); + // Base-field values: slots 7-9 + assert_eq!(layout.index(InputKey::Weight0), Some(base + 7)); + assert_eq!(layout.index(InputKey::F), Some(base + 8)); + assert_eq!(layout.index(InputKey::S0), Some(base + 9)); let aux_base = layout.index(InputKey::AuxCoord { offset: 0, index: 0, coord: 0 }).unwrap(); assert_eq!( diff --git a/crates/ace-codegen/src/tests/mod.rs b/crates/ace-codegen/src/tests/mod.rs index cce07f3337..e5e5c8dc69 100644 --- a/crates/ace-codegen/src/tests/mod.rs +++ b/crates/ace-codegen/src/tests/mod.rs @@ -1,5 +1,3 @@ mod basic; mod common; mod layout_masm; -mod processor_air; -mod synthetic_ood; diff --git a/crates/ace-codegen/src/tests/processor_air.rs b/crates/ace-codegen/src/tests/processor_air.rs deleted file mode 100644 index f36ed62ac5..0000000000 --- a/crates/ace-codegen/src/tests/processor_air.rs +++ /dev/null @@ -1,87 +0,0 @@ -use miden_air::{LiftedAir, ProcessorAir}; -use miden_core::{Felt, field::QuadFelt}; -use miden_crypto::stark::air::symbolic::{AirLayout, SymbolicAirBuilder}; - -use super::common::{ - eval_dag, eval_folded_constraints, eval_periodic_values, eval_quotient, fill_inputs, -}; -use crate::{ - AceConfig, InputKey, LayoutKind, build_ace_circuit_for_air, pipeline::build_ace_dag_for_air, -}; - -#[test] -fn processor_air_dag_matches_manual_eval() { - let air = ProcessorAir; - let config = AceConfig { - num_quotient_chunks: 2, - num_aux_inputs: 14, - layout: LayoutKind::Native, - }; - let artifacts = build_ace_dag_for_air::<_, Felt, QuadFelt>(&air, config).unwrap(); - let layout = artifacts.layout.clone(); - let inputs = fill_inputs(&layout); - let z_k = inputs[layout.index(InputKey::ZK).unwrap()]; - let periodic_values = - eval_periodic_values(&LiftedAir::::periodic_columns(&air), z_k); - - let air_layout = AirLayout { - preprocessed_width: 0, - main_width: layout.counts.width, - num_public_values: layout.counts.num_public, - permutation_width: layout.counts.aux_width, - num_permutation_challenges: layout.counts.num_randomness, - num_permutation_values: LiftedAir::::num_aux_values(&air), - num_periodic_columns: layout.counts.num_periodic, - }; - let mut builder = SymbolicAirBuilder::::new(air_layout); - LiftedAir::::eval(&air, &mut builder); - let constraint_layout = builder.constraint_layout(); - let base_constraints = builder.base_constraints(); - let ext_constraints = builder.extension_constraints(); - - let alpha = inputs[layout.index(InputKey::Alpha).unwrap()]; - let inv_vanishing = inputs[layout.index(InputKey::InvVanishing).unwrap()]; - - let acc = eval_folded_constraints::( - &base_constraints, - &ext_constraints, - &constraint_layout, - alpha, - &inputs, - &layout, - &periodic_values, - ); - let folded = acc * inv_vanishing; - let quotient = eval_quotient(&layout, &inputs); - let expected = folded - quotient; - - let actual = eval_dag(&artifacts.dag.nodes, artifacts.dag.root, &inputs, &layout); - assert_eq!(actual, expected); -} - -#[test] -#[allow(clippy::print_stdout)] -fn processor_air_chiplet_rows() { - let air = ProcessorAir; - let config = AceConfig { - num_quotient_chunks: 8, - num_aux_inputs: 14, - layout: LayoutKind::Masm, - }; - - let circuit = build_ace_circuit_for_air::<_, Felt, QuadFelt>(&air, config).unwrap(); - let encoded = circuit.to_ace().unwrap(); - let read_rows = encoded.num_read_rows(); - let eval_rows = encoded.num_eval_rows(); - let total_rows = read_rows + eval_rows; - - println!( - "ACE chiplet rows (ProcessorAir): read={}, eval={}, total={}, inputs={}, constants={}, nodes={}", - read_rows, - eval_rows, - total_rows, - encoded.num_inputs(), - encoded.num_constants(), - encoded.num_nodes() - ); -} diff --git a/crates/ace-codegen/src/tests/synthetic_ood.rs b/crates/ace-codegen/src/tests/synthetic_ood.rs deleted file mode 100644 index 042621fc3c..0000000000 --- a/crates/ace-codegen/src/tests/synthetic_ood.rs +++ /dev/null @@ -1,89 +0,0 @@ -//! Synthetic OOD tests derived from the air-script ACE test strategy. -//! -//! The air-script tests correct a random quotient so the ACE circuit evaluates -//! to zero. Here we apply the same idea to the Miden VM quotient recomposition -//! (barycentric chunk kernel) and keep the tests independent of the prover. - -use miden_air::ProcessorAir; -use miden_core::{Felt, field::QuadFelt}; -use miden_crypto::field::Field; - -use super::common::{eval_quotient, fill_inputs, zps_for_chunk}; -use crate::{ - AceConfig, EXT_DEGREE, InputKey, LayoutKind, circuit::emit_circuit, - pipeline::build_ace_dag_for_air, -}; - -#[test] -fn synthetic_ood_adjusts_quotient_to_zero() { - let config = AceConfig { - num_quotient_chunks: 8, - num_aux_inputs: 14, - layout: LayoutKind::Masm, - }; - - let artifacts = - build_ace_dag_for_air::<_, Felt, QuadFelt>(&ProcessorAir, config).expect("ace dag"); - let circuit = emit_circuit(&artifacts.dag, artifacts.layout.clone()).expect("ace circuit"); - - let mut inputs = fill_inputs(&artifacts.layout); - let root = circuit.eval(&inputs).expect("circuit eval"); - - let zps_0 = zps_for_chunk(&artifacts.layout, &inputs, 0); - let delta = root * zps_0.inverse(); - - let idx = artifacts - .layout - .index(InputKey::QuotientChunkCoord { offset: 0, chunk: 0, coord: 0 }) - .unwrap(); - inputs[idx] += delta; - - let result = circuit.eval(&inputs).expect("circuit eval"); - assert!(result.is_zero(), "ACE circuit must evaluate to zero"); - - // Sanity check: recomposition is well-defined and stable. - let quotient = eval_quotient(&artifacts.layout, &inputs); - assert_eq!(quotient, eval_quotient(&artifacts.layout, &inputs)); -} - -#[test] -fn quotient_next_inputs_do_not_affect_eval() { - let config = AceConfig { - num_quotient_chunks: 8, - num_aux_inputs: 14, - layout: LayoutKind::Masm, - }; - - let artifacts = - build_ace_dag_for_air::<_, Felt, QuadFelt>(&ProcessorAir, config).expect("ace dag"); - let circuit = emit_circuit(&artifacts.dag, artifacts.layout.clone()).expect("ace circuit"); - - let mut inputs = fill_inputs(&artifacts.layout); - - let root = circuit.eval(&inputs).expect("circuit eval"); - let zps_0 = zps_for_chunk(&artifacts.layout, &inputs, 0); - let delta = root * zps_0.inverse(); - let idx = artifacts - .layout - .index(InputKey::QuotientChunkCoord { offset: 0, chunk: 0, coord: 0 }) - .unwrap(); - inputs[idx] += delta; - assert!( - circuit.eval(&inputs).expect("circuit eval").is_zero(), - "precondition: zero root" - ); - - // Mutate all quotient_next inputs; evaluation should remain zero. - for chunk in 0..artifacts.layout.counts.num_quotient_chunks { - for coord in 0..EXT_DEGREE { - let idx = artifacts - .layout - .index(InputKey::QuotientChunkCoord { offset: 1, chunk, coord }) - .unwrap(); - inputs[idx] += QuadFelt::from(Felt::new(123 + (chunk * 7 + coord) as u64)); - } - } - - let result = circuit.eval(&inputs).expect("circuit eval"); - assert!(result.is_zero(), "quotient_next should not affect ACE eval"); -} diff --git a/crates/ace-codegen/src/unit_tests.rs b/crates/ace-codegen/src/unit_tests.rs index 05a0faf415..f6af0c2a23 100644 --- a/crates/ace-codegen/src/unit_tests.rs +++ b/crates/ace-codegen/src/unit_tests.rs @@ -4,9 +4,7 @@ use miden_core::{Felt, field::QuadFelt}; use miden_crypto::field::{Field, PrimeCharacteristicRing}; use crate::{ - AceCircuit, InputCounts, InputKey, InputLayout, - circuit::emit_circuit, - dag::{AceDag, DagBuilder}, + AceCircuit, InputCounts, InputKey, InputLayout, circuit::emit_circuit, dag::DagBuilder, }; /// Minimal layout with only public inputs populated. @@ -14,10 +12,11 @@ fn minimal_layout(num_public: usize) -> InputLayout { let counts = InputCounts { width: 0, aux_width: 0, + num_aux_boundary: 0, num_public, + num_vlpi: 0, num_randomness: 2, num_periodic: 0, - num_aux_inputs: 14, num_quotient_chunks: 1, }; InputLayout::new(counts) @@ -45,12 +44,12 @@ fn ace_simple_circuit_matches_hand_eval() { let prod = builder.mul(sum, a); let root = builder.sub(prod, c); - let dag = AceDag { nodes: builder.into_nodes(), root }; + let dag = builder.build(root); let circuit: AceCircuit = emit_circuit(&dag, layout.clone()).expect("emit circuit"); - let a_val = QuadFelt::from(Felt::new(3)); - let b_val = QuadFelt::from(Felt::new(5)); + let a_val = QuadFelt::from(Felt::new_unchecked(3)); + let b_val = QuadFelt::from(Felt::new_unchecked(5)); let c_val = (a_val + b_val) * a_val; // satisfies equation let inputs = build_inputs( @@ -83,13 +82,13 @@ fn ace_simple_circuit_with_shared_terms() { let rhs = builder.add(ac, bc); let root = builder.sub(lhs, rhs); - let dag = AceDag { nodes: builder.into_nodes(), root }; + let dag = builder.build(root); let circuit: AceCircuit = emit_circuit(&dag, layout.clone()).expect("emit circuit"); - let a_val = QuadFelt::from(Felt::new(7)); - let b_val = QuadFelt::from(Felt::new(2)); - let c_val = QuadFelt::from(Felt::new(11)); + let a_val = QuadFelt::from(Felt::new_unchecked(7)); + let b_val = QuadFelt::from(Felt::new_unchecked(2)); + let c_val = QuadFelt::from(Felt::new_unchecked(11)); let inputs = build_inputs( &layout, diff --git a/crates/assembly-syntax/Cargo.toml b/crates/assembly-syntax/Cargo.toml index e600f4f7db..546f19b4b5 100644 --- a/crates/assembly-syntax/Cargo.toml +++ b/crates/assembly-syntax/Cargo.toml @@ -14,6 +14,9 @@ homepage.workspace = true repository.workspace = true exclude.workspace = true +[package.metadata.cargo-shear] +ignored = ["serde_json"] + [features] default = ["std"] std = [ @@ -59,7 +62,7 @@ thiserror.workspace = true env_logger.workspace = true miden-test-serde-macros.workspace = true proptest.workspace = true -pretty_assertions = "1.4" +pretty_assertions = { workspace = true, features = ["std"] } serde_json = { workspace = true } [build-dependencies] diff --git a/crates/assembly-syntax/src/ast/alias.rs b/crates/assembly-syntax/src/ast/alias.rs index 01f3e9babb..7e143b9391 100644 --- a/crates/assembly-syntax/src/ast/alias.rs +++ b/crates/assembly-syntax/src/ast/alias.rs @@ -119,11 +119,7 @@ impl crate::prettier::PrettyPrint for Alias { fn render(&self) -> crate::prettier::Document { use crate::prettier::*; - let mut doc = self - .docs - .as_ref() - .map(|docstring| docstring.render()) - .unwrap_or(Document::Empty); + let mut doc = self.docs.as_ref().map(PrettyPrint::render).unwrap_or(Document::Empty); if self.visibility.is_public() { doc += display(self.visibility) + const_text(" "); diff --git a/crates/assembly-syntax/src/ast/attribute/meta.rs b/crates/assembly-syntax/src/ast/attribute/meta.rs index 31cd36b17f..4175f58c83 100644 --- a/crates/assembly-syntax/src/ast/attribute/meta.rs +++ b/crates/assembly-syntax/src/ast/attribute/meta.rs @@ -48,7 +48,9 @@ impl FromIterator for Meta { core::iter::once(expr) .chain(iter.map(|item| match item { MetaItem::Expr(expr) => expr, - MetaItem::KeyValue(..) => unsafe { core::hint::unreachable_unchecked() }, + MetaItem::KeyValue(..) => { + unreachable!("mixed MetaItem variants in iterator: expected Expr") + }, })) .collect(), ), @@ -56,7 +58,9 @@ impl FromIterator for Meta { core::iter::once((k, v)) .chain(iter.map(|item| match item { MetaItem::KeyValue(k, v) => (k, v), - MetaItem::Expr(_) => unsafe { core::hint::unreachable_unchecked() }, + MetaItem::Expr(_) => { + unreachable!("mixed MetaItem variants in iterator: expected KeyValue") + }, })) .collect(), ), diff --git a/crates/assembly-syntax/src/ast/attribute/mod.rs b/crates/assembly-syntax/src/ast/attribute/mod.rs index 19a50f16cd..3ae68e0f97 100644 --- a/crates/assembly-syntax/src/ast/attribute/mod.rs +++ b/crates/assembly-syntax/src/ast/attribute/mod.rs @@ -178,7 +178,7 @@ impl prettier::PrettyPrint for Attribute { let singleline_items = meta .items .iter() - .map(|item| item.render()) + .map(PrettyPrint::render) .reduce(|acc, item| acc + const_text(", ") + item) .unwrap_or(Document::Empty); let multiline_items = indent( @@ -186,7 +186,7 @@ impl prettier::PrettyPrint for Attribute { nl() + meta .items .iter() - .map(|item| item.render()) + .map(PrettyPrint::render) .reduce(|acc, item| acc + nl() + item) .unwrap_or(Document::Empty), ) + nl(); diff --git a/crates/assembly-syntax/src/ast/attribute/set.rs b/crates/assembly-syntax/src/ast/attribute/set.rs index ceca0f88bd..be2293dff3 100644 --- a/crates/assembly-syntax/src/ast/attribute/set.rs +++ b/crates/assembly-syntax/src/ast/attribute/set.rs @@ -44,7 +44,7 @@ impl AttributeSet { I: IntoIterator, { let mut this = Self { attrs: attrs.into_iter().collect() }; - this.attrs.sort_by_key(|attr| attr.id()); + this.attrs.sort_by_key(Attribute::id); this.attrs.dedup_by_key(|attr| attr.id()); this } diff --git a/crates/assembly-syntax/src/ast/constants/eval.rs b/crates/assembly-syntax/src/ast/constants/eval.rs index 6b2db46934..2dbd8440d1 100644 --- a/crates/assembly-syntax/src/ast/constants/eval.rs +++ b/crates/assembly-syntax/src/ast/constants/eval.rs @@ -330,7 +330,7 @@ where if let Some(name) = path.as_ident() { let name = name.with_span(path.span()); - if let Some(expr) = env.get(&name)?.map(|e| e.into_expr()) { + if let Some(expr) = env.get(&name)?.map(CachedConstantValue::into_expr) { env.on_eval_start(path.as_deref()); evaluating.push(path.clone()); continuations.push(Cont::Return(path.clone())); @@ -394,8 +394,8 @@ where } .into()); } - let lhs = Felt::new(lhs.as_int()); - let rhs = Felt::new(rhs.as_int()); + let lhs = Felt::new_unchecked(lhs.as_int()); + let rhs = Felt::new_unchecked(rhs.as_int()); IntValue::from(lhs / rhs) }, }; diff --git a/crates/assembly-syntax/src/ast/constants/expr.rs b/crates/assembly-syntax/src/ast/constants/expr.rs index 3b8a6b3473..9489b0d44a 100644 --- a/crates/assembly-syntax/src/ast/constants/expr.rs +++ b/crates/assembly-syntax/src/ast/constants/expr.rs @@ -72,7 +72,7 @@ impl ConstantExpr { #[track_caller] pub fn expect_felt(&self) -> Felt { match self { - Self::Int(spanned) => Felt::new(spanned.inner().as_int()), + Self::Int(spanned) => Felt::new_unchecked(spanned.inner().as_int()), other => panic!("expected constant expression to be a literal, got {other:#?}"), } } @@ -95,9 +95,8 @@ impl ConstantExpr { /// value, otherwise a bug occurred. #[track_caller] pub fn expect_value(&self) -> ConstantValue { - self.as_value().unwrap_or_else(|| { - panic!("expected constant expression to be a value, got {:#?}", self) - }) + self.as_value() + .unwrap_or_else(|| panic!("expected constant expression to be a value, got {self:#?}")) } /// Try to convert this expression into a [ConstantValue], if the expression is a value. @@ -198,8 +197,8 @@ impl ConstantExpr { Some(Self::Int(Span::new(span, value))) }, ConstantOp::Div => { - let lhs = Felt::new(lhs.as_int()); - let rhs = Felt::new(rhs.as_int()); + let lhs = Felt::new_unchecked(lhs.as_int()); + let rhs = Felt::new_unchecked(rhs.as_int()); let value = IntValue::from(lhs / rhs); Some(Self::Int(Span::new(span, value))) }, @@ -408,6 +407,10 @@ impl proptest::arbitrary::Arbitrary for ConstantExpr { #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] #[repr(u8)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr( + all(feature = "arbitrary", test), + miden_test_serde_macros::serde_test(binary_serde(true)) +)] pub enum ConstantOp { Add, Sub, @@ -417,7 +420,7 @@ pub enum ConstantOp { } impl ConstantOp { - const fn name(&self) -> &'static str { + const fn name(self) -> &'static str { match self { Self::Add => "Add", Self::Sub => "Sub", @@ -509,6 +512,10 @@ impl proptest::arbitrary::Arbitrary for ConstantOp { #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] #[repr(u8)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr( + all(feature = "arbitrary", test), + miden_test_serde_macros::serde_test(binary_serde(true)) +)] pub enum HashKind { /// Reduce a string to a word using Blake3 hash function Word, diff --git a/crates/assembly-syntax/src/ast/constants/mod.rs b/crates/assembly-syntax/src/ast/constants/mod.rs index 326663c939..3dde066d63 100644 --- a/crates/assembly-syntax/src/ast/constants/mod.rs +++ b/crates/assembly-syntax/src/ast/constants/mod.rs @@ -76,11 +76,7 @@ impl crate::prettier::PrettyPrint for Constant { fn render(&self) -> crate::prettier::Document { use crate::prettier::*; - let mut doc = self - .docs - .as_ref() - .map(|docstring| docstring.render()) - .unwrap_or(Document::Empty); + let mut doc = self.docs.as_ref().map(PrettyPrint::render).unwrap_or(Document::Empty); doc += flatten(const_text("const") + const_text(" ") + display(&self.name)); doc += const_text(" = "); diff --git a/crates/assembly-syntax/src/ast/constants/value.rs b/crates/assembly-syntax/src/ast/constants/value.rs index 77f40f0141..30139ba23a 100644 --- a/crates/assembly-syntax/src/ast/constants/value.rs +++ b/crates/assembly-syntax/src/ast/constants/value.rs @@ -19,6 +19,10 @@ use crate::{ #[derive(Clone)] #[repr(u8)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr( + all(feature = "arbitrary", test), + miden_test_serde_macros::serde_test(binary_serde(true)) +)] pub enum ConstantValue { /// A literal [`miden_core::Felt`] value. Int(Span) = 1, diff --git a/crates/assembly-syntax/src/ast/instruction/mod.rs b/crates/assembly-syntax/src/ast/instruction/mod.rs index 5f5443eca4..a98a913f73 100644 --- a/crates/assembly-syntax/src/ast/instruction/mod.rs +++ b/crates/assembly-syntax/src/ast/instruction/mod.rs @@ -242,7 +242,8 @@ pub enum Instruction { MemStream, AdvPipe, - AdvPush(ImmU8), + AdvPush, + AdvPushW, AdvLoadW, SysEvent(SystemEventNode), diff --git a/crates/assembly-syntax/src/ast/instruction/print.rs b/crates/assembly-syntax/src/ast/instruction/print.rs index c28c716218..13dd1bcd37 100644 --- a/crates/assembly-syntax/src/ast/instruction/print.rs +++ b/crates/assembly-syntax/src/ast/instruction/print.rs @@ -257,7 +257,8 @@ impl PrettyPrint for Instruction { Self::MemStream => const_text("mem_stream"), Self::AdvPipe => const_text("adv_pipe"), - Self::AdvPush(value) => inst_with_imm("adv_push", value), + Self::AdvPush => const_text("adv_push"), + Self::AdvPushW => const_text("adv_pushw"), Self::AdvLoadW => const_text("adv_loadw"), Self::SysEvent(sys_event) => inst_with_imm("adv", sys_event), @@ -390,7 +391,11 @@ mod tests { use miden_core::crypto::hash::Poseidon2; use miden_debug_types::Span; - use crate::{Felt, ast::*}; + use crate::{ + Felt, + ast::*, + parser::{IntValue, PushValue}, + }; #[test] fn test_instruction_display() { @@ -400,7 +405,7 @@ mod tests { let instruction = format!("{}", Instruction::Add); assert_eq!("add", instruction); - let instruction = format!("{}", Instruction::AddImm(Felt::new(5).into())); + let instruction = format!("{}", Instruction::AddImm(Felt::new_unchecked(5).into())); assert_eq!("add.5", instruction); let instruction = format!("{}", Instruction::ExpBitLength(32)); @@ -408,14 +413,17 @@ mod tests { let instruction = format!( "{}", - Instruction::PushFeltList(vec![Felt::new(3), Felt::new(4), Felt::new(8), Felt::new(9)]) + Instruction::PushFeltList(vec![ + Felt::new_unchecked(3), + Felt::new_unchecked(4), + Felt::new_unchecked(8), + Felt::new_unchecked(9) + ]) ); assert_eq!("push.3.4.8.9", instruction); let instruction = format!( "{}", - Instruction::Push(Immediate::Value(miden_debug_types::Span::unknown( - crate::parser::PushValue::Int(crate::parser::IntValue::U8(3)) - ))) + Instruction::Push(Immediate::Value(Span::unknown(PushValue::Int(IntValue::U8(3))))) ); assert_eq!("push.3", instruction); @@ -423,7 +431,7 @@ mod tests { let target = InvocationTarget::MastRoot(Span::unknown(digest)); let instruction = format!("{}", Instruction::Exec(target)); assert_eq!( - "exec.0x065c394c00227acff3545da5493cf1b79d9a9f5628db553d240edf8ef0cca04a", + "exec.0x23796e2a4ee91a63c116e11dbbc2ea599461766d1fb7b6599ca387cab2c3e64c", instruction ); } diff --git a/crates/assembly-syntax/src/ast/item/export.rs b/crates/assembly-syntax/src/ast/item/export.rs index 15a2e313fd..f64ebe34a4 100644 --- a/crates/assembly-syntax/src/ast/item/export.rs +++ b/crates/assembly-syntax/src/ast/item/export.rs @@ -47,10 +47,10 @@ impl Export { /// Returns the documentation for this item. pub fn docs(&self) -> Option<&str> { match self { - Self::Procedure(item) => item.docs().map(|spanned| spanned.into_inner()), - Self::Constant(item) => item.docs().map(|spanned| spanned.into_inner()), - Self::Type(item) => item.docs().map(|spanned| spanned.into_inner()), - Self::Alias(item) => item.docs().map(|spanned| spanned.into_inner()), + Self::Procedure(item) => item.docs().map(Span::into_inner), + Self::Constant(item) => item.docs().map(Span::into_inner), + Self::Type(item) => item.docs().map(Span::into_inner), + Self::Alias(item) => item.docs().map(Span::into_inner), } } diff --git a/crates/assembly-syntax/src/ast/item/index.rs b/crates/assembly-syntax/src/ast/item/index.rs index 1350953838..f613f484e8 100644 --- a/crates/assembly-syntax/src/ast/item/index.rs +++ b/crates/assembly-syntax/src/ast/item/index.rs @@ -3,9 +3,22 @@ #[repr(transparent)] pub struct ItemIndex(u16); +#[derive(Debug, Copy, Clone, PartialEq, Eq, thiserror::Error)] +#[error("invalid item index: too many items")] +pub struct ItemIndexError { + attempted: usize, +} + impl ItemIndex { + pub const MAX_ITEMS: usize = u16::MAX as usize + 1; + pub fn new(id: usize) -> Self { - Self(id.try_into().expect("invalid item index: too many items")) + Self::try_new(id).expect("invalid item index: too many items") + } + + pub fn try_new(id: usize) -> Result { + let raw = id.try_into().map_err(|_| ItemIndexError { attempted: id })?; + Ok(Self(raw)) } #[inline(always)] @@ -99,3 +112,84 @@ impl core::fmt::Display for ModuleIndex { write!(f, "{}", &self.as_usize()) } } + +#[cfg(test)] +mod regression_tests { + use std::{string::String, sync::Arc}; + + use miden_debug_types::{DefaultSourceManager, SourceSpan, Span}; + + use super::ItemIndex; + use crate::{ + Parse, ParseOptions, Path, + ast::{ + Constant, ConstantExpr, Export, Ident, Module, ModuleKind, SymbolResolutionError, + Visibility, + }, + parser::IntValue, + sema::{LimitKind, SemanticAnalysisError, SyntaxError}, + }; + + fn huge_library_masm() -> String { + let num_consts = usize::from(u16::MAX) + 2; + let mut masm = String::with_capacity(num_consts * 16); + for i in 0..num_consts { + masm.push_str("const A"); + masm.push_str(&format!("{i}")); + masm.push_str(" = 0\n"); + } + masm + } + + fn oversized_module_for_resolver() -> Module { + let mut module = Module::new(ModuleKind::Library, Path::new("::m::huge")); + for i in 0..=ItemIndex::MAX_ITEMS { + module.items.push(Export::Constant(Constant::new( + SourceSpan::UNKNOWN, + Visibility::Private, + Ident::new(format!("A{i}")).expect("valid identifier"), + ConstantExpr::Int(Span::unknown(IntValue::from(0u8))), + ))); + } + module + } + + #[test] + fn too_many_items_in_module_is_rejected_during_analysis() { + let source_manager = Arc::new(DefaultSourceManager::default()); + let err = huge_library_masm() + .parse_with_options( + source_manager, + ParseOptions::new(ModuleKind::Library, Path::new("::m::huge")), + ) + .expect_err("expected oversized module to be rejected during analysis"); + + let syntax_error = err.downcast_ref::().expect("expected SyntaxError report"); + assert!( + syntax_error.errors.iter().any(|error| { + matches!(error, SemanticAnalysisError::LimitExceeded { kind: LimitKind::Items, .. }) + }), + "expected item-limit error, got {:?}", + syntax_error.errors + ); + } + + #[test] + fn resolving_name_in_too_large_module_returns_structured_error() { + let source_manager = Arc::new(DefaultSourceManager::default()); + let module = oversized_module_for_resolver(); + let result = module.resolve(Span::unknown("A0"), source_manager); + + assert!(matches!(result, Err(SymbolResolutionError::TooManyItemsInModule { .. }))); + } + + #[test] + fn resolver_construction_for_too_large_module_returns_structured_error() { + let source_manager = Arc::new(DefaultSourceManager::default()); + let module = oversized_module_for_resolver(); + + let result = module.resolver(source_manager); + + assert!(matches!(result, Err(SymbolResolutionError::TooManyItemsInModule { .. }))); + } +} diff --git a/crates/assembly-syntax/src/ast/item/resolver/error.rs b/crates/assembly-syntax/src/ast/item/resolver/error.rs index 0955fbc64e..6c89632c61 100644 --- a/crates/assembly-syntax/src/ast/item/resolver/error.rs +++ b/crates/assembly-syntax/src/ast/item/resolver/error.rs @@ -5,7 +5,10 @@ use alloc::sync::Arc; use miden_debug_types::{SourceFile, SourceManager, SourceSpan}; -use crate::diagnostics::{Diagnostic, RelatedLabel, miette}; +use crate::{ + ast::ItemIndex, + diagnostics::{Diagnostic, RelatedLabel, miette}, +}; /// Represents an error that occurs during symbol resolution #[derive(Debug, Clone, thiserror::Error, Diagnostic)] @@ -51,6 +54,16 @@ pub enum SymbolResolutionError { #[related] actual: Option, }, + #[error("private symbol reference")] + #[diagnostic(help("only public items can be referenced from another module"))] + PrivateSymbol { + #[label("this symbol is private to another module")] + span: SourceSpan, + #[source_code] + source_file: Option>, + #[related] + defined: Option, + }, #[error("type expression nesting depth exceeded")] #[diagnostic(help("type expression nesting exceeded the maximum depth of {max_depth}"))] TypeExpressionDepthExceeded { @@ -77,6 +90,15 @@ pub enum SymbolResolutionError { source_file: Option>, max_depth: usize, }, + #[error("too many items in module")] + #[diagnostic(help("break this module up into smaller modules"))] + TooManyItemsInModule { + #[label("module item count exceeds the supported limit of {max_items}")] + span: SourceSpan, + #[source_code] + source_file: Option>, + max_items: usize, + }, } impl SymbolResolutionError { @@ -146,6 +168,24 @@ impl SymbolResolutionError { } } + pub fn private_symbol( + span: SourceSpan, + defined: SourceSpan, + source_manager: &dyn SourceManager, + ) -> Self { + let defined_source_file = source_manager.get(defined.source_id()).ok(); + let source_file = source_manager.get(span.source_id()).ok(); + Self::PrivateSymbol { + span, + source_file, + defined: Some( + RelatedLabel::advice("the referenced item is private") + .with_labeled_span(defined, "the referenced item is private") + .with_source_file(defined_source_file), + ), + } + } + pub fn type_expression_depth_exceeded( span: SourceSpan, max_depth: usize, @@ -176,4 +216,12 @@ impl SymbolResolutionError { max_depth, } } + + pub fn too_many_items_in_module(span: SourceSpan, source_manager: &dyn SourceManager) -> Self { + Self::TooManyItemsInModule { + span, + source_file: source_manager.get(span.source_id()).ok(), + max_items: ItemIndex::MAX_ITEMS, + } + } } diff --git a/crates/assembly-syntax/src/ast/item/resolver/mod.rs b/crates/assembly-syntax/src/ast/item/resolver/mod.rs index bbcc157bcf..bca844fe82 100644 --- a/crates/assembly-syntax/src/ast/item/resolver/mod.rs +++ b/crates/assembly-syntax/src/ast/item/resolver/mod.rs @@ -65,18 +65,21 @@ impl Spanned for SymbolResolution { /// /// This is used as a low-level symbol resolution primitive in the linker as well. pub struct LocalSymbolResolver { + source_manager: Arc, symbols: LocalSymbolTable, } impl LocalSymbolResolver { /// Create a new resolver using the provided [SymbolTable] and [SourceManager]. - pub fn new(symbols: S, source_manager: Arc) -> Self + pub fn new( + symbols: S, + source_manager: Arc, + ) -> Result where S: SymbolTable, { - Self { - symbols: LocalSymbolTable::new(symbols, source_manager), - } + let symbols = LocalSymbolTable::new(symbols, source_manager.clone())?; + Ok(Self { source_manager, symbols }) } /// Expand `path` using `get_import` to resolve a raw symbol name to an import in the current @@ -97,7 +100,7 @@ impl LocalSymbolResolver { #[inline] pub fn source_manager(&self) -> Arc { - self.symbols.source_manager_arc() + self.source_manager.clone() } /// Try to resolve `name` to an item, either local or external @@ -114,7 +117,7 @@ impl LocalSymbolResolver { path: Span<&Path>, ) -> Result { if path.is_absolute() { - return Ok(SymbolResolution::External(path.map(|p| p.into()))); + return Ok(SymbolResolution::External(path.map(Into::into))); } log::debug!(target: "local-symbol-resolver", "resolving path '{path}'"); let (ns, subpath) = path.split_first().expect("invalid item path"); @@ -142,7 +145,7 @@ impl LocalSymbolResolver { Err(SymbolResolutionError::invalid_sub_path( path.span(), item.span(), - self.symbols.source_manager(), + &*self.source_manager, )) }, SymbolResolution::MastRoot(digest) => { @@ -156,7 +159,7 @@ impl LocalSymbolResolver { Err(SymbolResolutionError::invalid_sub_path( path.span(), digest.span(), - self.symbols.source_manager(), + &*self.source_manager, )) }, SymbolResolution::Module { id, path, .. } => { diff --git a/crates/assembly-syntax/src/ast/item/resolver/symbol_table.rs b/crates/assembly-syntax/src/ast/item/resolver/symbol_table.rs index 441645e4a4..9a73592508 100644 --- a/crates/assembly-syntax/src/ast/item/resolver/symbol_table.rs +++ b/crates/assembly-syntax/src/ast/item/resolver/symbol_table.rs @@ -1,6 +1,6 @@ use alloc::{collections::BTreeMap, sync::Arc, vec::Vec}; -use miden_debug_types::{SourceManager, Span, Spanned}; +use miden_debug_types::{SourceManager, SourceSpan, Span, Spanned}; use super::{SymbolResolution, SymbolResolutionError}; use crate::{ @@ -15,6 +15,9 @@ use crate::{ const MAX_ALIAS_EXPANSION_DEPTH: usize = 128; /// This trait abstracts over any type which acts as a symbol table, e.g. a [crate::ast::Module]. +/// +/// Resolver construction uses [Self::checked_symbols], which must either return the full symbol +/// set or a structured error. pub trait SymbolTable { /// The concrete iterator type for the container. type SymbolIter: Iterator; @@ -22,28 +25,51 @@ pub trait SymbolTable { /// Get an iterator over the symbols in this symbol table, using the provided [SourceManager] /// to emit errors for symbols which are invalid/unresolvable. fn symbols(&self, source_manager: Arc) -> Self::SymbolIter; + + /// Get an iterator over the symbols in this symbol table, returning a structured error if the + /// full symbol set cannot be represented exactly. + /// + /// Override this when exact resolver construction needs validation, such as rejecting oversized + /// symbol sets. + fn checked_symbols( + &self, + source_manager: Arc, + ) -> Result { + Ok(self.symbols(source_manager)) + } } impl SymbolTable for &crate::library::ModuleInfo { type SymbolIter = alloc::vec::IntoIter; fn symbols(&self, _source_manager: Arc) -> Self::SymbolIter { - let module_items = self.items(); - let mut items = Vec::with_capacity(module_items.len()); + let mut items = Vec::with_capacity(self.raw_items().len()); - for (index, item) in module_items { + for (i, item) in self.raw_items().iter().enumerate() { let name = item.name().clone(); let span = name.span(); - - assert_eq!(index.as_usize(), items.len()); items.push(LocalSymbol::Item { name, - resolved: SymbolResolution::Local(Span::new(span, index)), + resolved: SymbolResolution::Local(Span::new(span, ItemIndex::new(i))), }); } items.into_iter() } + + fn checked_symbols( + &self, + source_manager: Arc, + ) -> Result { + if self.raw_items().len() > ItemIndex::MAX_ITEMS { + Err(SymbolResolutionError::too_many_items_in_module( + SourceSpan::UNKNOWN, + &*source_manager, + )) + } else { + Ok(self.symbols(source_manager)) + } + } } impl SymbolTable for &crate::ast::Module { @@ -90,6 +116,17 @@ impl SymbolTable for &crate::ast::Module { items.into_iter() } + + fn checked_symbols( + &self, + source_manager: Arc, + ) -> Result { + if self.items.len() > ItemIndex::MAX_ITEMS { + Err(SymbolResolutionError::too_many_items_in_module(self.span(), &*source_manager)) + } else { + Ok(self.symbols(source_manager)) + } + } } /// Represents a symbol within the context of a single module @@ -130,40 +167,58 @@ impl core::ops::Index for LocalSymbolTable { } impl LocalSymbolTable { - pub fn new(iter: S, source_manager: Arc) -> Self + fn build(iter: I, source_manager: Arc) -> Self where - S: SymbolTable, + I: Iterator, { let mut symbols = BTreeMap::default(); let mut items = Vec::with_capacity(16); - for (i, symbol) in iter.symbols(source_manager.clone()).enumerate() { + for (i, symbol) in iter.enumerate() { + let id = ItemIndex::try_new(i) + .expect("symbol iterators used by LocalSymbolTable::build must be pre-validated"); + let symbol = match symbol { + LocalSymbol::Item { + name, + resolved: SymbolResolution::Local(local), + } => LocalSymbol::Item { + name, + resolved: SymbolResolution::Local(Span::new(local.span(), id)), + }, + symbol => symbol, + }; log::debug!(target: "symbol-table::new", "registering {} symbol: {}", match symbol { LocalSymbol::Item { .. } => "local", LocalSymbol::Import { .. } => "imported", }, symbol.name()); - - let id = ItemIndex::new(i); let name = match &symbol { LocalSymbol::Item { name, .. } => name.clone().into_inner(), LocalSymbol::Import { name, .. } => name.clone().into_inner(), }; - symbols.insert(name, id); + if let Some(prev) = symbols.get(&name).copied() { + debug_assert!( + false, + "duplicate symbol '{name}' reached local resolver construction (previous={prev:?}, current={id:?})" + ); + } else { + symbols.insert(name.clone(), id); + } items.push(symbol); } Self { source_manager, symbols, items } } - #[inline(always)] - pub fn source_manager(&self) -> &dyn SourceManager { - &self.source_manager - } - - #[inline(always)] - pub fn source_manager_arc(&self) -> Arc { - self.source_manager.clone() + pub fn new( + iter: S, + source_manager: Arc, + ) -> Result + where + S: SymbolTable, + { + let symbols = iter.checked_symbols(source_manager.clone())?; + Ok(Self::build(symbols, source_manager)) } } @@ -478,4 +533,108 @@ mod tests { other => panic!("expected external resolution, got {other:?}"), } } + + #[test] + fn checked_symbols_rejects_oversized_module() { + let source_manager: Arc = Arc::new(DefaultSourceManager::default()); + let mut module = + crate::ast::Module::new(crate::ast::ModuleKind::Library, Path::new("::m::huge")); + + for i in 0..=ItemIndex::MAX_ITEMS { + module.items.push(crate::ast::Export::Constant(crate::ast::Constant::new( + SourceSpan::UNKNOWN, + crate::ast::Visibility::Private, + Ident::new(format!("A{i}")).expect("valid identifier"), + crate::ast::ConstantExpr::Int(Span::unknown(crate::parser::IntValue::from(0u8))), + ))); + } + + let result = (&module).checked_symbols(source_manager); + + assert!(matches!(result, Err(SymbolResolutionError::TooManyItemsInModule { .. }))); + } + + #[test] + fn checked_symbols_guard_custom_symbol_table_exact() { + struct ExactTooManySymbols; + + impl SymbolTable for ExactTooManySymbols { + type SymbolIter = alloc::vec::IntoIter; + + fn symbols(&self, _source_manager: Arc) -> Self::SymbolIter { + panic!("exact construction must not request unchecked symbols") + } + + fn checked_symbols( + &self, + source_manager: Arc, + ) -> Result { + Err(SymbolResolutionError::too_many_items_in_module( + SourceSpan::UNKNOWN, + &*source_manager, + )) + } + } + + let source_manager: Arc = Arc::new(DefaultSourceManager::default()); + let result = LocalSymbolTable::new(ExactTooManySymbols, source_manager); + + assert!(matches!(result, Err(SymbolResolutionError::TooManyItemsInModule { .. }))); + } + + #[cfg(test)] + struct DuplicateSymbolsForInvariantTest; + + #[cfg(test)] + impl SymbolTable for DuplicateSymbolsForInvariantTest { + type SymbolIter = alloc::vec::IntoIter; + + fn symbols(&self, _source_manager: Arc) -> Self::SymbolIter { + let first = LocalSymbol::Item { + name: Ident::new("dup").expect("valid identifier"), + resolved: SymbolResolution::Local(Span::unknown(ItemIndex::new(0))), + }; + let second = LocalSymbol::Item { + name: Ident::new("dup").expect("valid identifier"), + resolved: SymbolResolution::Local(Span::unknown(ItemIndex::new(1))), + }; + alloc::vec![first, second].into_iter() + } + } + + #[cfg(debug_assertions)] + #[test] + #[should_panic(expected = "duplicate symbol 'dup' reached local resolver construction")] + fn local_symbol_table_rejects_duplicate_symbols() { + let source_manager: Arc = Arc::new(DefaultSourceManager::default()); + let _table = LocalSymbolTable::new(DuplicateSymbolsForInvariantTest, source_manager); + } + + #[test] + fn local_symbol_table_duplicate_symbols_have_explicit_behavior() { + use std::panic::{AssertUnwindSafe, catch_unwind}; + + let source_manager: Arc = Arc::new(DefaultSourceManager::default()); + let result = catch_unwind(AssertUnwindSafe(|| { + LocalSymbolTable::new(DuplicateSymbolsForInvariantTest, source_manager) + })); + + if cfg!(debug_assertions) { + assert!( + result.is_err(), + "debug builds should panic when duplicates reach local resolver construction" + ); + } else { + let table = result + .expect("release builds should not panic on duplicate symbols") + .expect("release builds should still construct a table"); + let resolved = table + .get(Span::unknown("dup")) + .expect("release behavior should keep a deterministic symbol mapping"); + match resolved { + SymbolResolution::Local(id) => assert_eq!(id.into_inner(), ItemIndex::new(0)), + other => panic!("expected local symbol resolution, got {other:?}"), + } + } + } } diff --git a/crates/assembly-syntax/src/ast/module.rs b/crates/assembly-syntax/src/ast/module.rs index a7fd99004b..07fa3f7d4d 100644 --- a/crates/assembly-syntax/src/ast/module.rs +++ b/crates/assembly-syntax/src/ast/module.rs @@ -7,6 +7,8 @@ use miden_core::{ }; use miden_debug_types::{SourceFile, SourceManager, SourceSpan, Span, Spanned}; use miden_utils_diagnostics::Report; +#[cfg(feature = "arbitrary")] +use proptest::prelude::*; use smallvec::SmallVec; use super::{ @@ -18,7 +20,7 @@ use crate::{ PathBuf, ast::{self, Ident, types}, parser::ModuleParser, - sema::SemanticAnalysisError, + sema::{LimitKind, SemanticAnalysisError}, }; // MODULE KIND @@ -30,6 +32,10 @@ use crate::{ /// what operations can be performed in the body of procedures defined in the module. See the /// documentation for each variant for a summary of these differences. #[derive(Debug, Default, Copy, Clone, PartialEq, Eq)] +#[cfg_attr( + all(feature = "arbitrary", test), + miden_test_serde_macros::serde_test(binary_serde(true), serde_test(false)) +)] #[repr(u8)] pub enum ModuleKind { /// A library is a simple container of code that must be included into an executable module to @@ -84,6 +90,22 @@ impl fmt::Display for ModuleKind { } } +#[cfg(feature = "arbitrary")] +impl Arbitrary for ModuleKind { + type Parameters = (); + type Strategy = BoxedStrategy; + + fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { + any::() + .prop_map(|tag| match tag % 3 { + 0 => Self::Library, + 1 => Self::Executable, + _ => Self::Kernel, + }) + .boxed() + } +} + impl Serializable for ModuleKind { fn write_into(&self, target: &mut W) { target.write_u8(*self as u8) @@ -196,35 +218,41 @@ impl Module { self.span = span; } + fn ensure_item_capacity(&self, span: SourceSpan) -> Result<(), SemanticAnalysisError> { + if self.items.len() >= ItemIndex::MAX_ITEMS { + return Err(SemanticAnalysisError::LimitExceeded { span, kind: LimitKind::Items }); + } + + Ok(()) + } + + pub(crate) fn push_export(&mut self, item: Export) -> Result<(), SemanticAnalysisError> { + self.ensure_item_capacity(item.span())?; + self.items.push(item); + Ok(()) + } + /// Defines a constant, raising an error if the constant conflicts with a previous definition pub fn define_constant(&mut self, constant: Constant) -> Result<(), SemanticAnalysisError> { - for item in self.items.iter() { - if let Export::Constant(c) = item - && c.name == constant.name - { - return Err(SemanticAnalysisError::SymbolConflict { - span: constant.span, - prev_span: c.span, - }); - } + if let Some(prev) = self.items.iter().find(|item| item.name() == &constant.name) { + return Err(SemanticAnalysisError::SymbolConflict { + span: constant.span, + prev_span: prev.span(), + }); } - self.items.push(Export::Constant(constant)); + self.push_export(Export::Constant(constant))?; Ok(()) } /// Defines a type alias, raising an error if the alias conflicts with a previous definition pub fn define_type(&mut self, ty: TypeAlias) -> Result<(), SemanticAnalysisError> { - for item in self.items.iter() { - if let Export::Type(t) = item - && t.name() == ty.name() - { - return Err(SemanticAnalysisError::SymbolConflict { - span: ty.span(), - prev_span: t.span(), - }); - } + if let Some(prev) = self.items.iter().find(|item| item.name() == ty.name()) { + return Err(SemanticAnalysisError::SymbolConflict { + span: ty.span(), + prev_span: prev.span(), + }); } - self.items.push(Export::Type(ty.into())); + self.push_export(Export::Type(ty.into()))?; Ok(()) } @@ -245,7 +273,7 @@ impl Module { } // We only define constants for C-like enums - if ty.is_c_like() { + if !ty.is_c_like() { self.items.push(Export::Type(ty.into())); return Ok(()); } @@ -303,7 +331,7 @@ impl Module { })?; } - self.items.push(Export::Type(export.into())); + self.push_export(Export::Type(export.into()))?; Ok(()) } @@ -313,17 +341,18 @@ impl Module { pub fn define_procedure( &mut self, procedure: Procedure, - source_manager: Arc, + _source_manager: Arc, ) -> Result<(), SemanticAnalysisError> { - let name = procedure.name(); - let name = Span::new(name.span(), name.as_str()); - if let Ok(prev) = self.resolve(name, source_manager) { - let prev_span = prev.span(); - Err(SemanticAnalysisError::SymbolConflict { span: procedure.span(), prev_span }) - } else { - self.items.push(Export::Procedure(procedure)); - Ok(()) + if let Some(prev) = + self.items.iter().find(|item| item.name().as_str() == procedure.name().as_str()) + { + return Err(SemanticAnalysisError::SymbolConflict { + span: procedure.span(), + prev_span: prev.name().span(), + }); } + self.push_export(Export::Procedure(procedure))?; + Ok(()) } /// Defines an item alias, raising an error if the alias is invalid, or conflicts with a @@ -331,20 +360,23 @@ impl Module { pub fn define_alias( &mut self, item: Alias, - source_manager: Arc, + _source_manager: Arc, ) -> Result<(), SemanticAnalysisError> { if self.is_kernel() && item.visibility().is_public() { return Err(SemanticAnalysisError::ReexportFromKernel { span: item.span() }); } - let name = item.name(); - let name = Span::new(name.span(), name.as_str()); - if let Ok(prev) = self.resolve(name, source_manager) { - let prev_span = prev.span(); - Err(SemanticAnalysisError::SymbolConflict { span: item.span(), prev_span }) - } else { - self.items.push(Export::Alias(item)); - Ok(()) + if let Some(prev) = self + .items + .iter() + .find(|existing| existing.name().as_str() == item.name().as_str()) + { + return Err(SemanticAnalysisError::SymbolConflict { + span: item.name().span(), + prev_span: prev.name().span(), + }); } + self.push_export(Export::Alias(item))?; + Ok(()) } } @@ -432,7 +464,7 @@ impl Module { /// Returns true if this module has an entrypoint procedure defined, /// i.e. a `begin`..`end` block. pub fn has_entrypoint(&self) -> bool { - self.index_of(|p| p.is_main()).is_some() + self.index_of(Export::is_main).is_some() } /// Returns a reference to the advice map derived from this module @@ -568,7 +600,7 @@ impl Module { name: Span<&str>, source_manager: Arc, ) -> Result { - let resolver = self.resolver(source_manager); + let resolver = self.resolver(source_manager)?; resolver.resolve(name) } @@ -578,13 +610,16 @@ impl Module { path: Span<&Path>, source_manager: Arc, ) -> Result { - let resolver = self.resolver(source_manager); + let resolver = self.resolver(source_manager)?; resolver.resolve_path(path) } /// Construct a search structure that can resolve procedure names local to this module #[inline] - pub fn resolver(&self, source_manager: Arc) -> LocalSymbolResolver { + pub fn resolver( + &self, + source_manager: Arc, + ) -> Result { LocalSymbolResolver::new(self, source_manager) } @@ -610,7 +645,7 @@ impl Module { ty: &ast::TypeExpr, source_manager: Arc, ) -> Result, SymbolResolutionError> { - let mut type_resolver = ModuleTypeResolver::new(self, source_manager); + let mut type_resolver = self.type_resolver(source_manager)?; type_resolver.resolve(ty) } @@ -618,7 +653,7 @@ impl Module { pub fn type_resolver( &self, source_manager: Arc, - ) -> impl TypeResolver + '_ { + ) -> Result + '_, SymbolResolutionError> { ModuleTypeResolver::new(self, source_manager) } } @@ -712,9 +747,12 @@ struct ModuleTypeResolver<'a> { } impl<'a> ModuleTypeResolver<'a> { - pub fn new(module: &'a Module, source_manager: Arc) -> Self { - let resolver = module.resolver(source_manager); - Self { module, resolver } + pub fn new( + module: &'a Module, + source_manager: Arc, + ) -> Result { + let resolver = module.resolver(source_manager)?; + Ok(Self { module, resolver }) } } @@ -726,16 +764,16 @@ impl TypeResolver for ModuleTypeResolver<'_> { &mut self, context: SourceSpan, _gid: GlobalItemIndex, - ) -> Result { + ) -> Result { Err(SymbolResolutionError::undefined(context, &self.resolver.source_manager())) } fn get_local_type( &mut self, context: SourceSpan, id: ItemIndex, - ) -> Result, SymbolResolutionError> { + ) -> Result, SymbolResolutionError> { match &self.module[id] { - super::Export::Type(ty) => match ty { + Export::Type(ty) => match ty { TypeDecl::Alias(ty) => self.resolve(&ty.ty), TypeDecl::Enum(ty) => Ok(Some(ty.ty().clone())), }, diff --git a/crates/assembly-syntax/src/ast/path/path.rs b/crates/assembly-syntax/src/ast/path/path.rs index f4a194865c..2eaf06a6fd 100644 --- a/crates/assembly-syntax/src/ast/path/path.rs +++ b/crates/assembly-syntax/src/ast/path/path.rs @@ -44,7 +44,7 @@ impl<'de> serde::Deserialize<'de> for &'de Path { impl<'de> Visitor<'de> for PathVisitor { type Value = &'de Path; - fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result { + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("a borrowed Path") } @@ -204,7 +204,7 @@ impl Path { /// /// Returns `None` if the path cannot be losslessly represented as a single component. pub fn as_ident(&self) -> Option { - let mut components = self.components().filter_map(|c| c.ok()); + let mut components = self.components().filter_map(Result::ok); match components.next()? { component @ PathComponent::Normal(_) => { if components.next().is_none() { @@ -326,7 +326,7 @@ impl Path { let mut components = self.components(); match components.next()?.ok()? { PathComponent::Root => { - let first = components.next().and_then(|c| c.ok()).map(|c| c.as_str())?; + let first = components.next().and_then(Result::ok).map(|c| c.as_str())?; Some((first, components.as_path())) }, first @ PathComponent::Normal(_) => Some((first.as_str(), components.as_path())), @@ -481,6 +481,9 @@ impl Path { pub fn canonicalize(&self) -> Result { let mut buf = PathBuf::with_capacity(self.byte_len()); buf.extend_with_components(self.components())?; + if buf.byte_len() > u16::MAX as usize { + return Err(PathError::TooLong { max: u16::MAX as usize }); + } Ok(buf) } } @@ -598,8 +601,8 @@ impl PartialEq> for Path { } } -impl PartialEq> for Path { - fn eq(&self, other: &alloc::borrow::Cow<'_, Path>) -> bool { +impl PartialEq> for Path { + fn eq(&self, other: &Cow<'_, Path>) -> bool { self.inner == other.as_ref().inner } } @@ -683,4 +686,23 @@ mod tests { assert_eq!(canonicalized.as_path(), expected); Ok(()) } + + #[test] + fn test_canonicalize_path_rejects_canonical_result_longer_than_u16_max() { + let component = alloc::format!("{}-", "a".repeat(254)); + let mut source = alloc::string::String::new(); + for i in 0..255 { + if i > 0 { + source.push_str("::"); + } + source.push_str(&component); + } + + let path = Path::validate(&source).expect("source path must be pre-canonicalization valid"); + let err = path.canonicalize().expect_err( + "canonicalization must reject paths that exceed the serialization length bound", + ); + + assert!(matches!(err, PathError::TooLong { max } if max == u16::MAX as usize)); + } } diff --git a/crates/assembly-syntax/src/ast/path/path_buf.rs b/crates/assembly-syntax/src/ast/path/path_buf.rs index f9250c27ae..7c0d759d4f 100644 --- a/crates/assembly-syntax/src/ast/path/path_buf.rs +++ b/crates/assembly-syntax/src/ast/path/path_buf.rs @@ -278,12 +278,50 @@ impl<'a> TryFrom<&'a str> for PathBuf { } } +fn is_canonical_path(path: &Path) -> bool { + let mut is_absolute = false; + let mut saw_normal_component = false; + + for component in path.components() { + let component = match component { + Ok(component) => component, + Err(_) => return false, + }; + + match component { + PathComponent::Root => is_absolute = true, + component @ PathComponent::Normal(_) => { + let is_quoted = component.is_quoted(); + let component = component.as_str(); + let is_special = matches!(component, Path::KERNEL_PATH | Path::EXEC_PATH); + let requires_quoting = !is_special && Ident::requires_quoting(component); + + if !saw_normal_component && !is_absolute && is_special { + return false; + } + + if requires_quoting != is_quoted { + return false; + } + + saw_normal_component = true; + }, + } + } + + true +} + impl TryFrom for PathBuf { type Error = PathError; fn try_from(value: String) -> Result { - Path::validate(&value)?; - Ok(PathBuf { inner: value }) + let path = Path::validate(&value)?; + if is_canonical_path(path) { + Ok(Self { inner: value }) + } else { + path.canonicalize() + } } } @@ -341,11 +379,10 @@ impl Deserializable for PathBuf { let path = source.read_slice(len)?; let path = str::from_utf8(path).map_err(|e| DeserializationError::InvalidValue(e.to_string()))?; - Path::validate(path).map_err(|e| DeserializationError::InvalidValue(e.to_string()))?; - // We deserialize like this due to our deserialization tests expecting round-trips to be - // identical to what was serialized, though ideally we'd like to canonicalize paths that - // were deserialized. We should probably change how these tests work in the future. - Ok(PathBuf { inner: path.to_string() }) + let path = + Path::validate(path).map_err(|e| DeserializationError::InvalidValue(e.to_string()))?; + path.canonicalize() + .map_err(|e| DeserializationError::InvalidValue(e.to_string())) } } @@ -372,7 +409,7 @@ impl<'de> serde::Deserialize<'de> for PathBuf { impl<'de> Visitor<'de> for PathVisitor { type Value = PathBuf; - fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result { + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("a valid Path/PathBuf") } @@ -380,24 +417,20 @@ impl<'de> serde::Deserialize<'de> for PathBuf { where E: serde::de::Error, { - Path::validate(v).map_err(serde::de::Error::custom)?; - // We deserialize like this due to our deserialization tests expecting round-trips - // to be identical to what was serialized, though ideally we'd like - // to canonicalize paths that were deserialized. We should probably - // change how these tests work in the future. - Ok(PathBuf { inner: v.to_string() }) + Path::validate(v) + .map_err(serde::de::Error::custom)? + .canonicalize() + .map_err(serde::de::Error::custom) } fn visit_string(self, v: String) -> Result where E: serde::de::Error, { - Path::validate(&v).map_err(serde::de::Error::custom)?; - // We deserialize like this due to our deserialization tests expecting round-trips - // to be identical to what was serialized, though ideally we'd like - // to canonicalize paths that were deserialized. We should probably - // change how these tests work in the future. - Ok(PathBuf { inner: v }) + Path::validate(&v) + .map_err(serde::de::Error::custom)? + .canonicalize() + .map_err(serde::de::Error::custom) } } @@ -417,6 +450,7 @@ impl fmt::Display for PathBuf { /// Tests #[cfg(test)] mod tests { + use alloc::string::String; use miden_core::assert_matches; @@ -448,7 +482,7 @@ mod tests { assert_eq!(path.components().count(), 3); assert_eq!(path.last(), Some("baz")); assert_eq!(path.first(), Some("foo")); - assert_eq!(path.parent().map(|p| p.as_str()), Some("foo::bar")); + assert_eq!(path.parent().map(Path::as_str), Some("foo::bar")); } #[test] @@ -476,7 +510,7 @@ mod tests { assert_eq!(path.components().count(), 3); assert_eq!(path.last(), Some("item")); assert_eq!(path.first(), Some("foo")); - assert_eq!(path.parent().map(|p| p.as_str()), Some("foo::\"miden::base/account@0.1.0\"")); + assert_eq!(path.parent().map(Path::as_str), Some("foo::\"miden::base/account@0.1.0\"")); } #[test] @@ -560,7 +594,7 @@ mod tests { parent.as_str(), "::\"root_ns:root@1.0.0\"::abi_transform_tx_kernel_get_inputs_4" ); - assert_eq!(parent.parent().map(|p| p.as_str()), Some("::\"root_ns:root@1.0.0\"")); + assert_eq!(parent.parent().map(Path::as_str), Some("::\"root_ns:root@1.0.0\"")); assert!(p2.is_absolute()); assert_eq!(p2.components().count(), 4); @@ -571,7 +605,29 @@ mod tests { parent.as_str(), "::\"root_ns:root@1.0.0\"::abi_transform_tx_kernel_get_inputs_4" ); - assert_eq!(parent.parent().map(|p| p.as_str()), Some("::\"root_ns:root@1.0.0\"")); + assert_eq!(parent.parent().map(Path::as_str), Some("::\"root_ns:root@1.0.0\"")); + } + + #[test] + fn try_from_string_canonicalizes_like_str() { + let from_str = PathBuf::try_from("foo::\"bar\"").unwrap(); + let from_string = PathBuf::try_from(String::from("foo::\"bar\"")).unwrap(); + + assert_eq!(from_string, from_str); + assert_eq!(from_string.as_str(), "foo::bar"); + } + + #[test] + fn try_from_string_reuses_canonical_allocation() { + let value = String::from("foo::bar"); + let original_ptr = value.as_ptr(); + let original_capacity = value.capacity(); + + let path = PathBuf::try_from(value).unwrap(); + + assert_eq!(path.as_str(), "foo::bar"); + assert_eq!(path.inner.as_ptr(), original_ptr); + assert_eq!(path.inner.capacity(), original_capacity); } #[test] @@ -615,4 +671,40 @@ mod tests { let result = Path::validate("#foo::bar"); assert_matches!(result, Err(PathError::InvalidComponent(IdentError::InvalidChars { .. }))); } + + #[cfg(feature = "serde")] + #[test] + fn serde_deserialize_path_buf_canonicalizes_redundant_quotes() { + let path: PathBuf = serde_json::from_str(r#""\"foo\"::\"bar\"""#) + .expect("path deserialization must succeed"); + assert_eq!(path.as_str(), "foo::bar"); + } + + #[cfg(feature = "serde")] + #[test] + fn serde_deserialize_path_buf_preserves_required_quotes() { + let path: PathBuf = serde_json::from_value(serde_json::Value::String(String::from( + "::foo::\"miden::base/account@0.1.0\"", + ))) + .expect("path deserialization must succeed"); + assert_eq!(path.as_str(), "::foo::\"miden::base/account@0.1.0\""); + } + + #[cfg(feature = "serde")] + #[test] + fn serde_deserialize_path_buf_rejects_overflow_after_canonicalization() { + let component = format!("{}-", "a".repeat(254)); + let mut source = String::new(); + for i in 0..255 { + if i > 0 { + source.push_str("::"); + } + source.push_str(&component); + } + + let err = serde_json::from_value::(serde_json::Value::String(source)) + .expect_err("deserialization must fail when canonicalization exceeds u16::MAX bytes"); + let message = format!("{err}"); + assert!(message.contains("too long"), "unexpected error: {message}"); + } } diff --git a/crates/assembly-syntax/src/ast/procedure/name.rs b/crates/assembly-syntax/src/ast/procedure/name.rs index ae02b0a4b8..4382bff4a9 100644 --- a/crates/assembly-syntax/src/ast/procedure/name.rs +++ b/crates/assembly-syntax/src/ast/procedure/name.rs @@ -339,7 +339,7 @@ impl From for miette::SourceSpan { } } -impl core::ops::Deref for ProcedureName { +impl Deref for ProcedureName { type Target = str; #[inline(always)] diff --git a/crates/assembly-syntax/src/ast/procedure/procedure.rs b/crates/assembly-syntax/src/ast/procedure/procedure.rs index deb9129084..a5ad76bff7 100644 --- a/crates/assembly-syntax/src/ast/procedure/procedure.rs +++ b/crates/assembly-syntax/src/ast/procedure/procedure.rs @@ -262,17 +262,13 @@ impl crate::prettier::PrettyPrint for Procedure { fn render(&self) -> crate::prettier::Document { use crate::prettier::*; - let mut doc = self - .docs - .as_ref() - .map(|docstring| docstring.render()) - .unwrap_or(Document::Empty); + let mut doc = self.docs.as_ref().map(PrettyPrint::render).unwrap_or(Document::Empty); if !self.attrs.is_empty() { doc += self .attrs .iter() - .map(|attr| attr.render()) + .map(PrettyPrint::render) .reduce(|acc, attr| acc + nl() + attr) .unwrap_or(Document::Empty); } diff --git a/crates/assembly-syntax/src/ast/tests.rs b/crates/assembly-syntax/src/ast/tests.rs index 2c509c603d..b2be34eb36 100644 --- a/crates/assembly-syntax/src/ast/tests.rs +++ b/crates/assembly-syntax/src/ast/tests.rs @@ -507,21 +507,41 @@ fn test_ast_parsing_program_push() -> Result<(), Report> { inst!(Push(Immediate::Value(Span::unknown(10u8.into())))), inst!(Push(Immediate::Value(Span::unknown(500u16.into())))), inst!(Push(Immediate::Value(Span::unknown(70000u32.into())))), - inst!(Push(Immediate::Value(Span::unknown(Felt::new(5000000000_u64).into())))), - inst!(Push(Immediate::Value(Span::unknown(Felt::new(5000000000_u64).into())))), - inst!(Push(Immediate::Value(Span::unknown(Felt::new(7000000000_u64).into())))), - inst!(Push(Immediate::Value(Span::unknown(Felt::new(9000000000_u64).into())))), - inst!(Push(Immediate::Value(Span::unknown(Felt::new(11000000000_u64).into())))), + inst!(Push(Immediate::Value(Span::unknown( + Felt::new_unchecked(5000000000_u64).into() + )))), + inst!(Push(Immediate::Value(Span::unknown( + Felt::new_unchecked(5000000000_u64).into() + )))), + inst!(Push(Immediate::Value(Span::unknown( + Felt::new_unchecked(7000000000_u64).into() + )))), + inst!(Push(Immediate::Value(Span::unknown( + Felt::new_unchecked(9000000000_u64).into() + )))), + inst!(Push(Immediate::Value(Span::unknown( + Felt::new_unchecked(11000000000_u64).into() + )))), inst!(Push(Immediate::Value(Span::unknown(5u8.into())))), inst!(Push(Immediate::Value(Span::unknown(7u8.into())))), inst!(Push(Immediate::Value(Span::unknown(500u16.into())))), inst!(Push(Immediate::Value(Span::unknown(700u16.into())))), inst!(Push(Immediate::Value(Span::unknown(70000u32.into())))), inst!(Push(Immediate::Value(Span::unknown(90000u32.into())))), - inst!(Push(Immediate::Value(Span::unknown(Felt::new(5000000000_u64).into())))), - inst!(Push(Immediate::Value(Span::unknown(Felt::new(7000000000_u64).into())))), inst!(Push(Immediate::Value(Span::unknown( - WordValue([Felt::new(0), Felt::new(1), Felt::new(2), Felt::new(3)]).into() + Felt::new_unchecked(5000000000_u64).into() + )))), + inst!(Push(Immediate::Value(Span::unknown( + Felt::new_unchecked(7000000000_u64).into() + )))), + inst!(Push(Immediate::Value(Span::unknown( + WordValue([ + Felt::new_unchecked(0), + Felt::new_unchecked(1), + Felt::new_unchecked(2), + Felt::new_unchecked(3) + ]) + .into() )))) )); @@ -631,8 +651,8 @@ fn test_ast_parsing_module() -> Result<(), Report> { #[test] fn test_ast_parsing_adv_ops() -> Result<(), Report> { let context = SyntaxTestContext::new(); - let source = source_file!(&context, "begin adv_push.1 adv_loadw end"); - let forms = module!(begin!(inst!(AdvPush(1u8.into())), inst!(AdvLoadW))); + let source = source_file!(&context, "begin adv_push adv_pushw adv_loadw end"); + let forms = module!(begin!(inst!(AdvPush), inst!(AdvPushW), inst!(AdvLoadW))); assert_eq!(context.parse_forms(source)?, forms); Ok(()) } diff --git a/crates/assembly-syntax/src/ast/type.rs b/crates/assembly-syntax/src/ast/type.rs index 9c7e149f5e..376431776c 100644 --- a/crates/assembly-syntax/src/ast/type.rs +++ b/crates/assembly-syntax/src/ast/type.rs @@ -188,7 +188,7 @@ impl crate::prettier::PrettyPrint for FunctionType { let singleline_args = self .args .iter() - .map(|arg| arg.render()) + .map(PrettyPrint::render) .reduce(|acc, arg| acc + const_text(", ") + arg) .unwrap_or(Document::Empty); let multiline_args = indent( @@ -196,7 +196,7 @@ impl crate::prettier::PrettyPrint for FunctionType { nl() + self .args .iter() - .map(|arg| arg.render()) + .map(PrettyPrint::render) .reduce(|acc, arg| acc + const_text(",") + nl() + arg) .unwrap_or(Document::Empty), ) + nl(); @@ -210,7 +210,7 @@ impl crate::prettier::PrettyPrint for FunctionType { let results = self .results .iter() - .map(|r| r.render()) + .map(PrettyPrint::render) .reduce(|acc, r| acc + const_text(", ") + r) .unwrap_or(Document::Empty); args + const_text(" -> ") + const_text("(") + results + const_text(")") @@ -353,11 +353,11 @@ impl TypeExpr { TypeExpr::Array(t) => Ok(t .elem .resolve_type_with_depth(resolver, depth + 1)? - .map(|elem| types::Type::Array(Arc::new(types::ArrayType::new(elem, t.arity))))), + .map(|elem| Type::Array(Arc::new(types::ArrayType::new(elem, t.arity))))), TypeExpr::Ptr(ty) => Ok(ty .pointee .resolve_type_with_depth(resolver, depth + 1)? - .map(|pointee| types::Type::Ptr(Arc::new(types::PointerType::new(pointee))))), + .map(|pointee| Type::Ptr(Arc::new(types::PointerType::new(pointee))))), TypeExpr::Struct(t) => { let mut fields = Vec::with_capacity(t.fields.len()); for field in t.fields.iter() { @@ -369,7 +369,7 @@ impl TypeExpr { } } Ok(Some(Type::Struct(Arc::new(types::StructType::from_parts( - t.name.clone().map(|id| id.into_inner()), + t.name.clone().map(Ident::into_inner), t.repr.into_inner(), fields, ))))) @@ -513,7 +513,7 @@ impl crate::prettier::PrettyPrint for PointerType { let doc = const_text("ptr<") + self.pointee.render(); if let Some(addrspace) = self.addrspace.as_ref() { - doc + const_text(", ") + text(format!("addrspace({})", addrspace)) + const_text(">") + doc + const_text(", ") + text(format!("addrspace({addrspace})")) + const_text(">") } else { doc + const_text(">") } @@ -653,7 +653,7 @@ impl crate::prettier::PrettyPrint for StructType { let singleline_body = self .fields .iter() - .map(|field| field.render()) + .map(PrettyPrint::render) .reduce(|acc, field| acc + const_text(", ") + field) .unwrap_or(Document::Empty); let multiline_body = indent( @@ -661,7 +661,7 @@ impl crate::prettier::PrettyPrint for StructType { nl() + self .fields .iter() - .map(|field| field.render()) + .map(PrettyPrint::render) .reduce(|acc, field| acc + const_text(",") + nl() + field) .unwrap_or(Document::Empty), ) + nl(); @@ -810,11 +810,7 @@ impl crate::prettier::PrettyPrint for TypeAlias { fn render(&self) -> crate::prettier::Document { use crate::prettier::*; - let mut doc = self - .docs - .as_ref() - .map(|docstring| docstring.render()) - .unwrap_or(Document::Empty); + let mut doc = self.docs.as_ref().map(PrettyPrint::render).unwrap_or(Document::Empty); if self.visibility.is_public() { doc += display(self.visibility) + const_text(" "); @@ -993,16 +989,12 @@ impl crate::prettier::PrettyPrint for EnumType { fn render(&self) -> crate::prettier::Document { use crate::prettier::*; - let mut doc = self - .docs - .as_ref() - .map(|docstring| docstring.render()) - .unwrap_or(Document::Empty); + let mut doc = self.docs.as_ref().map(PrettyPrint::render).unwrap_or(Document::Empty); let variants = self .variants .iter() - .map(|v| v.render()) + .map(PrettyPrint::render) .reduce(|acc, v| acc + const_text(",") + nl() + v) .unwrap_or(Document::Empty); @@ -1172,11 +1164,7 @@ impl crate::prettier::PrettyPrint for Variant { fn render(&self) -> crate::prettier::Document { use crate::prettier::*; - let doc = self - .docs - .as_ref() - .map(|docstring| docstring.render()) - .unwrap_or(Document::Empty); + let doc = self.docs.as_ref().map(PrettyPrint::render).unwrap_or(Document::Empty); let name = display(&self.name); let name_and_payload = if let Some(value_ty) = self.value_ty.as_ref() { diff --git a/crates/assembly-syntax/src/ast/visit.rs b/crates/assembly-syntax/src/ast/visit.rs index f52543f07f..f404258172 100644 --- a/crates/assembly-syntax/src/ast/visit.rs +++ b/crates/assembly-syntax/src/ast/visit.rs @@ -303,6 +303,11 @@ pub fn visit_procedure(visitor: &mut V, procedure: &Procedure) -> ControlF where V: ?Sized + Visit, { + if let Some(signature) = procedure.signature() { + for ty in signature.args.iter().chain(signature.results.iter()) { + visitor.visit_type_expr(ty)?; + } + } visitor.visit_block(procedure.body()) } @@ -443,7 +448,7 @@ where use Instruction::*; let span = inst.span(); match &**inst { - U32ShrImm(imm) | U32ShlImm(imm) | U32RotrImm(imm) | U32RotlImm(imm) | AdvPush(imm) => { + U32ShrImm(imm) | U32ShlImm(imm) | U32RotrImm(imm) | U32RotlImm(imm) => { visitor.visit_immediate_u8(imm) }, Locaddr(imm) | LocLoad(imm) | LocLoadWBe(imm) | LocLoadWLe(imm) | LocStore(imm) @@ -503,11 +508,10 @@ where | MovDn10 | MovDn11 | MovDn12 | MovDn13 | MovDn14 | MovDn15 | MovDnW2 | MovDnW3 | Reversew | Reversedw | CSwap | CSwapW | CDrop | CDropW | PushFeltList(_) | Sdepth | Caller | Clk | MemLoad | MemLoadWBe | MemLoadWLe | MemStore | MemStoreWBe - | MemStoreWLe | MemStream | AdvPipe | AdvLoadW | Hash | HMerge | HPerm | MTreeGet - | MTreeSet | MTreeMerge | MTreeVerify | FriExt2Fold4 | DynExec | DynCall | DebugVar(_) - | HornerBase | HornerExt | CryptoStream | EvalCircuit | LogPrecompile | Emit => { - ControlFlow::Continue(()) - }, + | MemStoreWLe | MemStream | AdvPipe | AdvPush | AdvPushW | AdvLoadW | Hash | HMerge + | HPerm | MTreeGet | MTreeSet | MTreeMerge | MTreeVerify | FriExt2Fold4 | DynExec + | DynCall | DebugVar(_) | HornerBase | HornerExt | CryptoStream | EvalCircuit + | LogPrecompile | Emit => ControlFlow::Continue(()), } } @@ -895,6 +899,11 @@ pub fn visit_mut_procedure(visitor: &mut V, procedure: &mut Procedure) -> where V: ?Sized + VisitMut, { + if let Some(signature) = procedure.signature_mut() { + for ty in signature.args.iter_mut().chain(signature.results.iter_mut()) { + visitor.visit_mut_type_expr(ty)?; + } + } visitor.visit_mut_block(procedure.body_mut()) } @@ -1039,7 +1048,7 @@ where use Instruction::*; let span = inst.span(); match &mut **inst { - U32ShrImm(imm) | U32ShlImm(imm) | U32RotrImm(imm) | U32RotlImm(imm) | AdvPush(imm) => { + U32ShrImm(imm) | U32ShlImm(imm) | U32RotrImm(imm) | U32RotlImm(imm) => { visitor.visit_mut_immediate_u8(imm) }, Locaddr(imm) | LocLoad(imm) | LocLoadWBe(imm) | LocLoadWLe(imm) | LocStore(imm) @@ -1099,11 +1108,10 @@ where | MovDn10 | MovDn11 | MovDn12 | MovDn13 | MovDn14 | MovDn15 | MovDnW2 | MovDnW3 | Reversew | Reversedw | CSwap | CSwapW | CDrop | CDropW | PushFeltList(_) | Sdepth | Caller | Clk | MemLoad | MemLoadWBe | MemLoadWLe | MemStore | MemStoreWBe - | MemStoreWLe | MemStream | AdvPipe | AdvLoadW | Hash | HMerge | HPerm | MTreeGet - | MTreeSet | MTreeMerge | MTreeVerify | FriExt2Fold4 | DynExec | DynCall | DebugVar(_) - | HornerBase | HornerExt | EvalCircuit | CryptoStream | LogPrecompile | Emit => { - ControlFlow::Continue(()) - }, + | MemStoreWLe | MemStream | AdvPipe | AdvPush | AdvPushW | AdvLoadW | Hash | HMerge + | HPerm | MTreeGet | MTreeSet | MTreeMerge | MTreeVerify | FriExt2Fold4 | DynExec + | DynCall | DebugVar(_) | HornerBase | HornerExt | EvalCircuit | CryptoStream + | LogPrecompile | Emit => ControlFlow::Continue(()), } } diff --git a/crates/assembly-syntax/src/lib.rs b/crates/assembly-syntax/src/lib.rs index 89da1ea576..103d7616ba 100644 --- a/crates/assembly-syntax/src/lib.rs +++ b/crates/assembly-syntax/src/lib.rs @@ -40,4 +40,4 @@ pub use self::{ pub const MAX_REPEAT_COUNT: u32 = 1_000_000; /// The modulus of the Miden field as a raw u64 integer -pub(crate) const FIELD_MODULUS: u64 = miden_core::Felt::ORDER_U64; +pub(crate) const FIELD_MODULUS: u64 = Felt::ORDER_U64; diff --git a/crates/assembly-syntax/src/library/mod.rs b/crates/assembly-syntax/src/library/mod.rs index 776e1a52a2..8e2787fb8b 100644 --- a/crates/assembly-syntax/src/library/mod.rs +++ b/crates/assembly-syntax/src/library/mod.rs @@ -3,9 +3,11 @@ use alloc::{collections::BTreeMap, string::String, sync::Arc, vec::Vec}; use miden_core::{ Word, advice::AdviceMap, - mast::{MastForest, MastNodeExt, MastNodeId}, + mast::{MastForest, MastNodeExt, MastNodeId, UntrustedMastForest}, program::Kernel, - serde::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable}, + serde::{ + ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable, SliceReader, + }, }; use midenc_hir_type::{FunctionType, Type}; #[cfg(feature = "arbitrary")] @@ -13,7 +15,11 @@ use proptest::prelude::*; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; -use crate::ast::{AttributeSet, Ident, Path, PathBuf, ProcedureName}; +#[cfg(feature = "arbitrary")] +use crate::ast::QualifiedProcedureName; +#[cfg(feature = "serde")] +use crate::ast::path; +use crate::ast::{AttributeSet, ConstantValue, Ident, Path, PathBuf, PathComponent, ProcedureName}; mod error; mod module; @@ -103,7 +109,7 @@ pub struct ProcedureExport { /// The id of the MAST root node of the exported procedure pub node: MastNodeId, /// The fully-qualified path of the exported procedure - #[cfg_attr(feature = "serde", serde(with = "crate::ast::path"))] + #[cfg_attr(feature = "serde", serde(with = "path"))] pub path: Arc, /// The type signature of the exported procedure, if known #[cfg_attr(feature = "serde", serde(default))] @@ -163,7 +169,7 @@ impl Arbitrary for ProcedureExport { })); let nid = any::(); - let name = any::(); + let name = any::(); (nid, name, signature) .prop_map(|(nodeid, procname, signature)| Self { node: nodeid, @@ -179,18 +185,27 @@ impl Arbitrary for ProcedureExport { #[derive(Debug, Clone, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[cfg_attr(feature = "arbitrary", derive(proptest_derive::Arbitrary))] #[cfg_attr(all(feature = "arbitrary", test), miden_test_serde_macros::serde_test)] pub struct ConstantExport { /// The fully-qualified path of the exported constant - #[cfg_attr(feature = "serde", serde(with = "crate::ast::path"))] - #[cfg_attr( - feature = "arbitrary", - proptest(strategy = "crate::arbitrary::path::constant_path_random_length(1)") - )] + #[cfg_attr(feature = "serde", serde(with = "path"))] pub path: Arc, /// The constant-folded AST representing the value of this constant - pub value: crate::ast::ConstantValue, + pub value: ConstantValue, +} + +#[cfg(feature = "arbitrary")] +impl Arbitrary for ConstantExport { + type Parameters = (); + + fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { + let path = crate::arbitrary::path::constant_path_random_length(1); + let value = any::(); + + (path, value).prop_map(|(path, value)| Self { path, value }).boxed() + } + + type Strategy = BoxedStrategy; } #[derive(Debug, Clone, PartialEq, Eq)] @@ -198,10 +213,10 @@ pub struct ConstantExport { #[cfg_attr(all(feature = "arbitrary", test), miden_test_serde_macros::serde_test)] pub struct TypeExport { /// The fully-qualified path of the exported type declaration - #[cfg_attr(feature = "serde", serde(with = "crate::ast::path"))] + #[cfg_attr(feature = "serde", serde(with = "path"))] pub path: Arc, /// The type bound to `name` - pub ty: crate::ast::types::Type, + pub ty: Type, } #[cfg(feature = "arbitrary")] @@ -211,7 +226,7 @@ impl Arbitrary for TypeExport { fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { use proptest::strategy::{Just, Strategy}; let path = crate::arbitrary::path::user_defined_type_path_random_length(1); - let ty = Just(crate::ast::types::Type::Felt); + let ty = Just(Type::Felt); (path, ty).prop_map(|(path, ty)| Self { path, ty }).boxed() } @@ -227,7 +242,10 @@ impl Arbitrary for TypeExport { /// A library exports a set of one or more procedures. Currently, all exported procedures belong /// to the same top-level namespace. #[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(all(feature = "arbitrary", test), miden_test_serde_macros::serde_test)] +#[cfg_attr( + all(feature = "arbitrary", test), + miden_test_serde_macros::serde_test(binary_serde(true)) +)] pub struct Library { /// The content hash of this library, formed by hashing the roots of all exports in /// lexicographical order (by digest, not procedure name) @@ -303,6 +321,103 @@ impl Library { let mast_forest = Arc::make_mut(&mut self.mast_forest); mast_forest.advice_map_mut().extend(advice_map); } + + fn read_mast_forest( + source: &mut R, + validate_mast_forest: bool, + ) -> Result, DeserializationError> { + let mast_forest = if validate_mast_forest { + UntrustedMastForest::read_from(source)?.validate().map_err(|err| { + DeserializationError::InvalidValue(format!( + "library contains an invalid untrusted MAST forest: {err}" + )) + })? + } else { + MastForest::read_from(source)? + }; + + Ok(Arc::new(mast_forest)) + } + + fn read_from_with_mast_forest( + source: &mut R, + mast_forest: Arc, + ) -> Result { + let num_exports = source.read_usize()?; + if num_exports == 0 { + return Err(DeserializationError::InvalidValue(String::from("No exported procedures"))); + }; + let mut exports = BTreeMap::new(); + for _ in 0..num_exports { + let tag = source.read_u8()?; + let path: PathBuf = source.read()?; + let path = Arc::::from(path.into_boxed_path()); + let export = match tag { + 0 => { + let node = MastNodeId::from_u32_safe(source.read_u32()?, &mast_forest)?; + let signature = if source.read_bool()? { + Some(FunctionType::read_from(source)?) + } else { + None + }; + let attributes = AttributeSet::read_from(source)?; + LibraryExport::Procedure(ProcedureExport { + node, + path: path.clone(), + signature, + attributes, + }) + }, + 1 => { + let value = ConstantValue::read_from(source)?; + LibraryExport::Constant(ConstantExport { path: path.clone(), value }) + }, + 2 => { + let ty = Type::read_from(source)?; + LibraryExport::Type(TypeExport { path: path.clone(), ty }) + }, + invalid => { + return Err(DeserializationError::InvalidValue(format!( + "unknown LibraryExport tag: '{invalid}'" + ))); + }, + }; + let (path, export) = normalize_export_for_deserialization(export) + .map_err(DeserializationError::InvalidValue)?; + if exports.insert(path.clone(), export).is_some() { + return Err(DeserializationError::InvalidValue(format!( + "duplicate canonical export path in library artifact: '{path}'" + ))); + } + } + + Self::new(mast_forest, exports) + .map_err(|err| DeserializationError::InvalidValue(format!("{err}"))) + } + + /// Reads a library from `source` without validating the embedded MAST forest. + /// + /// This is only correct when serialization and deserialization happen within the same trust + /// domain. A typical use case is reloading bytes that were already validated before being + /// persisted to local storage controlled by the same trusted system. + /// + /// Do not use this for inbound artifact processing across a trust boundary, including bytes + /// received over the network or from another party. Authenticating the outer byte stream does + /// not prove that embedded MAST node digests are semantically valid. + pub fn read_from_unchecked( + source: &mut R, + ) -> Result { + let mast_forest = Self::read_mast_forest(source, false)?; + Self::read_from_with_mast_forest(source, mast_forest) + } + + /// Reads a library from `bytes` without validating the embedded MAST forest. + /// + /// See [`Library::read_from_unchecked`]. + pub fn read_from_bytes_unchecked(bytes: &[u8]) -> Result { + let mut source = SliceReader::new(bytes); + Self::read_from_unchecked(&mut source) + } } // ------------------------------------------------------------------------------------------------ @@ -358,6 +473,15 @@ impl Library { let export = self.exports.get(path.as_ref()).and_then(LibraryExport::as_procedure); export.map(|e| self.mast_forest()[e.node].digest()) } + + /// Returns the exact procedure node for the specified path, if it is present. + pub fn get_procedure_node_by_path(&self, path: impl AsRef) -> Option { + let path = path.as_ref().to_absolute(); + self.exports + .get(path.as_ref()) + .and_then(LibraryExport::as_procedure) + .map(|export| export.node) + } } /// Conversions @@ -376,11 +500,13 @@ impl Library { LibraryExport::Procedure(ProcedureExport { node, path, signature, attributes }) => { let proc_digest = self.mast_forest[*node].digest(); let name = path.last().unwrap(); - module.add_procedure( + module.add_procedure_with_provenance( ProcedureName::new(name).expect("valid procedure name"), proc_digest, signature.clone().map(Arc::new), attributes.clone(), + Some(*node), + Some(self.mast_forest.commitment()), ); }, LibraryExport::Constant(ConstantExport { path, value }) => { @@ -423,12 +549,9 @@ impl Library { self.write_into(&mut file); Ok(()) }) - .map_err(|p| { - match p.downcast::() { - // SAFETY: It is guaranteed safe to read Box - Ok(err) => unsafe { core::ptr::read(&*err) }, - Err(err) => std::panic::resume_unwind(err), - } + .map_err(|p| match p.downcast::() { + Ok(err) => *err, + Err(err) => std::panic::resume_unwind(err), })? } @@ -471,7 +594,7 @@ pub struct KernelLibrary { } #[cfg(feature = "serde")] -impl serde::Serialize for KernelLibrary { +impl Serialize for KernelLibrary { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, @@ -488,6 +611,14 @@ impl AsRef for KernelLibrary { } impl KernelLibrary { + fn try_from_library(library: Library) -> Result { + Self::try_from(Arc::new(library)).map_err(|err| { + DeserializationError::InvalidValue(format!( + "Failed to deserialize kernel library: {err}" + )) + }) + } + /// Returns the [Kernel] for this kernel library. pub fn kernel(&self) -> &Kernel { &self.kernel @@ -502,6 +633,30 @@ impl KernelLibrary { pub fn into_parts(self) -> (Kernel, ModuleInfo, Arc) { (self.kernel, self.kernel_info, self.library.mast_forest().clone()) } + + /// Reads a kernel library from `source` without validating the embedded MAST forest. + /// + /// This is only correct when serialization and deserialization happen within the same trust + /// domain. A typical use case is reloading bytes that were already validated before being + /// persisted to local storage controlled by the same trusted system. + /// + /// Do not use this for inbound artifact processing across a trust boundary, including bytes + /// received over the network or from another party. Authenticating the outer byte stream does + /// not prove that embedded MAST node digests are semantically valid. + pub fn read_from_unchecked( + source: &mut R, + ) -> Result { + let library = Library::read_from_unchecked(source)?; + Self::try_from_library(library) + } + + /// Reads a kernel library from `bytes` without validating the embedded MAST forest. + /// + /// See [`KernelLibrary::read_from_unchecked`]. + pub fn read_from_bytes_unchecked(bytes: &[u8]) -> Result { + let mut source = SliceReader::new(bytes); + Self::read_from_unchecked(&mut source) + } } impl TryFrom> for KernelLibrary { @@ -525,12 +680,14 @@ impl TryFrom> for KernelLibrary { let proc_digest = library.mast_forest[export.node].digest(); proc_digests.push(proc_digest); - kernel_module.add_procedure( + kernel_module.add_procedure_with_provenance( ProcedureName::new(export.path.last().unwrap()) .expect("valid procedure name"), proc_digest, export.signature.clone().map(Arc::new), export.attributes.clone(), + Some(export.node), + Some(library.mast_forest.commitment()), ); }, LibraryExport::Constant(export) => { @@ -577,6 +734,54 @@ impl KernelLibrary { // LIBRARY SERIALIZATION // ================================================================================================ +fn export_raw_leaf(path: &Path) -> Result<&str, String> { + match path.components().next_back() { + Some(Ok(PathComponent::Normal(leaf))) => Ok(leaf), + Some(Err(err)) => Err(format!("invalid export path '{path}': {err}")), + Some(Ok(PathComponent::Root)) | None => { + Err(format!("invalid export path (missing export leaf): '{path}'")) + }, + } +} + +fn canonicalize_export_path(path: &Path) -> Result, String> { + let canonical = path + .to_path_buf() + .canonicalize() + .map_err(|err| format!("invalid export path '{path}': {err}"))?; + Ok(Arc::::from(canonical.into_boxed_path())) +} + +fn normalize_export_for_deserialization( + mut export: LibraryExport, +) -> Result<(Arc, LibraryExport), String> { + let canonical_path = canonicalize_export_path(export.path().as_ref())?; + let leaf = export_raw_leaf(canonical_path.as_ref())?; + + match &export { + LibraryExport::Procedure(_) => { + ProcedureName::new(leaf).map_err(|err| { + format!( + "invalid procedure export leaf name '{leaf}' in path '{canonical_path}': {err}" + ) + })?; + }, + LibraryExport::Constant(_) | LibraryExport::Type(_) => { + Ident::new(leaf).map_err(|err| { + format!("invalid export leaf name '{leaf}' in path '{canonical_path}': {err}") + })?; + }, + } + + match &mut export { + LibraryExport::Procedure(export) => export.path = canonical_path.clone(), + LibraryExport::Constant(export) => export.path = canonical_path.clone(), + LibraryExport::Type(export) => export.path = canonical_path.clone(), + } + + Ok((canonical_path, export)) +} + /// NOTE: Serialization of libraries is likely to be deprecated in a future release impl Serializable for Library { fn write_into(&self, target: &mut W) { @@ -594,62 +799,13 @@ impl Serializable for Library { /// NOTE: Serialization of libraries is likely to be deprecated in a future release impl Deserializable for Library { fn read_from(source: &mut R) -> Result { - let mast_forest = Arc::new(MastForest::read_from(source)?); - - let num_exports = source.read_usize()?; - if num_exports == 0 { - return Err(DeserializationError::InvalidValue(String::from("No exported procedures"))); - }; - let mut exports = BTreeMap::new(); - for _ in 0..num_exports { - let tag = source.read_u8()?; - let path: PathBuf = source.read()?; - let path = Arc::::from(path.into_boxed_path()); - let export = match tag { - 0 => { - let node = MastNodeId::from_u32_safe(source.read_u32()?, &mast_forest)?; - let signature = if source.read_bool()? { - Some(FunctionType::read_from(source)?) - } else { - None - }; - let attributes = AttributeSet::read_from(source)?; - LibraryExport::Procedure(ProcedureExport { - node, - path: path.clone(), - signature, - attributes, - }) - }, - 1 => { - let value = crate::ast::ConstantValue::read_from(source)?; - LibraryExport::Constant(ConstantExport { path: path.clone(), value }) - }, - 2 => { - let ty = Type::read_from(source)?; - LibraryExport::Type(TypeExport { path: path.clone(), ty }) - }, - invalid => { - return Err(DeserializationError::InvalidValue(format!( - "unknown LibraryExport tag: '{invalid}'" - ))); - }, - }; - exports.insert(path, export); - } - - let digest = - mast_forest.compute_nodes_commitment(exports.values().filter_map(|e| match e { - LibraryExport::Procedure(e) => Some(&e.node), - LibraryExport::Constant(_) | LibraryExport::Type(_) => None, - })); - - Ok(Self { digest, exports, mast_forest }) + let mast_forest = Self::read_mast_forest(source, true)?; + Self::read_from_with_mast_forest(source, mast_forest) } } #[cfg(feature = "serde")] -impl serde::Serialize for Library { +impl Serialize for Library { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, @@ -657,7 +813,7 @@ impl serde::Serialize for Library { use serde::ser::SerializeStruct; struct LibraryExports<'a>(&'a BTreeMap, LibraryExport>); - impl serde::Serialize for LibraryExports<'_> { + impl Serialize for LibraryExports<'_> { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, @@ -681,7 +837,7 @@ impl serde::Serialize for Library { } #[cfg(feature = "serde")] -impl<'de> serde::Deserialize<'de> for Library { +impl<'de> Deserialize<'de> for Library { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, @@ -697,6 +853,28 @@ impl<'de> serde::Deserialize<'de> for Library { struct LibraryVisitor; + impl LibraryVisitor { + fn normalize_exports( + items: Vec, + ) -> Result, LibraryExport>, E> + where + E: serde::de::Error, + { + let mut exports = BTreeMap::new(); + for export in items { + let (path, export) = normalize_export_for_deserialization(export) + .map_err(serde::de::Error::custom)?; + if exports.insert(path.clone(), export).is_some() { + return Err(serde::de::Error::custom(format!( + "duplicate canonical export path in library artifact: '{path}'" + ))); + } + } + + Ok(exports) + } + } + impl<'de> Visitor<'de> for LibraryVisitor { type Value = Library; @@ -711,10 +889,10 @@ impl<'de> serde::Deserialize<'de> for Library { let mast_forest = seq .next_element()? .ok_or_else(|| serde::de::Error::invalid_length(0, &self))?; - let exports: Vec = seq + let export_items: Vec = seq .next_element()? .ok_or_else(|| serde::de::Error::invalid_length(1, &self))?; - let exports = exports.into_iter().map(|export| (export.path(), export)).collect(); + let exports = Self::normalize_exports(export_items)?; Library::new(mast_forest, exports).map_err(serde::de::Error::custom) } @@ -737,9 +915,7 @@ impl<'de> serde::Deserialize<'de> for Library { return Err(serde::de::Error::duplicate_field("exports")); } let items: Vec = map.next_value()?; - exports = Some( - items.into_iter().map(|export| (export.path(), export)).collect(), - ); + exports = Some(Self::normalize_exports(items)?); }, } } @@ -766,13 +942,8 @@ impl Serializable for KernelLibrary { /// NOTE: Serialization of libraries is likely to be deprecated in a future release impl Deserializable for KernelLibrary { fn read_from(source: &mut R) -> Result { - let library = Arc::new(Library::read_from(source)?); - - Self::try_from(library).map_err(|err| { - DeserializationError::InvalidValue(format!( - "Failed to deserialize kernel library: {err}" - )) - }) + let library = Library::read_from(source)?; + Self::try_from_library(library) } } @@ -812,7 +983,7 @@ impl Serializable for LibraryExport { } #[cfg(feature = "arbitrary")] -impl proptest::prelude::Arbitrary for Library { +impl Arbitrary for Library { type Parameters = (); fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { @@ -888,5 +1059,113 @@ impl proptest::prelude::Arbitrary for Library { .boxed() } - type Strategy = proptest::prelude::BoxedStrategy; + type Strategy = BoxedStrategy; +} + +#[cfg(test)] +mod tests { + #[cfg(feature = "serde")] + use super::*; + + #[cfg(feature = "serde")] + #[test] + fn serde_library_deserialization_rejects_duplicate_canonical_export_paths() { + let quoted = Arc::::from(Path::validate(r#"::foo::"bar""#).unwrap()); + let unquoted = Arc::::from(Path::validate("::foo::bar").unwrap()); + + let mut exports = BTreeMap::new(); + exports.insert( + quoted.clone(), + LibraryExport::Type(TypeExport { path: quoted, ty: Type::Felt }), + ); + exports.insert( + unquoted.clone(), + LibraryExport::Type(TypeExport { path: unquoted, ty: Type::Felt }), + ); + + let lib = + Library::new(Arc::new(MastForest::new()), exports).expect("library must validate"); + let json = serde_json::to_string(&lib).expect("library serialization must succeed"); + + let err = serde_json::from_str::(&json).expect_err( + "expected duplicate canonical export paths to be rejected during serde deserialization", + ); + let message = alloc::format!("{err}"); + assert!( + message.contains("duplicate canonical export path in library artifact"), + "unexpected error: {err}" + ); + } + + #[cfg(feature = "serde")] + #[test] + fn serde_library_deserialization_rejects_malformed_quoted_procedure_leaf() { + use miden_core::{ + mast::{BasicBlockNodeBuilder, MastForestContributor}, + operations::Operation, + }; + + let mut mast_forest = MastForest::new(); + let node = BasicBlockNodeBuilder::new(vec![Operation::Add], Vec::new()) + .add_to_forest(&mut mast_forest) + .expect("must create MAST node"); + mast_forest.make_root(node); + + let bad = Arc::::from(Path::validate(r#"::foo::"bad name""#).unwrap()); + let mut exports = BTreeMap::new(); + exports.insert(bad.clone(), LibraryExport::Procedure(ProcedureExport::new(node, bad))); + + let lib = Library::new(Arc::new(mast_forest), exports).expect("library must validate"); + let json = serde_json::to_string(&lib).expect("library serialization must succeed"); + + let err = serde_json::from_str::(&json) + .expect_err("expected malformed procedure export leaf name rejection during serde"); + let message = alloc::format!("{err}"); + assert!( + message.contains("invalid procedure export leaf name"), + "unexpected error: {err}" + ); + } + + #[cfg(feature = "serde")] + #[test] + fn serde_library_deserialization_rejects_malformed_quoted_constant_leaf() { + let bad = Arc::::from(Path::validate(r#"::foo::"bad name""#).unwrap()); + let mut exports = BTreeMap::new(); + exports.insert( + bad.clone(), + LibraryExport::Constant(ConstantExport { + path: bad, + value: ConstantValue::Int(miden_debug_types::Span::unknown( + crate::parser::IntValue::from(1u8), + )), + }), + ); + + let lib = + Library::new(Arc::new(MastForest::new()), exports).expect("library must validate"); + let json = serde_json::to_string(&lib).expect("library serialization must succeed"); + + let err = serde_json::from_str::(&json) + .expect_err("expected malformed constant export leaf name rejection during serde"); + let message = alloc::format!("{err}"); + assert!(message.contains("invalid export leaf name"), "unexpected error: {err}"); + } + + #[cfg(feature = "serde")] + #[test] + fn serde_library_deserialization_rejects_malformed_quoted_type_leaf() { + let bad = Arc::::from(Path::validate(r#"::foo::"bad name""#).unwrap()); + let mut exports = BTreeMap::new(); + exports.insert(bad.clone(), LibraryExport::Type(TypeExport { path: bad, ty: Type::Felt })); + + let lib = + Library::new(Arc::new(MastForest::new()), exports).expect("library must validate"); + let json = serde_json::to_string(&lib).expect("library serialization must succeed"); + + let err = serde_json::from_str::(&json) + .expect_err("expected malformed type export leaf name rejection during serde"); + let message = alloc::format!("{err}"); + assert!(message.contains("invalid export leaf name"), "unexpected error: {err}"); + } } diff --git a/crates/assembly-syntax/src/library/module.rs b/crates/assembly-syntax/src/library/module.rs index 3311132eb2..52af8a825f 100644 --- a/crates/assembly-syntax/src/library/module.rs +++ b/crates/assembly-syntax/src/library/module.rs @@ -1,6 +1,7 @@ use alloc::{sync::Arc, vec::Vec}; use core::ops::Index; +use miden_core::mast::MastNodeId; use midenc_hir_type::FunctionType; use crate::{ @@ -21,6 +22,10 @@ pub struct ModuleInfo { } impl ModuleInfo { + pub(crate) fn raw_items(&self) -> &[ItemInfo] { + &self.items + } + /// Returns a new [`ModuleInfo`] instantiated by library path and optional semantic version. /// /// The semantic version is optional, as currently the assembler allows assembling artifacts @@ -42,8 +47,27 @@ impl ModuleInfo { signature: Option>, attributes: AttributeSet, ) { - self.items - .push(ItemInfo::Procedure(ProcedureInfo { name, digest, signature, attributes })); + self.add_procedure_with_provenance(name, digest, signature, attributes, None, None); + } + + /// Adds a procedure to the module with optional source provenance. + pub fn add_procedure_with_provenance( + &mut self, + name: ProcedureName, + digest: Word, + signature: Option>, + attributes: AttributeSet, + source_root_id: Option, + source_library_commitment: Option, + ) { + self.items.push(ItemInfo::Procedure(ProcedureInfo { + name, + digest, + signature, + attributes, + source_root_id, + source_library_commitment, + })); } /// Adds a constant to the module. @@ -82,14 +106,19 @@ impl ModuleInfo { }) } - /// Returns the digest of the procedure with the provided name, if any. - pub fn get_procedure_digest_by_name(&self, name: &str) -> Option { + /// Returns the procedure info for the procedure with the provided name, if any. + pub fn get_procedure_by_name(&self, name: &str) -> Option<&ProcedureInfo> { self.items.iter().find_map(|info| match info { - ItemInfo::Procedure(proc) if proc.name.as_str() == name => Some(proc.digest), + ItemInfo::Procedure(proc) if proc.name.as_str() == name => Some(proc), _ => None, }) } + /// Returns the digest of the procedure with the provided name, if any. + pub fn get_procedure_digest_by_name(&self, name: &str) -> Option { + self.get_procedure_by_name(name).map(|proc| proc.digest) + } + /// Returns an iterator over the items in the module with their corresponding item index in the /// module. pub fn items(&self) -> impl ExactSizeIterator { @@ -177,6 +206,23 @@ pub struct ProcedureInfo { pub digest: Word, pub signature: Option>, pub attributes: AttributeSet, + /// The exact procedure root in the source library, if known. + /// + /// This is needed when multiple exported procedures share the same digest but carry different + /// diagnostics metadata. + pub source_root_id: Option, + /// The commitment of the source library forest that `source_root_id` belongs to, if known. + pub source_library_commitment: Option, +} + +impl ProcedureInfo { + pub fn source_root_id(&self) -> Option { + self.source_root_id + } + + pub fn source_library_commitment(&self) -> Option { + self.source_library_commitment + } } /// Stores the name and value of a constant diff --git a/crates/assembly-syntax/src/parse.rs b/crates/assembly-syntax/src/parse.rs index 5cf225a287..d867b52ea3 100644 --- a/crates/assembly-syntax/src/parse.rs +++ b/crates/assembly-syntax/src/parse.rs @@ -182,7 +182,7 @@ impl Parse for Arc { .uri() .path() .parse::() - .map(|p| p.into()) + .map(Into::into) .into_diagnostic() .wrap_err("cannot parse module as it has an invalid path/name")?, }; @@ -319,7 +319,7 @@ where None => self .name() .parse::() - .map(|p| p.into()) + .map(Into::into) .into_diagnostic() .wrap_err("cannot parse module as it has an invalid path/name")?, }; diff --git a/crates/assembly-syntax/src/parser/grammar.lalrpop b/crates/assembly-syntax/src/parser/grammar.lalrpop index 99d5a0437d..b7ace192d4 100644 --- a/crates/assembly-syntax/src/parser/grammar.lalrpop +++ b/crates/assembly-syntax/src/parser/grammar.lalrpop @@ -67,6 +67,7 @@ extern { "adv_loadw" => Token::AdvLoadw, "adv_pipe" => Token::AdvPipe, "adv_push" => Token::AdvPush, + "adv_pushw" => Token::AdvPushw, "adv_stack" => Token::AdvStack, "push_mapval" => Token::PushMapval, "push_mapval_count" => Token::PushMapvalCount, @@ -988,6 +989,8 @@ Inst: Instruction = { InstWithU32Immediate, ProcRef, "adv_pipe" => Instruction::AdvPipe, + "adv_push" => Instruction::AdvPush, + "adv_pushw" => Instruction::AdvPushW, "adv_loadw" => Instruction::AdvLoadW, "and" => Instruction::And, "eval_circuit" => Instruction::EvalCircuit, @@ -1561,7 +1564,6 @@ InstWithLocalIndex: Instruction = { #[inline] InstWithStackIndex: Instruction = { - "adv_push" "." => Instruction::AdvPush(Immediate::Value(Span::new(span!(source_id, l, r), i))), "dup" )?> =>? { let (span, idx) = i.map(|s| s.into_parts()).unwrap_or((SourceSpan::default(), 0)); Ok(match idx { @@ -1909,7 +1911,7 @@ IntValue: IntValue = { } else if n <= (u32::MAX as u64) { Ok(IntValue::U32(n as u32)) } else { - Ok(IntValue::Felt(Felt::new(n))) + Ok(IntValue::Felt(Felt::new_unchecked(n))) } }, @@ -1936,7 +1938,7 @@ WordValue: WordValue = { #[inline] Felt: Felt = { - => Felt::new(value.as_int()), + => Felt::new_unchecked(value.as_int()), } // SYMBOLS @@ -2128,6 +2130,7 @@ Opcode: &'static str = { "adv_loadw" => "adv_loadw", "adv_pipe" => "adv_pipe", "adv_push" => "adv_push", + "adv_pushw" => "adv_pushw", "adv_stack" => "adv_stack", "and" => "and", "eval_circuit" => "eval_circuit", diff --git a/crates/assembly-syntax/src/parser/lexer.rs b/crates/assembly-syntax/src/parser/lexer.rs index d8e943f8d9..0c9a89562f 100644 --- a/crates/assembly-syntax/src/parser/lexer.rs +++ b/crates/assembly-syntax/src/parser/lexer.rs @@ -541,7 +541,7 @@ impl<'input> Lexer<'input> { .map_err(|error| ParsingError::InvalidLiteral { span: self.span(), kind: int_error_kind_to_literal_error_kind( - error.kind(), + *error.kind(), LiteralErrorKind::FeltOverflow, ), }) @@ -624,7 +624,7 @@ fn pad_hex_if_needed<'a>(hex: &'a str) -> Cow<'a, str> { Cow::Borrowed(hex) } else { // allocate once, with exact capacity - let mut s = alloc::string::String::with_capacity(hex.len() + 1); + let mut s = String::with_capacity(hex.len() + 1); s.push('0'); s.push_str(hex); Cow::Owned(s) @@ -647,7 +647,7 @@ fn parse_hex<'input>( ParsingError::InvalidLiteral { span, kind: int_error_kind_to_literal_error_kind( - error.kind(), + *error.kind(), LiteralErrorKind::FeltOverflow, ), } @@ -673,7 +673,7 @@ fn parse_hex<'input>( ParsingError::InvalidLiteral { span, kind: int_error_kind_to_literal_error_kind( - error.kind(), + *error.kind(), LiteralErrorKind::FeltOverflow, ), } @@ -686,7 +686,7 @@ fn parse_hex<'input>( kind: LiteralErrorKind::FeltOverflow, }); } - *element = Felt::new(value); + *element = Felt::new_unchecked(value); } Ok(Token::HexWord(WordValue(word))) }, @@ -702,7 +702,7 @@ fn parse_bin(span: SourceSpan, bin_digits: &str) -> Result IntValue { } else if n <= (u32::MAX as u64) { IntValue::U32(n as u32) } else { - IntValue::Felt(Felt::new(n)) + IntValue::Felt(Felt::new_unchecked(n)) } } @@ -743,7 +743,7 @@ fn shrink_u32_bin(n: u32) -> BinEncodedValue { #[inline] fn int_error_kind_to_literal_error_kind( - kind: &IntErrorKind, + kind: IntErrorKind, overflow: LiteralErrorKind, ) -> LiteralErrorKind { match kind { diff --git a/crates/assembly-syntax/src/parser/mod.rs b/crates/assembly-syntax/src/parser/mod.rs index ba30f5dac1..ca42101918 100644 --- a/crates/assembly-syntax/src/parser/mod.rs +++ b/crates/assembly-syntax/src/parser/mod.rs @@ -10,7 +10,10 @@ macro_rules! span { lalrpop_util::lalrpop_mod!( #[expect(clippy::all)] + #[expect(clippy::redundant_closure_for_method_calls)] + #[expect(clippy::trivially_copy_pass_by_ref)] #[expect(unused_lifetimes)] + #[expect(unused_qualifications)] grammar, "/parser/grammar.rs" ); @@ -95,7 +98,7 @@ impl ModuleParser { ) -> Result, Report> { let path = path.as_ref(); if let Err(err) = Path::validate(path.as_str()) { - return Err(Report::msg(err.to_string()).with_source_code(source.clone())); + return Err(Report::msg(err.to_string()).with_source_code(source)); } let forms = parse_forms_internal(source.clone(), &mut self.interned) .map_err(|err| Report::new(err).with_source_code(source.clone()))?; @@ -270,7 +273,7 @@ mod module_walker { fn next_entry( &mut self, entry: &DirEntry, - ty: &FileType, + ty: FileType, ) -> Result, Report> { if ty.is_dir() { let dir = entry.path(); @@ -325,7 +328,7 @@ mod module_walker { .into_diagnostic(); match entry { - Ok((ref entry, ref file_type)) => { + Ok((ref entry, file_type)) => { match self.next_entry(entry, file_type).transpose() { None => {}, result => break result, diff --git a/crates/assembly-syntax/src/parser/token.rs b/crates/assembly-syntax/src/parser/token.rs index 1903919907..d0c97ccfde 100644 --- a/crates/assembly-syntax/src/parser/token.rs +++ b/crates/assembly-syntax/src/parser/token.rs @@ -174,7 +174,7 @@ impl proptest::arbitrary::Arbitrary for WordValue { fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { use proptest::{array::uniform4, strategy::Strategy}; - uniform4((0..crate::FIELD_MODULUS).prop_map(Felt::new)) + uniform4((0..crate::FIELD_MODULUS).prop_map(Felt::new_unchecked)) .prop_map(WordValue) .no_shrink() // Pure random values, no meaningful shrinking pattern .boxed() @@ -437,7 +437,7 @@ impl proptest::arbitrary::Arbitrary for IntValue { (num::u64::ANY) .prop_filter_map("valid felt value", |n| { if n > u32::MAX as u64 && n < crate::FIELD_MODULUS { - Some(IntValue::Felt(Felt::new(n))) + Some(IntValue::Felt(Felt::new_unchecked(n))) } else { None } @@ -483,6 +483,7 @@ pub enum Token<'input> { AdvLoadw, AdvPipe, AdvPush, + AdvPushw, AdvStack, PushMapval, PushMapvalCount, @@ -712,6 +713,7 @@ impl fmt::Display for Token<'_> { Token::AdvLoadw => write!(f, "adv_loadw"), Token::AdvPipe => write!(f, "adv_pipe"), Token::AdvPush => write!(f, "adv_push"), + Token::AdvPushw => write!(f, "adv_pushw"), Token::PushMapval => write!(f, "push_mapval"), Token::PushMapvalCount => write!(f, "push_mapval_count"), Token::PushMapvaln => write!(f, "push_mapvaln"), @@ -945,6 +947,7 @@ impl<'input> Token<'input> { | Token::AdvLoadw | Token::AdvPipe | Token::AdvPush + | Token::AdvPushw | Token::AdvStack | Token::PushMapval | Token::PushMapvalCount @@ -1132,6 +1135,7 @@ impl<'input> Token<'input> { ("adv_loadw", Token::AdvLoadw), ("adv_pipe", Token::AdvPipe), ("adv_push", Token::AdvPush), + ("adv_pushw", Token::AdvPushw), ("adv_stack", Token::AdvStack), ("push_mapval", Token::PushMapval), ("push_mapval_count", Token::PushMapvalCount), diff --git a/crates/assembly-syntax/src/sema/context.rs b/crates/assembly-syntax/src/sema/context.rs index 86e2415159..5381f1998b 100644 --- a/crates/assembly-syntax/src/sema/context.rs +++ b/crates/assembly-syntax/src/sema/context.rs @@ -17,6 +17,7 @@ use crate::ast::{ /// This maintains the state for semantic analysis of a single [Module]. pub struct AnalysisContext { constants: BTreeMap, + cached_constant_values: BTreeMap, imported: BTreeSet, procedures: BTreeSet, errors: Vec, @@ -37,7 +38,9 @@ impl constants::ConstEnvironment for AnalysisContext { } #[inline] fn get(&mut self, name: &Ident) -> Result>, Self::Error> { - if let Some(constant) = self.constants.get(name) { + if let Some(value) = self.cached_constant_values.get(name) { + Ok(Some(CachedConstantValue::Hit(value))) + } else if let Some(constant) = self.constants.get(name) { Ok(Some(CachedConstantValue::Miss(&constant.value))) } else if self.imported.contains(name) { // We don't have the definition available yet @@ -61,12 +64,25 @@ impl constants::ConstEnvironment for AnalysisContext { Ok(None) } } + + #[inline] + fn on_eval_completed(&mut self, name: Span<&Path>, value: &ConstantExpr) { + let Some(name) = name.as_ident() else { + return; + }; + if let Some(value) = value.as_value() { + self.cached_constant_values.insert(name, value); + } else { + self.cached_constant_values.remove(&name); + } + } } impl AnalysisContext { pub fn new(source_file: Arc, source_manager: Arc) -> Self { Self { constants: Default::default(), + cached_constant_values: Default::default(), imported: Default::default(), procedures: Default::default(), errors: Default::default(), @@ -116,6 +132,7 @@ impl AnalysisContext { /// attempting to define the same constant twice. pub fn register_constant(&mut self, constant: Constant) { let name = constant.name.clone(); + self.cached_constant_values.remove(&name); if let Some(prev) = self.constants.get(&name) { self.errors.push(SemanticAnalysisError::SymbolConflict { span: constant.span, @@ -130,6 +147,7 @@ impl AnalysisContext { /// /// This also has the effect of validating that the constant expressions themselves are valid. pub fn simplify_constants(&mut self) { + self.cached_constant_values.clear(); let constants = self.constants.keys().cloned().collect::>(); for constant in constants.iter() { @@ -137,11 +155,17 @@ impl AnalysisContext { constant.span(), PathBuf::from(constant.clone()).into(), )); - match crate::ast::constants::eval::expr(&expr, self) { + match constants::eval::expr(&expr, self) { Ok(value) => { + if let Some(cached) = value.as_value() { + self.cached_constant_values.insert(constant.clone(), cached); + } else { + self.cached_constant_values.remove(constant); + } self.constants.get_mut(constant).unwrap().value = value; }, Err(err) => { + self.cached_constant_values.remove(constant); self.errors.push(err); }, } @@ -214,3 +238,156 @@ impl AnalysisContext { #[cfg(not(feature = "std"))] fn emit_warnings(self) {} } + +#[cfg(test)] +mod tests { + use alloc::{boxed::Box, string::String, sync::Arc}; + use core::cell::Cell; + + use super::AnalysisContext; + use crate::{ + Path, PathBuf, + ast::{ + Constant, ConstantExpr, ConstantOp, ConstantValue, Ident, Visibility, + constants::{self, eval::CachedConstantValue}, + }, + debuginfo::{ + DefaultSourceManager, SourceContent, SourceLanguage, SourceManager, SourceSpan, Span, + Uri, + }, + parser::IntValue, + }; + + struct CountingEnv<'a> { + inner: &'a mut AnalysisContext, + hits: Cell, + misses: Cell, + } + + impl<'a> CountingEnv<'a> { + fn new(inner: &'a mut AnalysisContext) -> Self { + Self { + inner, + hits: Cell::new(0), + misses: Cell::new(0), + } + } + + fn hits(&self) -> usize { + self.hits.get() + } + + fn misses(&self) -> usize { + self.misses.get() + } + } + + impl constants::ConstEnvironment for CountingEnv<'_> { + type Error = super::SemanticAnalysisError; + + fn get_source_file_for( + &self, + span: SourceSpan, + ) -> Option> { + ::get_source_file_for(self.inner, span) + } + + fn get(&mut self, name: &Ident) -> Result>, Self::Error> { + let value = ::get(self.inner, name)?; + if let Some(ref value) = value { + match value { + CachedConstantValue::Hit(_) => self.hits.set(self.hits.get() + 1), + CachedConstantValue::Miss(_) => self.misses.set(self.misses.get() + 1), + } + } + Ok(value) + } + + fn get_by_path( + &mut self, + path: Span<&Path>, + ) -> Result>, Self::Error> { + if let Some(name) = path.as_ident() { + self.get(&name) + } else { + ::get_by_path(self.inner, path) + } + } + + fn on_eval_completed(&mut self, name: Span<&Path>, value: &ConstantExpr) { + ::on_eval_completed( + self.inner, name, value, + ); + } + } + + fn make_name(i: usize) -> Ident { + format!("C{i:05}").parse().expect("generated constant name must be valid") + } + + fn make_ref(name: Ident) -> ConstantExpr { + let path = Arc::::from(PathBuf::from(name)); + ConstantExpr::Var(Span::new(SourceSpan::default(), path)) + } + + fn make_shared_subexpression_chain(context: &mut AnalysisContext, depth: usize) { + for i in 0..depth { + let name = make_name(i); + let next = make_name(i + 1); + context.register_constant(Constant::new( + SourceSpan::default(), + Visibility::Public, + name, + ConstantExpr::BinaryOp { + span: SourceSpan::default(), + op: ConstantOp::Add, + lhs: Box::new(make_ref(next.clone())), + rhs: Box::new(make_ref(next)), + }, + )); + } + + context.register_constant(Constant::new( + SourceSpan::default(), + Visibility::Public, + make_name(depth), + ConstantExpr::Int(Span::new(SourceSpan::default(), IntValue::from(1_u32))), + )); + } + + #[test] + fn semantic_const_eval_memoizes_shared_subexpressions() { + let source_manager = Arc::new(DefaultSourceManager::default()); + let uri = + Uri::from(String::from("mem://const-eval-shared-subexpressions").into_boxed_str()); + let content = SourceContent::new( + SourceLanguage::Masm, + uri.clone(), + String::from("begin\n nop\nend\n").into_boxed_str(), + ); + let source_file = source_manager.load_from_raw_parts(uri, content); + let mut context = AnalysisContext::new(source_file, source_manager); + + // Each Ci references C(i+1) twice, so without memoization the number of misses would + // grow exponentially with depth. + let depth = 24; + make_shared_subexpression_chain(&mut context, depth); + + let root_name = make_name(0); + let mut env = CountingEnv::new(&mut context); + let root = make_ref(root_name); + let result = constants::eval::expr(&root, &mut env) + .expect("shared-subexpression constant graph should evaluate"); + + assert!( + matches!(result.as_value(), Some(ConstantValue::Int(_))), + "evaluation should produce a concrete integer constant value" + ); + assert_eq!(env.misses(), depth + 1, "each constant in the chain should miss at most once"); + assert_eq!( + env.hits(), + depth, + "the second reference to each dependency should be served from cache" + ); + } +} diff --git a/crates/assembly-syntax/src/sema/errors.rs b/crates/assembly-syntax/src/sema/errors.rs index 75ef8a0e37..8b5b39c01a 100644 --- a/crates/assembly-syntax/src/sema/errors.rs +++ b/crates/assembly-syntax/src/sema/errors.rs @@ -234,6 +234,8 @@ impl From for SemanticAnalysisError { /// Represents a system limit that was exceeded #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum LimitKind { + /// The total number of items in a module + Items, /// The total number of procedures in a module Procedures, /// The total number of procedure locals @@ -251,6 +253,7 @@ pub enum LimitKind { impl fmt::Display for LimitKind { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { + Self::Items => f.write_str("too many items in module"), Self::Procedures => f.write_str("too many procedures in module"), Self::Locals => f.write_str("too many procedure locals"), Self::Imports => f.write_str("too many imported procedures"), diff --git a/crates/assembly-syntax/src/sema/mod.rs b/crates/assembly-syntax/src/sema/mod.rs index 832a88c82d..58b6f9a827 100644 --- a/crates/assembly-syntax/src/sema/mod.rs +++ b/crates/assembly-syntax/src/sema/mod.rs @@ -6,7 +6,8 @@ mod tests; use alloc::{ boxed::Box, - collections::{BTreeSet, VecDeque}, + collections::{BTreeMap, BTreeSet, VecDeque}, + string::ToString, sync::Arc, vec::Vec, }; @@ -15,10 +16,11 @@ use miden_core::{Word, crypto::hash::Poseidon2}; use miden_debug_types::{SourceFile, SourceManager, Span, Spanned}; use smallvec::SmallVec; +use self::passes::{LocalInvokeTarget, VerifyInvokeTargets}; pub use self::{ context::AnalysisContext, - errors::{SemanticAnalysisError, SyntaxError}, - passes::{ConstEvalVisitor, VerifyInvokeTargets, VerifyRepeatCounts}, + errors::{LimitKind, SemanticAnalysisError, SyntaxError}, + passes::{ConstEvalVisitor, VerifyRepeatCounts}, }; use crate::{ast::*, parser::WordValue}; @@ -181,7 +183,13 @@ pub fn analyze( /// of a module graph and global program analysis to perform any remaining transformations. fn visit_items(module: &mut Module, analyzer: &mut AnalysisContext) -> Result<(), SyntaxError> { let is_kernel = module.is_kernel(); - let locals = BTreeSet::from_iter(module.items().iter().map(|p| p.name().clone())); + let locals = BTreeMap::from_iter( + module + .items() + .iter() + .map(|item| (item.name().as_str().to_string(), LocalInvokeTarget::from(item))), + ); + let mut used_aliases = BTreeSet::default(); let mut items = VecDeque::from(core::mem::take(&mut module.items)); while let Some(item) = items.pop_front() { match item { @@ -222,39 +230,72 @@ fn visit_items(module: &mut Module, analyzer: &mut AnalysisContext) -> Result<() analyzer, module, &locals, + &mut used_aliases, Some(procedure.name().clone()), ); let _ = visitor.visit_mut_procedure(&mut procedure); } - module.items.push(Export::Procedure(procedure)); + if let Err(err) = module.push_export(Export::Procedure(procedure)) { + analyzer.error(err); + } }, Export::Alias(mut alias) => { log::debug!(target: "verify-invoke", "visiting alias {}", alias.target()); { - let mut visitor = VerifyInvokeTargets::new(analyzer, module, &locals, None); + let mut visitor = VerifyInvokeTargets::new( + analyzer, + module, + &locals, + &mut used_aliases, + None, + ); let _ = visitor.visit_mut_alias(&mut alias); } - module.items.push(Export::Alias(alias)); + if let Err(err) = module.push_export(Export::Alias(alias)) { + analyzer.error(err); + } }, Export::Constant(mut constant) => { log::debug!(target: "verify-invoke", "visiting constant {}", constant.name()); { - let mut visitor = VerifyInvokeTargets::new(analyzer, module, &locals, None); + let mut visitor = VerifyInvokeTargets::new( + analyzer, + module, + &locals, + &mut used_aliases, + None, + ); let _ = visitor.visit_mut_constant(&mut constant); } - module.items.push(Export::Constant(constant)); + if let Err(err) = module.push_export(Export::Constant(constant)) { + analyzer.error(err); + } }, Export::Type(mut ty) => { log::debug!(target: "verify-invoke", "visiting type {}", ty.name()); { - let mut visitor = VerifyInvokeTargets::new(analyzer, module, &locals, None); + let mut visitor = VerifyInvokeTargets::new( + analyzer, + module, + &locals, + &mut used_aliases, + None, + ); let _ = visitor.visit_mut_type_decl(&mut ty); } - module.items.push(Export::Type(ty)); + if let Err(err) = module.push_export(Export::Type(ty)) { + analyzer.error(err); + } }, } } + for alias in module.aliases_mut() { + if alias.uses == 0 && used_aliases.contains(alias.name().as_str()) { + alias.uses = 1; + } + } + Ok(()) } diff --git a/crates/assembly-syntax/src/sema/passes/const_eval.rs b/crates/assembly-syntax/src/sema/passes/const_eval.rs index 2b222f9e30..746316ed12 100644 --- a/crates/assembly-syntax/src/sema/passes/const_eval.rs +++ b/crates/assembly-syntax/src/sema/passes/const_eval.rs @@ -61,7 +61,7 @@ where ))) => { // A reference to another constant was used, try to evaluate the expression let expr = expr.clone(); - match crate::ast::constants::eval::expr(&expr, self.env) { + match constants::eval::expr(&expr, self.env) { Ok(ConstantExpr::Int(value)) => value, // Unable to evaluate in the current context Ok(ConstantExpr::Var(_) | ConstantExpr::BinaryOp { .. }) => { @@ -131,7 +131,7 @@ where return ControlFlow::Continue(()); } - match crate::ast::constants::eval::expr(&constant.value, self.env) { + match constants::eval::expr(&constant.value, self.env) { Ok(evaluated) => { constant.value = evaluated; }, @@ -161,7 +161,7 @@ where Ok(Some(CachedConstantValue::Miss(expr @ ConstantExpr::Var(_)))) => { // A reference to another constant was used, try to evaluate the expression let expr = expr.clone(); - match crate::ast::constants::eval::expr(&expr, self.env) { + match constants::eval::expr(&expr, self.env) { Ok(ConstantExpr::Hash(HashKind::Event, _)) => (), // Unable to evaluate in the current context Ok(ConstantExpr::Var(_)) => return ControlFlow::Continue(()), @@ -203,7 +203,7 @@ where }, } } - crate::ast::visit::visit_mut_inst(self, inst) + visit::visit_mut_inst(self, inst) } fn visit_mut_immediate_u8(&mut self, imm: &mut Immediate) -> ControlFlow<()> { self.eval_const(imm) @@ -224,7 +224,7 @@ where let span = name.span(); match self.env.get_error(name) { Ok(Some(value)) => { - *imm = Immediate::Value(Span::new(span, value.clone())); + *imm = Immediate::Value(Span::new(span, value)); }, // The constant is externally-defined, and not available yet Ok(None) => (), @@ -246,7 +246,10 @@ where CachedConstantValue::Miss(ConstantExpr::Int(value)) | CachedConstantValue::Hit(ConstantValue::Int(value)), )) => { - *imm = Immediate::Value(Span::new(span, Felt::new(value.inner().as_int()))); + *imm = Immediate::Value(Span::new( + span, + Felt::new_unchecked(value.inner().as_int()), + )); }, Ok(Some( CachedConstantValue::Miss(ConstantExpr::Hash(HashKind::Event, string)) @@ -264,11 +267,11 @@ where ))) => { // A reference to another constant was used, try to evaluate the expression let expr = expr.clone(); - match crate::ast::constants::eval::expr(&expr, self.env) { + match constants::eval::expr(&expr, self.env) { Ok(ConstantExpr::Int(value)) => { *imm = Immediate::Value(Span::new( span, - Felt::new(value.inner().as_int()), + Felt::new_unchecked(value.inner().as_int()), )); }, Ok(ConstantExpr::Hash(HashKind::Event, value)) => { @@ -368,7 +371,7 @@ where ))) => { // A reference to another constant was used, try to evaluate the expression let expr = expr.clone(); - match crate::ast::constants::eval::expr(&expr, self.env) { + match constants::eval::expr(&expr, self.env) { Ok(ConstantExpr::Int(value)) => { *imm = Immediate::Value(Span::new( span, @@ -467,7 +470,7 @@ where Ok(Some(CachedConstantValue::Miss(expr @ ConstantExpr::Var(_)))) => { // A reference to another constant was used, try to evaluate the expression let expr = expr.clone(); - match crate::ast::constants::eval::expr(&expr, self.env) { + match constants::eval::expr(&expr, self.env) { Ok(ConstantExpr::Word(value)) => { *imm = Immediate::Value(Span::new(span, *value.inner())); }, diff --git a/crates/assembly-syntax/src/sema/passes/mod.rs b/crates/assembly-syntax/src/sema/passes/mod.rs index be760ea74d..7f4991c281 100644 --- a/crates/assembly-syntax/src/sema/passes/mod.rs +++ b/crates/assembly-syntax/src/sema/passes/mod.rs @@ -2,7 +2,5 @@ mod const_eval; mod verify_invoke; mod verify_repeat; -pub use self::{ - const_eval::ConstEvalVisitor, verify_invoke::VerifyInvokeTargets, - verify_repeat::VerifyRepeatCounts, -}; +pub(super) use self::verify_invoke::{LocalInvokeTarget, VerifyInvokeTargets}; +pub use self::{const_eval::ConstEvalVisitor, verify_repeat::VerifyRepeatCounts}; diff --git a/crates/assembly-syntax/src/sema/passes/verify_invoke.rs b/crates/assembly-syntax/src/sema/passes/verify_invoke.rs index b9a741f289..31ef4f7115 100644 --- a/crates/assembly-syntax/src/sema/passes/verify_invoke.rs +++ b/crates/assembly-syntax/src/sema/passes/verify_invoke.rs @@ -1,4 +1,9 @@ -use alloc::{boxed::Box, collections::BTreeSet, sync::Arc}; +use alloc::{ + boxed::Box, + collections::{BTreeMap, BTreeSet}, + string::{String, ToString}, + sync::Arc, +}; use core::ops::ControlFlow; use miden_debug_types::{SourceSpan, Span, Spanned}; @@ -9,6 +14,25 @@ use crate::{ sema::{AnalysisContext, SemanticAnalysisError}, }; +const MAX_ALIAS_EXPANSION_DEPTH: usize = 128; + +#[derive(Debug, Clone)] +pub(crate) enum LocalInvokeTarget { + Procedure, + Alias(AliasTarget), + Other(SourceSpan), +} + +impl From<&Export> for LocalInvokeTarget { + fn from(item: &Export) -> Self { + match item { + Export::Procedure(_) => Self::Procedure, + Export::Alias(alias) => Self::Alias(alias.target().clone()), + Export::Constant(_) | Export::Type(_) => Self::Other(item.span()), + } + } +} + /// This visitor visits every `exec`, `call`, `syscall`, and `procref`, and ensures that the /// invocation target for that call is resolvable to the extent possible within the current /// module's context. @@ -19,25 +43,28 @@ use crate::{ /// We attempt to apply as many call-related validations as we can here, however we are limited /// until later stages of compilation on what we can know in the context of a single module. /// As a result, more complex analyses are reserved until assembly. -pub struct VerifyInvokeTargets<'a> { +pub(crate) struct VerifyInvokeTargets<'a> { analyzer: &'a mut AnalysisContext, module: &'a mut Module, - procedures: &'a BTreeSet, + locals: &'a BTreeMap, + used_aliases: &'a mut BTreeSet, current_procedure: Option, invoked: BTreeSet, } impl<'a> VerifyInvokeTargets<'a> { - pub fn new( + pub(crate) fn new( analyzer: &'a mut AnalysisContext, module: &'a mut Module, - procedures: &'a BTreeSet, + locals: &'a BTreeMap, + used_aliases: &'a mut BTreeSet, current_procedure: Option, ) -> Self { Self { analyzer, module, - procedures, + locals, + used_aliases, current_procedure, invoked: Default::default(), } @@ -45,12 +72,105 @@ impl<'a> VerifyInvokeTargets<'a> { } impl VerifyInvokeTargets<'_> { + fn track_used_alias_name(&mut self, name: &str) { + self.used_aliases.insert(name.to_string()); + } + fn resolve_local(&mut self, name: &Ident) -> ControlFlow<()> { - if !self.procedures.contains(name) { + let mut visited = BTreeSet::default(); + self.resolve_local_name(name.span(), name.as_str(), &mut visited) + } + + fn resolve_local_name( + &mut self, + span: SourceSpan, + name: &str, + visited: &mut BTreeSet, + ) -> ControlFlow<()> { + if visited.len() > MAX_ALIAS_EXPANSION_DEPTH { self.analyzer.error(SemanticAnalysisError::SymbolResolutionError(Box::new( - SymbolResolutionError::undefined(name.span(), &self.analyzer.source_manager()), + SymbolResolutionError::alias_expansion_depth_exceeded( + span, + MAX_ALIAS_EXPANSION_DEPTH, + &self.analyzer.source_manager(), + ), ))); + return ControlFlow::Continue(()); + } + + if self.current_procedure.as_ref().is_some_and(|curr| curr.as_str() == name) { + self.analyzer.error(SemanticAnalysisError::SelfRecursive { span }); + return ControlFlow::Continue(()); + } + + let Some(item) = self.locals.get(name).cloned() else { + self.analyzer.error(SemanticAnalysisError::SymbolResolutionError(Box::new( + SymbolResolutionError::undefined(span, &self.analyzer.source_manager()), + ))); + return ControlFlow::Continue(()); + }; + + match &item { + LocalInvokeTarget::Procedure => ControlFlow::Continue(()), + LocalInvokeTarget::Other(actual) => { + self.analyzer.error(SemanticAnalysisError::SymbolResolutionError(Box::new( + SymbolResolutionError::invalid_symbol_type( + span, + "procedure", + *actual, + &self.analyzer.source_manager(), + ), + ))); + ControlFlow::Continue(()) + }, + LocalInvokeTarget::Alias(target) => { + self.track_used_alias_name(name); + + if !visited.insert(name.to_string()) { + self.analyzer.error(SemanticAnalysisError::SymbolResolutionError(Box::new( + SymbolResolutionError::alias_expansion_cycle( + span, + &self.analyzer.source_manager(), + ), + ))); + return ControlFlow::Continue(()); + } + + self.resolve_local_alias_target(span, target, visited) + }, + } + } + + fn resolve_local_alias_target( + &mut self, + span: SourceSpan, + target: &AliasTarget, + visited: &mut BTreeSet, + ) -> ControlFlow<()> { + match target { + AliasTarget::MastRoot(_) => ControlFlow::Continue(()), + AliasTarget::Path(path) => self.resolve_invocation_path(span, path.inner(), visited), + } + } + + fn resolve_invocation_path( + &mut self, + span: SourceSpan, + path: &Path, + visited: &mut BTreeSet, + ) -> ControlFlow<()> { + if let Some(name) = path.as_ident() { + return self.resolve_local_name(span, name.as_str(), visited); } + + if path.parent().is_some_and(|parent| parent == self.module.path()) { + return self.resolve_local_name(span, path.last().unwrap(), visited); + } + + if self.resolve_external(span, path).is_none() { + self.analyzer.error(SemanticAnalysisError::MissingImport { span }); + } + ControlFlow::Continue(()) } fn resolve_external(&mut self, span: SourceSpan, path: &Path) -> Option { @@ -64,12 +184,16 @@ impl VerifyInvokeTargets<'_> { log::debug!(target: "verify-invoke", "found import '{}'", import.target()); import.uses += 1; match import.target() { - AliasTarget::MastRoot(_) => { - self.analyzer.error(SemanticAnalysisError::InvalidInvokeTargetViaImport { - span, - import: import.span(), - }); - None + AliasTarget::MastRoot(digest) => { + if rest.is_empty() { + Some(InvocationTarget::MastRoot(*digest)) + } else { + self.analyzer.error(SemanticAnalysisError::InvalidInvokeTargetViaImport { + span, + import: import.span(), + }); + None + } }, // If we have an import like `use lib::lib`, the base `lib` has been shadowed, so // we cannot attempt to resolve further. Instead, we use the target path we have. @@ -85,13 +209,17 @@ impl VerifyInvokeTargets<'_> { let resolved = self.resolve_external(path.span(), path.inner())?; match resolved { InvocationTarget::MastRoot(digest) => { - self.analyzer.error( - SemanticAnalysisError::InvalidInvokeTargetViaImport { - span, - import: digest.span(), - }, - ); - None + if rest.is_empty() { + Some(InvocationTarget::MastRoot(digest)) + } else { + self.analyzer.error( + SemanticAnalysisError::InvalidInvokeTargetViaImport { + span, + import: digest.span(), + }, + ); + None + } }, // We can consider this path fully-resolved, and mark it absolute, if it is // not already @@ -110,9 +238,7 @@ impl VerifyInvokeTargets<'_> { } } fn track_used_alias(&mut self, name: &Ident) { - if let Some(alias) = self.module.aliases_mut().find(|a| a.name() == name) { - alias.uses += 1; - } + self.track_used_alias_name(name.as_str()); } } @@ -168,6 +294,13 @@ impl VisitMut for VerifyInvokeTargets<'_> { } fn visit_mut_procref(&mut self, target: &mut InvocationTarget) -> ControlFlow<()> { self.visit_mut_invoke_target(target)?; + // We intentionally use `InvokeKind::Exec` here rather than `InvokeKind::ProcRef`. + // A `procref` instruction captures a procedure reference for *later* invocation, + // but we must pessimistically treat it as an actual invocation because we cannot + // know the specific call kind at this point. `Exec` is the most general invocation + // kind, and the linker relies on this signal to correctly track procedure + // dependencies. Using `ProcRef` would only indicate "named somewhere" and would + // not carry the full weight of "this procedure is invoked". self.invoked.insert(Invoke::new(InvokeKind::Exec, target.clone())); ControlFlow::Continue(()) } @@ -180,7 +313,7 @@ impl VisitMut for VerifyInvokeTargets<'_> { Span::new(symbol.span(), PathBuf::from(symbol.clone()).into()) }, }; - let current = self.current_procedure.as_ref().map(|p| p.as_ident()); + let current = self.current_procedure.as_ref().map(ProcedureName::as_ident); if let Some(name) = path.as_ident() { let name = name.with_span(span); if current.is_some_and(|curr| curr == name) { @@ -210,10 +343,7 @@ impl VisitMut for VerifyInvokeTargets<'_> { return ControlFlow::Continue(()); }; - if let Some(via) = self.module.get_import_mut(ns) { - via.uses += 1; - assert!(via.is_used()); - } + self.track_used_alias_name(ns); ControlFlow::Continue(()) }, } @@ -272,20 +402,16 @@ impl VisitMut for VerifyInvokeTargets<'_> { fn visit_mut_type_ref(&mut self, path: &mut Span>) -> ControlFlow<()> { if let Some(name) = path.as_ident() { self.track_used_alias(&name); - } else if let Some((module, _)) = path.split_first() - && let Some(alias) = self.module.aliases_mut().find(|a| a.name().as_str() == module) - { - alias.uses += 1; + } else if let Some((module, _)) = path.split_first() { + self.track_used_alias_name(module); } ControlFlow::Continue(()) } fn visit_mut_constant_ref(&mut self, path: &mut Span>) -> ControlFlow<()> { if let Some(name) = path.as_ident() { self.track_used_alias(&name); - } else if let Some((module, _)) = path.split_first() - && let Some(alias) = self.module.aliases_mut().find(|a| a.name().as_str() == module) - { - alias.uses += 1; + } else if let Some((module, _)) = path.split_first() { + self.track_used_alias_name(module); } ControlFlow::Continue(()) } diff --git a/crates/assembly-syntax/src/sema/tests.rs b/crates/assembly-syntax/src/sema/tests.rs index 832432f6d0..3e6c478d4b 100644 --- a/crates/assembly-syntax/src/sema/tests.rs +++ b/crates/assembly-syntax/src/sema/tests.rs @@ -1,7 +1,17 @@ +use alloc::{ + string::{String, ToString}, + sync::Arc, +}; + +use miden_debug_types::{Span, Spanned}; + use crate::{ - MAX_REPEAT_COUNT, - ast::{Constant, Export, Module}, + MAX_REPEAT_COUNT, Path, + ast::{ + Constant, ConstantExpr, Export, Module, ModuleKind, TypeAlias, TypeExpr, Visibility, types, + }, diagnostics::reporting::PrintDiagnostic, + sema::SemanticAnalysisError, testing::SyntaxTestContext, }; @@ -17,6 +27,159 @@ fn exported_constant<'a>(module: &'a Module, name: &str) -> &'a Constant { } } +fn assert_symbol_conflict(error: &miden_utils_diagnostics::Report, symbol: &str) { + let syntax_error = error + .downcast_ref::() + .expect("expected SyntaxError report"); + + let (span, prev_span) = syntax_error + .errors + .iter() + .find_map(|err| match err { + SemanticAnalysisError::SymbolConflict { span, prev_span } => Some((span, prev_span)), + _ => None, + }) + .expect("expected at least one SymbolConflict error"); + + assert_ne!(span, prev_span, "conflicting definitions should point at distinct spans"); + assert_eq!( + span.source_id(), + prev_span.source_id(), + "conflict spans should refer to the same source file" + ); + + let span_text = syntax_error + .source_file + .source_slice(*span) + .expect("conflict span should be valid"); + let prev_span_text = syntax_error + .source_file + .source_slice(*prev_span) + .expect("previous conflict span should be valid"); + + assert!( + span_text.contains(symbol), + "conflict span should include symbol '{symbol}', got: {span_text:?}" + ); + assert!( + prev_span_text.contains(symbol), + "previous conflict span should include symbol '{symbol}', got: {prev_span_text:?}" + ); +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +enum DefinitionKind { + Alias, + Procedure, + Constant, + Type, +} + +impl DefinitionKind { + fn declaration(self, symbol: &str) -> String { + match self { + Self::Alias => format!("use ::dep::{}", quote_ident_if_needed(symbol)), + Self::Procedure => { + format!("proc {}\n nop\nend", quote_ident_if_needed(symbol)) + }, + Self::Constant => format!("const {symbol} = 1"), + Self::Type => format!("type {} = felt", quote_ident_if_needed(symbol)), + } + } +} + +fn quote_ident_if_needed(symbol: &str) -> String { + let is_bare_ident = symbol + .bytes() + .all(|b| b == b'_' || b.is_ascii_lowercase() || b.is_ascii_digit()); + if is_bare_ident { + symbol.to_string() + } else { + format!("\"{symbol}\"") + } +} + +fn assert_cross_kind_conflict(first: DefinitionKind, second: DefinitionKind) { + if is_constant_type_pair(first, second) { + assert_constant_type_conflict_via_module_api(first, second); + return; + } + + let symbol = if matches!(first, DefinitionKind::Constant) + || matches!(second, DefinitionKind::Constant) + { + "THING" + } else { + "thing" + }; + let context = SyntaxTestContext::default(); + let source = format!("{}\n{}\n", first.declaration(symbol), second.declaration(symbol)); + let message = format!("expected symbol conflict during analysis ({first:?} then {second:?})"); + let error = context.parse_module(source).expect_err(&message); + let rendered = format!("{}", PrintDiagnostic::new_without_color(&error)); + if error.downcast_ref::().is_none() { + panic!("expected SyntaxError ({first:?} then {second:?}), got: {rendered}"); + } + assert_symbol_conflict(&error, symbol); + assert!(rendered.contains("symbol conflict")); + assert!(rendered.contains(symbol)); +} + +fn is_constant_type_pair(first: DefinitionKind, second: DefinitionKind) -> bool { + matches!( + (first, second), + (DefinitionKind::Constant, DefinitionKind::Type) + | (DefinitionKind::Type, DefinitionKind::Constant) + ) +} + +fn assert_constant_type_conflict_via_module_api(first: DefinitionKind, second: DefinitionKind) { + let symbol = "dup"; + let mut module = Module::new(ModuleKind::Library, Path::new("mod")); + + match first { + DefinitionKind::Constant => module + .define_constant(constant_with_name(symbol)) + .expect("expected initial constant definition to succeed"), + DefinitionKind::Type => module + .define_type(type_alias_with_name(symbol)) + .expect("expected initial type definition to succeed"), + _ => unreachable!("only constant/type pairs should use this helper"), + } + + let result = match second { + DefinitionKind::Constant => module.define_constant(constant_with_name(symbol)), + DefinitionKind::Type => module.define_type(type_alias_with_name(symbol)), + _ => unreachable!("only constant/type pairs should use this helper"), + }; + assert!( + matches!(result, Err(SemanticAnalysisError::SymbolConflict { .. })), + "expected SymbolConflict when defining {second:?} after {first:?}, got {result:?}" + ); +} + +fn ident_with_name(name: &str) -> crate::ast::Ident { + crate::ast::Ident::from_raw_parts(Span::unknown(Arc::::from(name))) +} + +fn constant_with_name(name: &str) -> Constant { + let ident = ident_with_name(name); + Constant::new( + ident.span(), + Visibility::Private, + ident, + ConstantExpr::String(ident_with_name("value")), + ) +} + +fn type_alias_with_name(name: &str) -> TypeAlias { + TypeAlias::new( + Visibility::Private, + ident_with_name(name), + TypeExpr::Primitive(Span::unknown(types::Type::Felt)), + ) +} + #[test] fn repeat_count_zero_rejected_in_analysis() { let context = SyntaxTestContext::default(); @@ -101,3 +264,21 @@ pub const ACCOUNT_ID_SUFFIX_OFFSET = ACCOUNT_ID_AND_NONCE_OFFSET + 2 "expected semantic analysis to remove private local constant references from exported constants", ); } + +#[test] +fn define_items_detect_cross_kind_duplicates_for_all_pairs_and_orders() { + let kinds = [ + DefinitionKind::Alias, + DefinitionKind::Procedure, + DefinitionKind::Constant, + DefinitionKind::Type, + ]; + for first in kinds { + for second in kinds { + if first == second { + continue; + } + assert_cross_kind_conflict(first, second); + } + } +} diff --git a/crates/assembly-syntax/src/testing/pattern.rs b/crates/assembly-syntax/src/testing/pattern.rs index 6b0e8c87ef..d25efe4aab 100644 --- a/crates/assembly-syntax/src/testing/pattern.rs +++ b/crates/assembly-syntax/src/testing/pattern.rs @@ -36,12 +36,9 @@ impl Pattern { let input = input.as_ref(); if !self.is_match(input) { panic!( - r"expected string was not found in emitted diagnostics: -expected input to {expected} -matched against: `{actual}` -", - expected = self, - actual = input + "expected string was not found in emitted diagnostics:\n\ + expected input to {self}\n\ + matched against: `{input}`" ); } } @@ -54,13 +51,10 @@ matched against: `{actual}` let context = context.as_ref(); if !self.is_match(input) { panic!( - r"expected string was not found in emitted diagnostics: -expected input to {expected} -matched against: `{actual}` -full output: `{context}` -", - expected = self, - actual = input + "expected string was not found in emitted diagnostics:\n\ + expected input to {self}\n\ + matched against: `{input}`\n\ + full output: `{context}`" ); } } diff --git a/crates/assembly/Cargo.toml b/crates/assembly/Cargo.toml index 820e456093..9f48ca31ba 100644 --- a/crates/assembly/Cargo.toml +++ b/crates/assembly/Cargo.toml @@ -18,6 +18,7 @@ bench = false doctest = false [features] +arbitrary = ["std", "dep:proptest"] default = ["std"] std = [ "dep:miden-package-registry", @@ -25,6 +26,7 @@ std = [ "miden-core/std", "miden-mast-package/std", "miden-project/std", + "proptest?/std", "tempfile/getrandom", "thiserror/std", ] @@ -42,6 +44,7 @@ miden-project = { workspace = true, features = ["serde"] } # External dependencies env_logger = { workspace = true, optional = true } log.workspace = true +proptest = { workspace = true, optional = true } smallvec.workspace = true thiserror.workspace = true @@ -53,5 +56,6 @@ thiserror.workspace = true miden-assembly = { path = ".", default-features = false, features = ["testing"] } miden-mast-package = { workspace = true, features = ["arbitrary"] } insta = { workspace = true } +miden-test-serde-macros.workspace = true proptest = { workspace = true, features = ["std"] } tempfile.workspace = true diff --git a/crates/assembly/src/assembler.rs b/crates/assembly/src/assembler.rs index 6e881619f7..cd981389c3 100644 --- a/crates/assembly/src/assembler.rs +++ b/crates/assembly/src/assembler.rs @@ -168,6 +168,41 @@ impl Assembler { self.trim_paths = yes; self } + + pub(crate) fn invalid_invoke_target_report( + &self, + kind: InvokeKind, + callee: &InvocationTarget, + caller: GlobalItemIndex, + ) -> Report { + let span = callee.span(); + let source_file = self.source_manager.get(span.source_id()).ok(); + let context = SymbolResolutionContext { + span, + module: caller.module, + kind: Some(kind), + }; + + let path = match self.linker.resolve_invoke_target(&context, callee) { + Ok( + SymbolResolution::Exact { path, .. } + | SymbolResolution::Module { path, .. } + | SymbolResolution::External(path), + ) => Some(path.into_inner()), + Ok(SymbolResolution::Local(_) | SymbolResolution::MastRoot(_)) => None, + Err(err) => return Report::new(err), + } + .or_else(|| match callee { + InvocationTarget::Symbol(symbol) => Some(Path::from_ident(symbol).into_owned().into()), + InvocationTarget::Path(path) => Some(path.clone().into_inner()), + InvocationTarget::MastRoot(_) => None, + }); + + match path { + Some(path) => Report::new(LinkerError::InvalidInvokeTarget { span, source_file, path }), + None => Report::msg("invalid procedure reference: target is not a procedure"), + } + } } // ------------------------------------------------------------------------------------------------ @@ -349,8 +384,7 @@ impl Assembler { TargetType::Kernel => { if !self.kernel().is_empty() { return Err(Report::msg(format!( - "duplicate kernels present in the dependency graph: '{}@{ - }' conflicts with another kernel we've already linked", + "duplicate kernels present in the dependency graph: '{}@{}' conflicts with another kernel we've already linked", &package.name, &package.version ))); } @@ -559,7 +593,12 @@ impl Assembler { if !symbol.visibility().is_public() { continue; } - module_path.join(symbol.name()).into() + module_path + .join(symbol.name()) + .canonicalize() + .into_diagnostic()? + .into_boxed_path() + .into() }; let export = self.export_symbol( gid, @@ -567,7 +606,9 @@ impl Assembler { path.clone(), &mut mast_forest_builder, )?; - exports.insert(path, export); + if exports.insert(path.clone(), export).is_some() { + return Err(Report::new(AssemblerError::DuplicateExportPath { path })); + } } } @@ -625,6 +666,8 @@ impl Assembler { InvokeKind::ProcRef, SourceSpan::UNKNOWN, item.digest, + item.source_library_commitment(), + item.source_root_id(), mast_forest_builder, )?; ResolvedProcedure { node, signature: item.signature.clone() } @@ -689,11 +732,48 @@ impl Assembler { }, SymbolItem::Alias { alias, resolved } => { - // All aliases should've been resolved by now - let resolved = resolved.get().unwrap_or_else(|| { - panic!("unresolved alias {symbol_path} targeting: {}", alias.target()) - }); - return self.export_symbol(resolved, module_kind, symbol_path, mast_forest_builder); + if let Some(resolved) = resolved.get() { + return self.export_symbol( + resolved, + module_kind, + symbol_path, + mast_forest_builder, + ); + } + + let Some(ResolvedProcedure { node, signature }) = self.resolve_target( + InvokeKind::ProcRef, + &alias.target().into(), + gid, + mast_forest_builder, + )? + else { + return Err(self.unresolved_alias_report("export", &symbol_path, alias)); + }; + + let digest = mast_forest_builder + .get_mast_node(node) + .expect("resolved alias export node must exist") + .digest(); + let pctx = ProcedureContext::new( + gid, + /* is_program_entrypoint= */ false, + symbol_path.clone(), + Visibility::Public, + signature.clone(), + module_kind.is_kernel(), + self.source_manager.clone(), + ); + let procedure = pctx.into_procedure(digest, node); + self.linker.register_procedure_root(gid, digest)?; + mast_forest_builder.insert_procedure(gid, procedure)?; + + return Ok(LibraryExport::Procedure(ProcedureExport { + node, + path: symbol_path, + signature: signature.map(Arc::unwrap_or_clone), + attributes: Default::default(), + })); }, }; @@ -815,8 +895,7 @@ impl Assembler { self.apply_debug_options(&mut mast_forest); let mast = Arc::new(mast_forest); - let entry: Arc = - ast::Path::exec_path().join(ast::ProcedureName::MAIN_PROC_NAME).into(); + let entry: Arc = Path::exec_path().join(ast::ProcedureName::MAIN_PROC_NAME).into(); let entrypoint = LibraryExport::Procedure(ProcedureExport { node: entrypoint, path: entry.clone(), @@ -965,26 +1044,34 @@ impl Assembler { mast_forest_builder.insert_procedure(procedure_gid, procedure)?; }, SymbolItem::Alias { alias, resolved } => { - let procedure_gid = resolved.get().expect("resolved alias"); - match self.linker[procedure_gid].item() { - SymbolItem::Procedure(_) | SymbolItem::Compiled(ItemInfo::Procedure(_)) => { + let path: Arc = module_path.join(alias.name().as_str()).into(); + let procedure_gid = match resolved.get() { + Some(procedure_gid) => { + match self.linker[procedure_gid].item() { + SymbolItem::Procedure(_) + | SymbolItem::Compiled(ItemInfo::Procedure(_)) => {}, + SymbolItem::Constant(_) + | SymbolItem::Type(_) + | SymbolItem::Compiled(_) => { + continue; + }, + // A resolved alias will always refer to a non-alias item, this is + // because when aliases are resolved, they are resolved + // recursively. Had the alias chain been cyclical, we would have + // raised an error already. + SymbolItem::Alias { .. } => unreachable!(), + } + procedure_gid }, - SymbolItem::Constant(_) | SymbolItem::Type(_) | SymbolItem::Compiled(_) => { - continue; - }, - // A resolved alias will always refer to a non-alias item, this is because - // when aliases are resolved, they are resolved recursively. Had the alias - // chain been cyclical, we would have raised an error already. - SymbolItem::Alias { .. } => unreachable!(), - } - let path = module_path.join(alias.name().as_str()).into(); + None => procedure_gid, + }; // A program entrypoint is never an alias let is_program_entrypoint = false; let mut pctx = ProcedureContext::new( procedure_gid, is_program_entrypoint, path, - ast::Visibility::Public, + Visibility::Public, None, module_kind.is_kernel(), self.source_manager.clone(), @@ -1025,6 +1112,30 @@ impl Assembler { Ok(()) } + fn unresolved_alias_report( + &self, + action: &'static str, + symbol_path: &Path, + alias: &ast::Alias, + ) -> Report { + let span = alias.target().span(); + let reason = match alias.target() { + ast::AliasTarget::MastRoot(_) => { + "this digest target does not resolve to a known procedure" + }, + ast::AliasTarget::Path(_) => "this alias target does not resolve to a concrete item", + }; + + RelatedLabel::error(format!( + "unable to {action} alias '{symbol_path}' targeting '{}'", + alias.target() + )) + .with_labeled_span(span, reason) + .with_help("aliases must resolve to a concrete item before they can be used") + .with_source_file(self.source_manager.get(span.source_id()).ok()) + .into() + } + /// Compiles a single Miden Assembly procedure to its MAST representation. fn compile_procedure( &self, @@ -1357,10 +1468,16 @@ impl Assembler { let resolved = self.linker.resolve_invoke_target(&caller, target)?; match resolved { SymbolResolution::MastRoot(mast_root) => { + // Literal MAST-root references in MASM do not carry any source-level provenance, + // so there is no exact source root or source package commitment to thread through + // here. We could try to guess based on linked libraries, but any such heuristic + // would be ambiguous when multiple procedures share the same digest. let node = self.ensure_valid_procedure_mast_root( kind, target.span(), mast_root.into_inner(), + None, + None, mast_forest_builder, )?; Ok(Some(ResolvedProcedure { node, signature: None })) @@ -1379,6 +1496,8 @@ impl Assembler { kind, target.span(), p.digest, + p.source_library_commitment(), + p.source_root_id(), mast_forest_builder, )?; Ok(Some(ResolvedProcedure { node, signature: p.signature.clone() })) @@ -1410,6 +1529,8 @@ impl Assembler { kind: InvokeKind, span: SourceSpan, mast_root: Word, + source_library_commitment: Option, + source_root_id: Option, mast_forest_builder: &mut MastForestBuilder, ) -> Result { // Get the procedure from the assembler @@ -1435,7 +1556,11 @@ impl Assembler { } } - mast_forest_builder.ensure_external_link(mast_root) + mast_forest_builder.ensure_external_link_with_source( + mast_root, + source_library_commitment, + source_root_id, + ) } } diff --git a/crates/assembly/src/assembler/error.rs b/crates/assembly/src/assembler/error.rs index 70fbee4603..c8c000e215 100644 --- a/crates/assembly/src/assembler/error.rs +++ b/crates/assembly/src/assembler/error.rs @@ -1,6 +1,7 @@ use alloc::sync::Arc; use miden_assembly_syntax::{ + Path, debuginfo::{SourceFile, SourceSpan}, diagnostics::{Diagnostic, miette}, }; @@ -16,4 +17,7 @@ pub(super) enum AssemblerError { source_file: Option>, max_depth: usize, }, + #[error("duplicate definition found for export path '{path}'")] + #[diagnostic()] + DuplicateExportPath { path: Arc }, } diff --git a/crates/assembly/src/assembler/product.rs b/crates/assembly/src/assembler/product.rs index 89c46c93cc..e9a3e5fa9f 100644 --- a/crates/assembly/src/assembler/product.rs +++ b/crates/assembly/src/assembler/product.rs @@ -51,7 +51,7 @@ impl AssemblyProduct { // TODO(pauls): This can be removed when we remove Library/KernelLibrary/Program pub fn into_program(self) -> Result { assert_eq!(self.kind, TargetType::Executable); - let entry = ast::Path::exec_path().join(ast::ProcedureName::MAIN_PROC_NAME); + let entry = Path::exec_path().join(ast::ProcedureName::MAIN_PROC_NAME); let entrypoint = self.artifact.get_export_node_id(&entry); Ok(if let Some(kernel) = self.kernel { Program::with_kernel(self.artifact.mast_forest().clone(), entrypoint, kernel) diff --git a/crates/assembly/src/instruction/adv_ops.rs b/crates/assembly/src/instruction/adv_ops.rs deleted file mode 100644 index fe21617cfa..0000000000 --- a/crates/assembly/src/instruction/adv_ops.rs +++ /dev/null @@ -1,39 +0,0 @@ -use miden_assembly_syntax::{ - debuginfo::SourceSpan, - diagnostics::{RelatedLabel, Report}, -}; -use miden_core::operations::Operation; - -use super::BasicBlockBuilder; -use crate::{ADVICE_READ_LIMIT, ProcedureContext}; - -// NON-DETERMINISTIC (ADVICE) INPUTS -// ================================================================================================ - -/// Appends the number of ADVPOP operations specified by the instruction's immediate value to the -/// span. This pops the specified number of elements from the advice stack and pushes them onto the -/// operand stack. -/// -/// # Errors -/// Returns an error if the specified number of values to pushed is smaller than 1 or greater -/// than 16. -pub fn adv_push( - block_builder: &mut BasicBlockBuilder, - proc_ctx: &ProcedureContext, - n: u8, - span: SourceSpan, -) -> Result<(), Report> { - let min = 1; - let max = ADVICE_READ_LIMIT; - - if n < min || n > max { - return Err(RelatedLabel::error("invalid argument") - .with_labeled_span(span, "this instruction argument is out of range") - .with_help(format!("value must be in the range {min}..={max}")) - .with_source_file(proc_ctx.source_manager().get(span.source_id()).ok()) - .into()); - } - - block_builder.push_op_many(Operation::AdvPop, n as usize); - Ok(()) -} diff --git a/crates/assembly/src/instruction/field_ops.rs b/crates/assembly/src/instruction/field_ops.rs index d67d7d3396..3756f9dcea 100644 --- a/crates/assembly/src/instruction/field_ops.rs +++ b/crates/assembly/src/instruction/field_ops.rs @@ -9,7 +9,7 @@ use super::BasicBlockBuilder; use crate::{MAX_EXP_BITS, ONE, ProcedureContext, ZERO}; /// Field element representing TWO in the base field of the VM. -const TWO: Felt = Felt::new(2); +const TWO: Felt = Felt::new_unchecked(2); // ASSERTIONS // ================================================================================================ diff --git a/crates/assembly/src/instruction/mod.rs b/crates/assembly/src/instruction/mod.rs index e9761e04c4..efdb971ab7 100644 --- a/crates/assembly/src/instruction/mod.rs +++ b/crates/assembly/src/instruction/mod.rs @@ -17,7 +17,6 @@ use crate::{ push_value_ops, }; -mod adv_ops; mod crypto_ops; mod debug; mod env_ops; @@ -383,8 +382,10 @@ impl Assembler { Instruction::Caller => env_ops::caller(block_builder), Instruction::Clk => block_builder.push_op(Clk), Instruction::AdvPipe => block_builder.push_op(Pipe), - Instruction::AdvPush(n) => { - adv_ops::adv_push(block_builder, proc_ctx, n.expect_value(), n.span())? + Instruction::AdvPush => block_builder.push_op(AdvPop), + Instruction::AdvPushW => { + block_builder.push_ops([Pad; 4]); + block_builder.push_op(AdvPopW); }, Instruction::AdvLoadW => block_builder.push_op(AdvPopW), @@ -606,16 +607,12 @@ impl Assembler { // ----- emit instruction ------------------------------------------------------------- // emit: reads event ID from top of stack and execute the corresponding handler. Instruction::Emit => { - block_builder.push_ops([Operation::Emit]); + block_builder.push_ops([Emit]); }, // emit.: expands to `push., emit, drop` sequence leaving the stack unchanged. Instruction::EmitImm(event_id) => { let event_id_value = event_id.expect_value(); - block_builder.push_ops([ - Operation::Push(event_id_value), - Operation::Emit, - Operation::Drop, - ]); + block_builder.push_ops([Push(event_id_value), Emit, Drop]); }, // ----- trace instruction ------------------------------------------------------------ diff --git a/crates/assembly/src/instruction/procedures.rs b/crates/assembly/src/instruction/procedures.rs index b28fb707b5..94b565b593 100644 --- a/crates/assembly/src/instruction/procedures.rs +++ b/crates/assembly/src/instruction/procedures.rs @@ -34,7 +34,7 @@ impl Assembler { ) -> Result { let resolved = self .resolve_target(kind, callee, caller, mast_forest_builder)? - .expect("invocation target is not a procedure"); + .ok_or_else(|| self.invalid_invoke_target_report(kind, callee, caller))?; match kind { InvokeKind::ProcRef | InvokeKind::Exec => Ok(resolved.node), @@ -101,7 +101,9 @@ impl Assembler { caller, block_builder.mast_forest_builder_mut(), )? - .expect("invocation target is not a procedure"); + .ok_or_else(|| { + self.invalid_invoke_target_report(InvokeKind::ProcRef, callee, caller) + })?; // Note: it's ok to `unwrap()` here since `proc_body_id` was returned from // `mast_forest_builder` block_builder diff --git a/crates/assembly/src/instruction/u32_ops.rs b/crates/assembly/src/instruction/u32_ops.rs index 533edbc0f4..9bb91c82d8 100644 --- a/crates/assembly/src/instruction/u32_ops.rs +++ b/crates/assembly/src/instruction/u32_ops.rs @@ -340,14 +340,14 @@ pub fn u32rotr( .with_source_file(proc_ctx.source_manager().get(span.source_id()).ok()) .into()); } - span_builder.push_op(Push(Felt::new(1 << (32 - imm)))); + span_builder.push_op(Push(Felt::new_unchecked(1 << (32 - imm)))); span_builder.push_ops([U32mul, Add]); }, None => { // Compute 32 - b, where b is rotation amount on top of stack // Stack: [b, ...], push 32 to get [32, b, ...], swap to get [b, 32, ...] // U32sub computes second - top = 32 - b - span_builder.push_ops([Push(Felt::new(32)), Swap, U32sub, Drop]); + span_builder.push_ops([Push(Felt::new_unchecked(32)), Swap, U32sub, Drop]); append_pow2_op(span_builder); span_builder.push_ops([Mul, U32split, Add]); }, @@ -365,33 +365,33 @@ pub fn u32popcnt(span_builder: &mut BasicBlockBuilder) { // U32div computes second/top. Stack: [i, ...], push 2 to get [2, i, ...]. // U32div gives i/2. Output [remainder, quotient], drop remainder to keep quotient. Dup0, - Push(Felt::new(1 << 1)), U32div, Drop, - Push(Felt::new(0x55555555)), + Push(Felt::new_unchecked(1 << 1)), U32div, Drop, + Push(Felt::new_unchecked(0x55555555)), U32and, // U32sub computes second - top. Stack: [masked, i], gives i - masked U32sub, Drop, // i = (i & 0x33333333) + ((i >> 2) & 0x33333333); Dup0, - Push(Felt::new(1 << 2)), U32div, Drop, - Push(Felt::new(0x33333333)), + Push(Felt::new_unchecked(1 << 2)), U32div, Drop, + Push(Felt::new_unchecked(0x33333333)), U32and, Swap, - Push(Felt::new(0x33333333)), + Push(Felt::new_unchecked(0x33333333)), U32and, // U32add outputs [sum, carry], swap to drop carry and keep sum U32add, Swap, Drop, // i = (i + (i >> 4)) & 0x0F0F0F0F; Dup0, - Push(Felt::new(1 << 4)), U32div, Drop, + Push(Felt::new_unchecked(1 << 4)), U32div, Drop, // U32add outputs [sum, carry], swap to drop carry and keep sum U32add, Swap, Drop, - Push(Felt::new(0x0F0F0F0F)), + Push(Felt::new_unchecked(0x0F0F0F0F)), U32and, // return (i * 0x01010101) >> 24; // U32mul outputs [lo, hi], swap before drop to keep lo - Push(Felt::new(0x01010101)), + Push(Felt::new_unchecked(0x01010101)), U32mul, Swap, Drop, - Push(Felt::new(1 << 24)), U32div, Drop + Push(Felt::new_unchecked(1 << 24)), U32div, Drop ]; span_builder.push_ops(ops); } @@ -523,7 +523,7 @@ fn prepare_bitwise( .with_source_file(proc_ctx.source_manager().get(span.source_id()).ok()) .into()); } - block_builder.push_op(Push(Felt::new(1 << imm))); + block_builder.push_op(Push(Felt::new_unchecked(1 << imm))); }, None => { append_pow2_op(block_builder); diff --git a/crates/assembly/src/lib.rs b/crates/assembly/src/lib.rs index 07e4667ec0..0a50edd256 100644 --- a/crates/assembly/src/lib.rs +++ b/crates/assembly/src/lib.rs @@ -54,10 +54,6 @@ pub use self::{ // CONSTANTS // ================================================================================================ -/// The maximum number of elements that can be popped from the advice stack in a single `adv_push` -/// instruction. -const ADVICE_READ_LIMIT: u8 = 16; - /// The maximum number of bits by which a u32 value can be shifted in a bitwise operation. const MAX_U32_SHIFT_VALUE: u8 = 31; diff --git a/crates/assembly/src/linker/callgraph.rs b/crates/assembly/src/linker/callgraph.rs index 1bb6c32b4f..d1c8a47011 100644 --- a/crates/assembly/src/linker/callgraph.rs +++ b/crates/assembly/src/linker/callgraph.rs @@ -11,6 +11,10 @@ use crate::GlobalItemIndex; pub struct CycleError(BTreeSet); impl CycleError { + pub fn new(nodes: impl IntoIterator) -> Self { + Self(nodes.into_iter().collect()) + } + pub fn into_node_ids(self) -> impl ExactSizeIterator { self.0.into_iter() } @@ -42,7 +46,7 @@ pub struct CallGraph { impl CallGraph { /// Gets the set of edges from the given caller to its callees in the graph. pub fn out_edges(&self, gid: GlobalItemIndex) -> &[GlobalItemIndex] { - self.nodes.get(&gid).map(|out_edges| out_edges.as_slice()).unwrap_or(&[]) + self.nodes.get(&gid).map(Vec::as_slice).unwrap_or(&[]) } /// Inserts a node in the graph for `id`, if not already present. @@ -60,11 +64,15 @@ impl CallGraph { /// introduce a cycle, or that [Self::toposort] is run once the graph is built, in order to /// verify that the graph is valid and has no cycles. /// - /// NOTE: This function will panic if you attempt to add an edge from a function to itself, - /// which trivially introduces a cycle. All other cycle-inducing edges must be caught by a - /// call to [Self::toposort]. - pub fn add_edge(&mut self, caller: GlobalItemIndex, callee: GlobalItemIndex) { - assert_ne!(caller, callee, "a procedure cannot call itself"); + /// Returns an error if adding the edge would introduce a trivial self-cycle. + pub fn add_edge( + &mut self, + caller: GlobalItemIndex, + callee: GlobalItemIndex, + ) -> Result<(), CycleError> { + if caller == callee { + return Err(CycleError::new([caller])); + } // Make sure the callee is in the graph self.get_or_insert_node(callee); @@ -72,10 +80,11 @@ impl CallGraph { let callees = self.get_or_insert_node(caller); // If the caller already references the callee, we're done if callees.contains(&callee) { - return; + return Ok(()); } callees.push(callee); + Ok(()) } /// Removes the edge between `caller` and `callee` from the graph @@ -93,64 +102,59 @@ impl CallGraph { /// Construct the topological ordering of all nodes in the call graph. /// + /// Uses Kahn's algorithm with pre-computed in-degrees for O(V + E) complexity. + /// /// Returns `Err` if a cycle is detected in the graph pub fn toposort(&self) -> Result, CycleError> { if self.nodes.is_empty() { return Ok(vec![]); } - let mut output = Vec::with_capacity(self.nodes.len()); - let mut graph = self.clone(); + let num_nodes = self.nodes.len(); + let mut output = Vec::with_capacity(num_nodes); - // Build the set of roots by finding all nodes - // that have no predecessors - let mut has_preds = BTreeSet::default(); - for (_node, out_edges) in graph.nodes.iter() { - for succ in out_edges.iter() { - has_preds.insert(*succ); + // Compute in-degree for each node: O(V + E) + let mut in_degree: BTreeMap = + self.nodes.keys().map(|&k| (k, 0)).collect(); + for out_edges in self.nodes.values() { + for &succ in out_edges { + *in_degree.entry(succ).or_default() += 1; } } - let mut roots = - VecDeque::from_iter(graph.nodes.keys().copied().filter(|n| !has_preds.contains(n))); - - // If all nodes have predecessors, there must be a cycle, so just pick a node and let the - // algorithm find the cycle for that node so we have a useful error. Set a flag so that we - // can assert that the cycle was actually found as a sanity check - let mut expect_cycle = false; - if roots.is_empty() { - expect_cycle = true; - roots.extend(graph.nodes.keys().next()); - } - let mut successors = Vec::with_capacity(4); - while let Some(id) = roots.pop_front() { + // Seed the queue with all zero-in-degree nodes: O(V) + let mut queue: VecDeque = + in_degree.iter().filter(|&(_, °)| deg == 0).map(|(&n, _)| n).collect(); + + // Kahn's algorithm: process each node exactly once, each edge exactly once → O(V + E) + while let Some(id) = queue.pop_front() { output.push(id); - successors.clear(); - successors.extend(graph.nodes[&id].iter().copied()); - for mid in successors.drain(..) { - graph.remove_edge(id, mid); - if graph.num_predecessors(mid) == 0 { - roots.push_back(mid); + for &mid in self.out_edges(id) { + let deg = in_degree.get_mut(&mid).unwrap(); + *deg -= 1; + if *deg == 0 { + queue.push_back(mid); } } } - let has_cycle = graph - .nodes - .iter() - .any(|(n, out_edges)| !output.contains(n) || !out_edges.is_empty()); - if has_cycle { + // If not all nodes were visited, the remaining nodes participate in cycles + if output.len() != num_nodes { + let visited: BTreeSet = output.iter().copied().collect(); let mut in_cycle = BTreeSet::default(); - for (n, edges) in graph.nodes.iter() { - if edges.is_empty() { + for (&n, out_edges) in self.nodes.iter() { + if visited.contains(&n) { continue; } - in_cycle.insert(*n); - in_cycle.extend(edges.as_slice()); + in_cycle.insert(n); + for &succ in out_edges { + if !visited.contains(&succ) { + in_cycle.insert(succ); + } + } } Err(CycleError(in_cycle)) } else { - assert!(!expect_cycle, "we expected a cycle to be found, but one was not identified"); Ok(output) } } @@ -176,52 +180,111 @@ impl CallGraph { graph } + /// Computes the set of nodes in this graph which can reach `root`. + fn reverse_reachable(&self, root: GlobalItemIndex) -> BTreeSet { + // Build reverse adjacency map: O(V + E) + let mut predecessors: BTreeMap> = + self.nodes.keys().map(|&k| (k, Vec::new())).collect(); + for (&node, out_edges) in self.nodes.iter() { + for &succ in out_edges { + predecessors.entry(succ).or_default().push(node); + } + } + + // BFS on reverse graph: O(V + E) + let mut worklist = VecDeque::from_iter([root]); + let mut visited = BTreeSet::default(); + + while let Some(gid) = worklist.pop_front() { + if !visited.insert(gid) { + continue; + } + + if let Some(preds) = predecessors.get(&gid) { + worklist.extend(preds.iter().copied()); + } + } + + visited + } + /// Constructs the topological ordering of nodes in the call graph, for which `caller` is an /// ancestor. /// + /// Uses Kahn's algorithm with pre-computed in-degrees for O(V + E) complexity. + /// /// # Errors /// Returns an error if a cycle is detected in the graph. pub fn toposort_caller( &self, caller: GlobalItemIndex, ) -> Result, CycleError> { - let mut output = Vec::with_capacity(self.nodes.len()); - // Build a subgraph of `self` containing only those nodes reachable from `caller` - let mut graph = self.subgraph(caller); + let subgraph = self.subgraph(caller); + let num_nodes = subgraph.nodes.len(); + let mut output = Vec::with_capacity(num_nodes); + + // Compute in-degree for each node in the subgraph: O(V + E) + let mut in_degree: BTreeMap = + subgraph.nodes.keys().map(|&k| (k, 0)).collect(); + for out_edges in subgraph.nodes.values() { + for &succ in out_edges { + *in_degree.entry(succ).or_default() += 1; + } + } + + // Check if any cycle closes back to `caller` (i.e. caller has predecessors in its + // own reachable subgraph) + let caller_has_predecessors = in_degree.get(&caller).copied().unwrap_or(0) > 0; - // Remove all predecessor edges to `caller` - graph.nodes.iter_mut().for_each(|(_pred, out_edges)| { - out_edges.retain(|n| *n != caller); - }); + // Force `caller` as the root by zeroing its in-degree (equivalent to removing + // all back-edges to `caller`) + in_degree.insert(caller, 0); - let mut roots = VecDeque::from_iter([caller]); - let mut successors = Vec::with_capacity(4); - while let Some(id) = roots.pop_front() { + // Seed queue with `caller` as the sole root + let mut queue = VecDeque::from_iter([caller]); + + // Kahn's algorithm: O(V + E) + while let Some(id) = queue.pop_front() { output.push(id); - successors.clear(); - successors.extend(graph.nodes[&id].iter().copied()); - for mid in successors.drain(..) { - graph.remove_edge(id, mid); - if graph.num_predecessors(mid) == 0 { - roots.push_back(mid); + for &mid in subgraph.out_edges(id) { + // Skip back-edges to caller (already processed as root) + if mid == caller { + continue; + } + let deg = in_degree.get_mut(&mid).unwrap(); + *deg -= 1; + if *deg == 0 { + queue.push_back(mid); } } } - let has_cycle = graph - .nodes - .iter() - .any(|(n, out_edges)| output.contains(n) && !out_edges.is_empty()); + // Detect cycles: either caller had predecessors in its subgraph (a cycle closes + // back to it), or not all nodes were reachable (an internal cycle) + let has_cycle = caller_has_predecessors || output.len() != num_nodes; if has_cycle { + let visited: BTreeSet = output.iter().copied().collect(); let mut in_cycle = BTreeSet::default(); - for (n, edges) in graph.nodes.iter() { - if edges.is_empty() { - continue; + + // Collect nodes not processed by the sort (they're in internal cycles) + for (&n, out_edges) in subgraph.nodes.iter() { + if !visited.contains(&n) { + in_cycle.insert(n); + for &succ in out_edges { + if !visited.contains(&succ) { + in_cycle.insert(succ); + } + } } - in_cycle.insert(*n); - in_cycle.extend(edges.as_slice()); } + + // If caller has back-edges, include all nodes participating in the cycle + // through caller + if caller_has_predecessors { + in_cycle.extend(subgraph.reverse_reachable(caller)); + } + Err(CycleError(in_cycle)) } else { Ok(output) @@ -326,6 +389,53 @@ mod tests { assert_eq!(err.0.into_iter().collect::>(), &[A2, A3, B2, B3]); } + #[test] + fn callgraph_toposort_caller_with_reachable_cycle() { + let graph = callgraph_cycle(); + + let err = graph + .toposort_caller(A1) + .expect_err("expected toposort_caller to fail when a reachable cycle exists"); + assert_eq!(err.0.into_iter().collect::>(), &[A2, A3, B2, B3]); + } + + #[test] + fn callgraph_toposort_caller_root_closing_cycle() { + let graph = callgraph_cycle(); + + let err = graph + .toposort_caller(A2) + .expect_err("expected toposort_caller to detect cycle closing back into root"); + assert_eq!(err.0.into_iter().collect::>(), &[A2, A3, B2, B3]); + } + + #[test] + fn callgraph_add_edge_with_self_cycle_is_error() { + let mut graph = CallGraph::default(); + + let err = graph.add_edge(A1, A1).expect_err("expected self-edge to be rejected"); + assert_eq!(err.0.into_iter().collect::>(), &[A1]); + } + + #[test] + fn callgraph_rootless_cycle_toposort_is_error() { + let mut graph = CallGraph::default(); + graph.add_edge(A1, B1).expect("A1 -> B1 must be accepted"); + graph.add_edge(B1, A1).expect("B1 -> A1 must be accepted"); + + let err = graph.toposort().expect_err("expected topological sort to fail with cycle"); + assert_eq!(err.0.into_iter().collect::>(), &[A1, B1]); + } + + #[test] + fn callgraph_toposort_whole_graph_cycle_without_roots() { + let graph = callgraph_cycle_without_roots(); + let err = graph.toposort().expect_err( + "expected topological sort to fail when every node is blocked behind a cycle", + ); + assert_eq!(err.0.into_iter().collect::>(), &[A1, A2, A3]); + } + /// a::a1 -> a::a2 -> a::a3 /// | ^ /// v | @@ -333,12 +443,12 @@ mod tests { fn callgraph_simple() -> CallGraph { // Construct the graph let mut graph = CallGraph::default(); - graph.add_edge(A1, A2); - graph.add_edge(B1, B2); - graph.add_edge(A2, B2); - graph.add_edge(A2, A3); - graph.add_edge(B2, B3); - graph.add_edge(B3, A3); + graph.add_edge(A1, A2).expect("A1 -> A2 must be accepted"); + graph.add_edge(B1, B2).expect("B1 -> B2 must be accepted"); + graph.add_edge(A2, B2).expect("A2 -> B2 must be accepted"); + graph.add_edge(A2, A3).expect("A2 -> A3 must be accepted"); + graph.add_edge(B2, B3).expect("B2 -> B3 must be accepted"); + graph.add_edge(B3, A3).expect("B3 -> A3 must be accepted"); graph } @@ -350,12 +460,26 @@ mod tests { fn callgraph_cycle() -> CallGraph { // Construct the graph let mut graph = CallGraph::default(); - graph.add_edge(A1, A2); - graph.add_edge(B1, B2); - graph.add_edge(A2, B2); - graph.add_edge(B2, B3); - graph.add_edge(B3, A3); - graph.add_edge(A3, A2); + graph.add_edge(A1, A2).expect("A1 -> A2 must be accepted"); + graph.add_edge(B1, B2).expect("B1 -> B2 must be accepted"); + graph.add_edge(A2, B2).expect("A2 -> B2 must be accepted"); + graph.add_edge(B2, B3).expect("B2 -> B3 must be accepted"); + graph.add_edge(B3, A3).expect("B3 -> A3 must be accepted"); + graph.add_edge(A3, A2).expect("A3 -> A2 must be accepted"); + + graph + } + + /// a::a1 -> a::a2 -> a::a3 + /// ^ | + /// +-----------------+ + /// + /// Every node has in-degree 1, so Kahn's algorithm starts with an empty queue. + fn callgraph_cycle_without_roots() -> CallGraph { + let mut graph = CallGraph::default(); + graph.add_edge(A1, A2).expect("A1 -> A2 must be accepted"); + graph.add_edge(A2, A3).expect("A2 -> A3 must be accepted"); + graph.add_edge(A3, A1).expect("A3 -> A1 must be accepted"); graph } diff --git a/crates/assembly/src/linker/errors.rs b/crates/assembly/src/linker/errors.rs index c87d87a75c..b3a028c89c 100644 --- a/crates/assembly/src/linker/errors.rs +++ b/crates/assembly/src/linker/errors.rs @@ -44,6 +44,16 @@ pub enum LinkerError { #[error("duplicate definition found for module '{path}'")] #[diagnostic()] DuplicateModule { path: Arc }, + #[error("ambiguous module path resolution for '{path}'")] + #[diagnostic(help("matching module prefixes: {}", matches.join(", ")))] + AmbiguousModulePath { + #[label] + span: SourceSpan, + #[source_code] + source_file: Option>, + path: Arc, + matches: Box<[String]>, + }, #[error("undefined module '{path}'")] #[diagnostic()] UndefinedModule { @@ -73,6 +83,15 @@ pub enum LinkerError { source_file: Option>, callee: Arc, }, + #[error("kernel procedure '{callee}' can only be invoked via syscall")] + #[diagnostic()] + KernelProcNotSyscall { + #[label("non-syscall reference to kernel procedure")] + span: SourceSpan, + #[source_code] + source_file: Option>, + callee: Arc, + }, #[error("invalid procedure reference: path refers to a non-procedure item")] #[diagnostic()] InvalidInvokeTarget { diff --git a/crates/assembly/src/linker/mod.rs b/crates/assembly/src/linker/mod.rs index 8962ebe95c..9ede61fe5d 100644 --- a/crates/assembly/src/linker/mod.rs +++ b/crates/assembly/src/linker/mod.rs @@ -288,7 +288,7 @@ impl Linker { .into_iter() .enumerate() .map(|(idx, item)| { - let gid = module_index + ast::ItemIndex::new(idx); + let gid = module_index + ItemIndex::new(idx); self.callgraph.get_or_insert_node(gid); Symbol::new( item.name().clone(), @@ -398,6 +398,17 @@ impl Linker { // ------------------------------------------------------------------------------------------------ /// Analysis impl Linker { + fn cycle_error(&self, cycle: CycleError) -> LinkerError { + let iter = cycle.into_node_ids(); + let mut nodes = Vec::with_capacity(iter.len()); + for node in iter { + let module = self[node.module].path(); + let item = self[node].name(); + nodes.push(module.join(item).to_string()); + } + LinkerError::Cycle { nodes: nodes.into() } + } + /// Links `modules` using the current state of the linker. /// /// Returns the module indices corresponding to the provided modules, which are expected to @@ -424,7 +435,18 @@ impl Linker { &mut self, mut kernel: Box, ) -> Result, LinkerError> { + let original_module_len = self.modules.len(); + let original_callgraph = self.callgraph.clone(); let module_index = self.link_module(&mut kernel)?; + let original_kernel_index = self.kernel_index; + let original_module_kinds = self + .modules + .iter() + .enumerate() + .take(module_index.as_usize()) + .filter(|(_, module)| matches!(module.source(), ModuleSource::Ast)) + .map(|(module_index, module)| (module_index, module.kind())) + .collect::>(); // Set the module kind of all pending AST modules to Kernel, as we are linking a kernel for module in self.modules.iter_mut().take(module_index.as_usize()) { @@ -435,7 +457,16 @@ impl Linker { self.kernel_index = Some(module_index); - self.link_and_rewrite()?; + if let Err(err) = self.link_and_rewrite() { + self.kernel_index = original_kernel_index; + self.callgraph = original_callgraph; + self.modules.truncate(original_module_len); + for (module_index, module_kind) in original_module_kinds { + self.modules[module_index].set_kind(module_kind); + } + + return Err(err); + } Ok(vec![module_index]) } @@ -492,112 +523,130 @@ impl Linker { } // If no changes are being made, we're done - if self.modules.iter().all(|m| m.is_linked()) { + if self.modules.iter().all(LinkModule::is_linked) { return Ok(()); } // Obtain a set of resolvers for the pending modules so that we can do name resolution // before they are added to the graph - let resolver = SymbolResolver::new(self); - let mut edges = Vec::new(); - let mut cache = ResolverCache::default(); - - for (module_index, module) in self.modules.iter().enumerate() { - if !module.is_unlinked() { - continue; - } - - let module_index = ModuleIndex::new(module_index); + let pending_modules = self + .modules + .iter() + .enumerate() + .filter(|(_, module)| module.is_unlinked()) + .map(|(module_index, module)| (module_index, module.clone())) + .collect::>(); + let original_callgraph = self.callgraph.clone(); + + let result = { + let resolver = SymbolResolver::new(self); + let mut edges = Vec::new(); + let mut cache = ResolverCache::default(); + let mut linked_modules = Vec::new(); + + for (module_index, module) in self.modules.iter().enumerate() { + if !module.is_unlinked() { + continue; + } - for (symbol_idx, symbol) in module.symbols().enumerate() { - assert!( - symbol.is_unlinked(), - "an unlinked module should only have unlinked symbols" - ); + let module_index = ModuleIndex::new(module_index); - let gid = module_index + ItemIndex::new(symbol_idx); + for (symbol_idx, symbol) in module.symbols().enumerate() { + let gid = module_index + ItemIndex::new(symbol_idx); - // Perform any applicable rewrites to this item - rewrites::rewrite_symbol(gid, symbol, &resolver, &mut cache)?; + // Perform any applicable rewrites to this item + rewrites::rewrite_symbol(gid, symbol, &resolver, &mut cache)?; - // Update the linker graph - match symbol.item() { - SymbolItem::Compiled(_) | SymbolItem::Type(_) | SymbolItem::Constant(_) => (), - SymbolItem::Alias { alias, resolved } => { - if let Some(resolved) = resolved.get() { - log::debug!(target: "linker", " | resolved alias {} to item {resolved}", alias.target()); - if self[resolved].is_procedure() { - edges.push((gid, resolved)); - } - } else { - log::debug!(target: "linker", " | resolving alias {}..", alias.target()); - - let context = SymbolResolutionContext { - span: alias.target().span(), - module: module_index, - kind: None, - }; - if let Some(callee) = - resolver.resolve_alias_target(&context, alias)?.into_global_id() - { - log::debug!( - target: "linker", - " | resolved alias to gid {:?}:{:?}", - callee.module, - callee.index - ); - edges.push((gid, callee)); - resolved.set(Some(callee)); + // Update the linker graph + match symbol.item() { + SymbolItem::Compiled(_) | SymbolItem::Type(_) | SymbolItem::Constant(_) => { + }, + SymbolItem::Alias { alias, resolved } => { + if let Some(resolved) = resolved.get() { + log::debug!(target: "linker", " | resolved alias {} to item {resolved}", alias.target()); + if self[resolved].is_procedure() { + edges.push((gid, resolved)); + } + } else { + log::debug!(target: "linker", " | resolving alias {}..", alias.target()); + + let context = SymbolResolutionContext { + span: alias.target().span(), + module: module_index, + kind: None, + }; + if let Some(callee) = + resolver.resolve_alias_target(&context, alias)?.into_global_id() + { + log::debug!( + target: "linker", + " | resolved alias to gid {:?}:{:?}", + callee.module, + callee.index + ); + edges.push((gid, callee)); + resolved.set(Some(callee)); + } } - } - }, - SymbolItem::Procedure(proc) => { - // Add edges to all transitive dependencies of this item due to calls/symbol - // refs - let proc = proc.borrow(); - for invoke in proc.invoked() { - log::debug!(target: "linker", " | recording {} dependency on {}", invoke.kind, &invoke.target); - - let context = SymbolResolutionContext { - span: invoke.span(), - module: module_index, - kind: None, - }; - if let Some(callee) = resolver - .resolve_invoke_target(&context, &invoke.target)? - .into_global_id() - { - log::debug!( - target: "linker", - " | resolved dependency to gid {}:{}", - callee.module.as_usize(), - callee.index.as_usize() - ); - edges.push((gid, callee)); + }, + SymbolItem::Procedure(proc) => { + // Add edges to all transitive dependencies of this item due to + // calls/symbol refs + let proc = proc.borrow(); + for invoke in proc.invoked() { + log::debug!(target: "linker", " | recording {} dependency on {}", invoke.kind, &invoke.target); + + let context = SymbolResolutionContext { + span: invoke.span(), + module: module_index, + kind: None, + }; + if let Some(callee) = resolver + .resolve_invoke_target(&context, &invoke.target)? + .into_global_id() + { + log::debug!( + target: "linker", + " | resolved dependency to gid {}:{}", + callee.module.as_usize(), + callee.index.as_usize() + ); + edges.push((gid, callee)); + } } - } - }, + }, + } } - } - module.set_status(LinkStatus::Linked); - } + linked_modules.push(module_index); + } - edges - .into_iter() - .for_each(|(caller, callee)| self.callgraph.add_edge(caller, callee)); - - // Make sure the graph is free of cycles - self.callgraph.toposort().map_err(|cycle| { - let iter = cycle.into_node_ids(); - let mut nodes = Vec::with_capacity(iter.len()); - for node in iter { - let module = self[node.module].path(); - let item = self[node].name(); - nodes.push(module.join(item).to_string()); + let mut callgraph = self.callgraph.clone(); + for (caller, callee) in edges { + callgraph.add_edge(caller, callee).map_err(|cycle| self.cycle_error(cycle))?; } - LinkerError::Cycle { nodes: nodes.into() } - })?; + + // Make sure the graph is free of cycles + callgraph.toposort().map_err(|cycle| self.cycle_error(cycle))?; + + Ok::<_, LinkerError>((linked_modules, callgraph)) + }; + + match result { + Ok((linked_modules, callgraph)) => { + self.callgraph = callgraph; + for module_index in linked_modules { + self.modules[module_index.as_usize()].set_status(LinkStatus::Linked); + } + }, + Err(err) => { + self.callgraph = original_callgraph; + for (module_index, module) in pending_modules { + self.modules[module_index] = module; + } + return Err(err); + }, + } Ok(()) } @@ -787,7 +836,7 @@ impl Linker { &self, span: SourceSpan, gid: GlobalItemIndex, - ) -> Result { + ) -> Result { use miden_assembly_syntax::ast::TypeResolver; let symbol_resolver = SymbolResolver::new(self); @@ -877,3 +926,147 @@ impl Index for Linker { &self.modules[index.module.as_usize()][index.index] } } + +#[cfg(test)] +mod tests { + use std::{ + panic::{AssertUnwindSafe, catch_unwind}, + string::String, + sync::Arc, + }; + + use miden_assembly_syntax::{ + ast::{ + Ident, InvocationTarget, InvokeKind, ItemIndex, Path, SymbolResolutionError, + Visibility, types, + }, + debuginfo::{SourceSpan, Span}, + library::{ItemInfo, TypeInfo}, + }; + + use super::*; + use crate::testing::{TestContext, source_file}; + + #[test] + fn failed_kernel_link_restores_kernel_state() { + let context = TestContext::default(); + let source_manager = context.source_manager(); + let kernel_source = r#" + pub proc a + call.b + end + + proc b + call.a + end + "#; + + let userspace = context + .parse_module_with_path( + "userspace", + source_file!( + &context, + r#" + pub proc helper + push.1 + end + "# + ), + ) + .expect("userspace module parsing must succeed"); + + let mut linker = Linker::new(source_manager); + let userspace_index = linker + .link([userspace]) + .expect("userspace module must link successfully") + .into_iter() + .next() + .expect("linked module index must be returned"); + + let first_err = linker + .link_kernel( + context + .parse_kernel(source_file!(&context, kernel_source)) + .expect("kernel parsing must succeed"), + ) + .expect_err("expected cyclic kernel to be rejected"); + + assert!(first_err.to_string().contains("found a cycle in the call graph")); + assert!(!linker.has_nonempty_kernel(), "failed kernel link must not leave a kernel set"); + assert_eq!(linker[userspace_index].kind(), ast::ModuleKind::Library); + + let second_err = linker + .link_kernel( + context + .parse_kernel(source_file!(&context, kernel_source)) + .expect("kernel parsing must succeed"), + ) + .expect_err("expected cyclic kernel retry to be rejected"); + assert!(second_err.to_string().contains("found a cycle in the call graph")); + assert!(!second_err.to_string().contains("duplicate module")); + + let syscall_context = SymbolResolutionContext { + span: SourceSpan::UNKNOWN, + module: userspace_index, + kind: Some(InvokeKind::SysCall), + }; + let err = linker + .resolve_invoke_target( + &syscall_context, + &InvocationTarget::Symbol(Ident::new("a").expect("valid identifier")), + ) + .expect_err("expected syscall without a linked kernel to be rejected"); + assert!(matches!(err, LinkerError::InvalidSysCallTarget { .. })); + } + + #[test] + fn oversized_link_module_resolution_returns_structured_error() { + let context = TestContext::default(); + let mut linker = Linker::new(context.source_manager()); + let module_id = ModuleIndex::new(0); + let path = Arc::::from(Path::new("::m::huge")); + let mut symbols = Vec::with_capacity(ItemIndex::MAX_ITEMS + 1); + + for i in 0..=ItemIndex::MAX_ITEMS { + let name = Ident::new(format!("a{i}")).expect("valid identifier"); + symbols.push(Symbol::new( + name.clone(), + Visibility::Private, + LinkStatus::Unlinked, + SymbolItem::Compiled(ItemInfo::Type(TypeInfo { name, ty: types::Type::Felt })), + )); + } + + linker.modules.push( + LinkModule::new( + module_id, + ast::ModuleKind::Library, + LinkStatus::Unlinked, + ModuleSource::Mast, + path, + ) + .with_symbols(symbols), + ); + + let result = catch_unwind(AssertUnwindSafe(|| { + linker[module_id].resolve(Span::unknown("a0"), &SymbolResolver::new(&linker)) + })); + + let result = match result { + Ok(result) => result, + Err(panic) => { + let message = panic + .downcast_ref::<&str>() + .copied() + .or_else(|| panic.downcast_ref::().map(String::as_str)) + .expect("panic payload should be a string"); + panic!("expected graceful error, got panic: {message}"); + }, + }; + + assert!(matches!( + result, + Err(err) if matches!(*err, SymbolResolutionError::TooManyItemsInModule { .. }) + )); + } +} diff --git a/crates/assembly/src/linker/module.rs b/crates/assembly/src/linker/module.rs index 75842b89c3..f0b0fd6ec4 100644 --- a/crates/assembly/src/linker/module.rs +++ b/crates/assembly/src/linker/module.rs @@ -4,10 +4,10 @@ use core::{cell::Cell, ops::Index}; use miden_assembly_syntax::{ Path, ast::{ - self, AliasTarget, ItemIndex, LocalSymbol, LocalSymbolResolver, ModuleIndex, ModuleKind, + AliasTarget, ItemIndex, LocalSymbol, LocalSymbolResolver, ModuleIndex, ModuleKind, SymbolResolution, SymbolResolutionError, SymbolTable, }, - debuginfo::{SourceManager, Span, Spanned}, + debuginfo::{SourceManager, SourceSpan, Span, Spanned}, }; use super::{AdviceMap, LinkStatus, Symbol, SymbolItem, SymbolResolver}; @@ -182,7 +182,8 @@ impl LinkModule { resolver: &SymbolResolver<'_>, ) -> Result> { let container = LinkModuleIter { resolver, module: self }; - let local_resolver = LocalSymbolResolver::new(container, resolver.source_manager_arc()); + let local_resolver = + LocalSymbolResolver::new(container, resolver.source_manager_arc()).map_err(Box::new)?; local_resolver.resolve(name).map_err(Box::new) } @@ -193,7 +194,8 @@ impl LinkModule { resolver: &SymbolResolver<'_>, ) -> Result> { let container = LinkModuleIter { resolver, module: self }; - let local_resolver = LocalSymbolResolver::new(container, resolver.source_manager_arc()); + let local_resolver = + LocalSymbolResolver::new(container, resolver.source_manager_arc()).map_err(Box::new)?; local_resolver.resolve_path(path).map_err(Box::new) } } @@ -230,7 +232,7 @@ impl<'a, 'b: 'a> SymbolTable for LinkModuleIter<'a, 'b> { | SymbolItem::Constant(_) | SymbolItem::Type(_) => { let path = self.module.path.join(symbol.name()); - ast::LocalSymbol::Item { + LocalSymbol::Item { name: symbol.name().clone(), resolved: SymbolResolution::Exact { gid, @@ -244,7 +246,7 @@ impl<'a, 'b: 'a> SymbolTable for LinkModuleIter<'a, 'b> { if let Some(resolved) = resolved.get() { let path = self.resolver.item_path(gid); let span = name.span(); - ast::LocalSymbol::Import { + LocalSymbol::Import { name, resolution: Ok(SymbolResolution::Exact { gid: resolved, @@ -253,7 +255,7 @@ impl<'a, 'b: 'a> SymbolTable for LinkModuleIter<'a, 'b> { } } else { match alias.target() { - AliasTarget::MastRoot(root) => ast::LocalSymbol::Import { + AliasTarget::MastRoot(root) => LocalSymbol::Import { name, resolution: Ok(SymbolResolution::MastRoot(*root)), }, @@ -270,7 +272,7 @@ impl<'a, 'b: 'a> SymbolTable for LinkModuleIter<'a, 'b> { path.as_deref(), &source_manager, ); - ast::LocalSymbol::Import { name, resolution } + LocalSymbol::Import { name, resolution } }, } } @@ -280,4 +282,21 @@ impl<'a, 'b: 'a> SymbolTable for LinkModuleIter<'a, 'b> { .collect::>(); symbols.into_iter() } + + fn checked_symbols( + &self, + source_manager: Arc, + ) -> Result { + if self.module.symbols.len() > ItemIndex::MAX_ITEMS { + let span = self + .module + .symbols + .first() + .map(|symbol| symbol.name().span()) + .unwrap_or(SourceSpan::UNKNOWN); + Err(SymbolResolutionError::too_many_items_in_module(span, &*source_manager)) + } else { + Ok(self.symbols(source_manager)) + } + } } diff --git a/crates/assembly/src/linker/resolver/mod.rs b/crates/assembly/src/linker/resolver/mod.rs index 78e433f028..6faf5eb467 100644 --- a/crates/assembly/src/linker/resolver/mod.rs +++ b/crates/assembly/src/linker/resolver/mod.rs @@ -36,7 +36,7 @@ pub struct Resolver<'a, 'b: 'a> { /// avoid recomputing the same information over and over again. #[derive(Default)] pub struct ResolverCache { - pub types: BTreeMap, + pub types: BTreeMap, pub constants: BTreeMap, pub evaluating_constants: BTreeMap, } diff --git a/crates/assembly/src/linker/resolver/symbol_resolver.rs b/crates/assembly/src/linker/resolver/symbol_resolver.rs index 2f24a10e92..76ea86ea52 100644 --- a/crates/assembly/src/linker/resolver/symbol_resolver.rs +++ b/crates/assembly/src/linker/resolver/symbol_resolver.rs @@ -85,7 +85,7 @@ impl<'a> SymbolResolver<'a> { context: &SymbolResolutionContext, target: &InvocationTarget, ) -> Result { - match target { + let resolution = match target { InvocationTarget::MastRoot(mast_root) => { log::debug!(target: "name-resolver::invoke", "resolving {target}"); self.validate_syscall_digest(context, *mast_root)?; @@ -195,7 +195,38 @@ impl<'a> SymbolResolver<'a> { // will be checked resolution => Ok(resolution), }, + }?; + self.enforce_kernel_export_syscall_only(context, target, resolution) + } + + fn enforce_kernel_export_syscall_only( + &self, + context: &SymbolResolutionContext, + target: &InvocationTarget, + resolution: SymbolResolution, + ) -> Result { + if matches!(target, InvocationTarget::MastRoot(_)) { + return Ok(resolution); + } + if let SymbolResolution::Exact { gid, ref path } = resolution + && context.kind.is_some() + && !context.in_syscall() + { + // Root kernel attached via `with_kernel` is stored as ModuleKind::Library (MAST); + // `kernel_index` identifies it. AST kernel modules use ModuleKind::Kernel. + let target_is_kernel = self.graph.kernel_index.is_some_and(|ki| ki == gid.module) + || self.graph[gid.module].kind().is_kernel(); + let caller_is_kernel = self.graph.kernel_index.is_some_and(|ki| ki == context.module) + || self.graph[context.module].kind().is_kernel(); + if target_is_kernel && !caller_is_kernel { + return Err(LinkerError::KernelProcNotSyscall { + span: context.span, + source_file: self.graph.source_manager.get(context.span.source_id()).ok(), + callee: path.clone().into_inner(), + }); + } } + Ok(resolution) } fn validate_syscall_digest( @@ -269,6 +300,16 @@ impl<'a> SymbolResolver<'a> { context: &SymbolResolutionContext, path: Span<&Path>, ignored_imports: &mut BTreeSet>, + ) -> Result { + self.expand_path_from(context.module, context, path, ignored_imports) + } + + fn expand_path_from( + &self, + origin_module: ModuleIndex, + context: &SymbolResolutionContext, + path: Span<&Path>, + ignored_imports: &mut BTreeSet>, ) -> Result { let span = path.span(); let mut path = path.into_inner(); @@ -301,8 +342,19 @@ impl<'a> SymbolResolver<'a> { if path.starts_with_exactly(module_path.as_ref()) { if let Some((_, prev)) = longest_prefix.as_ref() { - if prev.components().count() < module_path.components().count() { + let prev_len = prev.components().count(); + let module_len = module_path.components().count(); + if prev_len < module_len { longest_prefix = Some((module.id(), module_path)); + } else if prev_len == module_len && prev != &module_path { + return Err(LinkerError::AmbiguousModulePath { + span, + source_file: self.source_manager().get(span.source_id()).ok(), + path: path.to_path_buf().into_boxed_path().into(), + matches: + alloc::vec![prev.to_string(), module_path.to_string(),] + .into_boxed_slice(), + }); } } else { longest_prefix = Some((module.id(), module_path)); @@ -344,19 +396,25 @@ impl<'a> SymbolResolver<'a> { { SymbolResolution::Local(item) => { log::trace!(target: "name-resolver::expand", "resolved '{symbol}' to local symbol: {}", context.module + item.into_inner()); + let gid = context.module + item.into_inner(); + self.ensure_item_visible(origin_module, gid, span)?; let path = self.module_path(context.module).join(&symbol); - Ok(SymbolResolution::Exact { - gid: context.module + item.into_inner(), - path: Span::new(span, path.into()), - }) + Ok(SymbolResolution::Exact { gid, path: Span::new(span, path.into()) }) }, SymbolResolution::External(path) => { log::trace!(target: "name-resolver::expand", "expanded '{symbol}' to unresolved external path '{path}'"); - self.expand_path(&context, path.as_deref(), ignored_imports) + self.expand_path_from( + origin_module, + &context, + path.as_deref(), + ignored_imports, + ) }, - resolved @ (SymbolResolution::MastRoot(_) | SymbolResolution::Exact { .. }) => { + resolved @ SymbolResolution::MastRoot(_) => Ok(resolved), + SymbolResolution::Exact { gid, path } => { log::trace!(target: "name-resolver::expand", "resolved '{symbol}' to exact definition"); - Ok(resolved) + self.ensure_item_visible(origin_module, gid, span)?; + Ok(SymbolResolution::Exact { gid, path }) }, SymbolResolution::Module { id, path: module_path } => { log::trace!(target: "name-resolver::expand", "resolved '{symbol}' to module: id={id} path={module_path}"); @@ -395,7 +453,8 @@ impl<'a> SymbolResolver<'a> { if ignored_imports.contains(imported_symbol) { log::trace!(target: "name-resolver::expand", "skipping import expansion of '{imported_symbol}': already expanded, resolving as absolute path instead"); let path = path.to_absolute(); - break self.expand_path( + break self.expand_path_from( + origin_module, &context, Span::new(span, path.as_ref()), ignored_imports, @@ -458,7 +517,8 @@ impl<'a> SymbolResolver<'a> { let partially_expanded = external_path.join(subpath); log::trace!(target: "name-resolver::expand", "partially expanded '{path}' to '{partially_expanded}'"); ignored_imports.insert(imported_symbol.to_string().into_boxed_str().into()); - break self.expand_path( + break self.expand_path_from( + origin_module, &context, Span::new(span, partially_expanded.as_path()), ignored_imports, @@ -473,7 +533,8 @@ impl<'a> SymbolResolver<'a> { // Try to expand the path by treating it as an absolute path let absolute = path.to_absolute(); log::trace!(target: "name-resolver::expand", "no import found for '{imported_symbol}' in '{path}': attempting to resolve as absolute path instead"); - break self.expand_path( + break self.expand_path_from( + origin_module, &context, Span::new(span, absolute.as_ref()), ignored_imports, @@ -488,6 +549,29 @@ impl<'a> SymbolResolver<'a> { } } + fn ensure_item_visible( + &self, + origin_module: ModuleIndex, + item: GlobalItemIndex, + span: SourceSpan, + ) -> Result<(), LinkerError> { + if origin_module == item.module { + return Ok(()); + } + + let symbol = &self.graph[item.module][item.index]; + if symbol.visibility().is_public() { + return Ok(()); + } + + Err(SymbolResolutionError::private_symbol( + span, + symbol.name().span(), + self.source_manager(), + ) + .into()) + } + pub fn resolve_local( &self, context: &SymbolResolutionContext, diff --git a/crates/assembly/src/linker/rewrites/module.rs b/crates/assembly/src/linker/rewrites/module.rs index 593013202e..56c0d085b9 100644 --- a/crates/assembly/src/linker/rewrites/module.rs +++ b/crates/assembly/src/linker/rewrites/module.rs @@ -191,7 +191,6 @@ impl<'a, 'b: 'a> VisitMut for ModuleRewriter<'a, 'b> { fn visit_mut_alias(&mut self, alias: &mut Alias) -> ControlFlow { match alias.target() { AliasTarget::MastRoot(_) => return ControlFlow::Continue(()), - AliasTarget::Path(path) if path.is_absolute() => return ControlFlow::Continue(()), AliasTarget::Path(_) => (), } log::debug!(target: "linker", " * rewriting alias target {}", alias.target()); diff --git a/crates/assembly/src/mast_forest_builder.rs b/crates/assembly/src/mast_forest_builder.rs index 37100f09ba..192baebbb6 100644 --- a/crates/assembly/src/mast_forest_builder.rs +++ b/crates/assembly/src/mast_forest_builder.rs @@ -11,8 +11,8 @@ use miden_core::{ mast::{ AsmOpId, BasicBlockNode, BasicBlockNodeBuilder, DecoratorFingerprint, DecoratorId, ExternalNodeBuilder, JoinNodeBuilder, MastForest, MastForestContributor, MastForestError, - MastNode, MastNodeBuilder, MastNodeExt, MastNodeFingerprint, MastNodeId, Remapping, - SubtreeIterator, + MastForestRootMap, MastNode, MastNodeBuilder, MastNodeExt, MastNodeFingerprint, MastNodeId, + Remapping, SubtreeIterator, }, operations::{AssemblyOp, Decorator, DecoratorList, Operation}, serde::Serializable, @@ -71,6 +71,12 @@ pub struct MastForestBuilder { /// A MastForest that contains the MAST of all statically-linked libraries, it's used to find /// precompiled procedures and copy their subtrees instead of inserting external nodes. statically_linked_mast: Arc, + /// Maps each statically linked source forest commitment to its position in the merged forest + /// root map. + statically_linked_forest_indices_by_commitment: BTreeMap, + /// Maps procedure roots from each source static library to their new root ID in the merged + /// static forest. + statically_linked_root_map: MastForestRootMap, /// Keeps track of the new ids assigned to nodes that are copied from the MAST of /// statically-linked libraries. statically_linked_mast_remapping: Remapping, @@ -108,8 +114,18 @@ impl MastForestBuilder { static_libraries: impl IntoIterator, ) -> Result { // All statically-linked libraries are merged into a single MastForest. - let forests = static_libraries.into_iter(); - let (statically_linked_mast, _remapping) = MastForest::merge(forests).into_diagnostic()?; + let forests = static_libraries.into_iter().collect::>(); + // TODO(#3067): `MastForest::commitment()` only hashes procedure root digests, so two + // forests with identical roots but different debug metadata share the same commitment. + // Using that commitment as a lookup key can point provenance from one static library at + // another library's root map and still select the wrong diagnostics metadata. + let statically_linked_forest_indices_by_commitment = forests + .iter() + .enumerate() + .map(|(idx, forest)| (forest.commitment(), idx)) + .collect(); + let (statically_linked_mast, statically_linked_root_map) = + MastForest::merge(forests.iter().copied()).into_diagnostic()?; // The AdviceMap of the statically-linked forest is copied to the forest being built. // // This might include excess advice map data in the built MastForest, but we currently do @@ -120,6 +136,8 @@ impl MastForestBuilder { Ok(MastForestBuilder { mast_forest, statically_linked_mast: Arc::new(statically_linked_mast), + statically_linked_forest_indices_by_commitment, + statically_linked_root_map, emit_debug_info: true, ..Self::default() }) @@ -1089,12 +1107,12 @@ impl MastForestBuilder { /// /// This must be called before copying nodes from the subtree to ensure all decorator IDs /// can be properly remapped. - fn collect_decorators_from_subtree(&mut self, root_id: &MastNodeId) -> Result<(), Report> { + fn collect_decorators_from_subtree(&mut self, root_id: MastNodeId) -> Result<(), Report> { // Clear the decorator remapping for this subtree self.statically_linked_decorator_remapping.clear(); // Iterate through all nodes in the subtree - for node_id in SubtreeIterator::new(root_id, &self.statically_linked_mast.clone()) { + for node_id in SubtreeIterator::new(&root_id, &self.statically_linked_mast.clone()) { // Get all decorator IDs used by this node let decorator_ids: Vec = { let mut ids = Vec::new(); @@ -1157,15 +1175,47 @@ impl MastForestBuilder { /// the inserted subtree is returned. /// * If dynamically-linked, then an external node is inserted, and its MastNodeId is returned /// - /// TODO(#2990): when multiple roots share the same digest but carry - /// different metadata, this always picks the first match. Needs a source - /// MastNodeId threaded from ProcedureInfo through the linker. - pub fn ensure_external_link(&mut self, mast_root: Word) -> Result { - if let Some(root_id) = self.statically_linked_mast.find_procedure_root(mast_root) { - self.copy_statically_linked_subtree(root_id) - } else { - self.ensure_node(ExternalNodeBuilder::new(mast_root)) + /// Adds a node corresponding to the given MAST root, preferring an exact source root when + /// provenance from a statically-linked library is available. + pub fn ensure_external_link_with_source( + &mut self, + mast_root: Word, + source_library_commitment: Option, + source_root_id: Option, + ) -> Result { + if let Some(root_id) = + self.find_statically_linked_root(source_library_commitment, source_root_id, mast_root) + { + return self.copy_statically_linked_subtree(root_id); + } + + self.ensure_node(ExternalNodeBuilder::new(mast_root)) + } + + fn find_statically_linked_root( + &self, + source_library_commitment: Option, + source_root_id: Option, + mast_root: Word, + ) -> Option { + if let (Some(source_library_commitment), Some(source_root_id)) = + (source_library_commitment, source_root_id) + { + let exact_root = self + .statically_linked_forest_indices_by_commitment + .get(&source_library_commitment) + .and_then(|forest_idx| { + self.statically_linked_root_map.map_root(*forest_idx, &source_root_id) + }); + + if let Some(exact_root) = exact_root + .filter(|root_id| self.statically_linked_mast[*root_id].digest() == mast_root) + { + return Some(exact_root); + } } + + self.statically_linked_mast.find_procedure_root(mast_root) } /// Copies a subtree from the statically linked forest into the builder's forest. @@ -1173,7 +1223,7 @@ impl MastForestBuilder { &mut self, root_id: MastNodeId, ) -> Result { - self.collect_decorators_from_subtree(&root_id)?; + self.collect_decorators_from_subtree(root_id)?; for old_id in SubtreeIterator::new(&root_id, &self.statically_linked_mast.clone()) { let node = self.statically_linked_mast[old_id].clone(); @@ -1347,15 +1397,15 @@ mod tests { // This will result in padding after Push(2) because Push operations get padded // Note: the following unpadded operations are 9 in number, indexed 0 to 8 let block1_ops = vec![ - Operation::Push(Felt::new(1)), + Operation::Push(Felt::new_unchecked(1)), Operation::Drop, Operation::Drop, Operation::Drop, Operation::Drop, Operation::Drop, Operation::Drop, - Operation::Push(Felt::new(2)), - Operation::Push(Felt::new(3)), + Operation::Push(Felt::new_unchecked(2)), + Operation::Push(Felt::new_unchecked(3)), ]; // [push drop drop drop drop drop drop push noop] [1] [2] [push noop] [3] [noop] [noop] [noop] let block1_raw_ops_len = block1_ops.len(); @@ -1370,7 +1420,7 @@ mod tests { ]; let block1_id = builder - .ensure_block(block1_ops.clone(), block1_decorators, vec![], vec![], vec![], vec![]) + .ensure_block(block1_ops, block1_decorators, vec![], vec![], vec![], vec![]) .unwrap(); // Sanity check the test itself makes sense @@ -1380,7 +1430,7 @@ mod tests { // Create second block with operations // Block2: [Push(4), Mul] - let block2_ops = vec![Operation::Push(Felt::new(4)), Operation::Mul]; + let block2_ops = vec![Operation::Push(Felt::new_unchecked(4)), Operation::Mul]; // Add decorators for each operation in block2 let block2_decorator1 = builder.ensure_decorator(Decorator::Trace(4)).unwrap(); @@ -1391,7 +1441,7 @@ mod tests { ]; // [push mul] [3] let block2_id = builder - .ensure_block(block2_ops.clone(), block2_decorators, vec![], vec![], vec![], vec![]) + .ensure_block(block2_ops, block2_decorators, vec![], vec![], vec![], vec![]) .unwrap(); // Merge the blocks @@ -1439,7 +1489,7 @@ mod tests { 0 => { // Should be Push(1) from block1 match &merged_ops[op_idx] { - Operation::Push(x) if *x == Felt::new(1) => { + Operation::Push(x) if *x == Felt::new_unchecked(1) => { assert_eq!( *trace_value, 1, "Decorator for Push(1) should have trace value 1" @@ -1451,7 +1501,7 @@ mod tests { 7 => { // Should be Push(2) from block1 match &merged_ops[op_idx] { - Operation::Push(x) if *x == Felt::new(2) => { + Operation::Push(x) if *x == Felt::new_unchecked(2) => { assert_eq!( *trace_value, 2, "Decorator for Push(2) should have trace value 2" @@ -1463,7 +1513,7 @@ mod tests { 9 => { // Should be Push(3) from block1 match &merged_ops[op_idx] { - Operation::Push(x) if *x == Felt::new(3) => { + Operation::Push(x) if *x == Felt::new_unchecked(3) => { assert_eq!( *trace_value, 3, "Decorator for Push(3) should have trace value 3" @@ -1475,7 +1525,7 @@ mod tests { 10 => { // Should be Push(4) from block2 match &merged_ops[op_idx] { - Operation::Push(x) if *x == Felt::new(4) => { + Operation::Push(x) if *x == Felt::new_unchecked(4) => { assert_eq!( *trace_value, 4, "Decorator for Push(4) should have trace value 4" @@ -1502,7 +1552,7 @@ mod tests { ), } } else { - panic!("Operation index {} is out of bounds", op_idx); + panic!("Operation index {op_idx} is out of bounds"); } }, _ => panic!("Expected Trace decorator"), @@ -1514,8 +1564,7 @@ mod tests { for expected_trace in expected_traces { assert!( found_traces.contains(&expected_trace), - "Missing trace value: {}", - expected_trace + "Missing trace value: {expected_trace}" ); } @@ -1843,8 +1892,9 @@ mod tests { static_forest.make_root(static_block_id); let mut builder = MastForestBuilder::new([&static_forest]).unwrap(); - let copied_block_id = - builder.ensure_external_link(static_forest[static_block_id].digest()).unwrap(); + let copied_block_id = builder + .ensure_external_link_with_source(static_forest[static_block_id].digest(), None, None) + .unwrap(); let local_var_id = builder .add_debug_var(DebugVarInfo::new("y", DebugVarLocation::Stack(1))) @@ -1893,15 +1943,15 @@ mod tests { fn test_statically_linked_padded_block_dedups_with_equivalent_local_block() { let mut source_builder = MastForestBuilder::new(&[]).unwrap(); let ops = vec![ - Operation::Push(Felt::new(1)), + Operation::Push(Felt::from_u32(1)), Operation::Drop, Operation::Drop, Operation::Drop, Operation::Drop, Operation::Drop, Operation::Drop, - Operation::Push(Felt::new(2)), - Operation::Push(Felt::new(3)), + Operation::Push(Felt::from_u32(2)), + Operation::Push(Felt::from_u32(3)), ]; let asm_op = AssemblyOp::new(None, "padded_ctx".into(), 1, "push.3".into()); @@ -1921,8 +1971,9 @@ mod tests { let expected_padded_idx = static_forest.debug_info().asm_ops_for_node(static_block)[0].0; let mut builder = MastForestBuilder::new([&static_forest]).unwrap(); - let copied_block_id = - builder.ensure_external_link(static_forest[static_block].digest()).unwrap(); + let copied_block_id = builder + .ensure_external_link_with_source(static_forest[static_block].digest(), None, None) + .unwrap(); let local_block_id = builder .ensure_block(ops, Vec::new(), vec![(8, asm_op)], vec![], vec![], vec![]) .unwrap(); @@ -2090,7 +2141,9 @@ mod tests { let (static_forest, _) = source_builder.build(); let mut builder = MastForestBuilder::new([&static_forest]).unwrap(); - let linked = builder.ensure_external_link(static_forest[alias_a].digest()).unwrap(); + let linked = builder + .ensure_external_link_with_source(static_forest[alias_a].digest(), None, None) + .unwrap(); builder.mast_forest.make_root(linked); let (forest, _) = builder.build(); @@ -2102,11 +2155,10 @@ mod tests { ); } - /// Digest-based linking picks the first root, so the second alias gets - /// the wrong metadata. Fixing this needs #2990. + /// Provenance-aware static linking can select the exact same-digest root instead of falling + /// back to the first digest match. #[test] - #[ignore = "requires #2990: source MastNodeId in ProcedureInfo"] - fn repro_statically_linked_same_digest_root_uses_first_alias_metadata() { + fn test_static_link_with_source_root_preserves_selected_alias_metadata() { let mut source_builder = MastForestBuilder::new(&[]).unwrap(); let alias_a = source_builder @@ -2145,10 +2197,15 @@ mod tests { }; let (exact_forest, _) = exact_builder.build(); - let mut digest_builder = MastForestBuilder::new([&static_forest]).unwrap(); - let linked_alias_b = - digest_builder.ensure_external_link(static_forest[alias_b].digest()).unwrap(); - let (linked_forest, _) = digest_builder.build(); + let mut provenance_builder = MastForestBuilder::new([&static_forest]).unwrap(); + let linked_alias_b = provenance_builder + .ensure_external_link_with_source( + static_forest[alias_b].digest(), + Some(static_forest.commitment()), + Some(alias_b), + ) + .unwrap(); + let (linked_forest, _) = provenance_builder.build(); assert_eq!( exact_forest @@ -2165,7 +2222,7 @@ mod tests { .unwrap() .context_name(), "alias_b", - "linking the second same-digest root by digest should preserve that root's metadata", + "provenance-aware linking should preserve the selected same-digest root metadata", ); } } diff --git a/crates/assembly/src/project.rs b/crates/assembly/src/project.rs index 0736771370..a552263777 100644 --- a/crates/assembly/src/project.rs +++ b/crates/assembly/src/project.rs @@ -6,15 +6,15 @@ use std::{ use miden_assembly_syntax::{ ModuleParser, - ast::{self, ModuleKind, Path as MasmPath}, + ast::{ModuleKind, Path as MasmPath}, diagnostics::Report, }; use miden_core::serde::{Deserializable, Serializable}; use miden_mast_package::{Package as MastPackage, Section, SectionId, TargetType}; -use miden_package_registry::{PackageId, PackageStore, Version as PackageVersion}; +use miden_package_registry::{PackageCache, PackageId, Version as PackageVersion}; use miden_project::{ - Linkage, Package as ProjectPackage, Profile, ProjectDependencyNodeProvenance, ProjectSource, - ProjectSourceOrigin, Target, + Linkage, Package as ProjectPackage, PreassembledDependencyMetadata, Profile, + ProjectDependencyNodeProvenance, ProjectSource, ProjectSourceOrigin, Target, }; use crate::{Assembler, assembler::debuginfo::DebugInfoSections, ast::Module}; @@ -45,7 +45,7 @@ impl Assembler { store: &'a mut S, ) -> Result, Report> where - S: PackageStore + ?Sized, + S: PackageCache + ?Sized, { let manifest_path = manifest_path.as_ref(); let source_manager = self.source_manager(); @@ -69,7 +69,7 @@ impl Assembler { store: &'a mut S, ) -> Result, Report> where - S: PackageStore + ?Sized, + S: PackageCache + ?Sized, { let source_manager = self.source_manager(); let dependency_graph = @@ -91,7 +91,7 @@ pub struct ProjectSourceInputs { pub support: Vec>, } -pub struct ProjectAssembler<'a, S: PackageStore + ?Sized> { +pub struct ProjectAssembler<'a, S: PackageCache + ?Sized> { assembler: Assembler, project: Arc, dependency_graph: DependencyGraph, @@ -100,7 +100,7 @@ pub struct ProjectAssembler<'a, S: PackageStore + ?Sized> { impl<'a, S> ProjectAssembler<'a, S> where - S: PackageStore + ?Sized, + S: PackageCache + ?Sized, { pub fn project(&self) -> &ProjectPackage { self.project.as_ref() @@ -317,7 +317,7 @@ where let node = self.dependency_graph.get(package_id)?; let node_version = node.version.clone(); - let package = match &node.provenance { + let (package, should_cache) = match &node.provenance { ProjectDependencyNodeProvenance::Source(ProjectSource::Virtual { .. }) => { return Err(Report::msg(format!( "package '{package_id}' is missing a manifest path", @@ -340,8 +340,7 @@ where .map(|target| target.inner().clone()) .ok_or_else(|| { Report::msg(format!( - "dependency '{}' does not define a library target", - package_id + "dependency '{package_id}' does not define a library target" )) })?; match self.try_reuse_registered_source_package( @@ -354,11 +353,14 @@ where manifest_path, workspace_root.as_deref(), )? { - RegisteredSourcePackage::Loaded(package) => ResolvedPackage { - linked_kernel_package: self - .resolve_linked_kernel_package(package.clone())?, - package, - }, + RegisteredSourcePackage::Loaded(package) => ( + ResolvedPackage { + linked_kernel_package: self + .resolve_linked_kernel_package(package.clone())?, + package, + }, + false, + ), reuse => { let package = self.assemble_source_package( package_id.clone(), @@ -370,9 +372,7 @@ where cache, )?; match reuse { - RegisteredSourcePackage::Missing => { - self.publish_source_dependency(package.package.clone())?; - }, + RegisteredSourcePackage::Missing => (), RegisteredSourcePackage::IndexedButUnreadable(expected) => { let actual = PackageVersion::new( package.package.version.clone(), @@ -380,14 +380,13 @@ where ); if actual != expected { return Err(Report::msg(format!( - "package '{}' version '{}' is already registered as '{}', but the canonical artifact could not be loaded and rebuilding from source produced '{}'; bump the semantic version or repair the package store", - package_id, node_version, expected, actual + "package '{package_id}' version '{node_version}' is already registered as '{expected}', but the canonical artifact could not be loaded and rebuilding from source produced '{actual}'; bump the semantic version or repair the package store" ))); } }, RegisteredSourcePackage::Loaded(_) => unreachable!(), } - package + (package, true) }, } }, @@ -395,31 +394,57 @@ where let package = self.load_canonical_package(package_id, &node_version)?.ok_or_else(|| { Report::msg(format!( - "dependency '{}' version '{}' was not found in the package registry", - package_id, node_version + "dependency '{package_id}' version '{node_version}' was not found in the package registry" )) })?; - ResolvedPackage { - linked_kernel_package: self.resolve_linked_kernel_package(package.clone())?, - package, - } + ( + ResolvedPackage { + linked_kernel_package: self + .resolve_linked_kernel_package(package.clone())?, + package, + }, + false, + ) }, ProjectDependencyNodeProvenance::Registry { selected, .. } => { let package = self.store.load_package(package_id, selected)?; - ResolvedPackage { - linked_kernel_package: self.resolve_linked_kernel_package(package.clone())?, - package, - } + ( + ResolvedPackage { + linked_kernel_package: self + .resolve_linked_kernel_package(package.clone())?, + package, + }, + false, + ) }, - ProjectDependencyNodeProvenance::Preassembled { path, selected } => { - let package = load_selected_preassembled_package(path, package_id, selected)?; - ResolvedPackage { - linked_kernel_package: self.resolve_linked_kernel_package(package.clone())?, - package, - } + ProjectDependencyNodeProvenance::Preassembled { + path, + selected, + kind, + requirements, + } => { + let package = load_selected_preassembled_package( + path, + package_id, + selected, + *kind, + requirements, + )?; + let should_cache = self.should_cache_preassembled_package(package_id, selected)?; + ( + ResolvedPackage { + linked_kernel_package: self + .resolve_linked_kernel_package(package.clone())?, + package, + }, + should_cache, + ) }, }; + if should_cache { + self.cache_resolved_package(&package)?; + } cache.insert(package_id.clone(), package.clone()); Ok(package) } @@ -521,17 +546,59 @@ where actual.describe(), ))), None => Err(Report::msg(format!( - "package '{}' version '{}' is already registered, but the canonical artifact is missing source provenance; bump the semantic version", - package_id, version + "package '{package_id}' version '{version}' is already registered, but the canonical artifact is missing source provenance; bump the semantic version" ))), }?; Ok(RegisteredSourcePackage::Loaded(package)) } - fn publish_source_dependency(&mut self, package: Arc) -> Result<(), Report> { + fn should_cache_preassembled_package( + &self, + package_id: &PackageId, + selected: &PackageVersion, + ) -> Result { + let Some(record) = self.store.get_by_semver(package_id, &selected.version) else { + return Ok(true); + }; + if record.version() != selected { + return Ok(false); + } + + match self.store.load_package(package_id, selected) { + Ok(_) => Ok(false), + Err(_) => Ok(true), + } + } + + fn cache_resolved_package(&mut self, package: &ResolvedPackage) -> Result<(), Report> { + self.cache_package(package.package.clone())?; + if let Some(kernel_package) = package.linked_kernel_package.clone() + && self.should_cache_linked_kernel_package(kernel_package.as_ref())? + { + self.cache_package(kernel_package)?; + } + Ok(()) + } + + fn should_cache_linked_kernel_package(&self, package: &MastPackage) -> Result { + let version = PackageVersion::new(package.version.clone(), package.digest()); + let Some(record) = self.store.get_by_semver(&package.name, &package.version) else { + return Ok(true); + }; + if record.version() != &version { + return Ok(false); + } + + match self.store.load_package(&package.name, &version) { + Ok(_) => Ok(false), + Err(_) => Ok(true), + } + } + + fn cache_package(&mut self, package: Arc) -> Result<(), Report> { self.store - .publish_package(package) + .cache_package(package) .map(|_| ()) .map_err(|error| Report::msg(error.to_string())) } @@ -678,7 +745,7 @@ fn module_path_from_relative( }) .collect::, Report>>()?; - if components.last().is_some_and(|component| *component == ast::Module::ROOT) { + if components.last().is_some_and(|component| *component == Module::ROOT) { components.pop(); } @@ -694,6 +761,8 @@ fn load_selected_preassembled_package( path: &FsPath, expected_name: &PackageId, selected: &PackageVersion, + expected_kind: TargetType, + expected_requirements: &BTreeMap, ) -> Result, Report> { let package = load_package_from_path(path)?; if &package.name != expected_name { @@ -716,6 +785,26 @@ fn load_selected_preassembled_package( ))); } + if package.kind != expected_kind { + return Err(Report::msg(format!( + "preassembled dependency '{}@{}' at '{}' no longer matches the dependency graph target kind '{}'", + expected_name, + actual, + path.display(), + expected_kind + ))); + } + + let actual_requirements = package_requirements(&package); + if &actual_requirements != expected_requirements { + return Err(Report::msg(format!( + "preassembled dependency '{}@{}' at '{}' no longer matches the dependency graph dependency requirements", + expected_name, + actual, + path.display() + ))); + } + Ok(package) } @@ -727,3 +816,21 @@ fn load_package_from_path(path: &FsPath) -> Result, Report> { })?; Ok(Arc::new(package)) } + +fn package_requirements( + package: &MastPackage, +) -> BTreeMap { + package + .manifest + .dependencies() + .map(|dependency| { + ( + dependency.name.clone(), + PreassembledDependencyMetadata { + version: PackageVersion::new(dependency.version.clone(), dependency.digest), + kind: dependency.kind, + }, + ) + }) + .collect() +} diff --git a/crates/assembly/src/project/build_provenance.rs b/crates/assembly/src/project/build_provenance.rs index d4f80f918a..a93a32acbe 100644 --- a/crates/assembly/src/project/build_provenance.rs +++ b/crates/assembly/src/project/build_provenance.rs @@ -7,6 +7,8 @@ use miden_core::{ utils::hash_string_to_word, }; use miden_mast_package::{Package as MastPackage, Section, SectionId}; +#[cfg(feature = "arbitrary")] +use proptest::prelude::*; use super::PackageBuildSettings; @@ -26,9 +28,9 @@ use super::PackageBuildSettings; /// /// The recorded fields differ by source origin: /// -/// - [`Self::Path`] tracks a hash of the effective manifest and the target's resolved source files, -/// along with a hash of the fully resolved dependency closure and the build-profile knobs that -/// affect the emitted package bytes. +/// - [`Self::Path`] tracks a hash of the selected target's build-provenance projection and resolved +/// source files, along with a hash of the fully resolved dependency closure and the build-profile +/// knobs that affect the emitted package bytes. /// - [`Self::Git`] records the repository identity and resolved revision instead of hashing the /// checked-out source tree directly, but still includes the dependency-closure hash and build /// settings for the same reuse decision. @@ -37,10 +39,14 @@ use super::PackageBuildSettings; /// for parent packages and is used in semver-bump diagnostics to explain why an existing canonical /// artifact no longer matches the current sources. #[derive(Debug, Clone, PartialEq, Eq)] +#[cfg_attr( + all(feature = "arbitrary", test), + miden_test_serde_macros::serde_test(binary_serde(true), serde_test(false)) +)] pub(super) enum PackageBuildProvenance { /// Provenance for a package assembled from sources addressed by a local filesystem path. Path { - /// Hash of the effective manifest plus the root/support modules that define the target. + /// Hash of the build-provenance projection plus the root/support modules for the target. source_hash: Word, /// Hash of the resolved dependency closure, including linkage and exact selected /// artifacts. @@ -286,3 +292,61 @@ impl Deserializable for PackageBuildProvenance { } } } + +#[cfg(feature = "arbitrary")] +impl Arbitrary for PackageBuildSettings { + type Parameters = (); + type Strategy = BoxedStrategy; + + fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { + (any::(), any::()) + .prop_map(|(emit_debug_info, trim_paths)| Self { emit_debug_info, trim_paths }) + .boxed() + } +} + +#[cfg(feature = "arbitrary")] +impl Arbitrary for PackageBuildProvenance { + type Parameters = (); + type Strategy = BoxedStrategy; + + fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { + let word = + proptest::collection::vec(proptest::char::range('a', 'z'), 1..16).prop_map(|chars| { + let material = chars.into_iter().collect::(); + hash_string_to_word(material.as_str()) + }); + let text = proptest::collection::vec( + proptest::prop_oneof![ + proptest::char::range('a', 'z'), + proptest::char::range('0', '9'), + Just('/'), + Just('-'), + Just('_'), + Just('.'), + Just(':'), + ], + 1..40, + ) + .prop_map(|chars| chars.into_iter().collect::()); + + proptest::prop_oneof![ + (word.clone(), word.clone(), any::()).prop_map( + |(source_hash, dependency_hash, build_settings)| Self::Path { + source_hash, + dependency_hash, + build_settings, + } + ), + (text.clone(), text, word, any::()).prop_map( + |(repo, resolved_revision, dependency_hash, build_settings)| Self::Git { + repo, + resolved_revision, + dependency_hash, + build_settings, + } + ), + ] + .boxed() + } +} diff --git a/crates/assembly/src/project/dependency_graph.rs b/crates/assembly/src/project/dependency_graph.rs index cb66106f39..0c6c1fc3fe 100644 --- a/crates/assembly/src/project/dependency_graph.rs +++ b/crates/assembly/src/project/dependency_graph.rs @@ -8,7 +8,7 @@ use std::path::Path as FsPath; use miden_assembly_syntax::diagnostics::Report; use miden_core::{Word, utils::hash_string_to_word}; -use miden_package_registry::{PackageId, PackageStore}; +use miden_package_registry::{PackageId, PackageRegistry}; use miden_project::{ Package as ProjectPackage, ProjectDependencyGraph, ProjectDependencyGraphBuilder, ProjectDependencyNode, ProjectDependencyNodeProvenance, ProjectSource, ProjectSourceOrigin, @@ -30,7 +30,7 @@ impl DependencyGraph { // CONSTRUCTORS // -------------------------------------------------------------------------------------------- - pub fn from_project_path( + pub fn from_project_path( manifest_path: impl AsRef, store: &S, source_manager: Arc, @@ -42,7 +42,7 @@ impl DependencyGraph { Ok(Self { dependency_graph, source_manager }) } - pub fn from_project( + pub fn from_project( project: Arc, store: &S, source_manager: Arc, @@ -52,7 +52,7 @@ impl DependencyGraph { let dependency_graph = if let Some(manifest_path) = project.manifest_path() { dependency_graph_builder.build_from_path(manifest_path)? } else { - dependency_graph_builder.build(project.clone())? + dependency_graph_builder.build(project)? }; Ok(Self { dependency_graph, source_manager }) @@ -151,13 +151,13 @@ impl DependencyGraph { profile_name: &str, origin: &ProjectSourceOrigin, manifest_path: &FsPath, - workspace_root: Option<&FsPath>, + _workspace_root: Option<&FsPath>, visiting: &mut BTreeSet, ) -> Result { let dependency_hash = self.compute_dependency_closure_hash(package_id, profile_name, visiting)?; - let build_settings = - PackageBuildSettings::from_profile(project.resolve_profile(profile_name)?); + let profile = project.resolve_profile(profile_name)?; + let build_settings = PackageBuildSettings::from_profile(profile); match origin { ProjectSourceOrigin::Git { repo, resolved_revision, .. } => { @@ -172,8 +172,8 @@ impl DependencyGraph { Ok(PackageBuildProvenance::Path { source_hash: project.compute_path_source_hash( target, + profile, manifest_path, - workspace_root, )?, dependency_hash, build_settings, @@ -264,8 +264,7 @@ impl DependencyGraph { .map(|target| target.inner().clone()) .ok_or_else(|| { Report::msg(format!( - "dependency '{}' does not define a library target", - package_id + "dependency '{package_id}' does not define a library target" )) })?; let provenance = self.expected_source_provenance_with_visited( diff --git a/crates/assembly/src/project/package_ext.rs b/crates/assembly/src/project/package_ext.rs index 25e06f626e..66cf626f4a 100644 --- a/crates/assembly/src/project/package_ext.rs +++ b/crates/assembly/src/project/package_ext.rs @@ -17,7 +17,7 @@ use miden_assembly_syntax::{ }; use miden_core::{Word, utils::hash_string_to_word}; use miden_package_registry::PackageId; -use miden_project::{DependencyVersionScheme, Package as ProjectPackage, Profile, Target}; +use miden_project::{Package as ProjectPackage, Profile, Target}; use super::TargetSourcePaths; use crate::SourceManager; @@ -39,8 +39,8 @@ pub(super) trait ProjectPackageExt { fn compute_path_source_hash( &self, target: &Target, + profile: &Profile, manifest_path: &FsPath, - workspace_root: Option<&FsPath>, ) -> Result; fn excluded_target_roots( @@ -51,8 +51,6 @@ pub(super) trait ProjectPackageExt { fn resolve_target_source_paths(&self, target: &Target) -> Result; - fn effective_manifest_hash_input(&self) -> Result; - fn resolve_profile(&self, name: &str) -> Result<&Profile, Report>; } @@ -125,8 +123,8 @@ impl ProjectPackageExt for ProjectPackage { fn compute_path_source_hash( &self, target: &Target, + profile: &Profile, manifest_path: &FsPath, - workspace_root: Option<&FsPath>, ) -> Result { let source_paths = self.resolve_target_source_paths(target)?; let project_root = manifest_path.parent().ok_or_else(|| { @@ -152,24 +150,7 @@ impl ProjectPackageExt for ProjectPackage { } inputs.sort_by(|a, b| a.0.cmp(&b.0)); - let mut material = format!( - "target:{}\nkind:{}\nnamespace:{}\n", - target.name.inner(), - target.ty, - target.namespace.inner() - ); - if workspace_root.is_some() { - material.push_str("manifest:effective\n"); - material.push_str(&self.effective_manifest_hash_input()?); - material.push('\n'); - } else { - let manifest_label = manifest_path - .strip_prefix(project_root) - .unwrap_or(manifest_path) - .display() - .to_string(); - inputs.push((format!("manifest:{manifest_label}"), manifest_path.to_path_buf())); - } + let mut material = self.build_provenance_projection(target, profile); for (label, path) in inputs { let bytes = fs::read(&path).map_err(|error| { Report::msg(format!("failed to read source input '{}': {error}", path.display())) @@ -212,45 +193,6 @@ impl ProjectPackageExt for ProjectPackage { Ok(TargetSourcePaths { root: root_path, root_dir, support }) } - fn effective_manifest_hash_input(&self) -> Result { - let mut manifest = self.to_toml()?; - - let mut workspace_dependencies = self - .dependencies() - .iter() - .filter_map(|dependency| match dependency.scheme() { - DependencyVersionScheme::Workspace { member, version } => Some(( - dependency.name().to_string(), - member.path().to_string(), - version.as_ref().map(ToString::to_string), - dependency.linkage(), - )), - DependencyVersionScheme::WorkspacePath { path, version } => Some(( - dependency.name().to_string(), - path.path().to_string(), - version.as_ref().map(ToString::to_string), - dependency.linkage(), - )), - _ => None, - }) - .collect::>(); - workspace_dependencies.sort_by(|a, b| a.0.cmp(&b.0)); - - if !workspace_dependencies.is_empty() { - manifest.push_str("\n# resolved_workspace_dependencies\n"); - for (name, member_path, version, linkage) in workspace_dependencies { - match version { - Some(version) => { - manifest.push_str(&format!("{name}={member_path}@{version}:{linkage}\n")); - }, - None => manifest.push_str(&format!("{name}={member_path}:{linkage}\n")), - } - } - } - - Ok(manifest) - } - fn resolve_profile(&self, name: &str) -> Result<&Profile, Report> { self.get_profile(name).ok_or_else(|| { Report::msg(format!( diff --git a/crates/assembly/src/project/tests.rs b/crates/assembly/src/project/tests.rs index 454faa5c1f..b71c7d5aec 100644 --- a/crates/assembly/src/project/tests.rs +++ b/crates/assembly/src/project/tests.rs @@ -457,6 +457,12 @@ end format!("regdep@1.0.0#{regdep_digest}") ] ); + let cached_packages = context.registry().cached_packages(); + assert!(cached_packages.iter().any(|entry| entry.starts_with("pathdep@1.0.0#"))); + assert!(cached_packages.iter().any(|entry| entry.starts_with("gitdep@1.0.0#"))); + assert!(cached_packages.iter().any(|entry| entry.starts_with("predep@1.0.0#"))); + assert!(!cached_packages.iter().any(|entry| entry.starts_with("runtime@"))); + assert!(!cached_packages.iter().any(|entry| entry.starts_with("regdep@"))); assert!(!dependency_names.iter().any(|name| name == "pathdep")); assert_eq!(package.kind, TargetType::Library); assert_eq!( @@ -485,6 +491,270 @@ end ); } +#[test] +fn source_dependency_with_preassembled_dependency_does_not_require_registry_entry() { + let tempdir = TempDir::new().unwrap(); + let context = TestContext::new(); + + let predep = + context.assemble_library_package_with_export("predep", "1.0.0", "deps::predep::leaf", []); + let predep_path = tempdir.path().join("predep.masp"); + predep.write_to_file(&predep_path).unwrap(); + + let pathdep_dir = tempdir.path().join("pathdep"); + write_file( + &pathdep_dir.join("miden-project.toml"), + r#"[package] +name = "pathdep" +version = "1.0.0" + +[lib] +path = "lib.masm" +namespace = "deps::pathdep" + +[dependencies] +predep = { path = "../predep.masp" } +"#, + ); + write_file( + &pathdep_dir.join("lib.masm"), + r#"use ::deps::predep + +pub proc call_predep + exec.predep::leaf +end +"#, + ); + + let root_dir = tempdir.path().join("root"); + let root_manifest = root_dir.join("miden-project.toml"); + write_file( + &root_manifest, + r#"[package] +name = "root" +version = "1.0.0" + +[lib] +path = "lib.masm" + +[dependencies] +pathdep = { path = "../pathdep" } +"#, + ); + write_file( + &root_dir.join("lib.masm"), + r#"use ::deps::pathdep + +pub proc entry + exec.pathdep::call_predep +end +"#, + ); + + let mut context = context; + let package = context + .assemble_library_package(&root_manifest, None) + .expect("source dependency with preassembled dependency should assemble"); + + assert_eq!(&package.name, "root"); +} + +#[test] +fn preassembled_dependency_bypasses_registry_semver_collision() { + let tempdir = TempDir::new().unwrap(); + let mut context = TestContext::new(); + + let registered_module = Module::parse( + "deps::predep", + ModuleKind::Library, + source_file!( + context, + r#"pub proc leaf + push.1 + drop +end +"# + ), + context.source_manager(), + ) + .unwrap(); + let registered_library = context.assemble_library([registered_module]).unwrap(); + let registered = MastPackage::from_library( + "predep".into(), + "1.0.0".parse().unwrap(), + TargetType::Library, + registered_library, + std::iter::empty::(), + ); + let registered_digest = registered.digest(); + context.registry_mut().add_package(registered.into()); + + let predep = + context.assemble_library_package_with_export("predep", "1.0.0", "deps::predep::leaf", []); + let predep_digest = predep.digest(); + assert_ne!(registered_digest, predep_digest); + let predep_path = tempdir.path().join("predep.masp"); + predep.write_to_file(&predep_path).unwrap(); + + let root_dir = tempdir.path().join("root"); + let root_manifest = root_dir.join("miden-project.toml"); + write_file( + &root_manifest, + r#"[package] +name = "root" +version = "1.0.0" + +[lib] +path = "lib.masm" + +[dependencies] +predep = { path = "../predep.masp" } +"#, + ); + write_file( + &root_dir.join("lib.masm"), + r#"use ::deps::predep + +pub proc entry + exec.predep::leaf +end +"#, + ); + + let package = context + .assemble_library_package(&root_manifest, None) + .expect("explicit preassembled path should bypass registry semver collisions"); + + assert_eq!(&package.name, "root"); + assert_eq!( + package + .manifest + .dependencies() + .find(|dependency| &dependency.name == "predep") + .unwrap() + .digest, + predep_digest + ); + assert!( + !context + .registry() + .cached_packages() + .iter() + .any(|entry| entry.starts_with("predep@")) + ); +} + +#[test] +fn preassembled_dependency_repairs_unreadable_exact_registry_artifact() { + let tempdir = TempDir::new().unwrap(); + let mut context = TestContext::new(); + + let predep = + context.assemble_library_package_with_export("predep", "1.0.0", "deps::predep::leaf", []); + let selected = context.registry_mut().add_package(predep.clone().into()); + context + .registry_mut() + .remove_package(&predep.name, &selected) + .expect("test should leave an indexed package without an artifact"); + + let predep_path = tempdir.path().join("predep.masp"); + predep.write_to_file(&predep_path).unwrap(); + + let root_dir = tempdir.path().join("root"); + let root_manifest = root_dir.join("miden-project.toml"); + write_file( + &root_manifest, + r#"[package] +name = "root" +version = "1.0.0" + +[lib] +path = "lib.masm" + +[dependencies] +predep = { path = "../predep.masp" } +"#, + ); + write_file( + &root_dir.join("lib.masm"), + r#"use ::deps::predep + +pub proc entry + exec.predep::leaf +end +"#, + ); + + context + .assemble_library_package(&root_manifest, None) + .expect("preassembled dependency should repair unreadable exact registry artifact"); + + assert!( + context + .registry() + .cached_packages() + .iter() + .any(|entry| entry == &format!("predep@{selected}")) + ); +} + +#[test] +fn preassembled_dependency_does_not_repair_readable_exact_registry_artifact() { + let tempdir = TempDir::new().unwrap(); + let mut context = TestContext::new(); + + let predep = + context.assemble_library_package_with_export("predep", "1.0.0", "deps::predep::leaf", []); + let selected = context.registry_mut().add_package(predep.clone().into()); + + let mut path_predep = MastPackage::read_from_bytes(&predep.to_bytes()).unwrap(); + path_predep.sections.push(Section::new( + SectionId::custom("preassembled-test").unwrap(), + Vec::from([1, 2, 3]), + )); + assert_eq!(path_predep.digest(), predep.digest()); + + let predep_path = tempdir.path().join("predep.masp"); + path_predep.write_to_file(&predep_path).unwrap(); + + let root_dir = tempdir.path().join("root"); + let root_manifest = root_dir.join("miden-project.toml"); + write_file( + &root_manifest, + r#"[package] +name = "root" +version = "1.0.0" + +[lib] +path = "lib.masm" + +[dependencies] +predep = { path = "../predep.masp" } +"#, + ); + write_file( + &root_dir.join("lib.masm"), + r#"use ::deps::predep + +pub proc entry + exec.predep::leaf +end +"#, + ); + + context + .assemble_library_package(&root_manifest, None) + .expect("preassembled dependency should use path artifact when exact registry entry loads"); + + assert!( + !context + .registry() + .cached_packages() + .iter() + .any(|entry| entry == &format!("predep@{selected}")) + ); +} + #[test] fn assembles_mixed_path_and_git_dependencies_with_shared_registry_semver_resolution() { let tempdir = TempDir::new().unwrap(); @@ -813,7 +1083,9 @@ end let error = context .assemble_library_package(&root_manifest, None) .expect_err("runtime dependency digest conflicts should fail"); - assert!(error.to_string().contains("conflicting runtime dependency 'runtime'")); + let error = error.to_string(); + assert!(error.contains("dependency resolution failed")); + assert!(error.contains("there is no version of runtime")); } #[test] @@ -1434,7 +1706,7 @@ end context.assemble_library_package(&root_manifest, None).expect( "source dependency should rebuild from source when the canonical artifact is unreadable", ); - assert_eq!(context.registry().loaded_packages(), vec![format!("dep@{}", dep_version)]); + assert_eq!(context.registry().loaded_packages(), vec![format!("dep@{dep_version}")]); } #[test] @@ -1548,6 +1820,93 @@ dep = { path = "dep" } ); } +#[test] +fn package_manifest_changes_without_build_effect_allow_source_dependency_reuse() { + let tempdir = TempDir::new().unwrap(); + let dep_dir = tempdir.path().join("dep"); + write_file( + &dep_dir.join("miden-project.toml"), + r#"[package] +name = "dep" +version = "1.0.0" + +[lib] +path = "lib.masm" +"#, + ); + write_file( + &dep_dir.join("lib.masm"), + r#"pub proc foo + push.1 +end +"#, + ); + + let root_dir = tempdir.path().join("root"); + let root_manifest = root_dir.join("miden-project.toml"); + write_file( + &root_manifest, + r#"[package] +name = "root" +version = "1.0.0" + +[lib] +path = "lib.masm" + +[dependencies] +dep = { path = "../dep" } +"#, + ); + write_file( + &root_dir.join("lib.masm"), + r#"pub proc entry + exec.::dep::foo +end +"#, + ); + + let mut context = TestContext::new(); + context + .assemble_library_package(&root_manifest, None) + .expect("initial build should succeed"); + let dep_record = context + .registry() + .get_by_semver(&PackageId::from("dep"), &"1.0.0".parse().unwrap()) + .expect("dependency should be registered"); + let dep_version = dep_record.version().clone(); + context.registry().clear_loaded_packages(); + + write_file( + &dep_dir.join("miden-project.toml"), + r#"# comments and formatting should not affect build provenance + +[package] +name = "dep" +version = "1.0.0" +description = "metadata-only update" + +[package.metadata.audit] +ticket = "ignored" + +[lib] +path = "src/lib.masm" + +[[bin]] +name = "unused" +path = "bin/unused.masm" + +[profile.unused] +debug = false +custom = "ignored" +"#, + ); + + context + .assemble_library_package(&root_manifest, None) + .expect("manifest-only changes outside build provenance should allow reuse"); + assert_eq!(context.registry().loaded_packages(), vec![format!("dep@{dep_version}")]); +} + #[test] fn git_dependency_reuses_canonical_revision_and_rejects_new_commit_without_semver_bump() { let tempdir = TempDir::new().unwrap(); @@ -1942,7 +2301,7 @@ fn preassembled_libraries_prefer_store_kernel_over_embedded_copy() { } #[test] -fn preassembled_libraries_fall_back_to_embedded_kernel_when_store_is_missing() { +fn preassembled_libraries_require_registered_kernel_when_store_is_missing() { let tempdir = TempDir::new().unwrap(); let (_, kernel_manifest) = write_transitive_kernel_program_project(tempdir.path()); let mid_manifest = tempdir.path().join("mid").join("miden-project.toml"); @@ -1952,11 +2311,6 @@ fn preassembled_libraries_fall_back_to_embedded_kernel_when_store_is_missing() { let kernel_package = build_context .assemble_library_package(&kernel_manifest, None) .expect("kernel package build should succeed"); - let expected_kernel = kernel_package - .try_into_kernel_library() - .expect("kernel package should round-trip as a kernel library") - .kernel() - .clone(); let mut mid_package = MastPackage::read_from_bytes( &build_context .assemble_library_package(&mid_manifest, None) @@ -1972,23 +2326,11 @@ fn preassembled_libraries_fall_back_to_embedded_kernel_when_store_is_missing() { let root_manifest = write_preassembled_kernel_executable_project(tempdir.path(), &mid_package_path); let mut context = TestContext::new(); - let package = context + let error = context .assemble_executable_package(&root_manifest, Some("main"), None) - .expect("executable package build should fall back to the embedded kernel"); - let embedded_kernel_package = package - .sections - .iter() - .find(|section| section.id == SectionId::KERNEL) - .map(|section| MastPackage::read_from_bytes(section.data.as_ref()).unwrap()) - .expect("executable package should embed the fallback kernel package"); - assert_eq!(embedded_kernel_package.version, kernel_package.version); - assert_eq!(embedded_kernel_package.digest(), kernel_package.digest()); - - let round_tripped_program = MastPackage::read_from_bytes(&package.to_bytes()) - .expect("serialized executable package should round-trip") - .try_into_program() - .expect("program reconstruction should use the embedded fallback kernel"); - assert_eq!(round_tripped_program.kernel(), &expected_kernel); + .expect_err("executable package build should reject unresolved kernel dependencies"); + assert!(error.to_string().contains("dependency resolution failed")); + assert!(error.to_string().contains("kernelpkg")); } #[test] @@ -2046,7 +2388,14 @@ fn preassembled_libraries_fall_back_to_embedded_kernel_when_store_artifact_is_un assert_eq!(embedded_kernel_package.digest(), kernel_package.digest()); assert_eq!( context.registry().loaded_packages(), - vec![format!("kernelpkg@{}", kernel_version)] + vec![format!("kernelpkg@{kernel_version}"), format!("kernelpkg@{kernel_version}")] + ); + assert!( + context + .registry() + .cached_packages() + .iter() + .any(|entry| entry == &format!("kernelpkg@{kernel_version}")) ); let round_tripped_program = MastPackage::read_from_bytes(&package.to_bytes()) @@ -2057,7 +2406,76 @@ fn preassembled_libraries_fall_back_to_embedded_kernel_when_store_artifact_is_un } #[test] -fn preassembled_libraries_without_store_or_embedded_kernel_leave_runtime_kernel_to_caller() { +fn preassembled_libraries_skip_embedded_kernel_cache_on_semver_collision() { + let tempdir = TempDir::new().unwrap(); + let (_, kernel_manifest) = write_transitive_kernel_program_project(tempdir.path()); + let mid_manifest = tempdir.path().join("mid").join("miden-project.toml"); + let mid_package_path = tempdir.path().join("mid-embedded.masp"); + + let mut build_context = TestContext::new(); + let kernel_package = build_context + .assemble_library_package(&kernel_manifest, None) + .expect("kernel package build should succeed"); + let mut mid_package = MastPackage::read_from_bytes( + &build_context + .assemble_library_package(&mid_manifest, None) + .expect("mid package build should succeed") + .to_bytes(), + ) + .expect("mid package should deserialize"); + mid_package + .sections + .push(Section::new(SectionId::KERNEL, kernel_package.to_bytes())); + mid_package.write_to_file(&mid_package_path).unwrap(); + + let conflicting_kernel_manifest = tempdir.path().join("conflicting-kernel/miden-project.toml"); + write_file( + &conflicting_kernel_manifest, + r#"[package] +name = "kernelpkg" +version = "1.0.0" + +[lib] +kind = "kernel" +path = "kernel.masm" +"#, + ); + write_file( + &conflicting_kernel_manifest.parent().unwrap().join("kernel.masm"), + r#"pub proc foo + push.1 + drop +end +"#, + ); + let conflicting_kernel = build_context + .assemble_library_package(&conflicting_kernel_manifest, None) + .expect("conflicting kernel package build should succeed"); + assert_ne!(conflicting_kernel.digest(), kernel_package.digest()); + + let root_manifest = + write_preassembled_kernel_executable_project(tempdir.path(), &mid_package_path); + let mut context = TestContext::new(); + context.registry_mut().add_package(kernel_package); + let mut project_assembler = context + .project_assembler_for_path(&root_manifest) + .expect("dependency graph should build"); + project_assembler.store.replace_semver_package(conflicting_kernel); + + project_assembler + .assemble(ProjectTargetSelector::Executable("main"), "dev") + .expect("embedded kernel fallback should not try to cache over a semver collision"); + assert!( + !project_assembler + .store + .cached_packages() + .iter() + .any(|entry| entry.starts_with("kernelpkg@")) + ); +} + +#[test] +fn preassembled_libraries_without_store_or_embedded_kernel_cannot_reconstruct_program() { let tempdir = TempDir::new().unwrap(); write_transitive_kernel_program_project(tempdir.path()); let mid_manifest = tempdir.path().join("mid").join("miden-project.toml"); @@ -2073,23 +2491,11 @@ fn preassembled_libraries_without_store_or_embedded_kernel_leave_runtime_kernel_ let root_manifest = write_preassembled_kernel_executable_project(tempdir.path(), &mid_package_path); let mut context = TestContext::new(); - let package = context + let error = context .assemble_executable_package(&root_manifest, Some("main"), None) - .expect("executable package build should succeed without an available kernel artifact"); - - assert!( - package - .manifest - .dependencies() - .any(|dependency| dependency.kind == TargetType::Kernel) - ); - assert!(!package.sections.iter().any(|section| section.id == SectionId::KERNEL)); - - let round_tripped_program = MastPackage::read_from_bytes(&package.to_bytes()) - .expect("serialized executable package should round-trip") - .try_into_program() - .expect("packages without a recoverable kernel should still convert to a program"); - assert!(round_tripped_program.kernel().is_empty()); + .expect_err("packages with unresolved kernel runtime dependencies must be rejected"); + assert!(error.to_string().contains("dependency resolution failed")); + assert!(error.to_string().contains("kernelpkg")); } #[test] @@ -2129,7 +2535,7 @@ fn embedded_kernel_package_must_match_runtime_dependency() { } #[test] -fn executable_packages_without_embedded_kernel_section_fall_back_to_empty_kernel() { +fn executable_packages_without_embedded_kernel_section_are_rejected() { let tempdir = TempDir::new().unwrap(); let manifest_path = write_kernel_program_project(tempdir.path()); @@ -2141,11 +2547,10 @@ fn executable_packages_without_embedded_kernel_section_fall_back_to_empty_kernel .expect("serialized executable package should round-trip"); round_tripped_package.sections.retain(|section| section.id != SectionId::KERNEL); - let round_tripped_program = round_tripped_package + let error = round_tripped_package .try_into_program() - .expect("packages without embedded kernels should still convert to a program"); - - assert!(round_tripped_program.kernel().is_empty()); + .expect_err("packages without embedded kernels should be rejected"); + assert!(error.to_string().contains("does not embed the kernel package required")); } #[test] @@ -2191,6 +2596,230 @@ end assert!(error.to_string().contains("no longer matches the dependency graph selection")); } +#[test] +fn preassembled_dependency_must_match_graph_selected_runtime_dependencies() { + let tempdir = TempDir::new().unwrap(); + let runtime_v1 = Arc::::from(MastPackage::generate( + "runtime".into(), + "1.0.0".parse().unwrap(), + TargetType::Library, + [], + )); + let runtime_v2 = Arc::::from(MastPackage::generate( + "runtime".into(), + "1.0.1".parse().unwrap(), + TargetType::Library, + [], + )); + let dep_package_path = tempdir.path().join("dep.masp"); + let dep_v1 = MastPackage::from_library( + "dep".into(), + "1.0.0".parse().unwrap(), + TargetType::Library, + runtime_v1.mast.clone(), + [miden_mast_package::Dependency { + name: PackageId::from("runtime"), + version: runtime_v1.version.clone(), + kind: TargetType::Library, + digest: runtime_v1.digest(), + }], + ); + dep_v1.write_to_file(&dep_package_path).unwrap(); + + let root_dir = tempdir.path().join("root"); + let root_manifest = root_dir.join("miden-project.toml"); + write_file( + &root_manifest, + r#"[package] +name = "root" +version = "1.0.0" + +[lib] +path = "lib.masm" + +[dependencies] +dep = { path = "../dep.masp" } +"#, + ); + write_file( + &root_dir.join("lib.masm"), + r#"pub proc entry + exec.::dep::foo +end +"#, + ); + + let mut context = TestContext::new(); + context.registry_mut().add_package(runtime_v1.clone()); + let mut project_assembler = context.project_assembler_for_path(&root_manifest).unwrap(); + let dep_v2 = MastPackage::from_library( + "dep".into(), + "1.0.0".parse().unwrap(), + TargetType::Library, + runtime_v1.mast.clone(), + [miden_mast_package::Dependency { + name: PackageId::from("runtime"), + version: runtime_v2.version.clone(), + kind: TargetType::Library, + digest: runtime_v2.digest(), + }], + ); + dep_v2.write_to_file(&dep_package_path).unwrap(); + + let error = project_assembler.assemble(ProjectTargetSelector::Library, "dev").expect_err( + "changing preassembled dependency metadata after graph construction should fail", + ); + assert!( + error + .to_string() + .contains("no longer matches the dependency graph dependency requirements") + ); +} + +#[test] +fn preassembled_dependency_must_match_graph_selected_dependency_kinds() { + let tempdir = TempDir::new().unwrap(); + let runtime = Arc::::from(MastPackage::generate( + "runtime".into(), + "1.0.0".parse().unwrap(), + TargetType::Library, + [], + )); + let dep_package_path = tempdir.path().join("dep.masp"); + let dep_v1 = MastPackage::from_library( + "dep".into(), + "1.0.0".parse().unwrap(), + TargetType::Library, + runtime.mast.clone(), + [miden_mast_package::Dependency { + name: PackageId::from("runtime"), + version: runtime.version.clone(), + kind: TargetType::Library, + digest: runtime.digest(), + }], + ); + dep_v1.write_to_file(&dep_package_path).unwrap(); + + let root_dir = tempdir.path().join("root"); + let root_manifest = root_dir.join("miden-project.toml"); + write_file( + &root_manifest, + r#"[package] +name = "root" +version = "1.0.0" + +[lib] +path = "lib.masm" + +[dependencies] +dep = { path = "../dep.masp" } +"#, + ); + write_file( + &root_dir.join("lib.masm"), + r#"pub proc entry + exec.::dep::foo +end +"#, + ); + + let mut context = TestContext::new(); + context.registry_mut().add_package(runtime.clone()); + let mut project_assembler = context.project_assembler_for_path(&root_manifest).unwrap(); + let dep_v2 = MastPackage::from_library( + "dep".into(), + "1.0.0".parse().unwrap(), + TargetType::Library, + runtime.mast.clone(), + [miden_mast_package::Dependency { + name: PackageId::from("runtime"), + version: runtime.version.clone(), + kind: TargetType::Kernel, + digest: runtime.digest(), + }], + ); + dep_v2.write_to_file(&dep_package_path).unwrap(); + + let error = project_assembler + .assemble(ProjectTargetSelector::Library, "dev") + .expect_err("changing preassembled dependency kinds after graph construction should fail"); + assert!( + error + .to_string() + .contains("no longer matches the dependency graph dependency requirements") + ); +} + +#[test] +fn preassembled_package_must_match_graph_selected_target_kind() { + let tempdir = TempDir::new().unwrap(); + let runtime = Arc::::from(MastPackage::generate( + "runtime".into(), + "1.0.0".parse().unwrap(), + TargetType::Library, + [], + )); + let dep_package_path = tempdir.path().join("dep.masp"); + let dep_v1 = MastPackage::from_library( + "dep".into(), + "1.0.0".parse().unwrap(), + TargetType::Library, + runtime.mast.clone(), + [miden_mast_package::Dependency { + name: PackageId::from("runtime"), + version: runtime.version.clone(), + kind: TargetType::Library, + digest: runtime.digest(), + }], + ); + dep_v1.write_to_file(&dep_package_path).unwrap(); + + let root_dir = tempdir.path().join("root"); + let root_manifest = root_dir.join("miden-project.toml"); + write_file( + &root_manifest, + r#"[package] +name = "root" +version = "1.0.0" + +[lib] +path = "lib.masm" + +[dependencies] +dep = { path = "../dep.masp" } +"#, + ); + write_file( + &root_dir.join("lib.masm"), + r#"pub proc entry + exec.::dep::foo +end +"#, + ); + + let mut context = TestContext::new(); + context.registry_mut().add_package(runtime.clone()); + let mut project_assembler = context.project_assembler_for_path(&root_manifest).unwrap(); + let dep_v2 = MastPackage::from_library( + "dep".into(), + "1.0.0".parse().unwrap(), + TargetType::Kernel, + runtime.mast.clone(), + [miden_mast_package::Dependency { + name: PackageId::from("runtime"), + version: runtime.version.clone(), + kind: TargetType::Library, + digest: runtime.digest(), + }], + ); + dep_v2.write_to_file(&dep_package_path).unwrap(); + + let error = project_assembler + .assemble(ProjectTargetSelector::Library, "dev") + .expect_err("changing preassembled package kind after graph construction should fail"); + assert!(error.to_string().contains("no longer matches the dependency graph target kind")); +} + fn write_kernel_program_project(root: &FsPath) -> PathBuf { let manifest_path = root.join("miden-project.toml"); write_file( diff --git a/crates/assembly/src/snapshots/miden_assembly__tests__advmap_push_nokey.snap b/crates/assembly/src/snapshots/miden_assembly__tests__advmap_push_nokey.snap index 26025efc58..287cf070be 100644 --- a/crates/assembly/src/snapshots/miden_assembly__tests__advmap_push_nokey.snap +++ b/crates/assembly/src/snapshots/miden_assembly__tests__advmap_push_nokey.snap @@ -8,10 +8,10 @@ begin push(4294967294) mstore drop - push(1997527880758456713) - push(5938778176324780339) - push(3220751449397998004) - push(3127914668806499073) + push(8155863851644706248) + push(17696238826619444718) + push(11456745663445894086) + push(9752867087467588168) noop noop push(17843484659000820118) diff --git a/crates/assembly/src/snapshots/miden_assembly__tests__decorators_external.snap b/crates/assembly/src/snapshots/miden_assembly__tests__decorators_external.snap index e70a335718..0096ce8cee 100644 --- a/crates/assembly/src/snapshots/miden_assembly__tests__decorators_external.snap +++ b/crates/assembly/src/snapshots/miden_assembly__tests__decorators_external.snap @@ -12,7 +12,7 @@ begin noop trace(0) end - external.0x68092b3b1675cca2da9f19e8941b590ded1c9804cbdac536c193d574d8ad0439 + external.0xf9805a40a530fbd7512bf1d5fe408fccf67b6943ff321bc9abc70268efb6c9e2 end trace(1) end diff --git a/crates/assembly/src/snapshots/miden_assembly__tests__link_time_const_evaluation_succeeds.snap b/crates/assembly/src/snapshots/miden_assembly__tests__link_time_const_evaluation_succeeds.snap index 2290689b99..0c99d276c1 100644 --- a/crates/assembly/src/snapshots/miden_assembly__tests__link_time_const_evaluation_succeeds.snap +++ b/crates/assembly/src/snapshots/miden_assembly__tests__link_time_const_evaluation_succeeds.snap @@ -14,7 +14,7 @@ begin incr noop end - external.0x21458fd12b211505c36fe477314b3149bd4b2214f3304cbafa04ea80579d4328 + external.0x6c0c95a9f04e21fe073801b42748ef0639eebd0467afd64c3d317b537451454d end basic_block add add end end diff --git a/crates/assembly/src/snapshots/miden_assembly__tests__module_alias.snap b/crates/assembly/src/snapshots/miden_assembly__tests__module_alias.snap index 3b9f879248..d29a0d50ad 100644 --- a/crates/assembly/src/snapshots/miden_assembly__tests__module_alias.snap +++ b/crates/assembly/src/snapshots/miden_assembly__tests__module_alias.snap @@ -15,6 +15,6 @@ begin push(2) pad end - external.0x9ca74bde31561aca2278d330b782707a5c9ee8dcb911bec58ebbd9544077d09a + external.0x8052467c52363b45144a505283fa04052ddc8bdc7d25899fad0ecd8a4246935f end end diff --git a/crates/assembly/src/snapshots/miden_assembly__tests__program_with_one_import_and_hex_call.snap b/crates/assembly/src/snapshots/miden_assembly__tests__program_with_one_import_and_hex_call.snap index a10dd19541..67d79539eb 100644 --- a/crates/assembly/src/snapshots/miden_assembly__tests__program_with_one_import_and_hex_call.snap +++ b/crates/assembly/src/snapshots/miden_assembly__tests__program_with_one_import_and_hex_call.snap @@ -17,7 +17,7 @@ begin noop noop end - external.0x77ca6b6f945bde6a7a7eec2f0d9ae96c8c5218ad6c1f4e573c6eab2d9b9607fb + external.0xf34befe5b657a0fb0222962f53ef81429084c9cd1cd41454c945351e5b2361e2 end call.0x20234ee941e53a15886e733cc8e041198c6e90d2a16ea18ce1030e8c3596dd38 end diff --git a/crates/assembly/src/snapshots/miden_assembly__tests__program_with_reexported_custom_alias_in_same_library.snap b/crates/assembly/src/snapshots/miden_assembly__tests__program_with_reexported_custom_alias_in_same_library.snap index f1432847fb..4a35b6d30c 100644 --- a/crates/assembly/src/snapshots/miden_assembly__tests__program_with_reexported_custom_alias_in_same_library.snap +++ b/crates/assembly/src/snapshots/miden_assembly__tests__program_with_reexported_custom_alias_in_same_library.snap @@ -17,8 +17,8 @@ begin noop noop end - external.0x63fc91874699cefb8f1add4642ce97d950b7fd0acd0f24512cdbde58c9cfb473 + external.0x881ada1004e7146b8fa0f179772b86c18b40cc6c2b5c7a68908c970a4f4ef3a6 end - external.0x06aeeabff4f4b6671fa30c5b9d64eeec7200e48a86c51982230956c6539ac309 + external.0xe4fc001d0ccf5fa121036acb5b8a2d3360ec6445d1c798a2bdb784587d5f9aae end end diff --git a/crates/assembly/src/snapshots/miden_assembly__tests__program_with_reexported_proc_in_another_library.snap b/crates/assembly/src/snapshots/miden_assembly__tests__program_with_reexported_proc_in_another_library.snap index f1432847fb..4a35b6d30c 100644 --- a/crates/assembly/src/snapshots/miden_assembly__tests__program_with_reexported_proc_in_another_library.snap +++ b/crates/assembly/src/snapshots/miden_assembly__tests__program_with_reexported_proc_in_another_library.snap @@ -17,8 +17,8 @@ begin noop noop end - external.0x63fc91874699cefb8f1add4642ce97d950b7fd0acd0f24512cdbde58c9cfb473 + external.0x881ada1004e7146b8fa0f179772b86c18b40cc6c2b5c7a68908c970a4f4ef3a6 end - external.0x06aeeabff4f4b6671fa30c5b9d64eeec7200e48a86c51982230956c6539ac309 + external.0xe4fc001d0ccf5fa121036acb5b8a2d3360ec6445d1c798a2bdb784587d5f9aae end end diff --git a/crates/assembly/src/snapshots/miden_assembly__tests__program_with_reexported_proc_in_same_library.snap b/crates/assembly/src/snapshots/miden_assembly__tests__program_with_reexported_proc_in_same_library.snap index f1432847fb..4a35b6d30c 100644 --- a/crates/assembly/src/snapshots/miden_assembly__tests__program_with_reexported_proc_in_same_library.snap +++ b/crates/assembly/src/snapshots/miden_assembly__tests__program_with_reexported_proc_in_same_library.snap @@ -17,8 +17,8 @@ begin noop noop end - external.0x63fc91874699cefb8f1add4642ce97d950b7fd0acd0f24512cdbde58c9cfb473 + external.0x881ada1004e7146b8fa0f179772b86c18b40cc6c2b5c7a68908c970a4f4ef3a6 end - external.0x06aeeabff4f4b6671fa30c5b9d64eeec7200e48a86c51982230956c6539ac309 + external.0xe4fc001d0ccf5fa121036acb5b8a2d3360ec6445d1c798a2bdb784587d5f9aae end end diff --git a/crates/assembly/src/testing.rs b/crates/assembly/src/testing.rs index 58fdaf92c8..c9bac240bc 100644 --- a/crates/assembly/src/testing.rs +++ b/crates/assembly/src/testing.rs @@ -243,7 +243,7 @@ mod package_features { use miden_mast_package::{Package, PackageId}; use miden_package_registry::{ - PackageIndex, PackageProvider, PackageRecord, PackageRegistry, PackageStore, + PackageCache, PackageIndex, PackageProvider, PackageRecord, PackageRegistry, PackageStore, PackageVersions, Version, VersionRequirement, }; @@ -256,12 +256,12 @@ mod package_features { index: BTreeMap, packages: BTreeMap<(PackageId, Version), Arc>, loads: Mutex>, + caches: Mutex>, } impl TestRegistry { pub fn add_package(&mut self, package: Arc) -> Version { - let version = - miden_package_registry::Version::new(package.version.clone(), package.digest()); + let version = Version::new(package.version.clone(), package.digest()); self.publish_package(package).expect("failed to add test package"); version } @@ -270,6 +270,10 @@ mod package_features { self.loads.lock().unwrap().clone() } + pub fn cached_packages(&self) -> Vec { + self.caches.lock().unwrap().clone() + } + pub fn clear_loaded_packages(&self) { self.loads.lock().unwrap().clear(); } @@ -281,6 +285,26 @@ mod package_features { ) -> Option> { self.packages.remove(&(package.clone(), version.clone())) } + + pub fn replace_semver_package(&mut self, package: Arc) -> Version { + let version = Version::new(package.version.clone(), package.digest()); + self.packages.retain(|(name, existing), _| { + name != &package.name || existing.version != package.version + }); + + let dependencies = package.manifest.dependencies().map(|dependency| { + let version = Version::new(dependency.version.clone(), dependency.digest); + (dependency.name.clone(), VersionRequirement::Exact(version)) + }); + let record = PackageRecord::new(version.clone(), dependencies) + .with_description(package.description.clone().unwrap_or_default()); + self.index + .entry(package.name.clone()) + .or_default() + .insert(package.version.clone(), record); + self.packages.insert((package.name.clone(), version.clone()), package); + version + } } impl PackageRegistry for TestRegistry { @@ -302,8 +326,7 @@ mod package_features { Ok(()) }, Entry::Occupied(_) => Err(Report::msg(format!( - "package '{}' version '{}' is already registered", - name, semver + "package '{name}' version '{semver}' is already registered" ))), } } @@ -322,12 +345,37 @@ mod package_features { } } - impl PackageStore for TestRegistry { + impl PackageCache for TestRegistry { type Error = Report; + fn cache_package(&mut self, package: Arc) -> Result { + let version = Version::new(package.version.clone(), package.digest()); + self.caches.lock().unwrap().push(format!("{}@{version}", package.name)); + if let Some(record) = self.get_by_semver(&package.name, &package.version) { + if record.version() == &version { + self.packages.insert((package.name.clone(), version.clone()), package); + return Ok(version); + } + return Err(Report::msg(format!( + "package '{}' version '{}' is already registered", + package.name, package.version + ))); + } + let dependencies = package.manifest.dependencies().map(|dependency| { + let version = Version::new(dependency.version.clone(), dependency.digest); + (dependency.name.clone(), VersionRequirement::Exact(version)) + }); + let record = PackageRecord::new(version.clone(), dependencies) + .with_description(package.description.clone().unwrap_or_default()); + self.register(package.name.clone(), record)?; + self.packages.insert((package.name.clone(), version.clone()), package); + Ok(version) + } + } + + impl PackageStore for TestRegistry { fn publish_package(&mut self, package: Arc) -> Result { - let version = - miden_package_registry::Version::new(package.version.clone(), package.digest()); + let version = Version::new(package.version.clone(), package.digest()); let dependencies = package .manifest .dependencies() @@ -430,7 +478,7 @@ mod package_features { version: &str, export: &str, dependencies: impl IntoIterator, - ) -> Box { + ) -> Box { use alloc::string::ToString; use miden_assembly_syntax::source_file; diff --git a/crates/assembly/src/tests.rs b/crates/assembly/src/tests.rs index 2617f212ab..4f211f8e01 100644 --- a/crates/assembly/src/tests.rs +++ b/crates/assembly/src/tests.rs @@ -1,5 +1,5 @@ use alloc::{ - collections::BTreeSet, + collections::{BTreeMap, BTreeSet}, string::{String, ToString}, vec::Vec, }; @@ -10,19 +10,22 @@ use std::{ }; use miden_assembly_syntax::{ - MAX_REPEAT_COUNT, ast::Path, diagnostics::WrapErr, library::LibraryExport, + MAX_REPEAT_COUNT, + ast::Path, + diagnostics::WrapErr, + library::{LibraryExport, ProcedureExport as LibraryProcedureExport}, }; use miden_core::{ Felt, Word, assert_matches, events::EventId, field::PrimeField64, mast::{ - CallNodeBuilder, JoinNodeBuilder, LoopNodeBuilder, MastForestContributor, MastNodeExt, - MastNodeId, SplitNodeBuilder, + CallNodeBuilder, JoinNodeBuilder, LoopNodeBuilder, MastForestContributor, MastNode, + MastNodeExt, MastNodeId, SplitNodeBuilder, }, operations::Operation, program::Program, - serde::{Deserializable, Serializable}, + serde::{Deserializable, DeserializationError, Serializable}, }; use miden_mast_package::{ ConstantExport, MastForest, Package, PackageExport, PackageId, PackageManifest, @@ -34,7 +37,8 @@ use proptest::{ }; use crate::{ - Assembler, Library, ModuleParser, PathBuf, ProjectSourceInputs, ProjectTargetSelector, + Assembler, KernelLibrary, Library, ModuleParser, PathBuf, ProjectSourceInputs, + ProjectTargetSelector, assembler::MAX_CONTROL_FLOW_NESTING, ast::{Module, ModuleKind, ProcedureName, QualifiedProcedureName}, diagnostics::{IntoDiagnostic, Report}, @@ -299,7 +303,7 @@ fn library_exports() -> Result<(), Report> { // make sure the library exports all exported procedures let expected_exports: BTreeSet> = [foo2.into(), foo3.into(), bar1.into(), bar2.into(), bar3.into(), bar5.into()].into(); - let actual_exports: BTreeSet<_> = lib2.exports().map(|export| export.path()).collect(); + let actual_exports: BTreeSet<_> = lib2.exports().map(LibraryExport::path).collect(); assert_eq!(expected_exports, actual_exports); // make sure foo2, bar2, and bar3 map to the same MastNode @@ -374,6 +378,59 @@ fn library_procedure_collision() -> Result<(), Report> { Ok(()) } +#[test] +fn static_library_same_digest_procedure_uses_exact_root_metadata() -> Result<(), Report> { + let context = TestContext::new(); + + let aliases = r#" + pub proc alias_a + add + end + + pub proc alias_b + add + end + "#; + let aliases = parse_module!(&context, "lib::aliases", aliases); + let library = Assembler::new(context.source_manager()).assemble_library([aliases])?; + + let program_source = source_file!( + &context, + r#" + use lib::aliases + + begin + exec.aliases::alias_b + end + "# + ); + + let program = Assembler::new(context.source_manager()) + .with_static_library(library)? + .assemble_program(program_source)?; + + let body_node_id = { + let root = program.entrypoint(); + match &program.mast_forest()[root] { + MastNode::Join(join_node) => join_node.second(), + _ => root, + } + }; + let context_name = program + .mast_forest() + .debug_info() + .first_asm_op_for_node(body_node_id) + .expect("statically linked procedure should preserve asm-op metadata") + .context_name(); + + assert!( + context_name.ends_with("alias_b"), + "expected alias_b metadata, got {context_name}" + ); + + Ok(()) +} + #[test] fn library_serialization() -> Result<(), Report> { let context = TestContext::new(); @@ -411,6 +468,259 @@ fn library_serialization() -> Result<(), Report> { Ok(()) } +/// Verifies that deserializing a library rejects procedure exports whose `MastNodeId` is not a +/// procedure root in the underlying MAST forest (issue #2831). +#[test] +fn library_deserialization_rejects_non_root_export() { + use miden_core::{ + mast::{BasicBlockNodeBuilder, MastForestContributor}, + serde::ByteWriter, + }; + + let context = TestContext::new(); + let source = r#" + pub proc foo + add + end + "#; + let module = parse_module!(&context, "test::foo", source); + + // Build a valid library. + let lib = Assembler::new(context.source_manager()).assemble_library([module]).unwrap(); + + // Clone the forest and add a non-root node. + let mut forest: MastForest = (**lib.mast_forest()).clone(); + let builder = BasicBlockNodeBuilder::new(vec![Operation::Add], vec![]); + let non_root_id = builder.add_to_forest(&mut forest).unwrap(); + assert!( + !forest.is_procedure_root(non_root_id), + "sanity check: new node should not be a root" + ); + + // Manually serialize a tampered library: forest + one export referencing the non-root node. + let mut tampered_bytes = Vec::new(); + forest.write_into(&mut tampered_bytes); + + // Number of exports. + 1usize.write_into(&mut tampered_bytes); + // Tag: 0 = Procedure export. + 0u8.write_into(&mut tampered_bytes); + // Fully qualified procedure path. + let path = PathBuf::new("::test::foo::foo").unwrap(); + path.write_into(&mut tampered_bytes); + // MastNodeId of the non-root node. + u32::from(non_root_id).write_into(&mut tampered_bytes); + // No function signature. + tampered_bytes.write_bool(false); + // Empty attribute set. + miden_assembly_syntax::ast::AttributeSet::default().write_into(&mut tampered_bytes); + + // Deserializing should fail because the export references a non-root node. + let result = Library::read_from_bytes(&tampered_bytes); + assert!( + result.is_err(), + "deserialization should reject exports referencing non-root nodes" + ); + let err_msg = result.unwrap_err().to_string(); + assert!( + err_msg.contains("no procedure root"), + "error should mention missing procedure root, got: {err_msg}" + ); +} + +fn read_usize_vint64(bytes: &[u8], offset: &mut usize) -> usize { + // This test patches raw bytes in place, so it needs byte offsets that ByteReader::read_usize + // does not expose. + let first_byte = bytes.get(*offset).copied().expect("out-of-bounds vint64 peek"); + let length = first_byte.trailing_zeros() as usize + 1; + + if length == 9 { + *offset += 1; + let end = (*offset).checked_add(8).expect("offset overflow while reading vint64"); + let chunk: [u8; 8] = bytes[*offset..end].try_into().expect("out-of-bounds vint64"); + *offset = end; + let value = u64::from_le_bytes(chunk); + usize::try_from(value).expect("encoded usize does not fit host usize") + } else { + let end = (*offset).checked_add(length).expect("offset overflow while reading vint64"); + let mut encoded = [0u8; 8]; + encoded[..length].copy_from_slice(&bytes[*offset..end]); + *offset = end; + let value = u64::from_le_bytes(encoded) >> length; + usize::try_from(value).expect("encoded usize does not fit host usize") + } +} + +fn locate_first_node_hash(bytes: &[u8]) -> (usize, usize) { + // Header: magic[4] + flags[1] + version[3] + let mut offset = 0usize; + offset += 4; + offset += 1; + offset += 3; + + let node_count = read_usize_vint64(bytes, &mut offset); + + // Roots: len (usize) + elements (u32 LE) + let roots_len = read_usize_vint64(bytes, &mut offset); + offset += roots_len * 4; + + // Basic block data: len (usize) + bytes + let bb_len = read_usize_vint64(bytes, &mut offset); + offset += bb_len; + + // Fixed-width node entries: one 8-byte entry per node. External nodes carry their digest in a + // separate section before internal node hashes, so count them while walking the entry table. + let mut external_count = 0usize; + for _ in 0..node_count { + let end = offset.checked_add(8).expect("offset overflow while reading node entry"); + let entry_bytes: [u8; 8] = bytes[offset..end].try_into().expect("out-of-bounds node entry"); + let entry = u64::from_le_bytes(entry_bytes); + let discriminant = (entry >> 60) as u8; + if discriminant == 8 { + external_count += 1; + } + offset = end; + } + + offset += external_count * 32; + + (offset, node_count) +} + +fn build_library_bytes_with_spoofed_first_node_digest( + lib: &Library, + spoof_seed: &str, +) -> (Vec, Word) { + use miden_core::serde::{ByteWriter, Serializable}; + + // Serialize the MastForest in stripped form so the byte layout is minimal and stable. + let forest = lib.mast_forest().as_ref(); + let original_digest = forest[MastNodeId::new_unchecked(0)].digest(); + let mut forest_bytes = Vec::new(); + forest.write_stripped(&mut forest_bytes); + + let (node_hashes_start, node_count) = locate_first_node_hash(&forest_bytes); + assert!(node_count > 0, "expected at least one node info entry"); + + // Patch node 0 digest in-place. + let spoofed_digest = miden_core::utils::hash_string_to_word(spoof_seed); + assert_ne!(spoofed_digest, original_digest, "spoofed digest must differ"); + + let mut spoofed_digest_bytes = Vec::new(); + spoofed_digest.write_into(&mut spoofed_digest_bytes); + assert_eq!(spoofed_digest_bytes.len(), 32, "Word must serialize to 32 bytes"); + + let node0_digest_offset = node_hashes_start; + forest_bytes[node0_digest_offset..node0_digest_offset + 32] + .copy_from_slice(&spoofed_digest_bytes); + + // Re-encode a library byte stream using the spoofed forest bytes. + let mut bytes = forest_bytes; + bytes.write_usize(lib.exports().count()); + for export in lib.exports() { + export.write_into(&mut bytes); + } + (bytes, spoofed_digest) +} + +#[test] +fn regression_library_deserialisation_rejects_spoofed_mast_node_digests() { + let lib_src = r#" +pub proc p + push.1 +end +"#; + let lib = Assembler::default() + .assemble_library([lib_src]) + .expect("library assembly must succeed"); + + let (bytes, _) = + build_library_bytes_with_spoofed_first_node_digest(&lib, "spoofed-library-digest"); + let err = Library::read_from_bytes(&bytes) + .expect_err("expected library deserialization to reject inconsistent node digests"); + assert!( + err.to_string().contains("invalid untrusted MAST forest"), + "expected untrusted-MAST validation failure, got: {err}" + ); + assert!( + err.to_string().contains("hash mismatch for node"), + "expected digest mismatch failure, got: {err}" + ); +} + +#[test] +fn unchecked_library_deserialisation_accepts_spoofed_mast_node_digests() { + let lib_src = r#" +pub proc p + push.1 +end +"#; + let lib = Assembler::default() + .assemble_library([lib_src]) + .expect("library assembly must succeed"); + + let (bytes, spoofed_digest) = + build_library_bytes_with_spoofed_first_node_digest(&lib, "spoofed-library-digest"); + let deserialized = Library::read_from_bytes_unchecked(&bytes) + .expect("unchecked library deserialization must accept spoofed node digests"); + + assert_eq!( + deserialized.mast_forest()[MastNodeId::new_unchecked(0)].digest(), + spoofed_digest + ); +} + +#[test] +fn regression_kernel_library_deserialisation_rejects_spoofed_mast_node_digests() { + let kernel_src = r#" +pub proc k1 + push.1 +end +"#; + let kernel_lib = Assembler::default() + .assemble_kernel(kernel_src) + .expect("kernel assembly must succeed"); + + let (bytes, _) = build_library_bytes_with_spoofed_first_node_digest( + kernel_lib.as_ref(), + "spoofed-kernel-digest", + ); + let err = KernelLibrary::read_from_bytes(&bytes) + .expect_err("expected kernel library deserialization to reject inconsistent node digests"); + assert!( + err.to_string().contains("invalid untrusted MAST forest"), + "expected untrusted-MAST validation failure, got: {err}" + ); + assert!( + err.to_string().contains("hash mismatch for node"), + "expected digest mismatch failure, got: {err}" + ); +} + +#[test] +fn unchecked_kernel_library_deserialisation_accepts_spoofed_mast_node_digests() { + let kernel_src = r#" +pub proc k1 + push.1 +end +"#; + let kernel_lib = Assembler::default() + .assemble_kernel(kernel_src) + .expect("kernel assembly must succeed"); + + let (bytes, spoofed_digest) = build_library_bytes_with_spoofed_first_node_digest( + kernel_lib.as_ref(), + "spoofed-kernel-digest", + ); + let deserialized = KernelLibrary::read_from_bytes_unchecked(&bytes) + .expect("unchecked kernel deserialization must accept spoofed node digests"); + + assert_eq!( + deserialized.mast_forest()[MastNodeId::new_unchecked(0)].digest(), + spoofed_digest + ); +} + #[test] fn get_module_by_path() -> Result<(), Report> { let context = TestContext::new(); @@ -828,7 +1138,7 @@ end #[test] fn enum_felt_discriminant_too_large_is_rejected() -> TestResult { let context = TestContext::default(); - let modulus = miden_core::Felt::ORDER_U64; + let modulus = Felt::ORDER_U64; let source = source_file!( &context, format!( @@ -853,7 +1163,7 @@ end #[test] fn constant_expression_overflow_is_rejected() -> TestResult { let context = TestContext::default(); - let modulus_minus_one = miden_core::Felt::ORDER_U64 - 1; + let modulus_minus_one = Felt::ORDER_U64 - 1; let source = source_file!( &context, format!( @@ -3689,7 +3999,7 @@ end let assembled = Assembler::default().assemble_program(program_src); assert!( assembled.is_err(), - "expected out-of-range constant results to be rejected (must not silently alias via `Felt::new`)" + "expected out-of-range constant results to be rejected (must not silently alias via `Felt::new_unchecked`)" ); } @@ -4930,6 +5240,101 @@ fn regression_empty_kernel_library_is_rejected() { assert_diagnostic_lines!(err, "library must contain at least one exported procedure"); } +#[test] +fn regression_empty_kernel_package_is_rejected_without_panicking() { + use std::panic::{AssertUnwindSafe, catch_unwind}; + + let context = TestContext::default(); + let source_manager = context.source_manager(); + let kernel_lib = Assembler::new(source_manager.clone()) + .assemble_kernel( + r#" + pub proc foo + add + end + "#, + ) + .expect("kernel assembly should succeed"); + let mut package = *Package::from_library( + PackageId::from("kernel"), + "1.0.0".parse().unwrap(), + TargetType::Kernel, + Arc::new(kernel_lib.as_ref().clone()), + [], + ); + package.manifest = PackageManifest::new([]).expect("empty package manifest should be valid"); + + let linked = catch_unwind(AssertUnwindSafe(|| { + Assembler::new(source_manager) + .link_package(Arc::new(package), miden_project::Linkage::Dynamic) + })); + assert!(linked.is_ok(), "assembler panicked while linking an empty kernel package"); + + let error = linked.unwrap().expect_err("empty kernel packages should be rejected"); + assert_diagnostic_lines!( + error, + "invalid kernel package: does not export any kernel procedures" + ); +} + +/// Reproduces issue #3035: a MAST with padded basic blocks grows when debug info is cleared and the +/// forest is compacted via self-merge. +#[test] +fn issue_3035_compact_after_clear_debug_info_does_not_grow_mast() -> TestResult { + let context = TestContext::default(); + let module = context.parse_module_with_path( + "issue_3035::repro", + source_file!( + &context, + " + pub proc repro + add + push.100 + end + " + ), + )?; + + let library = Assembler::new(context.source_manager()).assemble_library([module])?; + let mut forest = library.mast_forest().as_ref().clone(); + assert!( + forest + .nodes() + .iter() + .filter_map(|node| node.get_basic_block()) + .any(|block| { block.operations().count() > block.raw_operations().count() }), + "test input must create at least one padded basic block" + ); + + forest.clear_debug_info(); + let stripped_size = forest.to_bytes().len(); + let stripped_without_debug_info_size = { + let mut bytes = Vec::new(); + forest.write_stripped(&mut bytes); + bytes.len() + }; + let stripped_nodes = forest.nodes().len(); + let (compacted, _) = forest.compact(); + let compacted_size = compacted.to_bytes().len(); + let compacted_without_debug_info_size = { + let mut bytes = Vec::new(); + compacted.write_stripped(&mut bytes); + bytes.len() + }; + let compacted_nodes = compacted.nodes().len(); + + assert!( + compacted_size <= stripped_size, + "MastForest::compact increased serialized size after clear_debug_info(): \ + stripped={stripped_size}, compacted={compacted_size}, \ + stripped_without_debug_info={stripped_without_debug_info_size}, \ + compacted_without_debug_info={compacted_without_debug_info_size}, \ + stripped_nodes={stripped_nodes}, compacted_nodes={compacted_nodes}" + ); + + Ok(()) +} + /// Test for issue #1644: verify that single-forest merge doesn't preserves node digests #[test] fn issue_1644_single_forest_merge_identity() -> TestResult { @@ -5001,9 +5406,9 @@ fn issue_1644_single_forest_merge_identity() -> TestResult { new_merged_forest.nodes().iter().zip(merged_forest.nodes().iter()).enumerate() { if orig_node.digest() != merged_node.digest() { - eprintln!("Node {} digest violation:", i); - eprintln!(" Original: {:?}", orig_node); - eprintln!(" Merged: {:?}", merged_node); + eprintln!("Node {i} digest violation:"); + eprintln!(" Original: {orig_node:?}"); + eprintln!(" Merged: {merged_node:?}"); eprintln!(" Original digest: {:?}", orig_node.digest()); eprintln!(" Merged digest: {:?}", merged_node.digest()); @@ -5019,7 +5424,7 @@ fn issue_1644_single_forest_merge_identity() -> TestResult { .enumerate() { if new_merged_forest[*orig_root].digest() != merged_forest[*merged_root].digest() { - eprintln!("Root {} digest violation:", i); + eprintln!("Root {i} digest violation:"); eprintln!(" Original: {:?}", original_forest[*orig_root].digest()); eprintln!(" Merged: {:?}", merged_forest[*merged_root].digest()); should_panic = true; @@ -5049,7 +5454,7 @@ fn overlong_total_path_is_rejected_without_panic() { // but the total byte length exceeds u16::MAX (the binary serialization length prefix). let component = "a".repeat(255); let num_components: usize = 300; - let mut path_str = alloc::string::String::with_capacity(num_components * (component.len() + 2)); + let mut path_str = String::with_capacity(num_components * (component.len() + 2)); for i in 0..num_components { if i > 0 { path_str.push_str("::"); @@ -5263,6 +5668,123 @@ fn test_cross_module_constant_resolution_as_local_definition() -> TestResult { Ok(()) } +#[test] +fn importing_private_constant_from_another_module_is_rejected() -> TestResult { + let context = TestContext::default(); + + let module_a = context.parse_module_with_path( + "cycle::module_a", + source_file!( + &context, + r#" + const A_VAL = 10 + pub proc a_proc + push.A_VAL + end + "# + ), + )?; + + let module_b = context.parse_module_with_path( + "cycle::module_b", + source_file!( + &context, + r#" + use cycle::module_a::A_VAL + pub proc b_proc + push.A_VAL + end + "# + ), + )?; + + let err = Assembler::new(context.source_manager()) + .assemble_library([module_a, module_b]) + .expect_err("expected private constant import to be rejected"); + assert_diagnostic!(&err, "private symbol reference"); + assert_diagnostic!(&err, "only public items can be referenced from another module"); + + Ok(()) +} + +#[test] +fn importing_private_constant_from_another_module_by_absolute_path_is_rejected() -> TestResult { + let context = TestContext::default(); + + let module_a = context.parse_module_with_path( + "cycle::module_a", + source_file!( + &context, + r#" + const A_VAL = 10 + pub proc a_proc + push.A_VAL + end + "# + ), + )?; + + let module_b = context.parse_module_with_path( + "cycle::module_b", + source_file!( + &context, + r#" + use ::cycle::module_a::A_VAL + pub proc b_proc + push.A_VAL + end + "# + ), + )?; + + let err = Assembler::new(context.source_manager()) + .assemble_library([module_a, module_b]) + .expect_err("expected private absolute constant import to be rejected"); + assert_diagnostic!(&err, "private symbol reference"); + assert_diagnostic!(&err, "only public items can be referenced from another module"); + + Ok(()) +} + +#[test] +fn importing_private_type_from_another_module_is_rejected() -> TestResult { + let context = TestContext::default(); + + let module_a = context.parse_module_with_path( + "cycle::module_a", + source_file!( + &context, + r#" + type PrivateType = felt + pub proc a_proc + nop + end + "# + ), + )?; + + let module_b = context.parse_module_with_path( + "cycle::module_b", + source_file!( + &context, + r#" + use cycle::module_a::PrivateType + pub proc b_proc(value: PrivateType) + nop + end + "# + ), + )?; + + let err = Assembler::new(context.source_manager()) + .assemble_library([module_a, module_b]) + .expect_err("expected private type import to be rejected"); + assert_diagnostic!(&err, "private symbol reference"); + assert_diagnostic!(&err, "only public items can be referenced from another module"); + + Ok(()) +} + #[test] fn test_cross_module_constant_reexport_chain_in_procedure_scope() -> TestResult { let context = TestContext::new(); @@ -5358,16 +5880,107 @@ fn test_issue_2696_imported_constant_with_private_dependency() -> TestResult { } #[test] -fn test_cross_module_constant_cycle_in_procedure_scope_is_structured_error() { +fn imported_main_alias_self_call_is_structured_error() { use std::panic::{AssertUnwindSafe, catch_unwind}; let context = TestContext::new(); + let program = r#" + use ::$exec::"$main"->alias_main - let a = parse_module!( - &context, - "cycle::a", - r#" - use cycle::b + begin + call.alias_main + end + "#; + + let assembled = catch_unwind(AssertUnwindSafe(|| { + Assembler::new(context.source_manager()).assemble_program(program) + })); + + assert!(assembled.is_ok(), "assembler panicked during assembly"); + let err = assembled + .unwrap() + .expect_err("expected self-referential alias call to be rejected"); + assert_diagnostic!(&err, "invalid recursive procedure call"); + assert_diagnostic!(&err, "this call is self-recursive"); +} + +#[test] +fn rootless_call_cycle_is_structured_error() { + use std::panic::{AssertUnwindSafe, catch_unwind}; + + let context = TestContext::new(); + let program = r#" + begin + call.b + end + + proc b + call."$main" + end + "#; + + let assembled = catch_unwind(AssertUnwindSafe(|| { + Assembler::new(context.source_manager()).assemble_program(program) + })); + + assert!(assembled.is_ok(), "assembler panicked during assembly"); + let err = assembled.unwrap().expect_err("expected cyclic program to be rejected"); + assert_diagnostic!(&err, "found a cycle in the call graph"); + assert_diagnostic!(&err, "::$exec::$main"); + assert_diagnostic!(&err, "b"); +} + +#[test] +fn cyclic_link_retry_is_structured_error_without_panicking() { + use std::panic::{AssertUnwindSafe, catch_unwind}; + + use crate::linker::Linker; + + let context = TestContext::new(); + let module = context + .parse_program(source_file!( + &context, + r#" + begin + call.b + end + + proc b + call."$main" + end + "# + )) + .expect("program parsing must succeed"); + let source_manager = context.source_manager(); + + let first_attempt = catch_unwind(AssertUnwindSafe(|| { + let mut linker = Linker::new(source_manager.clone()); + let first_err = linker + .link([module.clone()]) + .expect_err("expected cyclic program to be rejected on first link"); + let second_err = linker + .link(core::iter::empty()) + .expect_err("expected cyclic program to be rejected on second link"); + (first_err, second_err) + })); + + assert!(first_attempt.is_ok(), "linker panicked while retrying a cyclic link"); + let (first_err, second_err) = first_attempt.unwrap(); + assert!(first_err.to_string().contains("found a cycle in the call graph")); + assert!(second_err.to_string().contains("found a cycle in the call graph")); +} + +#[test] +fn test_cross_module_constant_cycle_in_procedure_scope_is_structured_error() { + use std::panic::{AssertUnwindSafe, catch_unwind}; + + let context = TestContext::new(); + + let a = parse_module!( + &context, + "cycle::a", + r#" + use cycle::b pub proc use_cycle push.A @@ -5440,6 +6053,308 @@ fn imported_error_message_cycle_is_rejected_without_panicking() { assert_diagnostic!(&err, "pub const ERR_B = a::ERR_A"); } +#[test] +fn exporting_unresolved_digest_alias_preserves_digest_without_panicking() { + use std::panic::{AssertUnwindSafe, catch_unwind}; + + let context = TestContext::new(); + let digest = Word::default(); + let module = context + .parse_module_with_path( + "m::n", + source_file!( + &context, + "pub use 0x0000000000000000000000000000000000000000000000000000000000000000 -> foo\n" + ), + ) + .expect("module parsing must succeed"); + + let assembled = catch_unwind(AssertUnwindSafe(|| { + Assembler::new(context.source_manager()).assemble_library([module]) + })); + + assert!(assembled.is_ok(), "assembly panicked, expected library assembly to succeed"); + let library = assembled + .unwrap() + .expect("expected digest alias export to assemble successfully"); + assert_eq!(library.get_procedure_root_by_path("m::n::foo"), Some(digest)); +} + +#[test] +fn path_alias_chain_to_digest_assembles_without_panicking() { + use std::panic::{AssertUnwindSafe, catch_unwind}; + + let context = TestContext::new(); + let digest = Word::default(); + let module = context + .parse_module_with_path( + "m::n", + source_file!( + &context, + r#" + pub use 0x0000000000000000000000000000000000000000000000000000000000000000 -> foo + pub use m::n::foo->bar + + pub proc calls_bar + call.bar + end + "# + ), + ) + .expect("module parsing must succeed"); + + let assembled = catch_unwind(AssertUnwindSafe(|| { + Assembler::new(context.source_manager()).assemble_library([module]) + })); + + assert!(assembled.is_ok(), "assembly panicked, expected library assembly to succeed"); + let library = assembled + .unwrap() + .expect("expected digest alias chain to assemble successfully"); + assert_eq!(library.get_procedure_root_by_path("m::n::bar"), Some(digest)); + assert!(library.get_procedure_root_by_path("m::n::calls_bar").is_some()); +} + +#[test] +fn imported_digest_alias_invoke_assembles_without_panicking() { + use std::panic::{AssertUnwindSafe, catch_unwind}; + + let program = r#" + use 0x0000000000000000000000000000000000000000000000000000000000000000 -> foo + + begin + exec.foo + end + "#; + + let assembled = + catch_unwind(AssertUnwindSafe(|| Assembler::default().assemble_program(program))); + + assert!( + assembled.is_ok(), + "assembly panicked, expected opaque digest invoke to be allowed" + ); + assembled + .unwrap() + .expect("expected digest-backed invoke alias to assemble successfully"); +} + +#[test] +fn imported_digest_alias_invoke_is_not_reported_unused_when_warnings_are_errors() { + use std::sync::Arc; + + use crate::{DefaultSourceManager, Parse, ParseOptions, ast::ModuleKind}; + + let source_manager: Arc = Arc::new(DefaultSourceManager::default()); + let program = r#" + use 0x0000000000000000000000000000000000000000000000000000000000000000 -> foo + + begin + exec.foo + end + "#; + + let mut options = ParseOptions::new(ModuleKind::Executable, "main"); + options.warnings_as_errors = true; + + <&str as Parse>::parse_with_options(program, source_manager, options) + .expect("expected digest-backed invoke alias to count as used"); +} + +#[test] +fn imported_digest_alias_forward_decl_is_not_reported_unused_when_warnings_are_errors() { + use std::sync::Arc; + + use crate::{DefaultSourceManager, Parse, ParseOptions, ast::ModuleKind}; + + let source_manager: Arc = Arc::new(DefaultSourceManager::default()); + let program = r#" + proc helper + exec.foo + end + + use 0x0000000000000000000000000000000000000000000000000000000000000000 -> foo + + begin + call.helper + end + "#; + + let mut options = ParseOptions::new(ModuleKind::Executable, "main"); + options.warnings_as_errors = true; + + <&str as Parse>::parse_with_options(program, source_manager, options) + .expect("expected forward-declared digest alias to count as used"); +} + +#[test] +fn forward_declared_import_used_by_alias_target_is_not_reported_unused_when_warnings_are_errors() { + use std::sync::Arc; + + use crate::{DefaultSourceManager, Parse, ParseOptions, ast::ModuleKind}; + + let source_manager: Arc = Arc::new(DefaultSourceManager::default()); + let module = r#" + pub use foo::bar -> baz + use external::module -> foo + "#; + + let mut options = ParseOptions::new(ModuleKind::Library, "m"); + options.warnings_as_errors = true; + + <&str as Parse>::parse_with_options(module, source_manager, options) + .expect("expected forward-declared import used by alias target to count as used"); +} + +#[test] +fn forward_declared_import_used_by_type_ref_is_not_reported_unused_when_warnings_are_errors() { + use std::sync::Arc; + + use crate::{DefaultSourceManager, Parse, ParseOptions, ast::ModuleKind}; + + let source_manager: Arc = Arc::new(DefaultSourceManager::default()); + let module = r#" + type Local = foo::Type + use external::module -> foo + "#; + + let mut options = ParseOptions::new(ModuleKind::Library, "m"); + options.warnings_as_errors = true; + + <&str as Parse>::parse_with_options(module, source_manager, options) + .expect("expected forward-declared import used by type ref to count as used"); +} + +#[test] +fn forward_declared_import_used_by_proc_signature_is_not_reported_unused_when_warnings_are_errors() +{ + use std::sync::Arc; + + use crate::{DefaultSourceManager, Parse, ParseOptions, ast::ModuleKind}; + + let source_manager: Arc = Arc::new(DefaultSourceManager::default()); + let module = r#" + pub proc check(value: foo::Type) -> foo::Type + nop + end + use external::module -> foo + "#; + + let mut options = ParseOptions::new(ModuleKind::Library, "m"); + options.warnings_as_errors = true; + + <&str as Parse>::parse_with_options(module, source_manager, options) + .expect("expected forward-declared import used by signature type to count as used"); +} + +#[test] +fn kernel_import_used_by_proc_signature_is_not_reported_unused_when_warnings_are_errors() { + let context = TestContext::new(); + context + .parse_kernel(source_file!( + &context, + r#" + use external::module -> foo + + pub proc check(value: foo::Type) -> foo::Type + nop + end + "# + )) + .expect("expected kernel signature type import to count as used"); +} + +#[test] +fn forward_declared_import_used_by_constant_ref_is_not_reported_unused_when_warnings_are_errors() { + use std::sync::Arc; + + use crate::{DefaultSourceManager, Parse, ParseOptions, ast::ModuleKind}; + + let source_manager: Arc = Arc::new(DefaultSourceManager::default()); + let module = r#" + const LOCAL = foo::BAR + use external::module -> foo + "#; + + let mut options = ParseOptions::new(ModuleKind::Library, "m"); + options.warnings_as_errors = true; + + <&str as Parse>::parse_with_options(module, source_manager, options) + .expect("expected forward-declared import used by constant ref to count as used"); +} + +#[test] +fn imported_digest_alias_subpath_is_rejected_without_panicking() { + use std::panic::{AssertUnwindSafe, catch_unwind}; + + let program = r#" + use 0x0000000000000000000000000000000000000000000000000000000000000000 -> foo + + begin + exec.foo::bar + end + "#; + + let assembled = + catch_unwind(AssertUnwindSafe(|| Assembler::default().assemble_program(program))); + + assert!(assembled.is_ok(), "assembly panicked, expected a structured error"); + let err = assembled + .unwrap() + .expect_err("expected digest-backed invoke subpath to be rejected"); + assert_diagnostic!(&err, "invalid procedure path: not an item"); +} + +#[test] +fn invoking_local_type_alias_returns_error_instead_of_panicking() { + use std::panic::{AssertUnwindSafe, catch_unwind}; + + let masm = "type foo = u32\nbegin\n exec.foo\nend\n"; + + let result = catch_unwind(AssertUnwindSafe(|| Assembler::default().assemble_program(masm))); + + let result = result.expect("assembly panicked, expected a structured error"); + let err = result.expect_err("assembly unexpectedly succeeded"); + assert_diagnostic!(&err, "invalid symbol reference: wrong type"); + assert_diagnostic!(&err, "expected this symbol to reference a procedure item"); +} + +#[test] +fn invoking_local_type_alias_is_rejected_during_semantic_analysis() { + let context = TestContext::new(); + let masm = source_file!(&context, "type foo = u32\nbegin\n exec.foo\nend\n"); + + let err = context + .parse_program(masm) + .expect_err("semantic analysis unexpectedly accepted invoking a local type alias"); + assert_diagnostic!(&err, "invalid symbol reference: wrong type"); + assert_diagnostic!(&err, "expected this symbol to reference a procedure item"); +} + +#[test] +fn invoking_imported_type_alias_returns_error_instead_of_panicking() { + use std::panic::{AssertUnwindSafe, catch_unwind}; + + let context = TestContext::new(); + let lib = context + .parse_module_with_path("test::types", source_file!(&context, "pub type foo = u32\n")) + .expect("library module parsing must succeed"); + let library = Assembler::new(context.source_manager()) + .assemble_library([lib]) + .expect("library assembly must succeed"); + + let mut assembler = Assembler::new(context.source_manager()); + assembler.link_dynamic_library(library).expect("library linking must succeed"); + + let program = "use test::types\nbegin\n exec.types::foo\nend\n"; + let result = catch_unwind(AssertUnwindSafe(|| assembler.assemble_program(program))); + + let result = result.expect("assembly panicked, expected a structured error"); + let err = result.expect_err("assembly unexpectedly succeeded"); + assert_diagnostic!(&err, "invalid procedure reference: path refers to a non-procedure item"); + assert_diagnostic!(&err, "test::types::foo"); +} + #[test] fn test_cross_module_quoted_identifier_resolution() -> TestResult { let context = TestContext::default(); @@ -5491,6 +6406,135 @@ fn test_cross_module_quoted_identifier_resolution() -> TestResult { Ok(()) } +#[test] +fn regression_symbol_resolution_duplicate_module_paths_are_rejected_during_linking() { + fn try_assemble_program_with_link_order(libs: &[Arc]) -> Result<(), Report> { + let program_source = r#" +begin + exec.::foo::bar::add +end +"#; + + let mut assembler = Assembler::default(); + for lib in libs { + assembler.link_static_library(lib)?; + } + + assembler.assemble_program(program_source).map(|_| ()) + } + + let context = TestContext::default(); + let source_manager = context.source_manager(); + + let legit_mod = context + .parse_module_with_path( + "::foo::bar", + r#" +pub proc add + add.1 +end +"#, + ) + .expect("module must parse and analyse"); + + let attacker_mod = context + .parse_module_with_path(r#"::foo::"bar""#, "pub proc add add.2 end") + .expect("module must parse and analyse"); + + let legit_lib = Assembler::new(source_manager.clone()) + .assemble_library([legit_mod]) + .expect("library assembly must succeed"); + let attacker_lib = Assembler::new(source_manager) + .assemble_library([attacker_mod]) + .expect("library assembly must succeed"); + + let err = try_assemble_program_with_link_order(&[legit_lib.clone(), attacker_lib.clone()]) + .expect_err("expected duplicate canonical module namespace to be rejected"); + assert_diagnostic!(err, "duplicate definition found for module '::foo::bar'"); + + let err = try_assemble_program_with_link_order(&[attacker_lib, legit_lib]) + .expect_err("expected duplicate canonical module namespace to be rejected"); + assert_diagnostic!(err, "duplicate definition found for module '::foo::bar'"); +} + +#[test] +fn regression_symbol_resolution_in_library_canonical_export_collision_is_rejected() { + let context = TestContext::default(); + let source_manager = context.source_manager(); + let legit_mod = context + .parse_module_with_path("::foo::bar", "pub proc add add.1 end") + .expect("module must parse and analyse"); + let attacker_mod = context + .parse_module_with_path(r#"::foo::"bar""#, "pub proc add add.2 end") + .expect("module must parse and analyse"); + + let err = Assembler::new(source_manager) + .assemble_library([legit_mod, attacker_mod]) + .expect_err("expected duplicate canonical export paths to be rejected during assembly"); + assert_diagnostic!(err, "duplicate definition found for export path '::foo::bar::add'"); +} + +#[test] +fn regression_symbol_resolution_export_leaf_name_collision_should_be_rejected() { + let base = Assembler::default() + .assemble_library([r#" +pub proc p + push.1 +end +"#]) + .expect("base library assembly must succeed"); + let node = base + .exports() + .find_map(|e| e.as_procedure()) + .expect("expected at least one procedure export") + .node; + + let quoted = Arc::::from(Path::validate(r#"::foo::"bar""#).unwrap()); + let unquoted = Arc::::from(Path::validate("::foo::bar").unwrap()); + + let mut exports = BTreeMap::new(); + exports.insert( + quoted.clone(), + LibraryExport::Procedure(LibraryProcedureExport::new(node, quoted)), + ); + exports.insert( + unquoted.clone(), + LibraryExport::Procedure(LibraryProcedureExport::new(node, unquoted)), + ); + + let lib = Library::new(Arc::clone(base.mast_forest()), exports).expect("library must validate"); + let err = Library::read_from_bytes(&lib.to_bytes()).expect_err( + "expected duplicate canonical export paths to be rejected during deserialization", + ); + assert_matches!(err, DeserializationError::InvalidValue(_)); +} + +#[test] +fn regression_symbol_resolution_malformed_quoted_export_leaf_should_return_error_not_panic() { + let base = Assembler::default() + .assemble_library([r#" +pub proc p + push.1 +end +"#]) + .expect("base library assembly must succeed"); + let node = base + .exports() + .find_map(|e| e.as_procedure()) + .expect("expected at least one procedure export") + .node; + + let bad = Arc::::from(Path::validate(r#"::foo::"bad name""#).unwrap()); + + let mut exports = BTreeMap::new(); + exports.insert(bad.clone(), LibraryExport::Procedure(LibraryProcedureExport::new(node, bad))); + + let lib = Library::new(Arc::clone(base.mast_forest()), exports).expect("library must validate"); + let err = Library::read_from_bytes(&lib.to_bytes()) + .expect_err("expected malformed procedure export leaf names to be rejected"); + assert_matches!(err, DeserializationError::InvalidValue(_)); +} + #[test] fn test_kernel_linking_against_its_own_library() -> TestResult { let context = TestContext::default(); @@ -5748,6 +6792,45 @@ end assert_diagnostic!(err, "invalid syscall"); } +#[test] +fn regression_kernel_exports_are_syscall_only_for_all_non_syscall_entrypoints() { + let context = TestContext::default(); + let source_manager = context.source_manager(); + + let kernel_src = r#" +pub proc k1 + push.1 +end +"#; + + let kernel = Assembler::new(source_manager.clone()) + .assemble_kernel(kernel_src) + .expect("kernel assembly must succeed"); + + let cases = vec![ + ( + "exec", + "proc user\n exec.::$kernel::k1\nend\n\nbegin\n call.user\nend\n".to_string(), + ), + ( + "call", + "proc user\n call.::$kernel::k1\nend\n\nbegin\n call.user\nend\n".to_string(), + ), + ( + "procref", + "proc user\n procref.::$kernel::k1\n dropw\nend\n\nbegin\n call.user\nend\n" + .to_string(), + ), + ]; + + for (kind, program_src) in cases { + let err = Assembler::with_kernel(source_manager.clone(), kernel.clone()) + .assemble_program(program_src) + .expect_err(&format!("kernel exports should be syscall-only, but {kind} succeeded")); + assert_diagnostic!(err, "syscall"); + } +} + #[test] fn test_linking_imported_symbols_with_duplicate_prefix_components() -> TestResult { let context = TestContext::default(); diff --git a/crates/assembly/tests/fixtures/protocol/kernel/bin/main-alt.masm b/crates/assembly/tests/fixtures/protocol/kernel/bin/main-alt.masm index 411644105d..d4e0538b91 100644 --- a/crates/assembly/tests/fixtures/protocol/kernel/bin/main-alt.masm +++ b/crates/assembly/tests/fixtures/protocol/kernel/bin/main-alt.masm @@ -8,9 +8,6 @@ proc invoke_user_script end begin - # At program start, initialize the kernel environment - exec.$kernel::init - # Execute the user script whose entrypoint digest is on top of the stack exec.invoke_user_script end diff --git a/crates/assembly/tests/fixtures/protocol/kernel/bin/main.masm b/crates/assembly/tests/fixtures/protocol/kernel/bin/main.masm index 411644105d..d4e0538b91 100644 --- a/crates/assembly/tests/fixtures/protocol/kernel/bin/main.masm +++ b/crates/assembly/tests/fixtures/protocol/kernel/bin/main.masm @@ -8,9 +8,6 @@ proc invoke_user_script end begin - # At program start, initialize the kernel environment - exec.$kernel::init - # Execute the user script whose entrypoint digest is on top of the stack exec.invoke_user_script end diff --git a/crates/assembly/tests/fixtures/protocol/kernel/miden-project.toml b/crates/assembly/tests/fixtures/protocol/kernel/miden-project.toml index e87e320759..dd3513a1e1 100644 --- a/crates/assembly/tests/fixtures/protocol/kernel/miden-project.toml +++ b/crates/assembly/tests/fixtures/protocol/kernel/miden-project.toml @@ -15,5 +15,4 @@ name = "entry-alt" path = "bin/main-alt.masm" [dependencies] -miden-core.workspace = true miden-utils.workspace = true diff --git a/crates/assembly/tests/fixtures/protocol/miden-project.toml b/crates/assembly/tests/fixtures/protocol/miden-project.toml index dba8b90c5b..d27e7d6f08 100644 --- a/crates/assembly/tests/fixtures/protocol/miden-project.toml +++ b/crates/assembly/tests/fixtures/protocol/miden-project.toml @@ -6,7 +6,6 @@ members = [ ] [workspace.dependencies] -miden-core = { path = "../../../../../lib/core/asm" } miden-utils = { path = "utils", linkage = "static" } miden-tx = { path = "kernel" } diff --git a/crates/assembly/tests/fixtures/protocol/userspace/miden-project.toml b/crates/assembly/tests/fixtures/protocol/userspace/miden-project.toml index a294dab6db..0e25d34893 100644 --- a/crates/assembly/tests/fixtures/protocol/userspace/miden-project.toml +++ b/crates/assembly/tests/fixtures/protocol/userspace/miden-project.toml @@ -7,6 +7,5 @@ namespace = "miden::protocol" path = "mod.masm" [dependencies] -miden-core.workspace = true miden-utils = { workspace = true, linkage = "dynamic" } miden-tx.workspace = true diff --git a/crates/debug-types/Cargo.toml b/crates/debug-types/Cargo.toml index 41edc7d24a..bc48388d71 100644 --- a/crates/debug-types/Cargo.toml +++ b/crates/debug-types/Cargo.toml @@ -14,16 +14,21 @@ homepage.workspace = true repository.workspace = true exclude.workspace = true +[package.metadata.cargo-shear] +ignored = ["serde_json"] + [features] default = ["std"] std = [ "memchr/std", "miden-formatting/std", "miden-utils-sync/std", + "proptest?/std", "serde/std", "serde_spanned?/std", "thiserror/std", ] +arbitrary = ["std", "dep:proptest"] serde = ["dep:serde", "dep:serde_spanned", "serde_spanned?/serde"] [dependencies] @@ -35,8 +40,14 @@ miden-utils-indexing.workspace = true # External dependencies memchr = { version = "2.7", default-features = false } -miette = { package = "miden-miette", version = "8.0", default-features = false, features = ["fancy-no-syscall", "derive"] } +miette = { workspace = true, features = ["fancy-no-syscall", "derive"] } paste.workspace = true +proptest = { workspace = true, optional = true } serde = { workspace = true, optional = true } serde_spanned = { version = "1.0", optional = true, default-features = false } thiserror.workspace = true + +[dev-dependencies] +miden-test-serde-macros.workspace = true +proptest.workspace = true +serde_json.workspace = true diff --git a/crates/debug-types/src/lib.rs b/crates/debug-types/src/lib.rs index e2006bf73f..9c59149a44 100644 --- a/crates/debug-types/src/lib.rs +++ b/crates/debug-types/src/lib.rs @@ -11,11 +11,15 @@ mod source_file; mod source_manager; mod span; +#[cfg(feature = "arbitrary")] +use alloc::vec; use alloc::{string::String, sync::Arc}; use miden_crypto::utils::{ ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable, }; +#[cfg(feature = "arbitrary")] +use proptest::prelude::*; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; #[cfg(feature = "serde")] @@ -41,6 +45,10 @@ pub use self::{ /// the location of a source file, whether on disk, on the network, or elsewhere. #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr( + all(feature = "arbitrary", test), + miden_test_serde_macros::serde_test(binary_serde(true)) +)] pub struct Uri(Arc); impl Uri { @@ -187,6 +195,35 @@ impl core::str::FromStr for Uri { } } +#[cfg(feature = "arbitrary")] +impl Arbitrary for Uri { + type Parameters = (); + type Strategy = BoxedStrategy; + + fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { + use alloc::string::String; + + proptest::collection::vec( + proptest::prop_oneof![ + proptest::char::range('a', 'z'), + proptest::char::range('A', 'Z'), + proptest::char::range('0', '9'), + Just('/'), + Just(':'), + Just('.'), + Just('-'), + Just('_'), + Just('#'), + Just('?'), + Just('@'), + ], + 1..48, + ) + .prop_map(|chars| Self::from(chars.into_iter().collect::())) + .boxed() + } +} + // TESTS // ================================================================================================ diff --git a/crates/debug-types/src/location.rs b/crates/debug-types/src/location.rs index af369f41e0..073ea24500 100644 --- a/crates/debug-types/src/location.rs +++ b/crates/debug-types/src/location.rs @@ -3,6 +3,8 @@ use core::{fmt, ops::Range}; use miden_crypto::utils::{ ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable, }; +#[cfg(feature = "arbitrary")] +use proptest::prelude::*; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; @@ -14,6 +16,7 @@ use super::{ /// A [Location] represents file and span information for portability across source managers #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] +#[cfg_attr(all(feature = "arbitrary", test), miden_test_serde_macros::serde_test)] pub struct Location { /// The path to the source file in which the relevant source code can be found pub uri: Uri, @@ -43,6 +46,10 @@ impl Location { /// A [FileLineCol] represents traditional file/line/column information for use in rendering. #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] +#[cfg_attr( + all(feature = "arbitrary", test), + miden_test_serde_macros::serde_test(binary_serde(true)) +)] pub struct FileLineCol { /// The path to the source file in which the relevant source code can be found pub uri: Uri, @@ -104,3 +111,30 @@ impl Deserializable for FileLineCol { Ok(Self::new(uri, line, column)) } } + +#[cfg(feature = "arbitrary")] +impl Arbitrary for Location { + type Parameters = (); + type Strategy = BoxedStrategy; + + fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { + (any::(), any::(), any::()) + .prop_map(|(uri, start, end)| { + let (start, end) = if start <= end { (start, end) } else { (end, start) }; + Self::new(uri, ByteIndex::new(start), ByteIndex::new(end)) + }) + .boxed() + } +} + +#[cfg(feature = "arbitrary")] +impl Arbitrary for FileLineCol { + type Parameters = (); + type Strategy = BoxedStrategy; + + fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { + (any::(), any::(), any::()) + .prop_map(|(uri, line, column)| Self::new(uri, line, column)) + .boxed() + } +} diff --git a/crates/debug-types/src/source_file.rs b/crates/debug-types/src/source_file.rs index c8b36a1261..9a6f7d8bb7 100644 --- a/crates/debug-types/src/source_file.rs +++ b/crates/debug-types/src/source_file.rs @@ -6,6 +6,8 @@ use alloc::{ }; use core::{fmt, num::NonZeroU32, ops::Range}; +#[cfg(feature = "arbitrary")] +use proptest::prelude::*; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; @@ -21,6 +23,22 @@ pub enum SourceLanguage { Other(&'static str), } +#[cfg(feature = "arbitrary")] +impl Arbitrary for SourceLanguage { + type Parameters = (); + type Strategy = BoxedStrategy; + + fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { + prop_oneof![ + Just(Self::Masm), + Just(Self::Rust), + Just(Self::Other("other")), + Just(Self::Other("unknown")), + ] + .boxed() + } +} + impl AsRef for SourceLanguage { fn as_ref(&self) -> &str { match self { @@ -54,7 +72,7 @@ impl miette::SourceCode for SourceFile { span: &miette::SourceSpan, context_lines_before: usize, context_lines_after: usize, - ) -> Result + 'a>, miette::MietteError> { + ) -> Result + 'a>, miette::MietteError> { let mut start = u32::try_from(span.offset()).map_err(|_| miette::MietteError::OutOfBounds)?; let len = u32::try_from(span.len()).map_err(|_| miette::MietteError::OutOfBounds)?; @@ -62,7 +80,7 @@ impl miette::SourceCode for SourceFile { if context_lines_before > 0 { let line_index = self.content.line_index(start.into()); let start_line_index = line_index.saturating_sub(context_lines_before as u32); - start = self.content.line_start(start_line_index).map(|idx| idx.to_u32()).unwrap_or(0); + start = self.content.line_start(start_line_index).map(ByteIndex::to_u32).unwrap_or(0); } if context_lines_after > 0 { let line_index = self.content.line_index(end.into()); @@ -382,7 +400,7 @@ impl miette::SourceCode for SourceFileRef { span: &miette::SourceSpan, context_lines_before: usize, context_lines_after: usize, - ) -> Result + 'a>, miette::MietteError> { + ) -> Result + 'a>, miette::MietteError> { self.file.read_span(span, context_lines_before, context_lines_after) } } @@ -771,6 +789,7 @@ fn compute_line_starts(text: &str, text_offset: Option) -> Vec { #[derive(Default, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] #[cfg_attr(feature = "serde", serde(transparent))] +#[cfg_attr(all(feature = "arbitrary", test), miden_test_serde_macros::serde_test)] pub struct ByteIndex(pub u32); impl ByteIndex { @@ -866,6 +885,16 @@ impl fmt::Display for ByteIndex { } } +#[cfg(feature = "arbitrary")] +impl Arbitrary for ByteIndex { + type Parameters = (); + type Strategy = BoxedStrategy; + + fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { + any::().prop_map(Self).boxed() + } +} + /// An offset in bytes relative to some [ByteIndex] #[derive(Default, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct ByteOffset(i64); @@ -928,6 +957,7 @@ macro_rules! declare_dual_number_and_index_type { #[derive(Default, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] #[cfg_attr(feature = "serde", serde(transparent))] + #[cfg_attr(all(feature = "arbitrary", test), miden_test_serde_macros::serde_test)] pub struct $index_name(pub u32); impl $index_name { @@ -1047,10 +1077,24 @@ macro_rules! declare_dual_number_and_index_type { } } + #[cfg(feature = "arbitrary")] + impl Arbitrary for $index_name { + type Parameters = (); + type Strategy = BoxedStrategy; + + fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { + any::().prop_map(Self).boxed() + } + } + #[doc = concat!("A one-indexed ", $description, " number")] #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] #[cfg_attr(feature = "serde", serde(transparent))] + #[cfg_attr( + all(feature = "arbitrary", test), + miden_test_serde_macros::serde_test(binary_serde(true)) + )] pub struct $number_name(NonZeroU32); impl Default for $number_name { @@ -1230,6 +1274,30 @@ impl Deserializable for ColumnNumber { } } +#[cfg(feature = "arbitrary")] +impl Arbitrary for LineNumber { + type Parameters = (); + type Strategy = BoxedStrategy; + + fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { + (1..=u32::MAX) + .prop_map(|value| Self::new(value).expect("non-zero value")) + .boxed() + } +} + +#[cfg(feature = "arbitrary")] +impl Arbitrary for ColumnNumber { + type Parameters = (); + type Strategy = BoxedStrategy; + + fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { + (1..=u32::MAX) + .prop_map(|value| Self::new(value).expect("non-zero value")) + .boxed() + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/crates/debug-types/src/source_manager.rs b/crates/debug-types/src/source_manager.rs index a798e52ac6..c70b49e1ee 100644 --- a/crates/debug-types/src/source_manager.rs +++ b/crates/debug-types/src/source_manager.rs @@ -2,6 +2,8 @@ use alloc::{boxed::Box, collections::BTreeMap, string::String, sync::Arc}; use core::{error::Error, fmt::Debug}; use miden_utils_indexing::IndexVec; +#[cfg(feature = "arbitrary")] +use proptest::prelude::*; use super::*; @@ -13,6 +15,7 @@ use super::*; #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] #[cfg_attr(feature = "serde", serde(transparent))] +#[cfg_attr(all(feature = "arbitrary", test), miden_test_serde_macros::serde_test)] pub struct SourceId(u32); impl From for SourceId { @@ -78,6 +81,16 @@ impl TryFrom for SourceId { } } +#[cfg(feature = "arbitrary")] +impl Arbitrary for SourceId { + type Parameters = (); + type Strategy = BoxedStrategy; + + fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { + any::().prop_map(Self::from).boxed() + } +} + // SOURCE MANAGER // ================================================================================================ @@ -343,7 +356,7 @@ impl DefaultSourceManagerImpl { self.files .push(file_clone) .expect("system limit: source manager has exhausted its supply of source ids"); - self.uris.insert(uri.clone(), id); + self.uris.insert(uri, id); file } @@ -474,7 +487,7 @@ mod error_assertions { use super::*; /// Asserts at compile time that the passed error has Send + Sync + 'static bounds. - fn _assert_error_is_send_sync_static(_: E) {} + fn _assert_error_is_send_sync_static(_: E) {} fn _assert_source_manager_error_bounds(err: SourceManagerError) { _assert_error_is_send_sync_static(err); diff --git a/crates/debug-types/src/span.rs b/crates/debug-types/src/span.rs index e6562432fc..287a540448 100644 --- a/crates/debug-types/src/span.rs +++ b/crates/debug-types/src/span.rs @@ -68,7 +68,7 @@ impl Span { } #[cfg(feature = "serde")] -impl<'de, T: serde::Deserialize<'de>> serde::Deserialize<'de> for Span { +impl<'de, T: Deserialize<'de>> Deserialize<'de> for Span { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, @@ -79,7 +79,7 @@ impl<'de, T: serde::Deserialize<'de>> serde::Deserialize<'de> for Span { } #[cfg(feature = "serde")] -impl serde::Serialize for Span { +impl Serialize for Span { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, diff --git a/crates/lib/core/Cargo.toml b/crates/lib/core/Cargo.toml index d0f605820f..2337563478 100644 --- a/crates/lib/core/Cargo.toml +++ b/crates/lib/core/Cargo.toml @@ -28,6 +28,7 @@ path = "tests/main.rs" [features] default = ["std"] std = ["miden-assembly/std", "miden-utils-sync/std"] +constraints-tools = ["std", "dep:miden-air", "dep:miden-ace-codegen"] [dependencies] # Miden dependencies @@ -36,28 +37,34 @@ miden-core.workspace = true miden-crypto.workspace = true miden-processor.workspace = true miden-utils-sync.workspace = true +miden-air = { workspace = true, optional = true } +miden-ace-codegen = { workspace = true, optional = true } # External dependencies thiserror.workspace = true [dev-dependencies] criterion.workspace = true -miden-ace-codegen = { path = "../../ace-codegen" } +miden-ace-codegen.workspace = true miden-air.workspace = true +miden-lifted-stark.workspace = true miden-processor = { workspace = true, features = ["testing"] } miden-prover.workspace = true miden-utils-testing.workspace = true miden-verifier.workspace = true num = { version = "0.4" } -num-bigint = { version = "0.4" } -pretty_assertions = { version = "1.4" } rand = { version = "0.9", default-features = false } -rand_chacha = { version = "0.9", default-features = false } -rstest = { version = "0.26" } -serde_json.workspace = true +rand_chacha = { workspace = true } +rstest = { workspace = true } +bincode.workspace = true [build-dependencies] env_logger.workspace = true fs-err = { version = "3.1" } miden-assembly = { workspace = true, features = ["std"] } miden-package-registry = { workspace = true, features = ["resolver"] } + +[[bin]] +name = "regenerate-constraints" +path = "src/bin/regenerate-constraints.rs" +required-features = ["constraints-tools"] diff --git a/crates/lib/core/asm/collections/mmr.masm b/crates/lib/core/asm/collections/mmr.masm index 71bf97fa18..906b75fd53 100644 --- a/crates/lib/core/asm/collections/mmr.masm +++ b/crates/lib/core/asm/collections/mmr.masm @@ -6,16 +6,22 @@ use miden::core::math::u64 #! #! This MMR implementation supports only u32 positions. #! +#! The position must refer to an existing leaf: `pos < num_leaves`, where `num_leaves` is stored +#! at `mmr_ptr[0]`. The procedure fails instead of returning an empty or sentinel word when `pos` +#! is outside the current MMR. +#! #! Stack transition: #! Input: [pos, mmr_ptr, ...] #! Output: [N, ...] where `N` is the leaf and `R` is the MMR peak that owns the leaf. -#! -#! Cycles: 118 pub proc get # load the num_leaves of the MMR (2 cycles) dup.1 mem_load # stack: [num_leaves, pos, mmr_ptr, ...] + # assert `pos < num_leaves` + dup.1 dup.1 u32assert2 u32lt assert.err="position is not an existing MMR leaf" + # stack: [num_leaves, pos, mmr_ptr, ...] + # compute `num_leaves & pos`, this contains all peaks before `pos` (and maybe some after the owning peak) (3 cycles) dup.1 dup.1 u32and # stack: [before_candidates, num_leaves, pos, mmr_ptr, ...] @@ -24,7 +30,7 @@ pub proc get dup.1 swap sub # stack: [owner_candidates, num_leaves, pos, mmr_ptr, ...] - # compute `ilog2(owner_candidates)` and `2**depth`, it corresponds to the owner peak and its depth (61 cycles) + # compute `ilog2(owner_candidates)` and `2**depth`, it corresponds to the owner peak and its depth (83 cycles) ilog2 dup.0 pow2 # stack: [owner_peak, depth, num_leaves, pos, mmr_ptr, ...] @@ -44,7 +50,7 @@ pub proc get movup.2 dup.1 sub # stack: [relative_pos, peaks_before, depth, mmr_ptr, ...] - # compute `popcount(peaks_before)`, the count peaks before the target to be skipped when loading from mem (2 cycles) + # compute `popcount(peaks_before)`, the count peaks before the target to be skipped when loading from mem (36 cycles) swap u32assert u32popcnt # stack: [peak_count, relative_pos, depth, mmr_ptr, ...] @@ -67,7 +73,7 @@ pub proc get drop drop # (2 cycles) # stack: [leaf, ...] else - # verify and get the leaf (9 cycles) + # verify and get the leaf (10 cycles) mtree_get # stack: [leaf, root, ...] @@ -83,9 +89,9 @@ end #! #! Input: [num_leaves, ...] #! Output: [num_peaks, ...] -#! Cycles: 69 +#! Cycles: 67 pub proc num_leaves_to_num_peaks - # count number of peaks (69 cycles) + # count number of peaks (67 cycles) u32split u32popcnt swap u32popcnt add # => [count, ...] end @@ -122,7 +128,7 @@ end #! starting with the MMR forest (its total leaves count) followed by its peaks. #! The address is expected to be word-aligned. #! -#! Cycles: 164 + 9 * extra_peak_pair cycles +#! Cycles: 162 + 9 * extra_peak_pair cycles #! where `extra_peak` is the number of peak pairs in addition to the first #! 16, i.e. `round_up((num_of_peaks - 16) / 2)` pub proc unpack @@ -132,7 +138,7 @@ pub proc unpack # advice_stack => [NUM_LEAVES, peaks*, ...] # load the size from the advice stack (10 cycles) - padw adv_loadw movdn.3 drop drop drop + adv_pushw movdn.3 drop drop drop # operand_stack => [num_leaves, HASH, mmr_ptr, ...] # advice_stack => [peaks*, ...] @@ -181,13 +187,13 @@ end #! #! Input: [mmr_ptr, ...] #! Output: [HASH, ...] -#! Cycles: 130 + 3 * num_peaks +#! Cycles: 128 + 3 * num_peaks pub proc pack # load num_leaves (2 cycles) dup mem_load # => [num_leaves, mmr_ptr, ...] - # compute num_peaks (69 cycles) + # compute num_peaks (67 cycles) exec.num_leaves_to_num_peaks # => [num_peaks, mmr_ptr, ...] @@ -224,7 +230,7 @@ end #! #! Input: [EL, mmr_ptr, ...] #! Output: [...] -#! Cycles: 147 + 39 * peak_merges +#! Cycles: 145 + 39 * peak_merges pub proc add # get num_leaves (2 cycles) dup.4 mem_load @@ -235,7 +241,7 @@ pub proc add # => [num_leaves, EL, mmr_ptr] dup exec.num_leaves_to_num_peaks - # [num_peaks, num_leaves, EL, mmr_ptr] (70 cycles) + # [num_peaks, num_leaves, EL, mmr_ptr] (68 cycles) # compute peaks_end (6 cycles) mul.4 movup.6 add add.4 @@ -293,4 +299,4 @@ pub proc add # clean stack (5 cycles) dropw drop -end \ No newline at end of file +end diff --git a/crates/lib/core/asm/collections/smt.masm b/crates/lib/core/asm/collections/smt.masm index ba626dcc3f..1d43c66788 100644 --- a/crates/lib/core/asm/collections/smt.masm +++ b/crates/lib/core/asm/collections/smt.masm @@ -14,6 +14,11 @@ const LEAF_DEPTH = 64 # Each key-value pair is two words, and a leaf can hold up to 1024 pairs. const MAX_LEAF_SIZE = 8192 +# Domain identifier used when hashing SMT leaves. Matches `SmtLeaf::LEAF_DOMAIN` in miden-crypto +# and is mixed into the Poseidon2 capacity word to domain-separate leaf hashes from ordinary +# inner Merkle nodes. +const LEAF_DOMAIN = 0x13af + # EXPORTS # ================================================================================================= @@ -34,8 +39,8 @@ const MAX_LEAF_SIZE = 8192 #! Cycles #! Leaf empty: 66 cycles #! Leaf single: 115 cycles -#! Leaf multiple, non-empty value: 189 + 3 * pair_count -#! Leaf multiple, empty value: 186 + 3 * pair_count +#! Leaf multiple, non-empty value: 189 + 6 * pair_count +#! Leaf multiple, empty value: 186 + 6 * pair_count pub proc get # Prepare for `mtree_get` # (6 cycles) @@ -66,7 +71,7 @@ pub proc get # Get leaf pre-image from advice map. Push the leaf preimage size on the stack # (0 cycles) - adv.push_mapvaln adv_push.1 + adv.push_mapvaln adv_push # => [leaf_size, NV, K, R] # Consistency check: assert this is actually a valid leaf. @@ -85,8 +90,8 @@ pub proc get # Push leaf pre-image on stack (single K-V pair) # (1 cycle) drop - padw adv_loadw - padw adv_loadw + adv_pushw + adv_pushw swapw # => [K, V, NV, K, R] @@ -100,15 +105,15 @@ pub proc get dupw.1 movdnw.3 # => [V, K, NV, V, R] - # Hash leaf preimage and ensure that it equals node value - # (27 cycles) - hmerge assert_eqw + # Hash leaf preimage with domain separation and ensure that it equals node value + # (28 cycles) + push.LEAF_DOMAIN exec.poseidon2::merge_in_domain assert_eqw # => [V, R] else # => [leaf_size, NV, K, R] - # (125 + 3 * leaf_size / 8 cycles if V is not empty) - # (122 + 3 * leaf_size / 8 cycles if V is empty) + # (125 + 6 * leaf_size / 8 cycles if V is not empty) + # (122 + 6 * leaf_size / 8 cycles if V is empty) exec.get_multi_leaf_value # => [V, R] end @@ -141,15 +146,17 @@ end #! Leaf multiple #! X cycles pub proc set - # Prepare stack for adv.push_mtnode - # (X cycles) + # Prepare stack for mtree_get + # (5 cycles) movupw.2 dup.11 push.LEAF_DEPTH # => [depth, leaf_index=K[3], R, V, K] - # Push MT node on advice stack (in structural order for adv_loadw), cleanup operand stack, - # and then push MT node on operand stack (NV) - # (X cycles) - adv.push_mtnode drop drop movdnw.2 padw adv_loadw + # Retrieve node value (NV) from the Merkle store AND verify its Merkle path against R. + # Performing this check up-front binds NV to root R at position K[3] before any branch of + # this procedure inspects the leaf preimage. Every downstream path either hashes the leaf + # preimage against NV or calls mtree_set. + # (14 cycles) + mtree_get swapw movdnw.3 # => [NV, V, K, R] # (X cycles) @@ -176,7 +183,7 @@ pub proc set # Retrieve leaf pre-image on advice stack, and push leaf size on stack # Note: the rest of the leaf pre-image will be pulled out later # (4 cycles) - adv.push_mapvaln adv_push.1 + adv.push_mapvaln adv_push # => [leaf_size, NV, V, K, R] # Leaf size will be a multiple of 8 (each kv-pair in a leaf is 8 elements) @@ -187,9 +194,17 @@ pub proc set if.true # Single kv-pair case - # (1 cycle) - drop dropw - # => [V, K, R] + drop + # => [NV, V, K, R] + + # Load the advice-provided single-leaf preimage (K_l, V_l) and assert + # hash_in_domain(K_l, V_l, LEAF_DOMAIN) == NV. + adv_pushw adv_pushw + # => [V_l, K_l, NV, V, K, R] + dupw dupw.2 push.LEAF_DOMAIN exec.poseidon2::merge_in_domain + # => [hash_in_domain(K_l, V_l, LEAF_DOMAIN), V_l, K_l, NV, V, K, R] + movupw.3 assert_eqw.err="invalid single-leaf preimage: hash does not match node value" + # => [V_l, K_l, V, K, R] # (remove key/value: X cycles) # (insert; leaf single after insertion: X cycles) @@ -247,8 +262,8 @@ end #! Operand stack: [V, R] #! #! Cycles: -#! Non-empty: 125 + 3 * pair_count -#! Empty: 122 + 3 * pair_count +#! Non-empty: 125 + 6 * pair_count +#! Empty: 122 + 6 * pair_count @locals(8192) proc get_multi_leaf_value # First, we'll pipe all the pairs in the leaf from the advice stack. @@ -268,8 +283,9 @@ proc get_multi_leaf_value locaddr.0 swap # => [num_words, ptr, COM, K, R] - # Cycles: 56 + 3 * num_words / 2 - exec.mem::pipe_double_words_preimage_to_memory + # Push the leaf domain separator. + # Cycles: 58 + 3 * num_words + push.LEAF_DOMAIN exec.mem::pipe_double_words_preimage_to_memory_with_domain # => [ptr_end, K, R] # (4 cycles) @@ -332,60 +348,48 @@ proc set_empty_leaf #=> [V == ZERO, ZERO, V, K, R] if.true - # Inserting an empty value; this is a no-op (4 cycles) + # Inserting an empty value; this is a no-op. The top-level mtree_get in + # `set` already authenticated that the leaf is empty at K[3]. dropw #=> [V (=ZERO), K, R, ...] - # Prepare stack: verify that the leaf is actually empty - # (X cycles) - movupw.2 swapw dup.11 movdn.4 push.LEAF_DEPTH movdn.4 - #=> [V (=ZERO), depth, K[3], R, K, ...] - - # (1 cycle) - mtree_verify - #=> [V (=ZERO), depth, K[3], R, K, ...] - - # Prepare stack for return (X cycles) - movup.4 drop movup.4 drop movupw.2 dropw + swapw dropw #=> [V (=ZERO), R, ...] else # Inserting a non-empty value (4 cycles) dropw #=> [V, K, R, ...] - # Update advice map (swap to put K on top for key = hash(K || V)) - swapw adv.insert_hdword swapw + # Update advice map (swap to put K on top for the leaf-domain + # hash key hash_in_domain(K || V, LEAF_DOMAIN)). + swapw push.LEAF_DOMAIN movdn.8 adv.insert_hdword_d movup.8 drop swapw #=> [V, K, R, ...] - # Compute hash([K, V]); the new node value (NV) - # (20 cycles) - dupw.1 hmerge + # Compute hash_in_domain([K, V], LEAF_DOMAIN); the new node value (NV) + # (21 cycles) + dupw.1 push.LEAF_DOMAIN exec.poseidon2::merge_in_domain # => [NV, K, R] # Prepare stack for `mtree_set` (5 cycles) movupw.2 dup.11 push.LEAF_DEPTH #=> [depth, K[3], R, NV, K] - # Insert node in Merkle store (29 cycles) + # Insert node in Merkle store. V_in_leaf returned by mtree_set is + # authenticated and already known to be ZERO from the top-level + # mtree_get, so we use it directly as the empty return value. mtree_set - #=> [V_in_leaf, R_new, K] - - # Check that V_in_leaf is indeed empty (15 cycles) - padw assert_eqw - #=> [R_new, K] + #=> [V_in_leaf (=ZERO), R_new, K] - # Prepare stack for return (9 cycles) - swapw dropw padw + movupw.2 dropw #=> [ZERO, R_new] end end #! Inserts or removes a value associated with the given key. The leaf to which we're inserting is -#! guaranteed to hold a single key-value pair (provided on the advice stack). +#! guaranteed to hold a single key-value pair with preimage (K_l, V_l). #! #! Inputs: -#! Operand stack: [V, K, R, ...] -#! Advice stack: [K_in_leaf, V_in_leaf] +#! Operand stack: [V_l, K_l, V, K, R, ...] #! #! Outputs: #! Operand stack: [V_old, R_new, ...] @@ -394,39 +398,34 @@ end #! Insert; leaf single after insertion: X cycles #! Insert; leaf multiple after insertion: X cycles proc set_single_leaf - # Check if we're inserting or removing a value - # (X cycles) - padw eqw - # => [V==ZERO, ZERO, V, K, R, ...] + # Check if we're inserting or removing a value. V lives at word 2, so dup it + # without disturbing the validated preimage at words 0-1. + dupw.2 padw eqw + # => [V==ZERO, ZERO, V, V_l, K_l, V, K, R, ...] if.true # we're removing the value associated with K (if any) - # (4 cycles) - dropw - # => [V, K, R, ...] + dropw dropw + # => [V_l, K_l, V, K, R, ...] - # (X cycles) exec.remove_single_leaf # => [V_old, R_new] else # we're inserting the key/value pair - # (4 cycles) - dropw - # => [V, K, R, ...] + dropw dropw + # => [V_l, K_l, V, K, R, ...] - # (X cycles) exec.insert_single_leaf # => [V_old, R_new] end end -#! Inserts a value at the given key. The leaf to which we're inserting is -#! guaranteed to hold a single key-value pair (provided on the advice stack). +#! Inserts a value at the given key. The leaf to which we're inserting is guaranteed to hold a +#! single key-value pair with preimage (K_l, V_l). #! #! Inputs: -#! Operand stack: [V, K, R, ...] -#! Advice stack: [K_in_leaf, V_in_leaf] +#! Operand stack: [V_l, K_l, V, K, R, ...] #! #! Outputs: #! Operand stack: [V_old, R_new, ...] @@ -435,57 +434,43 @@ end #! Leaf single after insertion: X cycles #! Leaf multiple after insertion: X cycles proc insert_single_leaf - # Push the leaf pre-image on stack - # (X cycles) - padw adv_loadw - padw adv_loadw - # => [V_in_leaf, K_in_leaf, V, K, R] - # Check if the key stored in the leaf is the same as K - # (X cycles) movupw.3 movupw.2 eqw - # => [K_in_leaf==K, K_in_leaf, K, V_in_leaf, V, R] + # => [K_l==K, K_l, K, V_l, V, R] if.true # Leaf stays a "single" variant - # (4 cycles) dropw - # => [K, V_in_leaf, V, R] + # => [K, V_l, V, R] - # Update advice map (5 cycles, swap to put K on top for key = hash(K || V)) - movupw.2 swapw adv.insert_hdword swapw - # => [V, K, V_in_leaf, R] + # Update advice map (swap to put K on top for the leaf-domain + # hash key hash_in_domain(K || V, LEAF_DOMAIN)). + movupw.2 swapw push.LEAF_DOMAIN movdn.8 adv.insert_hdword_d movup.8 drop swapw + # => [V, K, V_l, R] - # Compute hash([K, V]); the new node value (NV) + # Compute hash_in_domain([K, V], LEAF_DOMAIN); the new node value (NV) # (X cycles) - dupw.1 hmerge - # => [NV, K, V_in_leaf, R] + dupw.1 push.LEAF_DOMAIN exec.poseidon2::merge_in_domain + # => [NV, K, V_l, R] # Prepare stack to update Merkle store - # (X cycles) movupw.3 dup.11 push.LEAF_DEPTH - # => [depth, K[3], R, NV, K, V_in_leaf] + # => [depth, K[3], R, NV, K, V_l] - # Update Merkle store (29 cycles) mtree_set - # => [NV_old, R_new, K, V_in_leaf] + # => [NV_old, R_new, K, V_l] - # Confirm that claimed `V_in_leaf` from advice provider is correct by checking if - # `[K, V_in_leaf]` hashes to `NV_old` - # (33 cycles) - movupw.2 dupw.3 swapw hmerge assert_eqw - # => [R_new, V_in_leaf] - - # Clean up stack for return - # (1 cycle) - swapw - # => [V_in_leaf, R_new] + # Preimage is already validated by the caller, so no re-validation here. Drop NV_old + # and K, return [V_l, R_new]. + dropw swapw dropw swapw + # => [V_l, R_new] else # Leaf becomes a Multiple kv-pair case + # => [K_l, K, V_l, V, R] exec.insert_single_to_multi_leaf - # => [V_in_leaf, R_new] + # => [V_l, R_new] end end @@ -586,92 +571,57 @@ proc insert_single_to_multi_leaf end #! Removes the provided key/value pair from the leaf. The leaf to which we're inserting is -#! guaranteed to hold a single key-value pair (provided on the advice stack). Hence, after the +#! guaranteed to hold a single key-value pair (K_l, V_l). Hence, after the #! operation, the leaf will be empty. #! #! Inputs: -#! Operand stack: [V (=ZERO), K, R, ...] -#! Advice stack: [K_in_leaf, V_in_leaf] +#! Operand stack: [V_l, K_l, V (=ZERO), K, R, ...] #! #! Outputs: #! Operand stack: [V_old, R_new, ...] #! #! Cycles: X proc remove_single_leaf - # Push the leaf pre-image on stack - # (0 cycles) - padw adv_loadw - padw adv_loadw - # => [V_in_leaf, K_in_leaf, V, K, R] - # Check if the key stored in the leaf is the same as K - # (X cycles) movupw.3 movupw.2 eqw - # => [K_in_leaf==K, K_in_leaf, K, V_in_leaf, V, R] + # => [K_l==K, K_l, K, V_l, V, R] if.true # Keys match; we're removing the value associated with K # (4 cycles) dropw - # => [K, V_in_leaf, V, R] + # => [K, V_l, V, R] - # Update advice map (5 cycles, swap to put K on top for key = hash(K || V)) - movupw.2 swapw adv.insert_hdword swapw - # => [V, K, V_in_leaf, R] + # Update advice map (swap to put K on top for the leaf-domain + # hash key hash_in_domain(K || V, LEAF_DOMAIN)). + movupw.2 swapw push.LEAF_DOMAIN movdn.8 adv.insert_hdword_d movup.8 drop swapw + # => [V, K, V_l, R] # Prepare the stack for `mtree_set` # Note that the new node value will be the empty word, so we can use `V` # as the node value (since we confirmed that it's `ZERO`) # (7 cycles) movupw.3 dup.11 push.LEAF_DEPTH - # => [depth, K[3], R, V, K, V_in_leaf] + # => [depth, K[3], R, V, K, V_l] # (29 cycles) mtree_set - # => [NV_old, R_new, K, V_in_leaf, ...] - - # Confirm that hmerge([K, V_in_leaf]) = NV_old - # (33 cycles) - movupw.2 dupw.3 - swapw hmerge - assert_eqw - # => [R_new, V_in_leaf, ...] + # => [NV_old, R_new, K, V_l] - # Cleanup stack for return (1 cycle) - swapw - # => [V_in_leaf, R_new, ...] + # Caller already validated the preimage and mtree_set verifies NV_old against R, + # so no re-validation here. Drop NV_old and K, return [V_l, R_new]. + dropw swapw dropw swapw + # => [V_l, R_new] else - # Keys don't match; this is a no-op - # We need to ensure that hash([K_in_leaf, V_in_leaf]) = NV; - # that is, we need to verify the advice provider's claims. - # If all checks pass, we're done. - - # => [K_in_leaf, K, V_in_leaf, V, R] - - # We no longer need V, since we're not removing anything - movupw.3 dropw - # => [K_in_leaf, K, V_in_leaf, R] - - # Prepare stack for mtree_get - movupw.3 dup.11 push.LEAF_DEPTH - # => [depth, K[3], R, K_in_leaf, K, V_in_leaf] - - # Retrieve node value (NV) from merkle tree - mtree_get - # => [NV, R, K_in_leaf, K, V_in_leaf] - - # Cleanup stack (we no longer need K) - movupw.3 dropw - # => [NV, R, K_in_leaf, V_in_leaf] - - # Ensure that hash([K_in_leaf, V_in_leaf]) == NV - movupw.2 movupw.3 swapw hmerge assert_eqw - # => [R] - - # Prepare stack for return - padw - # => [ZERO, R] + # Keys don't match; this is a no-op. The advice provider's claims were + # already verified at the top of `set`: mtree_get bound NV to R at K[3], + # and the caller asserted hash_in_domain(K_l, V_l, LEAF_DOMAIN) == NV. + # V is known to be ZERO. + # => [K_l, K, V_l, V (=ZERO), R] + + dropw dropw dropw + # => [V (=ZERO), R] end end @@ -692,7 +642,7 @@ end @locals(8192) proc set_multi_leaf # We'll have to pipe all the pairs from the advice stack. Let's get the - # stack ready for pipe_double_words_preimage_to_memory. + # stack ready for pipe_double_words_preimage_to_memory_with_domain. movdn.12 # => [NV, V, K, leaf_size, R] @@ -713,7 +663,7 @@ proc set_multi_leaf locaddr.0 swap # => [num_words, ptr, COM; NV, K, V, leaf_size, R] - exec.mem::pipe_double_words_preimage_to_memory + push.LEAF_DOMAIN exec.mem::pipe_double_words_preimage_to_memory_with_domain # => [end_ptr; NV, K, V, leaf_size, R] movdn.12 @@ -1122,7 +1072,7 @@ proc hash_and_insert_mem dup.1 dup.1 # => [start_addr, end_addr, start_addr, end_addr, leaf_index, R, ...] - exec.poseidon2::hash_words + push.LEAF_DOMAIN exec.poseidon2::hash_words_with_domain # => [NV, start_addr, end_addr, leaf_index, R, ...] adv.insert_mem diff --git a/crates/lib/core/asm/collections/sorted_array.masm b/crates/lib/core/asm/collections/sorted_array.masm index b65ab392e0..da4d806deb 100644 --- a/crates/lib/core/asm/collections/sorted_array.masm +++ b/crates/lib/core/asm/collections/sorted_array.masm @@ -9,14 +9,17 @@ const LOWERBOUND_KEY_VALUE_EVENT = event("miden::core::collections::sorted_array #! Finds a value in a sorted array of words. #! -#! This function will crash if the following conditions aren't met: -#! - words must be sorted in non-decreasing order, -#! - start_ptr, end_ptr are word-aligned -#! - `start_ptr <= end_ptr` +#! **The input array must be sorted in non-decreasing lexicographic order.** The host event handler validates this and will return an error if the array is not sorted. #! #! Input: [VALUE, start_ptr, end_ptr] #! Output: [is_value_found, value_ptr, start_ptr, end_ptr] #! +#! # Panics +#! +#! Panics if: +#! - start_ptr, end_ptr are not word-aligned +#! - `start_ptr > end_ptr` +#! #! Cycles: #! Value exists: 46 cycles #! Value doesn't exist and the array is empty: 25 cycles @@ -26,15 +29,15 @@ const LOWERBOUND_KEY_VALUE_EVENT = event("miden::core::collections::sorted_array pub proc find_word # Call the non-deterministic lowerbound advisor (5 cycles) emit.LOWERBOUND_ARRAY_EVENT - adv_push.2 + adv_push adv_push #=> [was_value_found, maybe_value_ptr, VALUE, start_ptr, end_ptr] if.true # assert `start_ptr <= maybe_value_ptr < end_ptr` (15 cycles) dup dup.6 u32assert2.err="maybe_value_ptr is not u32" - u32gte assert.err="lowerbound_array invariant: maybe_value_ptr < start_ptr" + u32gte assert.err="lowerbound_array invariant: maybe_value_ptr must be >= start_ptr" dup dup.7 u32assert2.err="maybe_value_ptr is not u32" - u32lt assert.err="lowerbound_array invariant: maybe_value_ptr >= end_ptr" + u32lt assert.err="lowerbound_array invariant: maybe_value_ptr must be < end_ptr" #=> [maybe_value_ptr, VALUE, start_ptr, end_ptr] # dereference maybe_value_ptr (8 cycles) @@ -43,7 +46,7 @@ pub proc find_word # check if it matches the requested VALUE (15 cycles) exec.word::eq - dup assert.err="lowerbound_array invariant: value_ptr not pointing to VALUE" + dup assert.err="lowerbound_array invariant: value_ptr must point to VALUE" #=> [is_value_found, maybe_value_ptr, start_ptr, end_ptr] else # the value was not found @@ -81,7 +84,7 @@ pub proc find_word # there was no match, the first array element must be larger than VALUE # (123 cycles) exec.word::lt - assert.err="lowerbound_array invariant: start_ptr not greater than VALUE" + assert.err="lowerbound_array invariant: start_ptr must point to a word greater than VALUE" # No value was found (1 cycle) push.0 @@ -102,7 +105,7 @@ pub proc find_word # there was no match, the last array element must be smaller than VALUE # (119 cycles) exec.word::gt - assert.err="lowerbound_array invariant: last word not smaller than VALUE" + assert.err="lowerbound_array invariant: last word must be smaller than VALUE" # No value was found (1 cycle) push.0 @@ -110,10 +113,19 @@ pub proc find_word else # The value was not found, and the maybe_value_ptr is neither the start nor the end # of the list. Make sure that: + # - `start_ptr <= maybe_value_ptr < end_ptr`, and # - `the value at maybe_value_ptr-1 < VALUE`, and - # - `the value at maybe_value_ptr > VALUE` + # - `the value at maybe_value_ptr > VALUE`. + # `maybe_value_ptr` must already be word aligned to allow reading values. #=> [maybe_value_ptr, VALUE, start_ptr, end_ptr] + # `maybe_value_ptr` bounds check + dup dup.6 u32assert2.err="maybe_value_ptr is not u32" + u32gte assert.err="lowerbound_array invariant: maybe_value_ptr must be >= start_ptr" + + dup dup.7 u32assert2.err="maybe_value_ptr is not u32" + u32lt assert.err="lowerbound_array invariant: maybe_value_ptr must be < end_ptr" + # Duplicate VALUE word (5 cycles) movdn.4 dupw #=> [VALUE, VALUE, maybe_value_ptr, start_ptr, end_ptr] @@ -124,7 +136,7 @@ pub proc find_word # there was no match, MAYBE_VALUE must be larger than VALUE (123 cycles) exec.word::lt - assert.err="lowerbound_array invariant: *maybe_value_ptr not greater than VALUE" + assert.err="lowerbound_array invariant: *maybe_value_ptr must be greater than VALUE" # dereference `maybe_value_ptr-4` (11 cycles) padw dup.8 sub.4 mem_loadw_le @@ -132,7 +144,7 @@ pub proc find_word # there was no match, MAYBE_VALUE_PREV must be smaller than VALUE (119 cycles) exec.word::gt - assert.err="lowerbound_array invariant: *(maybe_value_ptr-4) not smaller than VALUE" + assert.err="lowerbound_array invariant: *(maybe_value_ptr-4) must be smaller than VALUE" # No value was found (1 cycle) push.0 @@ -146,20 +158,18 @@ end #! Finds a key in a sorted array of (key, value) word tuples. #! +#! **The keys in the array must be sorted in non-decreasing lexicographic order.** The host event handler validates this and will return an error if the keys are not sorted. +#! #! Inputs: [KEY, start_ptr, end_ptr] #! Outputs: [is_key_found, key_ptr, start_ptr, end_ptr] #! #! # Panics #! #! Panics if: -#! - keys are not sorted in non-decreasing order, #! - start_ptr is not word-aligned #! - end_ptr is not double-word-aligned with the start_ptr: #! - `(end_ptr - start_ptr)` must be divisible by 8 #! - `start_ptr > end_ptr` -#! -#! Inputs: [KEY, start_ptr, end_ptr] -#! Output: [is_key_found, key_ptr, start_ptr, end_ptr] pub proc find_key_value push.1 # => [use_full_key = 1, KEY, start_ptr, end_ptr] @@ -176,13 +186,14 @@ end #! Half-key means that, out of the keys in the array, only half of the key - the most significant #! element (prefix) and the second most significant element (suffix) - need to match. #! +#! **The half-keys in the array must be sorted in non-decreasing lexicographic order.** The host event handler validates this and will return an error if the half-keys are not sorted. +#! #! Inputs: [key_suffix, key_prefix, start_ptr, end_ptr] #! Output: [is_key_found, key_ptr, start_ptr, end_ptr] #! #! # Panics #! #! Panics if: -#! - keys are not sorted in non-decreasing order, #! - start_ptr is not word-aligned #! - end_ptr is not double-word-aligned with the start_ptr: #! - `(end_ptr - start_ptr)` must be divisible by 8 @@ -211,13 +222,14 @@ end #! upon loading the key for comparison, its two least significant elements are zeroized. #! This effectively means that only a match on the two most significant elements is required. #! +#! **The keys in the array must be sorted in non-decreasing lexicographic order.** The host event handler validates this and will return an error if the keys are not sorted. +#! #! Input: [KEY, start_ptr, end_ptr, use_full_key] #! Output: [is_key_found, key_ptr, start_ptr, end_ptr] #! #! # Panics #! #! Panics if: -#! - keys are not sorted in non-decreasing order, #! - start_ptr is not word-aligned #! - end_ptr is not double-word-aligned with the start_ptr: #! - `(end_ptr - start_ptr)` must be divisible by 8 @@ -239,15 +251,15 @@ proc find_partial_key_value movup.6 loc_store.0 # => [KEY, start_ptr, end_ptr] - adv_push.2 + adv_push adv_push #=> [was_key_found, maybe_key_ptr, KEY, start_ptr, end_ptr] if.true # assert `start_ptr <= maybe_key_ptr < end_ptr` (15 cycles) dup dup.6 u32assert2.err="maybe_key_ptr is not u32" - u32gte assert.err="lowerbound_key_value invariant: maybe_key_ptr < start_ptr" + u32gte assert.err="lowerbound_key_value invariant: maybe_key_ptr must be >= start_ptr" dup dup.7 u32assert2.err="maybe_key_ptr is not u32" - u32lt assert.err="lowerbound_key_value invariant: maybe_key_ptr >= end_ptr" + u32lt assert.err="lowerbound_key_value invariant: maybe_key_ptr must be < end_ptr" #=> [maybe_key_ptr, KEY, start_ptr, end_ptr] # make sure maybe_key_ptr is pointing to a key, not value (10 cycles) @@ -263,7 +275,7 @@ proc find_partial_key_value # check if it matches the requested KEY (15 cycles) exec.word::eq - dup assert.err="lowerbound_key_value invariant: key_ptr not pointing to KEY" + dup assert.err="lowerbound_key_value invariant: key_ptr must point to KEY" #=> [is_key_found, maybe_key_ptr, start_ptr, end_ptr] else # pre-compute is_start_ptr, is_end_ptr to reduce the depth of the @@ -278,7 +290,7 @@ proc find_partial_key_value # the key was not found, `maybe_key_ptr = start_ptr` if.true - # the list is empty and `start_ptr = end_ptr` (both are equal to `maybe_value_ptr`) + # the list is empty and `start_ptr = end_ptr` (both are equal to `maybe_key_ptr`) #=> [maybe_key_ptr = start_ptr = end_ptr, KEY, start_ptr, end_ptr] # Prepare output (6 cycles) @@ -299,7 +311,7 @@ proc find_partial_key_value # there was no match, the first map element must be larger than KEY # (123 cycles) exec.word::lt - assert.err="lowerbound_key_value invariant: start_ptr not greater than KEY" + assert.err="lowerbound_key_value invariant: start_ptr must point to a key greater than KEY" # No value was found (1 cycle) push.0 @@ -308,7 +320,7 @@ proc find_partial_key_value else if.true # the key was not found, `maybe_key_ptr = end_ptr` - # the list is not empty, otherwise `maybe_value_ptr = start_ptr` and handled above + # the list is not empty, otherwise `maybe_key_ptr = start_ptr` and handled above # assert `the key before end_ptr < KEY` #=> [maybe_key_ptr = end_ptr, KEY, start_ptr, end_ptr] @@ -323,7 +335,7 @@ proc find_partial_key_value # there was no match, the last map element must be smaller than KEY # (119 cycles) exec.word::gt - assert.err="lowerbound_key_value invariant: last key-value pair not smaller than KEY" + assert.err="lowerbound_key_value invariant: last key-value pair must be smaller than KEY" # No value was found (1 cycle) push.0 @@ -331,10 +343,19 @@ proc find_partial_key_value else # The key was not found, and the maybe_key_ptr is neither the start nor the end # of the list. Make sure that: + # - `start_ptr <= maybe_key_ptr < end_ptr`, and + # - `maybe_key_ptr` is word aligned with `start_ptr`, and # - `the key at maybe_key_ptr-1 < KEY`, and # - `the key at maybe_key_ptr > KEY` #=> [maybe_key_ptr, KEY, start_ptr, end_ptr] + # `maybe_key_ptr` bounds check + dup dup.6 u32assert2.err="maybe_key_ptr is not u32" + u32gte assert.err="lowerbound_key_value invariant: maybe_key_ptr must be >= start_ptr" + + dup dup.7 u32assert2.err="maybe_key_ptr is not u32" + u32lt assert.err="lowerbound_key_value invariant: maybe_key_ptr must be < end_ptr" + # make sure maybe_key_ptr is pointing to a key, not value (10 cycles) dup dup.6 sub u32assert2.err="maybe_key_ptr is not u32" u32mod.8 assertz.err="lowerbound_key_value invariant: key_ptr must be double-word aligned with start_ptr" @@ -349,7 +370,7 @@ proc find_partial_key_value # there was no match, `*maybe_key_ptr` must be larger than KEY (123 cycles) exec.word::lt - assert.err="lowerbound_key_value invariant: MAYBE_KEY not greater than KEY" + assert.err="lowerbound_key_value invariant: MAYBE_KEY must be greater than KEY" #=> [KEY, maybe_key_ptr, start_ptr, end_ptr] # dereference `maybe_key_ptr-8` (previous key) (22 cycles) @@ -361,7 +382,7 @@ proc find_partial_key_value # there was no match, `*(maybe_key_ptr-8)` must be smaller than KEY (119 cycles) exec.word::gt - assert.err="lowerbound_key_value invariant: MAYBE_KEY_PREV not smaller than KEY" + assert.err="lowerbound_key_value invariant: MAYBE_KEY_PREV must be smaller than KEY" # No value was found (1 cycle) push.0 diff --git a/crates/lib/core/asm/crypto/aead.masm b/crates/lib/core/asm/crypto/aead.masm index a2ea2fb5b9..7673f98cbb 100644 --- a/crates/lib/core/asm/crypto/aead.masm +++ b/crates/lib/core/asm/crypto/aead.masm @@ -34,14 +34,14 @@ const AEAD_DECRYPT_EVENT=event("miden::core::crypto::aead::decrypt") #! - rate(8) will contain the initial keystream #! - capacity(4) constains the capacity portion of the state proc init_state - # Stack: [nonce(4), key(4), ...] + # Stack: [key(4), nonce(4), ...] # Initialize capacity with all zeros padw - # => [cap(4), nonce(4), key(4), ...] + # => [cap(4), key(4), nonce(4), ...] movdnw.2 - # => [nonce(4), key(4), cap(4), ...] + # => [key(4), nonce(4), cap(4), ...] # Apply initial permutation to mix key and nonce hperm @@ -80,9 +80,9 @@ end #! Encrypts plaintext data from memory using the `crypto_stream` instruction. #! -#! This procedure encrypts plaintext and automatically adds a padding block at the end. -#! The padding block [1, 0, 0, 0, 0, 0, 0, 0] is written to memory and encrypted, ensuring -#! proper AEAD operation without requiring the caller to handle padding manually. +#! This procedure encrypts plaintext and automatically includes a padding block at the end. +#! The padding block [1, 0, 0, 0, 0, 0, 0, 0] is encrypted without requiring the caller +#! to write padding into the plaintext buffer manually. #! This, however, requires the plaintext length to be a multiple of 8. This assumption is made #! both in this procedure as well as in the decryption procedure. #! @@ -113,13 +113,16 @@ end #! - Plaintext must be at word-aligned addresses (addr % 4 == 0) #! - Each block is 8 field elements (2 words) #! - Blocks must be stored contiguously in memory -#! - src_ptr and dst_ptr MUST be different (in-place encryption not supported) -#! This is because crypto_stream reads and writes in the same clock cycle +#! +#! # Panics +#! +#! Panics if the source and destination memory ranges overlap +#! (in-place encryption not supported). #! #! Padding: #! - Padding is AUTOMATIC - caller should NOT pad the plaintext -#! - The procedure writes [1, 0, 0, 0, 0, 0, 0, 0] to dst_ptr + (num_blocks * 8) -#! - This padding block is then encrypted along with the data +#! - The procedure writes encrypted padding to dst_ptr + (num_blocks * 8) +#! - The plaintext buffer is not modified #! - For empty plaintext (num_blocks = 0), only the padding block is encrypted #! #! Cycles (estimate): 77 + 2 * n @@ -134,6 +137,15 @@ pub proc encrypt # will cause the procedure to encrypt the wrong amount of data, but this is safe - # the resulting tag will authenticate whatever was actually encrypted. + # Assert source and destination memory ranges do not overlap. + # Uses (num_blocks+1)*8 as conservative range size for both sides. + dup.10 add.1 mul.8 + dup dup.10 add + dup.11 swap u32gte + swap dup.11 add + dup.10 swap u32gte + or assert.err="source and destination ranges must not overlap" + exec.init_state # => [rate(8), capacity(4), src_ptr, dst_ptr, num_blocks, ...] @@ -173,36 +185,27 @@ pub proc encrypt drop # => [rate(8), capacity(4), src_ptr_final, dst_ptr_final, ...] - # Write padding block [1,0,0,0,0,0,0,0] to memory at dst_ptr_final - # This padding block will be encrypted along with the data + # apply permutation to refresh keystream for the final padded block + hperm + # => [rate'(8), capacity'(4), src_ptr_final, dst_ptr_final, ...] - dup.12 - # => [dst_ptr_final, rate(8), capacity(4), src_ptr_final, dst_ptr_final, ...] + # encrypt the padding block by combining the keystream with the implicit + # padding word [1,0,0,0,0,0,0,0] + add.1 + # => [encrypted_padding(8), capacity'(4), src_ptr_final, dst_ptr_final, ...] - # Write first word [1,0,0,0] to dst_ptr_final - push.[1,0,0,0] - # => [1, 0, 0, 0, dst_ptr_final, rate(8), capacity(4), src_ptr_final, dst_ptr_final, ...] - dup.4 - # => [dst_ptr_final, 1, 0, 0, 0, dst_ptr_final, rate(8), capacity(4), src_ptr_final, dst_ptr_final, ...] + # write the first ciphertext word to dst_ptr_final without disturbing the rate + dup.13 movdn.4 dupw movup.8 + # => [dst_ptr_final, encrypted_padding[0..4], encrypted_padding(8), capacity'(4), src_ptr_final, dst_ptr_final, ...] mem_storew_le dropw - # => [dst_ptr_final, rate(8), capacity(4), src_ptr_final, dst_ptr_final, ...] + # => [encrypted_padding(8), capacity'(4), src_ptr_final, dst_ptr_final, ...] - # Write second word [0,0,0,0] to dst_ptr_final + 4 - padw - # => [0, 0, 0, 0, dst_ptr_final, rate(8), capacity(4), src_ptr_final, dst_ptr_final, ...] - movup.4 add.4 - # => [dst_ptr_final+4, 0, 0, 0, 0, rate(8), capacity(4), src_ptr_final, dst_ptr_final, ...] + # write the second ciphertext word to dst_ptr_final + 4 and restore rate order + swapw dup.13 add.4 movdn.4 dupw movup.8 + # => [dst_ptr_final+4, encrypted_padding[4..8], encrypted_padding[4..8], encrypted_padding[0..4], capacity'(4), src_ptr_final, dst_ptr_final, ...] mem_storew_le dropw - # => [rate(8), capacity(4), src_ptr_final, dst_ptr_final, ...] - - # Encrypt the padding block using crypto_stream - # Apply permutation to refresh keystream - hperm - # => [rate'(8), capacity'(4), src_ptr_final, dst_ptr_final, ...] - - # Encrypt the padding block at dst_ptr_final - crypto_stream - # => [encrypted_padding(8), capacity'(4), src_ptr_final+8, dst_ptr_final+8, ...] + swapw + # => [encrypted_padding(8), capacity'(4), src_ptr_final, dst_ptr_final, ...] # Generate authentication tag from current sponge state # Apply final permutation @@ -220,8 +223,8 @@ end #! Decrypts and authenticates ciphertext using non-deterministic advice. #! -#! This procedure implements AEAD decryption with automatic tag verification and -#! automatic padding handling. It mirrors the encrypt procedure's padding behavior. +#! This procedure implements AEAD decryption with automatic tag verification. It mirrors +#! the encrypt procedure's padding behavior while leaving the plaintext output unpadded. #! #! Decryption Flow: #! 1. Computes tag location: src_ptr + (num_blocks + 1) * 8 @@ -247,12 +250,11 @@ end #! The encrypted padding is at: src_ptr + (num_blocks * 8) #! The tag is at: src_ptr + (num_blocks + 1) * 8 #! -#! - Output at dst_ptr: [plaintext_block_0(8), ..., plaintext_block_n(8), padding(8)] -#! Length: (num_blocks + 1) * 8 elements -#! The padding block [1, 0, 0, 0, 0, 0, 0, 0] is automatically written -#! Caller can ignore or remove the padding block if needed +#! - Output at dst_ptr: [plaintext_block_0(8), ..., plaintext_block_n(8)] +#! Length: num_blocks * 8 elements +#! The padding block is authenticated but not written to the plaintext output. #! -#! Event: Emits AEAD_DECRYPT event with (nonce, key, src_ptr, dst_ptr, num_blocks) +#! Event: Emits AEAD_DECRYPT event with (key, nonce, src_ptr, dst_ptr, num_blocks) #! The host event handler must: #! - Read full ciphertext from memory at src_ptr ((num_blocks + 1) * 8 elements) #! - Read authentication tag from memory at src_ptr + (num_blocks + 1) * 8 @@ -262,7 +264,11 @@ end #! #! Memory Requirements: #! - Same as encrypt: word-aligned addresses, contiguous blocks -#! - src_ptr and dst_ptr MUST be different (in-place operation not supported) +#! +#! # Panics +#! +#! Panics if the source and destination memory ranges overlap +#! (in-place decryption not supported). #! #! Security: #! - Tag verification happens in the MASM procedure via re-encryption @@ -285,79 +291,87 @@ end #! - The deterministic keystream creates a bijection between plaintext and ciphertext #! - Any deviation from correct plaintext causes assertion failure #! -#! Note: This procedure does NOT remove padding. The caller must handle padding removal. +#! Note: This procedure does not write the padding block to the plaintext output. #! #! Cycles (estimate): 177 + 3.5 * n #! Where: #! - n = number of field elements in the plaintext (excludes the padding block) #! - For num_blocks data blocks: n = 8 * num_blocks pub proc decrypt - # Stack: [nonce(4), key(4), src_ptr, dst_ptr, num_blocks, ...] + # Stack: [key(4), nonce(4), src_ptr, dst_ptr, num_blocks, ...] # Input validation note: This procedure does not validate num_blocks or alignment. # Alignment errors are caught by the VM memory subsystem. Incorrect num_blocks # values are caught by tag verification - if num_blocks doesn't match what was # used during encryption, the tag comparison will fail and execution will halt. + # Assert source and destination memory ranges do not overlap. + dup.10 add.1 mul.8 + dup dup.10 add + dup.11 swap u32gte + swap dup.11 add + dup.10 swap u32gte + or assert.err="source and destination ranges must not overlap" + # Compute the pointer to the tag for later use # tag is at src_ptr + (num_blocks + 1) * 8 because of automatic padding block dup.10 add.1 mul.8 dup.9 add movdn.11 - # => [nonce(4), key(4), src_ptr, dst_ptr, num_blocks, tag_ptr, ...] + # => [key(4), nonce(4), src_ptr, dst_ptr, num_blocks, tag_ptr, ...] - # Emit event to trigger host-side decryption - # The event handler will push plaintext data blocks onto the advice stack + # emit event to trigger host-side decryption + # the event handler will push plaintext data blocks onto the advice stack emit.AEAD_DECRYPT_EVENT - # => [nonce(4), key(4), src_ptr, dst_ptr, num_blocks, tag_ptr, ...] - # Advice stack now contains: plaintext data blocks (no padding) in reverse order compatible + # => [key(4), nonce(4), src_ptr, dst_ptr, num_blocks, tag_ptr, ...] + # advice stack now contains: plaintext data blocks (no padding) in reverse order compatible # with adv_pipe - # Prepare to load plaintext data blocks from advice stack + # prepare to load plaintext data blocks from advice stack dup.10 # num_blocks dup.10 # dst_ptr - # => [dst_ptr, num_blocks, nonce(4), key(4), src_ptr, dst_ptr, num_blocks, tag_ptr, ...] + # => [dst_ptr, num_blocks, key(4), nonce(4), src_ptr, dst_ptr, num_blocks, tag_ptr, ...] - # Setup for adv_pipe loop + # setup for adv_pipe loop padw padw padw - # => [0(4), 0(4), 0(4), dst_ptr, num_blocks, nonce(4), key(4), src_ptr, dst_ptr, num_blocks, tag_ptr, ...] + # => [0(4), 0(4), 0(4), dst_ptr, num_blocks, key(4), nonce(4), src_ptr, dst_ptr, num_blocks, tag_ptr, ...] dup.13 neq.0 - # => [continue?, 0(4), 0(4), 0(4), dst_ptr, num_blocks, nonce(4), ...] + # => [continue?, 0(4), 0(4), 0(4), dst_ptr, num_blocks, key(4), ...] - # Load plaintext data blocks from advice stack + # load plaintext data blocks from advice stack while.true - adv_pipe # Reads 8 elements from advice, writes to dst_ptr, increments dst_ptr by 8 - # => [DATA1(4), DATA0(4), 0(4), dst_ptr+8, num_blocks, nonce(4), key(4), src_ptr, dst_ptr, num_blocks, tag_ptr, ...] + adv_pipe # reads 8 elements from advice, writes to dst_ptr, increments dst_ptr by 8 + # => [DATA1(4), DATA0(4), 0(4), dst_ptr+8, num_blocks, key(4), nonce(4), src_ptr, dst_ptr, num_blocks, tag_ptr, ...] - movup.13 sub.1 # Duplicate counter, decrement it - dup movdn.14 # Duplicate and move decremented value down to overwrite old counter + movup.13 sub.1 # duplicate counter, decrement it + dup movdn.14 # duplicate and move decremented value down to overwrite old counter neq.0 end - # Clean up adv_pipe working area + # clean up adv_pipe working area dropw dropw dropw - # => [dst_ptr_final, 0, nonce(4), key(4), src_ptr, dst_ptr, num_blocks, tag_ptr, ...] + # => [dst_ptr_final, 0, key(4), nonce(4), src_ptr, dst_ptr, num_blocks, tag_ptr, ...] drop drop - # => [nonce(4), key(4), src_ptr, dst_ptr, num_blocks, tag_ptr, ...] + # => [key(4), nonce(4), src_ptr, dst_ptr, num_blocks, tag_ptr, ...] - # Swap src_ptr and dst_ptr to call encrypt on the plaintext - # This will re-encrypt the data blocks (adding padding automatically) to compute tag + # swap src_ptr and dst_ptr to call encrypt on the plaintext + # this will re-encrypt the data blocks (adding padding automatically) to compute tag movup.9 movup.9 swap movdn.9 movdn.9 - # => [nonce(4), key(4), dst_ptr, src_ptr, num_blocks, tag_ptr, ...] + # => [key(4), nonce(4), dst_ptr, src_ptr, num_blocks, tag_ptr, ...] - # Re-encrypt plaintext to compute authentication tag + # re-encrypt plaintext to compute authentication tag exec.encrypt # => [computed_tag(4), tag_ptr, ...] - # Verify computed tag matches expected tag from ciphertext - padw # Prepare stack for loading expected tag - movup.8 # Get tag_ptr - mem_loadw_le # Load expected tag from memory + # verify computed tag matches expected tag from ciphertext + padw # prepare stack for loading expected tag + movup.8 # get tag_ptr + mem_loadw_le # load expected tag from memory # => [expected_tag(4), computed_tag(4), ...] eqw assert.err="AEAD tag mismatch" - dropw dropw # Clean up stack + dropw dropw # clean up stack # => [] end diff --git a/crates/lib/core/asm/crypto/dsa/ecdsa_k256_keccak.masm b/crates/lib/core/asm/crypto/dsa/ecdsa_k256_keccak.masm index 9b306a5928..96f45550a0 100644 --- a/crates/lib/core/asm/crypto/dsa/ecdsa_k256_keccak.masm +++ b/crates/lib/core/asm/crypto/dsa/ecdsa_k256_keccak.masm @@ -56,10 +56,10 @@ const SIG_LEN_FELTS = 17 # 65.div_ceil(4) @locals(48) pub proc verify # Load the compressed public key (9 felts) into local memory at locaddr.[0..9] - padw adv_loadw loc_storew_le.0 + adv_pushw loc_storew_le.0 adv_loadw loc_storew_le.4 dropw - adv_push.1 loc_store.8 + adv_push loc_store.8 # Compute the expected commitment and ensure it matches the provided PK_COMM push.PK_LEN_FELTS locaddr.0 exec.poseidon2::hash_elements @@ -84,7 +84,7 @@ pub proc verify adv_loadw loc_storew_le.32 adv_loadw loc_storew_le.36 adv_loadw loc_storew_le.40 dropw - adv_push.1 loc_store.44 + adv_push loc_store.44 # => [...] # Invoke the deferred verification precompile with in-memory calldata @@ -154,12 +154,12 @@ end #! `Poseidon2(Poseidon2(Poseidon2(pk) || Poseidon2(digest)) || Poseidon2(sig))` #! - `TAG`: `[ECDSA_VERIFY_EVENT, result, 0, 0]` #! - `result`: 1 if signature is valid, 0 if invalid -pub proc verify_prehash_impl +proc verify_prehash_impl emit.ECDSA_VERIFY_EVENT # => [pk_ptr, digest_ptr, sig_ptr, ...] # Read verification result from advice stack (provided by the host) - adv_push.1 + adv_push # => [result, pk_ptr, digest_ptr, sig_ptr, ...] # Compute commitment: COMM = Poseidon2(Poseidon2(Poseidon2(pk) || Poseidon2(digest)) || Poseidon2(sig)) diff --git a/crates/lib/core/asm/crypto/dsa/eddsa_ed25519.masm b/crates/lib/core/asm/crypto/dsa/eddsa_ed25519.masm index 20d86144b0..7d7e6e63bc 100644 --- a/crates/lib/core/asm/crypto/dsa/eddsa_ed25519.masm +++ b/crates/lib/core/asm/crypto/dsa/eddsa_ed25519.masm @@ -56,7 +56,7 @@ const SIG_LEN_FELTS = 16 # 64.div_ceil(4) @locals(72) pub proc verify # Load the public key (8 felts = 32 bytes) from advice into locaddr[0..8] - padw adv_loadw loc_storew_le.0 + adv_pushw loc_storew_le.0 adv_loadw loc_storew_le.4 dropw # => [PK_COMM, MSG, ...] @@ -70,7 +70,7 @@ pub proc verify # => [...] # Load the signature (16 felts = 64 bytes) from advice into locaddr[16..32] - padw adv_loadw loc_storew_le.16 + adv_pushw loc_storew_le.16 adv_loadw loc_storew_le.20 adv_loadw loc_storew_le.24 adv_loadw loc_storew_le.28 dropw @@ -221,12 +221,12 @@ end #! - `COMM`: `Poseidon2(Poseidon2(Poseidon2(pk) || Poseidon2(k_digest)) || Poseidon2(sig))` #! - `TAG`: `[EDDSA_VERIFY_EVENT, result, 0, 0]` #! - `result`: host verification result (1 or 0) -pub proc verify_prehash_impl +proc verify_prehash_impl emit.EDDSA_VERIFY_EVENT # => [pk_ptr, k_digest_ptr, sig_ptr, ...] # Read verification result from advice stack (provided by the host). - adv_push.1 + adv_push # => [result, pk_ptr, k_digest_ptr, sig_ptr, ...] # Compute COMM_PK = poseidon2::hash_memory(pk_ptr, PK_LEN_FELTS) diff --git a/crates/lib/core/asm/crypto/dsa/falcon512_poseidon2.masm b/crates/lib/core/asm/crypto/dsa/falcon512_poseidon2.masm index 4368cb6ac2..0741885396 100644 --- a/crates/lib/core/asm/crypto/dsa/falcon512_poseidon2.masm +++ b/crates/lib/core/asm/crypto/dsa/falcon512_poseidon2.masm @@ -30,13 +30,13 @@ const FALCON_DIV_EVENT = event("miden::core::crypto::dsa::falcon512_poseidon2::f #! Note that it is the responsibility of the calling procedure to ensure that `a_hi` and `a_lo` are #! within the appropriate range i.e., they are u32-s. #! -#! Cycles: 27 +#! Cycles: 29 pub proc mod_12289 emit.FALCON_DIV_EVENT # the advice stack contains now [qhi, qlo, r, ...] where q = qhi * 2^32 + qlo is quotient # and r is remainder - adv_push.2 + adv_push adv_push u32assert2 # => [qlo, qhi, a_hi, a_lo, ...] @@ -54,8 +54,10 @@ pub proc mod_12289 # => [M * q / 2^32, (M * q) % 2^32, a_hi, a_lo, ...] # => [res_hi, res_lo, a_hi, a_lo, ...] - adv_push.1 - dup + adv_push + # Advice values are untrusted. U32SUB/U32ADD only constrain their output limbs in the AIR, + # so we must validate the remainder before feeding it into u32 arithmetic. + dup u32assert2 push.M u32overflowing_sub # => [borrow, diff, r, res_hi, res_lo, a_hi, a_lo, ...] @@ -191,11 +193,10 @@ pub proc load_h_s2_and_product ## which simplifies to ## ## pi(tau_inv) * tau == h(tau_inv) * s2(tau_inv) - adv_push.2 - # advice stack has [tau0, tau1, ...] with tau0 on top (ready to pop first) - # adv_push.2: pops tau0 first, then tau1 → stack is [tau0, tau1, ...] (_le format) + adv_push adv_push + # => [tau0, tau1, ...] dup.1 dup.1 ext2inv # duplicate tau, compute inverse → [tau_inv0, tau_inv1, tau0, tau1, ...] - loc_storew_le.4 # store [tau_inv0, tau_inv1, tau0, tau1] - tau_inv first for horner + loc_storew_le.4 # store [tau_inv0, tau_inv1, tau0, tau1] - tau_inv first for Horner # => [tau_inv0, tau_inv1, tau0, tau1, Y, 0, 0, 0, 0, ptr, tau_inv_ptr, acc0, acc1, ...] # 2) Load the coefficients of the h polynomial and evaluate it at tau_inv @@ -635,8 +636,8 @@ pub proc verify # 2) Load the NONCE from the advice provider. This is encoded as 8 field elements - padw adv_loadw - padw adv_loadw + adv_pushw + adv_pushw #=> [NONCE1, NONCE0, MSG, ...] swapw #=> [NONCE0, NONCE1, MSG, ...] diff --git a/crates/lib/core/asm/crypto/hashes/keccak256.masm b/crates/lib/core/asm/crypto/hashes/keccak256.masm index eada6959e7..e84f8827c1 100644 --- a/crates/lib/core/asm/crypto/hashes/keccak256.masm +++ b/crates/lib/core/asm/crypto/hashes/keccak256.masm @@ -99,7 +99,7 @@ end #! - TAG = [KECCAK_HASH_BYTES_EVENT, len_bytes, 0, 0] encodes the precompile identifier and the byte length as metadata #! - DIGEST_U32[8] = [d_0, ..., d_7] = Keccak256(INPUT_U8[len_bytes]) @locals(8) -pub proc hash_bytes_impl +proc hash_bytes_impl emit.KECCAK_HASH_BYTES_EVENT # => [ptr, len_bytes, ...] diff --git a/crates/lib/core/asm/crypto/hashes/poseidon2.masm b/crates/lib/core/asm/crypto/hashes/poseidon2.masm index 6950ba13e7..69a313ec56 100644 --- a/crates/lib/core/asm/crypto/hashes/poseidon2.masm +++ b/crates/lib/core/asm/crypto/hashes/poseidon2.masm @@ -6,13 +6,31 @@ #! consume an amount of data which is a multiple of the rate (2 words). #! #! Input: [] -#! Output: [PERM, PERM, PERM, ...] +#! Output: [R0, R1, C, ...] +#! +#! Where R0, R1, C are three zero words representing the initial Poseidon2 hasher state +#! (R0 on top of stack). #! #! Cycles: 12 pub proc init_no_padding padw padw padw end +#! Prepares the top of the stack with the hasher initial state, using a caller-supplied capacity +#! word. +#! +#! The caller must have placed the capacity word `C` on top of the stack before invoking this +#! procedure. No padding handling is performed: callers must absorb data which is a multiple of +#! the rate (2 words), or handle odd-length absorption themselves. +#! +#! Input: [C, ...] +#! Output: [R0=0w, R1=0w, C, ...] +#! +#! Cycles: 8 +pub proc init_with_capacity + padw padw +end + #! Given the hasher state, returns the hash output (digest). #! #! Input: [R0, R1, C, ...] @@ -110,43 +128,49 @@ pub proc hash_double_words # => [HASH] end -#! Hashes the memory `start_addr` to `end_addr`, handles odd number of elements. +#! Hashes the memory `start_addr` to `end_addr` with a domain identifier, handling an odd number +#! of words. #! #! Requires `start_addr ≤ end_addr`, `end_addr` is not inclusive. #! Requires `start_addr` and `end_addr` to be word-aligned. #! -#! Input: [start_addr, end_addr, ...] +#! Input: [domain, start_addr, end_addr, ...] #! Output: [H, ...] #! #! Cycles: -#! - even words: 53 cycles + 3 * words -#! - odd words: 65 cycles + 3 * words -#! where `words` is the `start_addr - end_addr - 1` -pub proc hash_words +#! - even words: 54 cycles + 3 * words +#! - odd words: 66 cycles + 3 * words +#! where `words` is `(end_addr - start_addr) / 4`. +pub proc hash_words_with_domain + # Move the domain past the address pair so we can reuse the standard hash_words control flow. + # (1 cycle) + movdn.2 + # => [start_addr, end_addr, domain, ...] + # enforce `start_addr ≤ end_addr` dup.1 dup.1 u32assert2 u32gte assert # figure out if the range is for an odd number of words (11 cycles) dup.1 dup.1 sub div.4 is_odd - # => [is_odd, start_addr, end_addr, ...] + # => [is_odd, start_addr, end_addr, domain, ...] # make the start/end range even (6 cycles) movup.2 dup.1 mul.4 sub - # => [end_addr, is_odd, start_addr, ...] + # => [end_addr, is_odd, start_addr, domain, ...] - # move start_addr to the right stack position (1 cycles) + # move start_addr to the right stack position (1 cycle) movup.2 - # => [start_addr, end_addr, is_odd, ...] + # => [start_addr, end_addr, is_odd, domain, ...] - # prepare hasher state (14 cycles) - dup.2 mul.4 push.0.0.0 movup.3 padw padw - # => [R0, R1, C, start_addr, end_addr, is_odd, ...] + # prepare hasher state with capacity `[is_odd*4, domain, 0, 0]` (14 cycles) + dup.2 mul.4 push.0.0 movup.6 movup.3 padw padw + # => [R0=0w, R1=0w, C=[is_odd*4, domain, 0, 0], start_addr, end_addr, is_odd, ...] # (4 + 3 * words cycles) exec.absorb_double_words_from_memory # => [R0', R1', C', end_addr, end_addr, is_odd, ...] - # (1 cycles) + # (1 cycle) movup.14 # => [is_odd, R0', R1', C', end_addr, end_addr, ...] @@ -155,7 +179,7 @@ pub proc hash_words # start_addr and end_addr are equal after calling `absorb_double_words_from_memory`, and both # point to the last element. Load the last word (6 cycles) dropw dup.9 mem_loadw_le - # => [R1, C, end_addr, end_addr, ...] + # => [W, C', end_addr, end_addr, ...] # set the padding and compute the permutation (5 cycles) padw swapw exec.permute @@ -169,6 +193,27 @@ pub proc hash_words # => [HASH] end +#! Hashes the memory `start_addr` to `end_addr`, handles odd number of elements. +#! +#! Equivalent to `hash_words_with_domain` with `domain = 0`. +#! +#! Requires `start_addr ≤ end_addr`, `end_addr` is not inclusive. +#! Requires `start_addr` and `end_addr` to be word-aligned. +#! +#! Input: [start_addr, end_addr, ...] +#! Output: [H, ...] +#! +#! Cycles: +#! - even words: 55 cycles + 3 * words +#! - odd words: 67 cycles + 3 * words +#! where `words` is `(end_addr - start_addr) / 4`. +pub proc hash_words + push.0 + # => [domain=0, start_addr, end_addr, ...] + + exec.hash_words_with_domain +end + #! Initializes the hasher state required for the `hash_elements_with_state` procedure. #! #! Depending on the provided pad_inputs_flag, this procedure initializes the hasher state using @@ -447,14 +492,14 @@ end #! - A is the word to be hashed. #! - B is the resulting hash, computed as `Poseidon2(A)`. #! -#! Cycles: 20 +#! Cycles: 19 pub proc hash hash end #! Merges two words (256-bit digests) via Poseidon2 hash. #! -#! Inputs: [B, A] +#! Inputs: [A, B] #! Outputs: [C] #! #! Where: @@ -466,6 +511,31 @@ pub proc merge hmerge end +#! Merges two words (256-bit digests) via Poseidon2 hash with a domain identifier. +#! +#! Inputs: [domain, A, B, ...] +#! Outputs: [C, ...] +#! +#! Where: +#! - A and B are the words to be merged (A corresponds to the first rate word). +#! - C is the resulting hash, computed with capacity `[0, domain, 0, 0]`. +#! +#! Cycles: 16 +pub proc merge_in_domain + # move `domain` past the two words so we can reuse the `adv.insert_hdword_d` capacity-word + # construction pattern (1 cycle) + movdn.8 + # => [A, B, domain, ...] + + # build the hperm state [A, B, [0, domain, 0, 0]] (5 cycles) + push.0.0 movup.10 push.0 movdnw.2 + # => [A, B, [0, domain, 0, 0], ...] + + # run the permutation (1 cycle) and squeeze the digest (9 cycles) + hperm + exec.squeeze_digest +end + #! Performs Poseidon2 permutation on the hasher state. #! #! Inputs: [R0, R1, C] diff --git a/crates/lib/core/asm/crypto/hashes/sha256.masm b/crates/lib/core/asm/crypto/hashes/sha256.masm index 4687360087..8965e173d9 100644 --- a/crates/lib/core/asm/crypto/hashes/sha256.masm +++ b/crates/lib/core/asm/crypto/hashes/sha256.masm @@ -1508,6 +1508,27 @@ proc consume_padding_message_schedule movdn.7 end +#! Asserts that all words in a 512-bit SHA256 message block are valid u32 values. +#! +#! Input: [m0, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13, m14, m15, ...] +#! Output: [m0, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13, m14, m15, ...] +#! +#! Where: +#! - m0 through m15 are the 32-bit words of the SHA256 message block. +#! +#! Panics if: +#! - any message word is not a valid 32-bit unsigned integer. +proc assert_message_block_u32 + u32assertw.err="invalid sha256 message word" + movupw.3 + u32assertw.err="invalid sha256 message word" + movupw.3 + u32assertw.err="invalid sha256 message word" + movupw.3 + u32assertw.err="invalid sha256 message word" + movupw.3 +end + #! SHA256 2-to-1 hash (merge): Given 64 -bytes input, computes 32 -bytes SHA256 digest #! #! Input: [m0, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13, m14, m15, ...] @@ -1520,7 +1541,14 @@ end #! maintaining big endian byte order. #! #! SHA256 digest is represented in terms of eight 32 -bit words ( big endian byte order ). +#! +#! Panics if: +#! - any input message word is not a valid 32-bit unsigned integer. +#! +#! Invocation: exec pub proc merge + exec.assert_message_block_u32 + push.0x5be0cd19.0x1f83d9ab.0x9b05688c.0x510e527f push.0xa54ff53a.0x3c6ef372.0xbb67ae85.0x6a09e667 @@ -1542,11 +1570,17 @@ end #! maintaining big endian byte order. #! #! SHA256 digest is represented in terms of eight 32 -bit words ( big endian byte order ). +#! +#! Panics if: +#! - any input message word is not a valid 32-bit unsigned integer. +#! +#! Invocation: exec pub proc hash # apply padding, see padding rule in section 5.1.1 of # https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf push.256.0.0.0.0.0.0.2147483648 swapdw + exec.assert_message_block_u32 push.0x5be0cd19.0x1f83d9ab.0x9b05688c.0x510e527f push.0xa54ff53a.0x3c6ef372.0xbb67ae85.0x6a09e667 @@ -1561,6 +1595,12 @@ end #! #! Input: [addr, len, ...] #! Output: [dig0, dig1, dig2, dig3, dig4, dig5, dig6, dig7, ...] +#! +#! Panics if: +#! - any loaded message word is not a valid 32-bit unsigned integer. +#! - padding range checks fail. +#! +#! Invocation: exec @locals(48) pub proc hash_bytes # loc.0 (input address) @@ -1611,10 +1651,10 @@ pub proc hash_bytes # Consume sha256 blocks loc_load.28 u32assert neq.0 while.true - padw loc_load.0 u32assert u32overflowing_add.12 assertz.err="range check failed: padding" mem_loadw_be movdnw.2 - padw loc_load.0 u32assert u32overflowing_add.8 assertz.err="range check failed: padding" mem_loadw_be movdnw.2 - padw loc_load.0 u32assert u32overflowing_add.4 assertz.err="range check failed: padding" mem_loadw_be movdnw.2 - padw loc_load.0 u32assert u32overflowing_add.0 assertz.err="range check failed: padding" mem_loadw_be movdnw.2 + padw loc_load.0 u32assert u32overflowing_add.12 assertz.err="range check failed: padding" mem_loadw_be u32assertw.err="invalid sha256 message word" movdnw.2 + padw loc_load.0 u32assert u32overflowing_add.8 assertz.err="range check failed: padding" mem_loadw_be u32assertw.err="invalid sha256 message word" movdnw.2 + padw loc_load.0 u32assert u32overflowing_add.4 assertz.err="range check failed: padding" mem_loadw_be u32assertw.err="invalid sha256 message word" movdnw.2 + padw loc_load.0 u32assert u32overflowing_add.0 assertz.err="range check failed: padding" mem_loadw_be u32assertw.err="invalid sha256 message word" movdnw.2 exec.prepare_message_schedule_and_consume loc_load.0 u32assert u32overflowing_add.16 assertz.err="range check failed: padding" loc_store.0 diff --git a/crates/lib/core/asm/crypto/hashes/sha512.masm b/crates/lib/core/asm/crypto/hashes/sha512.masm index bb127381fa..1a20c876fc 100644 --- a/crates/lib/core/asm/crypto/hashes/sha512.masm +++ b/crates/lib/core/asm/crypto/hashes/sha512.masm @@ -39,7 +39,7 @@ end #! Input: [ptr, len_bytes, ...] #! Output: [COMM, TAG, DIGEST_U32[16], ...] @locals(24) -pub proc hash_bytes_impl +proc hash_bytes_impl emit.SHA512_HASH_BYTES_EVENT # => [ptr, len_bytes, ...] diff --git a/crates/lib/core/asm/math/u128.masm b/crates/lib/core/asm/math/u128.masm index 689dbabb97..1f71493138 100644 --- a/crates/lib/core/asm/math/u128.masm +++ b/crates/lib/core/asm/math/u128.masm @@ -1519,10 +1519,10 @@ pub proc divmod(b: u128, a: u128) -> (remainder: u128, quotient: u128) # ==== Phase 0: Load r and q from advice ==== - padw adv_loadw u32assertw + adv_pushw u32assertw # => [r0, r1, r2, r3, b0, b1, b2, b3, a0, a1, a2, a3] - padw adv_loadw u32assertw + adv_pushw u32assertw # => [q0, q1, q2, q3, r0, r1, r2, r3, b0, b1, b2, b3, a0, a1, a2, a3] # 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 diff --git a/crates/lib/core/asm/math/u256.masm b/crates/lib/core/asm/math/u256.masm index 415c6c3afd..b7795d4770 100644 --- a/crates/lib/core/asm/math/u256.masm +++ b/crates/lib/core/asm/math/u256.masm @@ -1,80 +1,64 @@ pub type u256 = struct { lo: u128, hi: u128 } -# ===== LIMB ORDER HELPERS ======================================================================== +# ===== ADDITION ================================================================================== -#! Reorders the top u256 value between LE and BE limb order. This is an involution. -#! Input/Output (LE <-> BE): -#! [x0, x1, x2, x3, x4, x5, x6, x7, ...] <-> [x7, x6, x5, x4, x3, x2, x1, x0, ...] -proc u256_le_to_be - reversew - swapw - reversew -end +#! Performs addition of two unsigned 256 bit integers preserving the overflow. +#! Stack transition looks as follows: +#! [b0, b1, b2, b3, b4, b5, b6, b7, a0, a1, a2, a3, a4, a5, a6, a7, ...] +#! -> [overflow, c0, c1, c2, c3, c4, c5, c6, c7, ...], where c = (a + b) % 2^256. +pub proc overflowing_add(b: u256, a: u256) -> (i1, u256) + # Processes limbs in LE order; the c-block accumulates top-down on the stack and is + # reversed back to LE before returning. -#! Reorders two u256 values between LE and BE limb order. -proc u256_le_to_be_pair - exec.u256_le_to_be - swapdw - exec.u256_le_to_be - swapdw -end + # Setup: [b0..b7, a0..a7] -> [a0..a3, b0..b3, b4..b7, a4..a7] + swapw + swapw.2 -# ===== ADDITION ================================================================================== + # limb 0 + movup.4 + u32overflowing_add -#! Adds rhs (b) to lhs (a) in BE limb order and returns (overflow, sum). -#! Input stack: [b7, b6, b5, b4, b3, b2, b1, b0, a7, a6, a5, a4, a3, a2, a1, a0, ...] -#! Output stack: [overflow, c7, c6, c5, c4, c3, c2, c1, c0, ...], where c = (a + b) % 2^256. -proc add_with_carry_be(rhs: u256, lhs: u256) -> (i1, u256) - swapw.3 + # limb 1 + movup.5 movup.3 - movup.7 - u32overflowing_add - movup.4 - movup.7 u32overflowing_add3 + + # limb 2 + movup.5 movup.4 - movup.6 u32overflowing_add3 - movup.4 + + # limb 3 + movup.5 movup.5 u32overflowing_add3 + + # Mid-algorithm setup: bury carry3 + the four c-limbs to bring a4..a7 into shallow range. + # [carry3, c3..c0, b4..b7, a4..a7] -> [carry3, a4..a7, b4..b7, c3..c0] movdn.12 swapw.2 movup.12 - movup.4 - movup.8 + + # limbs 4-7: all movups now within movup.8 + movup.5 + movup.2 u32overflowing_add3 - movup.4 - movup.7 + + movup.5 + movup.3 u32overflowing_add3 + + movup.5 movup.4 - movup.6 u32overflowing_add3 - movup.4 + + movup.5 movup.5 u32overflowing_add3 -end -#! Performs addition of two unsigned 256 bit integers discarding the overflow. -#! Stack transition looks as follows: -#! [b0, b1, b2, b3, b4, b5, b6, b7, a0, a1, a2, a3, a4, a5, a6, a7, ...] -#! -> [c0, c1, c2, c3, c4, c5, c6, c7, ...], where c = (a + b) % 2^256. -pub proc wrapping_add(rhs: u256, lhs: u256) -> u256 - exec.u256_le_to_be_pair - exec.add_with_carry_be - drop - exec.u256_le_to_be -end - -#! Performs addition of two unsigned 256 bit integers preserving the overflow. -#! Stack transition looks as follows: -#! [b0, b1, b2, b3, b4, b5, b6, b7, a0, a1, a2, a3, a4, a5, a6, a7, ...] -#! -> [overflow, c0, c1, c2, c3, c4, c5, c6, c7, ...], where c = (a + b) % 2^256. -pub proc overflowing_add(rhs: u256, lhs: u256) -> (i1, u256) - exec.u256_le_to_be_pair - exec.add_with_carry_be + # Stack now: [overflow, c7, c6, c5, c4, c3, c2, c1, c0]. Reverse the c-block to LE. movdn.8 - exec.u256_le_to_be + reversew swapw reversew movup.8 end @@ -82,113 +66,121 @@ end #! Stack transition looks as follows: #! [b0, b1, b2, b3, b4, b5, b6, b7, a0, a1, a2, a3, a4, a5, a6, a7, ...] #! -> [c0, c1, c2, c3, c4, c5, c6, c7, overflow, ...], where c = (a + b) % 2^256. -pub proc widening_add(rhs: u256, lhs: u256) -> (u256, i1) - exec.u256_le_to_be_pair - exec.add_with_carry_be +pub proc widening_add(b: u256, a: u256) -> (u256, i1) + exec.overflowing_add movdn.8 - exec.u256_le_to_be +end + +#! Performs addition of two unsigned 256 bit integers discarding the overflow. +#! Stack transition looks as follows: +#! [b0, b1, b2, b3, b4, b5, b6, b7, a0, a1, a2, a3, a4, a5, a6, a7, ...] +#! -> [c0, c1, c2, c3, c4, c5, c6, c7, ...], where c = (a + b) % 2^256. +pub proc wrapping_add(b: u256, a: u256) -> u256 + exec.overflowing_add + drop end # ===== SUBTRACTION =============================================================================== -#! Subtracts rhs (b) from lhs (a) in BE limb order. -#! Input stack: [b7, b6, b5, b4, b3, b2, b1, b0, a7, a6, a5, a4, a3, a2, a1, a0, ...] -proc sub_with_borrow_be(rhs: u256, lhs: u256) -> (i1, u256) - # rhs = b, lhs = a; see stack order above. - # u32overflowing_sub computes second - top; u32widening_add computes top + second. - # For each limb i: sum = b_i + borrow, diff = a_i - sum, borrow = borrow_sub + carry_sum. - swapw.3 # bring a0..a3 above b0..b3 - movup.3 # a0 to top - movup.7 # b0 to top - u32overflowing_sub # borrow0, diff0 +#! Performs subtraction of two unsigned 256 bit integers preserving the underflow. +#! Stack transition looks as follows: +#! [b0, b1, b2, b3, b4, b5, b6, b7, a0, a1, a2, a3, a4, a5, a6, a7, ...] +#! -> [underflow, c0, c1, c2, c3, c4, c5, c6, c7, ...], where c = (a - b) % 2^256. +pub proc overflowing_sub(b: u256, a: u256) -> (i1, u256) + # Processes limbs in LE order. Per limb: sum = b_i + borrow, diff = a_i - sum, + # borrow = borrow_sub + carry_sum. The c-block accumulates top-down on the stack + # and is reversed back to LE before returning. + + # Setup: [b0..b7, a0..a7] -> [a0..a3, b0..b3, b4..b7, a4..a7] + swapw + swapw.2 + + # limb 0 + movup.4 + u32overflowing_sub # limb 1 - movup.7 # b1 - u32widening_add # sum1, carry1 - movup.5 # a1 - swap # sum1 on top, a1 second - u32overflowing_sub # borrow1, diff1 - movup.2 # carry1 - add # borrow1 += carry1 + movup.5 + u32widening_add + movup.3 + swap + u32overflowing_sub + movup.2 + add # limb 2 - movup.6 # b2 + movup.5 u32widening_add - movup.5 # a2 + movup.4 swap u32overflowing_sub movup.2 add # limb 3 - movup.5 # b3 + movup.5 u32widening_add - movup.5 # a3 + movup.5 swap u32overflowing_sub movup.2 add + # Mid-algorithm setup: bury borrow3 + the four c-limbs to bring a4..a7 into shallow range. + # [borrow3, c3..c0, b4..b7, a4..a7] -> [borrow3, a4..a7, b4..b7, c3..c0] + movdn.12 + swapw.2 + movup.12 + # limb 4 - movup.12 # b4 + movup.5 u32widening_add - movup.9 # a4 + movup.2 swap u32overflowing_sub movup.2 add # limb 5 - movup.11 # b5 + movup.5 u32widening_add - movup.9 # a5 + movup.3 swap u32overflowing_sub movup.2 add # limb 6 - movup.10 # b6 + movup.5 u32widening_add - movup.9 # a6 + movup.4 swap u32overflowing_sub movup.2 add # limb 7 - movup.9 # b7 + movup.5 u32widening_add - movup.9 # a7 + movup.5 swap u32overflowing_sub movup.2 add + + # Stack now: [underflow, c7, c6, c5, c4, c3, c2, c1, c0]. Reverse the c-block to LE. + movdn.8 + reversew swapw reversew + movup.8 end #! Performs subtraction of two unsigned 256 bit integers discarding the underflow. #! Stack transition looks as follows: #! [b0, b1, b2, b3, b4, b5, b6, b7, a0, a1, a2, a3, a4, a5, a6, a7, ...] #! -> [c0, c1, c2, c3, c4, c5, c6, c7, ...], where c = (a - b) % 2^256. -pub proc wrapping_sub(rhs: u256, lhs: u256) -> u256 - # rhs = b, lhs = a; stack order is [b..., a..., ...]. - exec.u256_le_to_be_pair - exec.sub_with_borrow_be +pub proc wrapping_sub(b: u256, a: u256) -> u256 + exec.overflowing_sub drop - exec.u256_le_to_be -end - -#! Performs subtraction of two unsigned 256 bit integers preserving the underflow. -#! Stack transition looks as follows: -#! [b0, b1, b2, b3, b4, b5, b6, b7, a0, a1, a2, a3, a4, a5, a6, a7, ...] -#! -> [underflow, c0, c1, c2, c3, c4, c5, c6, c7, ...], where c = (a - b) % 2^256. -pub proc overflowing_sub(rhs: u256, lhs: u256) -> (i1, u256) - # rhs = b, lhs = a; stack order is [b..., a..., ...]. - exec.u256_le_to_be_pair - exec.sub_with_borrow_be - movdn.8 - exec.u256_le_to_be - movup.8 end # ===== BITWISE OPERATIONS ======================================================================== @@ -197,7 +189,7 @@ end #! Stack transition looks as follows: #! [b0, b1, b2, b3, b4, b5, b6, b7, a0, a1, a2, a3, a4, a5, a6, a7, ...] #! -> [c0, c1, c2, c3, c4, c5, c6, c7, ...], where c = a & b. -pub proc and(rhs: u256, lhs: u256) -> u256 +pub proc and(b: u256, a: u256) -> u256 swapw.3 movup.3 movup.7 @@ -230,7 +222,7 @@ end #! Stack transition looks as follows: #! [b0, b1, b2, b3, b4, b5, b6, b7, a0, a1, a2, a3, a4, a5, a6, a7, ...] #! -> [c0, c1, c2, c3, c4, c5, c6, c7, ...], where c = a | b. -pub proc or(rhs: u256, lhs: u256) -> u256 +pub proc or(b: u256, a: u256) -> u256 swapw.3 movup.3 movup.7 @@ -263,7 +255,7 @@ end #! Stack transition looks as follows: #! [b0, b1, b2, b3, b4, b5, b6, b7, a0, a1, a2, a3, a4, a5, a6, a7, ...] #! -> [c0, c1, c2, c3, c4, c5, c6, c7, ...], where c = a ^ b. -pub proc xor(rhs: u256, lhs: u256) -> u256 +pub proc xor(b: u256, a: u256) -> u256 swapw.3 movup.3 movup.7 @@ -295,7 +287,7 @@ end #! Returns 1 if the top u256 value is zero; lower stack values are preserved. #! Stack transition looks as follows: #! [a0, a1, a2, a3, a4, a5, a6, a7, ...] -> [is_zero, ...]. -pub proc eqz(rhs: u256, lhs: u256) -> i1 +pub proc eqz(a: u256) -> i1 eq.0 repeat.7 swap @@ -307,415 +299,154 @@ end #! Returns 1 if two unsigned 256 bit integers are equal. #! Stack transition looks as follows: #! [b0, b1, b2, b3, b4, b5, b6, b7, a0, a1, a2, a3, a4, a5, a6, a7, ...] -> [is_equal, ...]. -pub proc eq(rhs: u256, lhs: u256) -> i1 - exec.u256_le_to_be_pair - swapw.3 - eqw - movdn.8 - dropw - dropw - movdn.8 - eqw - movdn.8 - dropw - dropw - and -end - -# ===== MULTIPLICATION ============================================================================ - -#! Multiplies and accumulates one 32-bit limb with carry (internal helper). -#! Input: [k, c, b, a, ...] -> Output: [new_k, result, ...]. -proc mulstep - # Input: [k, c, b, a, ...] - # k = carry from previous step - # c = partial sum to accumulate into - # b = multiplier limb - # a = multiplicand limb - # Output: [new_k, result, ...] - - movdn.2 # [c, b, k, a, ...] - u32widening_madd # [lo, hi, a, ...] (computes c*b+k) - movup.2 # [a, lo, hi, ...] - u32overflowing_add # [carry, result, hi, ...] (computes a+lo) - movup.2 # [hi, carry, result, ...] - add # [new_k, result, ...] (computes hi+carry) -end - -#! Multiplies four limbs using mulstep (internal helper). -#! Expects stack layout prepared by wrapping_mul. -proc mulstep4 - movup.12 - dup.1 - movup.10 - push.0 # start k at 0 - exec.mulstep - swap - movdn.9 - dup.1 - movup.9 - movup.13 - swap.3 - exec.mulstep - swap - movdn.8 - dup.1 +pub proc eq(b: u256, a: u256) -> i1 + # Compare each (a_i, b_i) pair and AND-fold the result. movup.8 - movup.12 - swap.3 - exec.mulstep - swap - movdn.7 - dup.1 - movup.7 - movup.11 - swap.3 - exec.mulstep - swap - movdn.6 -end - -#! Performs multiplication of two unsigned 256 bit integers discarding the overflow. -#! The input values are assumed to be represented using 32 bit limbs, but this is not checked. -#! Stack transition looks as follows: -#! [b0, b1, b2, b3, b4, b5, b6, b7, a0, a1, a2, a3, a4, a5, a6, a7, ...] -> [c0, c1, c2, c3, c4, c5, c6, c7, ...] -#! where c = (a * b) % 2^256, and a0, b0, and c0 are least significant 32-bit limbs of a, b, and c respectively. -@locals(24) -pub proc wrapping_mul(rhs: u256, lhs: u256) -> u256 - exec.u256_le_to_be_pair - # Memory storing setup - loc_storew_be.0 - dropw - # b[5-8] at 0 - loc_storew_be.4 - # b[0-4] at 1 - push.0 dropw - # b[0] at top of stack, followed by a[0-7] - movdn.8 - loc_storew_be.8 - # a[0-4] at 2 - swapw - loc_storew_be.12 - # a[5-8] at 3 - padw - loc_storew_be.16 - loc_storew_be.20 - # p at 4 and 5 - - # b[0] - dropw - swapw - padw - loc_loadw_be.16 - movdnw.2 - movup.12 - - exec.mulstep4 + eq - movdn.9 - movdn.9 - swapw - loc_storew_be.16 - dropw - padw - loc_loadw_be.20 - swapw - movup.9 - movup.9 - - dup.1 - movup.6 - movup.10 - swap.3 - exec.mulstep - swap - movdn.5 - dup.1 - movup.5 - movup.9 - swap.3 - exec.mulstep - swap - movdn.4 - dup.1 - movup.4 movup.8 - swap.3 - exec.mulstep - swap - movdn.3 - swap movup.2 - movup.6 - swap.3 - exec.mulstep + eq + and - drop - loc_storew_be.20 - dropw - - # b[1] - padw - loc_loadw_be.16 - padw - loc_loadw_be.20 movup.7 - dropw - padw - loc_loadw_be.12 padw - loc_loadw_be.8 # load the xs - padw - loc_loadw_be.4 movup.2 - movdn.3 - push.0 dropw # only need b[1] - - exec.mulstep4 - - movdn.9 - movdn.9 - swapw - movdn.3 - padw - loc_loadw_be.16 - push.0 dropw # only need p[0] - movdn.3 - # save p[0-3] to memory, not needed any more - loc_storew_be.16 - dropw - - padw - loc_loadw_be.20 - movup.3 - drop - swapw - movup.9 - movup.9 + eq + and - dup.1 movup.6 - movup.9 - swap.3 - exec.mulstep - swap - movdn.7 - dup.1 + movup.2 + eq + and + movup.5 - movup.7 - swap.3 - exec.mulstep - swap - movdn.5 - swap - movup.3 + movup.2 + eq + and + movup.4 - swap.3 - exec.mulstep + movup.2 + eq + and - drop - swap - drop - loc_storew_be.20 - dropw - - # b[2] - padw - loc_loadw_be.16 - padw - loc_loadw_be.20 - movup.7 - movup.7 - dropw - padw - loc_loadw_be.12 padw - loc_loadw_be.8 # load the xs - padw - loc_loadw_be.4 - swap - movdn.3 - push.0 dropw # only need b[1] + movup.3 + movup.2 + eq + and - exec.mulstep4 + movup.2 + movup.2 + eq + and +end - movdn.9 - movdn.9 - swapw - movdn.3 - movdn.3 - padw - loc_loadw_be.16 - drop drop - movdn.3 - movdn.3 - loc_storew_be.16 - dropw +# ===== MULTIPLICATION ============================================================================ - padw - loc_loadw_be.20 - movup.3 - movup.3 - drop - drop - swapw - movup.9 - movup.9 +#! Computes (a + c*b + k) on 32-bit limbs and splits the 64-bit result into low and high +#! halves. result is the low 32 bits; new_k is the high 32 bits, used as the carry into +#! the next limb. +#! Input: [b, c, k, a, ...] -> Output: [new_k, result, ...]. +proc mulstep + u32widening_madd # [lo, hi, a, ...] (lo + hi*2^32 = c*b + k) + movup.2 # [a, lo, hi, ...] + u32overflowing_add # [carry, result, hi, ...] (result = (a+lo) mod 2^32) + movup.2 # [hi, carry, result, ...] + add # [new_k, result, ...] (new_k = hi + carry) +end - dup.1 - movup.6 - movup.8 - swap.3 - exec.mulstep - swap - movdn.6 - dup.1 - movup.5 - movup.6 - swap.3 - exec.mulstep - swap - swap drop - movdn.3 - drop drop drop - loc_storew_be.20 - dropw - - # b[3] - padw - loc_loadw_be.16 - padw - loc_loadw_be.20 - - movup.7 movup.7 movup.7 - dropw - padw - loc_loadw_be.12 padw - loc_loadw_be.8 - - padw - loc_loadw_be.4 - movdn.3 - push.0 dropw - - exec.mulstep4 - - movdn.9 - movdn.9 +#! Performs multiplication of two unsigned 256 bit integers discarding the overflow. +#! The input values are assumed to be represented using 32 bit limbs, but this is not checked. +#! Stack transition looks as follows: +#! [b0, b1, b2, b3, b4, b5, b6, b7, a0, a1, a2, a3, a4, a5, a6, a7, ...] +#! -> [c0, c1, c2, c3, c4, c5, c6, c7, ...], where c = (a * b) % 2^256. +@locals(16) +pub proc wrapping_mul(b: u256, a: u256) -> u256 + # Schoolbook row-by-row in LE limb order: for row i in 0..8 and j in 0..7-i, + # p[i+j] += a[j] * b[i] + carry + # Carry chains across the j-iteration; mulstep fuses the per-limb multiply-and-add. + # + # a[0..7] stays on stack throughout (deepest 8 cells); each row caches b[i] one slot + # above the a's, with the running carry k on top. Per-j reads a[j] via dup.{j+2} and + # b[i] via dup.2. Only p lives in local memory. + # + # Memory layout (16 local cells): + # mem[0..7] = b[0..7] + # mem[8..15] = p[0..7] (running partial result) + loc_storew_le.0 dropw # b0..b3 -> mem[0..3] + loc_storew_le.4 dropw # b4..b7 -> mem[4..7] + padw loc_storew_le.8 # p0..p3 = 0 -> mem[8..11] + loc_storew_le.12 dropw # p4..p7 = 0 -> mem[12..15] + + # ----- row 0: b[0] * a[0..7] (p starts at 0, so madd alone suffices) ----- + loc_load.0 push.0 + dup.2 dup.2 u32widening_madd loc_store.8 + dup.3 dup.2 u32widening_madd loc_store.9 + dup.4 dup.2 u32widening_madd loc_store.10 + dup.5 dup.2 u32widening_madd loc_store.11 + dup.6 dup.2 u32widening_madd loc_store.12 + dup.7 dup.2 u32widening_madd loc_store.13 + dup.8 dup.2 u32widening_madd loc_store.14 + dup.9 dup.2 u32widening_madd loc_store.15 + drop drop - swapw - movup.3 - padw - loc_loadw_be.16 - drop - movup.3 + # ----- row 1: b[1] * a[0..6] ----- + loc_load.1 push.0 + dup.2 dup.2 loc_load.9 movdn.3 exec.mulstep swap loc_store.9 + dup.3 dup.2 loc_load.10 movdn.3 exec.mulstep swap loc_store.10 + dup.4 dup.2 loc_load.11 movdn.3 exec.mulstep swap loc_store.11 + dup.5 dup.2 loc_load.12 movdn.3 exec.mulstep swap loc_store.12 + dup.6 dup.2 loc_load.13 movdn.3 exec.mulstep swap loc_store.13 + dup.7 dup.2 loc_load.14 movdn.3 exec.mulstep swap loc_store.14 + dup.8 dup.2 loc_load.15 movdn.3 exec.mulstep swap loc_store.15 + drop drop - loc_storew_be.16 - dropw - padw - loc_loadw_be.20 - movdn.3 - push.0 dropw - swapw - movup.9 - movup.9 + # ----- row 2: b[2] * a[0..5] ----- + loc_load.2 push.0 + dup.2 dup.2 loc_load.10 movdn.3 exec.mulstep swap loc_store.10 + dup.3 dup.2 loc_load.11 movdn.3 exec.mulstep swap loc_store.11 + dup.4 dup.2 loc_load.12 movdn.3 exec.mulstep swap loc_store.12 + dup.5 dup.2 loc_load.13 movdn.3 exec.mulstep swap loc_store.13 + dup.6 dup.2 loc_load.14 movdn.3 exec.mulstep swap loc_store.14 + dup.7 dup.2 loc_load.15 movdn.3 exec.mulstep swap loc_store.15 + drop drop - swap - movup.5 - movup.6 - swap.3 - exec.mulstep + # ----- row 3: b[3] * a[0..4] ----- + loc_load.3 push.0 + dup.2 dup.2 loc_load.11 movdn.3 exec.mulstep swap loc_store.11 + dup.3 dup.2 loc_load.12 movdn.3 exec.mulstep swap loc_store.12 + dup.4 dup.2 loc_load.13 movdn.3 exec.mulstep swap loc_store.13 + dup.5 dup.2 loc_load.14 movdn.3 exec.mulstep swap loc_store.14 + dup.6 dup.2 loc_load.15 movdn.3 exec.mulstep swap loc_store.15 + drop drop - drop - movdn.3 - push.0 dropw - - # b[4] - padw - loc_loadw_be.12 padw - loc_loadw_be.8 # load the xs - # OPTIM: don't need a[4-7], but can't use mulstep4 if we don't load - - padw - loc_loadw_be.0 - push.0 dropw # b[4] - - exec.mulstep4 - dropw drop drop # OPTIM: don't need a[4-7], but can't use mulstep4 if we don't load - - # b[5] - padw - loc_loadw_be.12 - padw - loc_loadw_be.0 - movup.2 movdn.3 - push.0 dropw - movup.7 - dup.1 - movup.6 - push.0 - exec.mulstep - swap - movdn.7 - movup.4 - dup.2 - movup.7 - swap.3 - exec.mulstep - swap - movdn.5 - swap - movup.3 - movup.4 - swap.3 - exec.mulstep - drop - swap - drop + # ----- row 4: b[4] * a[0..3] ----- + loc_load.4 push.0 + dup.2 dup.2 loc_load.12 movdn.3 exec.mulstep swap loc_store.12 + dup.3 dup.2 loc_load.13 movdn.3 exec.mulstep swap loc_store.13 + dup.4 dup.2 loc_load.14 movdn.3 exec.mulstep swap loc_store.14 + dup.5 dup.2 loc_load.15 movdn.3 exec.mulstep swap loc_store.15 + drop drop - # b[6] - padw - loc_loadw_be.12 - padw - loc_loadw_be.0 - swap - movdn.3 - push.0 dropw - movup.6 - dup.1 - movup.6 - push.0 - exec.mulstep - swap - movdn.6 - swap - movup.4 - movup.5 - swap.3 - exec.mulstep - drop - movdn.2 + # ----- row 5: b[5] * a[0..2] ----- + loc_load.5 push.0 + dup.2 dup.2 loc_load.13 movdn.3 exec.mulstep swap loc_store.13 + dup.3 dup.2 loc_load.14 movdn.3 exec.mulstep swap loc_store.14 + dup.4 dup.2 loc_load.15 movdn.3 exec.mulstep swap loc_store.15 drop drop - # b[7] - padw - loc_loadw_be.12 - padw - loc_loadw_be.0 + # ----- row 6: b[6] * a[0..1] ----- + loc_load.6 push.0 + dup.2 dup.2 loc_load.14 movdn.3 exec.mulstep swap loc_store.14 + dup.3 dup.2 loc_load.15 movdn.3 exec.mulstep swap loc_store.15 + drop drop - movdn.3 push.0 dropw - movup.4 - movup.5 - movdn.2 - push.0 - exec.mulstep - drop - movdn.3 - drop drop drop + # ----- row 7: b[7] * a[0] ----- + loc_load.7 push.0 + dup.2 dup.2 loc_load.15 movdn.3 exec.mulstep swap loc_store.15 + drop drop - padw - loc_loadw_be.16 - swapw - exec.u256_le_to_be - # drop intermediate x and carry words to match the documented output - swapdw dropw dropw - swapdw dropw dropw + # Drop a[0..7] from stack and load c[0..7] from memory. + dropw dropw + padw loc_loadw_le.12 # [c4, c5, c6, c7, ...] + padw loc_loadw_le.8 # [c0, c1, c2, c3, c4, c5, c6, c7, ...] end diff --git a/crates/lib/core/asm/math/u64.masm b/crates/lib/core/asm/math/u64.masm index 27a014b005..ec6e4922a4 100644 --- a/crates/lib/core/asm/math/u64.masm +++ b/crates/lib/core/asm/math/u64.masm @@ -53,7 +53,7 @@ end #! The input values are assumed to be represented using 32 bit limbs, but this is not checked. #! Stack transition looks as follows: #! [b_lo, b_hi, a_lo, a_hi, ...] -> [c_lo, c_hi, ...], where c = (a - b) % 2^64 -#! This takes 11 cycles. +#! This takes 12 cycles. pub proc wrapping_sub(b: u64, a: u64) -> u64 movup.3 movup.3 # => [a_lo, a_hi, b_lo, b_hi] movup.2 # => [b_lo, a_lo, a_hi, b_hi] @@ -72,7 +72,7 @@ end #! The input values are assumed to be represented using 32 bit limbs, but this is not checked. #! Stack transition looks as follows: #! [b_lo, b_hi, a_lo, a_hi, ...] -> [underflow, c_lo, c_hi, ...], where c = (a - b) % 2^64 -#! This takes 15 cycles. +#! This takes 14 cycles. pub proc overflowing_sub(b: u64, a: u64) -> (i1, u64) movup.3 movup.3 # => [a_lo, a_hi, b_lo, b_hi] movup.2 # => [b_lo, a_lo, a_hi, b_hi] @@ -119,37 +119,36 @@ end #! Stack transition looks as follows: #! [b_lo, b_hi, a_lo, a_hi, ...] -> [c_lo, c_mid_lo, c_mid_hi, c_hi, ...], where #! c = a * b is represented as a 128-bit value split into 4 32-bit limbs. -#! This takes 22 cycles. +#! This takes 23 cycles. pub proc widening_mul(b: u64, a: u64) -> u128 - # => [b_lo, b_hi, a_lo, a_hi, ...] - reversew - # => [a_hi, a_lo, b_hi, b_lo, ...] (effectively [x_hi, x_lo, y_hi, y_lo] for x*y) + # c = a*b = a_lo*b_lo + (a_lo*b_hi + a_hi*b_lo)*2^32 + a_hi*b_hi*2^64 + # Partial products accumulate high-first on the stack, then reversew flips to LE. - # Core 128-bit multiplication algorithm (operates on BE limb order) + # => [b_lo, b_hi, a_lo, a_hi, ...] + dup.0 dup.3 - dup.2 - # => [x_lo, y_lo, x_hi, x_lo, y_hi, y_lo, ...] + # => [a_lo, b_lo, b_lo, b_hi, a_lo, a_hi, ...] u32widening_mul - # => [p0_lo, p0_hi, x_hi, x_lo, y_hi, y_lo, ...] + # => [p0_lo, p0_hi, b_lo, b_hi, a_lo, a_hi, ...] where p0 = a_lo * b_lo swap - # => [p0_hi, p0_lo, x_hi, x_lo, y_hi, y_lo, ...] - dup.4 - movup.4 - # => [x_lo, y_hi, p0_hi, p0_lo, x_hi, y_hi, y_lo, ...] - u32widening_madd - # => [t1_lo, t1_hi, p0_lo, x_hi, y_hi, y_lo, ...] where t1 = y_hi * x_lo + p0_hi + # => [p0_hi, p0_lo, b_lo, b_hi, a_lo, a_hi, ...] + dup.3 movup.5 - dup.4 - # => [y_hi, y_lo, t1_lo, t1_hi, p0_lo, x_hi, y_hi, ...] + # => [a_lo, b_hi, p0_hi, p0_lo, b_lo, b_hi, a_hi, ...] + u32widening_madd + # => [t1_lo, t1_hi, p0_lo, b_lo, b_hi, a_hi, ...] where t1 = a_lo * b_hi + p0_hi + movup.3 + dup.5 + # => [a_hi, b_lo, t1_lo, t1_hi, p0_lo, b_hi, a_hi, ...] u32widening_madd - # => [t2_lo, t2_hi, t1_hi, p0_lo, x_hi, y_hi, ...] where t2 = y_lo * y_hi + t1_lo + # => [t2_lo, t2_hi, t1_hi, p0_lo, b_hi, a_hi, ...] where t2 = a_hi * b_lo + t1_lo swap - # => [t2_hi, t2_lo, t1_hi, p0_lo, x_hi, y_hi, ...] - movup.5 + # => [t2_hi, t2_lo, t1_hi, p0_lo, b_hi, a_hi, ...] + movup.4 movup.5 - # => [y_hi, x_hi, t2_hi, t2_lo, t1_hi, p0_lo, ...] + # => [a_hi, b_hi, t2_hi, t2_lo, t1_hi, p0_lo, ...] u32widening_madd - # => [t3_lo, t3_hi, t2_lo, t1_hi, p0_lo, ...] where t3 = x_hi * y_hi + t2_hi + # => [t3_lo, t3_hi, t2_lo, t1_hi, p0_lo, ...] where t3 = a_hi * b_hi + t2_hi swap # => [t3_hi, t3_lo, t2_lo, t1_hi, p0_lo, ...] movup.3 @@ -157,14 +156,10 @@ pub proc widening_mul(b: u64, a: u64) -> u128 # => [t3_lo, t1_hi, t3_hi, t2_lo, p0_lo, ...] u32widening_add # => [sum, carry, t3_hi, t2_lo, p0_lo, ...] where sum = (t3_lo + t1_hi) mod 2^32 - swap - # => [carry, sum, t3_hi, t2_lo, p0_lo, ...] - movup.2 - # => [t3_hi, carry, sum, t2_lo, p0_lo, ...] + movdn.2 + # => [carry, t3_hi, sum, t2_lo, p0_lo, ...] add - # => [c_hi, c_mid_hi, c_mid_lo, c_lo, ...] (BE order) - - # Convert BE output to LE + # => [c_hi, c_mid_hi, c_mid_lo, c_lo, ...] reversew # => [c_lo, c_mid_lo, c_mid_hi, c_hi, ...] end @@ -175,7 +170,7 @@ end #! The input values are assumed to be represented using 32 bit limbs, but this is not checked. #! Stack transition looks as follows: #! [b_lo, b_hi, a_lo, a_hi, ...] -> [c, ...], where c = 1 when a < b, and 0 otherwise. -#! This takes 12 cycles. +#! This takes 13 cycles. pub proc lt(b: u64, a: u64) -> i1 movup.3 movup.3 # => [a_lo, a_hi, b_lo, b_hi, ...] @@ -265,7 +260,7 @@ end #! The input values are assumed to be represented using 32 bit limbs, but this is not checked. #! Stack transition looks as follows: #! [b_lo, b_hi, a_lo, a_hi, ...] -> [c, ...], where c = 1 when a == b, and 0 otherwise. -#! This takes 5 cycles. +#! This takes 6 cycles. pub proc eq(b: u64, a: u64) -> i1 movup.2 # => [a_lo, b_lo, b_hi, a_hi] eq # => [a_lo==b_lo, b_hi, a_hi] @@ -278,7 +273,7 @@ end #! The input values are assumed to be represented using 32 bit limbs, but this is not checked. #! Stack transition looks as follows: #! [b_lo, b_hi, a_lo, a_hi, ...] -> [c, ...], where c = 1 when a != b, and 0 otherwise. -#! This takes 5 cycles. +#! This takes 8 cycles. pub proc neq(b: u64, a: u64) -> i1 movup.2 # => [a_lo, b_lo, b_hi, a_hi] neq # => [a_lo!=b_lo, b_hi, a_hi] @@ -303,7 +298,7 @@ end #! The input values are assumed to be represented using 32 bit limbs, but this is not checked. #! Stack transition looks as follows: #! [b_lo, b_hi, a_lo, a_hi, ...] -> [c_lo, c_hi, ...], where c = min(a, b). -#! This takes 23 cycles. +#! This takes 27 cycles. pub proc min(b: u64, a: u64) -> u64 movup.3 movup.3 # => [a_lo, a_hi, b_lo, b_hi, ...] @@ -321,7 +316,7 @@ end #! The input values are assumed to be represented using 32 bit limbs, but this is not checked. #! Stack transition looks as follows: #! [b_lo, b_hi, a_lo, a_hi, ...] -> [c_lo, c_hi, ...], where c = max(a, b). -#! This takes 24 cycles. +#! This takes 27 cycles. pub proc max(b: u64, a: u64) -> u64 movup.3 movup.3 # => [a_lo, a_hi, b_lo, b_hi, ...] @@ -378,7 +373,7 @@ pub proc divmod(b: u64, a: u64) -> (remainder: u64, quotient: u64) # Advice stack now has [q_hi, q_lo, r_hi, r_lo] # => [b_lo, b_hi, a_lo, a_hi, ...] - adv_push.2 + adv_push adv_push # Pops from advice: first q_hi, then q_lo, pushes them # => [q_lo, q_hi, b_lo, b_hi, a_lo, a_hi, ...] u32assert2 @@ -434,7 +429,7 @@ pub proc divmod(b: u64, a: u64) -> (remainder: u64, quotient: u64) #========================================================================== # REMAINDER BLOCK: Get remainder and verify b > r #========================================================================== - adv_push.2 + adv_push adv_push # Pops from advice: first r_hi, then r_lo # => [r_lo, r_hi, prod_hi, prod_lo, q_lo, q_hi, b_lo, b_hi, a_lo, a_hi, ...] u32assert2 @@ -571,7 +566,7 @@ end #! The shift value n should be in the range [0, 64), otherwise it will result in an error. #! Stack transition looks as follows: #! [n, a_lo, a_hi, ...] -> [c_lo, c_hi, ...], where c = a >> n. -#! This takes 49 cycles. +#! This takes 60 or 61 cycles, depending on n. pub proc shr(n: u32, a: u64) -> u64 # ========================================================================== # RIGHT SHIFT: Computes a >> n where a is 64-bit and n is shift amount @@ -579,31 +574,27 @@ pub proc shr(n: u32, a: u64) -> u64 # Output: [c_lo, c_hi, ...] where c = a >> n # ========================================================================== - # Convert LE to internal BE format: [n, a_lo, a_hi] -> [n, a_hi, a_lo] - movup.2 # [a_hi, n, a_lo] - swap # [n, a_hi, a_lo] - # --- STEP 1: Compute 2^n and split into hi/lo --- pow2 - # [2^b, a_hi, a_lo, ...] + # [2^b, a_lo, a_hi, ...] u32split swap - # [pow_hi, pow_lo, a_hi, a_lo, ...] + # [pow_hi, pow_lo, a_lo, a_hi, ...] # For b=0: pow_hi=0, pow_lo=1 # For b=1: pow_hi=0, pow_lo=2 # For b=32: pow_hi=1, pow_lo=0 # --- STEP 2: Compute divisor = pow_hi + pow_lo --- dup.1 - # [pow_lo, pow_hi, pow_lo, a_hi, a_lo, ...] + # [pow_lo, pow_hi, pow_lo, a_lo, a_hi, ...] add - # [pow_hi+pow_lo, pow_lo, a_hi, a_lo, ...] + # [pow_hi+pow_lo, pow_lo, a_lo, a_hi, ...] # For b=0: divisor=1, pow_lo=1 # For b=1: divisor=2, pow_lo=2 # --- STEP 3: First division - a_hi / divisor --- - movup.2 + movup.3 # [a_hi, pow_hi+pow_lo, pow_lo, a_lo, ...] swap # [pow_hi+pow_lo, a_hi, pow_lo, a_lo, ...] @@ -692,6 +683,8 @@ pub proc shr(n: u32, a: u64) -> u64 add # [c_lo, quot1, !borrow, ...] # c_lo = rem1 * multiplier + quot2 + # This add is safe: when !borrow=1, multiplier = 2^32 / pow_lo and rem1 < pow_lo, so + # rem1 * multiplier <= 2^32 - multiplier and adding quot2 < multiplier stays below 2^32. # --- STEP 9: Conditional swap to get final result --- dup.2 @@ -717,7 +710,7 @@ end #! The rotation amount n should be in the range [0, 64), otherwise it will result in an error. #! Stack transition looks as follows: #! [n, a_lo, a_hi, ...] -> [c_lo, c_hi, ...], where c = a <<< n (rotate left). -#! This takes 35 cycles. +#! This takes 46 cycles. pub proc rotl(n: u32, a: u64) -> u64 # ========================================================================== # LEFT ROTATION: Computes a <<< n (rotate left by n bits) @@ -725,46 +718,42 @@ pub proc rotl(n: u32, a: u64) -> u64 # Output: [c_lo, c_hi, ...] where c = a <<< n # ========================================================================== - # Convert LE to internal BE format: [n, a_lo, a_hi] -> [n, a_hi, a_lo] - movup.2 # [a_hi, n, a_lo] - swap # [n, a_hi, a_lo] - # --- STEP 1: Compute swap_flag = (31 - n) borrow, i.e., n > 31 --- push.31 - # [31, b, a_hi, a_lo, ...] + # [31, b, a_lo, a_hi, ...] dup.1 - # [b, 31, b, a_hi, a_lo, ...] + # [b, 31, b, a_lo, a_hi, ...] u32overflowing_sub # Computes: 31 - b - # [borrow, diff, b, a_hi, a_lo, ...] + # [borrow, diff, b, a_lo, a_hi, ...] # borrow = 1 if b > 31, else 0 swap - # [diff, borrow, b, a_hi, a_lo, ...] + # [diff, borrow, b, a_lo, a_hi, ...] drop - # [borrow, b, a_hi, a_lo, ...] + # [borrow, b, a_lo, a_hi, ...] # borrow indicates if b > 31 (swap_flag) movdn.3 - # [b, a_hi, a_lo, borrow, ...] + # [b, a_lo, a_hi, borrow, ...] # --- STEP 2: Compute shift_amt = b & 31 and 2^shift_amt --- push.31 - # [31, b, a_hi, a_lo, borrow, ...] + # [31, b, a_lo, a_hi, borrow, ...] u32and - # [b&31, a_hi, a_lo, borrow, ...] + # [b&31, a_lo, a_hi, borrow, ...] # shift_amt = b mod 32 pow2 - # [2^shift_amt, a_hi, a_lo, borrow, ...] + # [2^shift_amt, a_lo, a_hi, borrow, ...] dup - # [2^shift_amt, 2^shift_amt, a_hi, a_lo, borrow, ...] + # [2^shift_amt, 2^shift_amt, a_lo, a_hi, borrow, ...] - movup.3 + movup.2 # [a_lo, 2^shift_amt, 2^shift_amt, a_hi, borrow, ...] # --- STEP 3: Shift the low limb: a_lo * 2^shift_amt --- @@ -791,34 +780,21 @@ pub proc rotl(n: u32, a: u64) -> u64 # lo2 = (a_hi * 2^shift_amt + hi1) mod 2^32 # hi2 = overflow (bits that wrap around) - swap - # [hi2, lo2, lo1, borrow, ...] - # --- STEP 5: Carry the overflow to the low bits --- - # c_lo = lo1 + hi2 (the overflow wraps to low bits in rotation) - movup.2 - # [lo1, hi2, lo2, borrow, ...] + # c_lo_computed = lo1 + hi2 (the rotation overflow wraps to low bits) + movdn.2 + # [hi2, lo1, lo2, borrow, ...] add - # [c_lo, lo2, borrow, ...] - # c_lo = lo1 + hi2 - - swap - # [lo2, c_lo, borrow, ...] - # lo2 becomes c_hi + # [c_lo_computed, lo2, borrow, ...] # --- STEP 6: Conditionally swap based on b > 31 --- movup.2 - # [borrow, lo2, c_lo, ...] - # borrow = 1 if b > 31 - + # [borrow, c_lo_computed, lo2, ...] cswap - # If borrow=1 (b>31): swap -> [c_lo, lo2, ...] - # If borrow=0 (b<=31): no swap -> [lo2, c_lo, ...] - # Result in BE format: [c_hi, c_lo, ...] - - # Convert BE output to LE: [c_hi, c_lo] -> [c_lo, c_hi] - swap + # borrow=1 (b>31): [lo2, c_lo_computed, ...] + # borrow=0 (b<=31): [c_lo_computed, lo2, ...] + # In both cases the top is c_lo and the second is c_hi. end #! Performs right rotation of one unsigned 64-bit integer. @@ -826,7 +802,7 @@ end #! The rotation amount n should be in the range [0, 64), otherwise it will result in an error. #! Stack transition looks as follows: #! [n, a_lo, a_hi, ...] -> [c_lo, c_hi, ...], where c = a >>> n (rotate right). -#! This takes 44 cycles. +#! This takes 60 cycles. pub proc rotr(n: u32, a: u64) -> u64 # ========================================================================== # RIGHT ROTATION: Computes a >>> n (rotate right by n bits) @@ -834,111 +810,117 @@ pub proc rotr(n: u32, a: u64) -> u64 # Output: [c_lo, c_hi, ...] where c = a >>> n # # Strategy: Rotate right by n = left rotate by (64 - n) - # For n in [0,64), we compute left shift by (32 - (n&31)) - # and conditionally swap limbs based on n < 32 + # For n in [0,64), we compute left shift by ((32 - (n&31)) & 31) + # and conditionally swap limbs when the rotation crosses the 32-bit boundary # ========================================================================== - # Convert LE to internal BE format: [n, a_lo, a_hi] -> [n, a_hi, a_lo] - movup.2 # [a_hi, n, a_lo] - swap # [n, a_hi, a_lo] - - # --- STEP 1: Compute swap_flag = (n < 32) --- + # --- STEP 1: Compute is_upper_half = (n > 31) --- push.31 - # [31, b, a_hi, a_lo, ...] + # [31, b, a_lo, a_hi, ...] dup.1 - # [b, 31, b, a_hi, a_lo, ...] + # [b, 31, b, a_lo, a_hi, ...] + + u32overflowing_sub + # [borrow, diff, b, a_lo, a_hi, ...] + # borrow = 1 if b > 31, else 0 - u32lt - # [b<32, b, a_hi, a_lo, ...] - # flag = 1 if b < 32, else 0 + swap + # [diff, borrow, b, a_lo, a_hi, ...] + + drop + # [borrow, b, a_lo, a_hi, ...] + # borrow indicates whether n is in the upper half [32, 63] movdn.3 - # [b, a_hi, a_lo, flag, ...] + # [b, a_lo, a_hi, borrow, ...] - # --- STEP 2: Compute complement shift amount = 32 - (b & 31) --- + # --- STEP 2: Compute complement shift amount = (32 - (b & 31)) & 31 --- push.31 - # [31, b, a_hi, a_lo, flag, ...] + # [31, b, a_lo, a_hi, borrow, ...] u32and - # [b&31, a_hi, a_lo, flag, ...] + # [b&31, a_lo, a_hi, borrow, ...] # shift_amt = b mod 32 + dup + # [shift_amt, shift_amt, a_lo, a_hi, borrow, ...] + neq.0 + not + # [shift_amt == 0, shift_amt, a_lo, a_hi, borrow, ...] + + movdn.4 + # [shift_amt, a_lo, a_hi, borrow, shift_amt == 0, ...] + push.32 - # [32, b&31, a_hi, a_lo, flag, ...] + # [32, shift_amt, a_lo, a_hi, borrow, shift_amt == 0, ...] swap - # [b&31, 32, a_hi, a_lo, flag, ...] + # [shift_amt, 32, a_lo, a_hi, borrow, shift_amt == 0, ...] u32wrapping_sub - # [32-(b&31), a_hi, a_lo, flag, ...] - # complement_shift = 32 - (b mod 32) + # [32-shift_amt, a_lo, a_hi, borrow, shift_amt == 0, ...] + + push.31 + # [31, 32-shift_amt, a_lo, a_hi, borrow, shift_amt == 0, ...] + u32and + # [(32-shift_amt)&31, a_lo, a_hi, borrow, shift_amt == 0, ...] + # complement_shift = (32 - (b mod 32)) mod 32 pow2 - # [2^complement_shift, a_hi, a_lo, flag, ...] + # [2^complement_shift, a_lo, a_hi, borrow, shift_amt == 0, ...] dup - # [2^complement_shift, 2^complement_shift, a_hi, a_lo, flag, ...] + # [2^complement_shift, 2^complement_shift, a_lo, a_hi, borrow, shift_amt == 0, ...] - movup.3 - # [a_lo, 2^complement_shift, 2^complement_shift, a_hi, flag, ...] + movup.2 + # [a_lo, 2^complement_shift, 2^complement_shift, a_hi, borrow, shift_amt == 0, ...] # --- STEP 3: Left shift low limb by complement amount --- - mul - # [a_lo * 2^complement_shift, 2^complement_shift, a_hi, flag, ...] - # This is a full field multiplication - - u32split swap - # [hi1, lo1, 2^complement_shift, a_hi, flag, ...] + u32widening_mul + # [lo1, hi1, 2^complement_shift, a_hi, borrow, shift_amt == 0, ...] + # lo1 = (a_lo * 2^complement_shift) mod 2^32 # hi1 = overflow bits (shift into high) - # lo1 = remaining bits + + swap + # [hi1, lo1, 2^complement_shift, a_hi, borrow, shift_amt == 0, ...] # --- STEP 4: Left shift high limb by complement amount and add overflow --- movup.3 - # [a_hi, hi1, lo1, 2^complement_shift, flag, ...] + # [a_hi, hi1, lo1, 2^complement_shift, borrow, shift_amt == 0, ...] movup.3 - # [2^complement_shift, a_hi, hi1, lo1, flag, ...] - - mul - # [a_hi * 2^complement_shift, hi1, lo1, flag, ...] - - add - # [(a_hi * 2^complement_shift) + hi1, lo1, flag, ...] - # This combines the shifted high limb with overflow from low + # [2^complement_shift, a_hi, hi1, lo1, borrow, shift_amt == 0, ...] - u32split swap - # [hi2, lo2, lo1, flag, ...] + u32widening_madd + # [lo2, hi2, lo1, borrow, shift_amt == 0, ...] + # lo2 = (a_hi * 2^complement_shift + hi1) mod 2^32 # hi2 = overflow bits (wrap around to low) - # lo2 = new high limb value # --- STEP 5: Carry the overflow to the low bits --- - movup.2 - # [lo1, hi2, lo2, flag, ...] + # c_lo_computed = lo1 + hi2 (overflow wraps to low bits) + # The add cannot overflow: hi2 < 2^complement_shift and + # lo1 = (a_lo * 2^complement_shift) mod 2^32 is a multiple of 2^complement_shift, + # so lo1 + hi2 < 2^32. + movdn.2 + # [hi2, lo1, lo2, borrow, shift_amt == 0, ...] add - # [lo1 + hi2, lo2, flag, ...] - # c_lo = lo1 + hi2 (overflow wraps to low bits) - - swap - # [lo2, c_lo, flag, ...] - # lo2 = c_hi + # [c_lo_computed, lo2, borrow, shift_amt == 0, ...] - # --- STEP 6: Conditionally swap based on b < 32 --- + # --- STEP 6: Conditionally swap based on (n > 31) == (n mod 32 == 0) --- movup.2 - # [flag, lo2, c_lo, ...] - # flag = 1 if b < 32 + # [borrow, c_lo_computed, lo2, shift_amt == 0, ...] - not - # [!flag, lo2, c_lo, ...] - # !flag = 1 if b >= 32 + movup.3 + # [shift_amt == 0, borrow, c_lo_computed, lo2, ...] + eq + # [swap_flag, c_lo_computed, lo2, ...] + # swap_flag = 1 for n in [1, 32] and 0 for n in {0} U [33, 63] cswap - # If !flag=1 (b>=32): swap -> [c_lo, lo2, ...] - # If !flag=0 (b<32): no swap -> [lo2, c_lo, ...] - # Result in BE format: [c_hi, c_lo, ...] - - # Convert BE output to LE: [c_hi, c_lo] -> [c_lo, c_hi] - swap + # swap_flag=1: [lo2, c_lo_computed, ...] + # swap_flag=0: [c_lo_computed, lo2, ...] + # In both cases the top is c_lo and the second is c_hi. end #! Counts the number of leading zeros of one unsigned 64-bit integer. diff --git a/crates/lib/core/asm/mem.masm b/crates/lib/core/asm/mem.masm index 4cc8d81ed6..2a751e6aee 100644 --- a/crates/lib/core/asm/mem.masm +++ b/crates/lib/core/asm/mem.masm @@ -14,8 +14,22 @@ use miden::core::crypto::hashes::poseidon2 #! - read_ptr is the memory pointer where the words to copy are stored. #! - write_ptr is the memory pointer where the words will be copied. #! +#! # Panics +#! +#! Panics if the source range `[read_ptr, read_ptr + 4*n)` and destination range +#! `[write_ptr, write_ptr + 4*n)` overlap. +#! #! Total cycles: 15 + 16 * num_words pub proc memcopy_words + # Assert source and destination ranges do not overlap. + # Non-overlap: write_ptr >= read_ptr + 4*n OR read_ptr >= write_ptr + 4*n + dup mul.4 + dup dup.3 add + dup.4 swap u32gte + swap dup.4 add + dup.3 swap u32gte + or assert.err="source and destination ranges must not overlap" + # The loop variable is changed with an add instead of sub because the former # uses one fewer cycle. So here the counter is negated. (1 cycles) # stack: [-n, read_ptr, write_ptr, ...] @@ -70,8 +84,21 @@ end #! - read_ptr is the memory pointer where the elements to copy are stored. #! - write_ptr is the memory pointer where the elements will be copied. #! +#! # Panics +#! +#! Panics if the source range `[read_ptr, read_ptr + n)` and destination range +#! `[write_ptr, write_ptr + n)` overlap. +#! #! Total cycles: 7 + 14 * num_elements pub proc memcopy_elements + # Assert source and destination ranges do not overlap. + # Non-overlap: write_ptr >= read_ptr + n OR read_ptr >= write_ptr + n + dup dup.2 add + dup.3 swap u32gte + dup.1 dup.4 add + dup.3 swap u32gte + or assert.err="source and destination ranges must not overlap" + # The loop variable is changed with an `add` instead of `sub` because the former uses one fewer # cycle. So here the counter is negated. (1 cycle) neg @@ -110,8 +137,8 @@ end #! Outputs: [R0', R1', C', write_ptr] #! #! Where: -#! - R0 is the first rate word (positions 0-3, on top of stack). -#! - R1 is the second rate word / digest (positions 4-7). +#! - R0 is the first rate word / digest (positions 0-3, on top of stack). +#! - R1 is the second rate word (positions 4-7). #! - C is the capacity word (positions 8-11). #! - write_ptr is the memory pointer where the words will be copied. #! - end_ptr is the memory pointer where the copying should end. @@ -264,7 +291,7 @@ end #! - COMMITMENT is the commitment that the one calculated during this procedure will be compared #! with. #! -#! Total cycles: 56 + 3 * num_words / 2 +#! Total cycles: 56 + 3 * num_words pub proc pipe_double_words_preimage_to_memory # Assert precondition (8 cycles). dup is_odd assertz.err="pipe_double_words_preimage_to_memory: num_words must be even" @@ -281,7 +308,7 @@ pub proc pipe_double_words_preimage_to_memory # => [R0, R1, C, write_ptr, end_ptr, COMMITMENT, ...] # (9 + 3 * num_words cycles) - # (e.g., 25 cycles for 4 words) + # (e.g., 21 cycles for 4 words) exec.pipe_double_words_to_memory # => [R0, R1, C, write_ptr', COMMITMENT, ...] @@ -295,3 +322,56 @@ pub proc pipe_double_words_preimage_to_memory # Assert the commitment (11 cycles). assert_eqw.err="pipe_double_words_preimage_to_memory: COMMITMENT does not match" end + +#! Moves an even number of words from the advice stack to memory and asserts that their +#! domain-tagged sequential hash matches a given commitment. +#! +#! Like `pipe_double_words_preimage_to_memory`, but initializes the Poseidon2 capacity word to +#! `[0, domain, 0, 0]`. +#! +#! Inputs: [domain, num_words, write_ptr, COMMITMENT] +#! Outputs: [write_ptr'] +#! +#! Where: +#! - domain is the domain identifier placed into the second element of the capacity word. +#! - num_words is the number of words which will be copied to the memory (must be even). +#! - write_ptr is the memory pointer where the words will be copied. +#! - write_ptr' is the memory pointer to the end of the copied words. +#! - COMMITMENT is the domain-tagged digest that the preimage must hash to. +#! +#! Total cycles: 57 + 3 * num_words +pub proc pipe_double_words_preimage_to_memory_with_domain + # Bring `num_words` to the top so we can check and consume it below (1 cycle). + swap + # => [num_words, domain, write_ptr, COMMITMENT, ...] + + # Assert precondition (8 cycles). + dup is_odd assertz.err="pipe_double_words_preimage_to_memory_with_domain: num_words must be even" + # => [num_words, domain, write_ptr, COMMITMENT, ...] + + # Compute end_ptr = write_ptr + num_words * 4 and reorder the stack (5 cycles). + mul.4 dup.2 add movup.2 + # => [write_ptr, end_ptr, domain, COMMITMENT, ...] + + # Build the capacity word `[0, domain, 0, 0]` on top of the stack (4 cycles). + push.0.0 movup.4 push.0 + # => [C=[0, domain, 0, 0], write_ptr, end_ptr, COMMITMENT, ...] + + # Fill in R0 and R1 with zeros (8 cycles). + exec.poseidon2::init_with_capacity + # => [R0, R1, C, write_ptr, end_ptr, COMMITMENT, ...] + + # (9 + 3 * num_words cycles) + exec.pipe_double_words_to_memory + # => [R0', R1', C', write_ptr', COMMITMENT, ...] + + # Leave just the digest on the stack (9 cycles). + exec.poseidon2::squeeze_digest + # => [DIGEST, write_ptr', COMMITMENT, ...] + + # Move write_ptr out of the way so we can assert the commitment (2 cycles). + movup.4 movdn.8 + + # Assert the commitment (11 cycles). + assert_eqw.err="pipe_double_words_preimage_to_memory_with_domain: COMMITMENT does not match" +end diff --git a/crates/lib/core/asm/pcs/fri/frie2f4.masm b/crates/lib/core/asm/pcs/fri/frie2f4.masm index d528795a73..b6773b104a 100644 --- a/crates/lib/core/asm/pcs/fri/frie2f4.masm +++ b/crates/lib/core/asm/pcs/fri/frie2f4.masm @@ -2,17 +2,18 @@ use miden::core::crypto::hashes::poseidon2 use miden::core::stark::constants use miden::core::pcs::fri::helper -#! Stores the layer commitments C followed by [d_size, t_depth, a1, a0] and [poe, p, e1, e0] where: +#! Stores the layer commitments C followed by [d_size, t_depth, a0, a1] and [poe, p, e0, e1] where: #! 1) d_size is the domain size divided by 4 of the domain corresponding to C. #! 2) t_depth is the tree depth of the Merkle tree with commitment C. #! 3) (a0, a1) is the folding challenge to create the next layer. -#! 4) p is the query index and (e0, e1) is the evaluation at the first layer and poe is g^p with -#! g being the initial domain generator. +#! 4) p is the domain-order query index and (e0, e1) is the evaluation at the first layer and +#! poe is g^rev(p) with g being the initial domain generator and rev(.) the bit-reversal over +#! the LDE domain. #! TODO: This pre-processing function should in fact compute d_size and t_depth for each C #! starting from the original domain size. @locals(16) pub proc preprocess - adv_push.1 + adv_push # => [num_queries, g, ...] exec.constants::fri_com_ptr # => [layer_ptr, num_queries, g, ...] @@ -28,7 +29,7 @@ pub proc preprocess dup.5 #[ptr, Q, num_queries, ptr,..] u32wrapping_add.4 #[ptr+4, Q, num_queries, ptr, ..] swap.6 #[ptr, Q, num_queries, ptr+4, ..] - mem_storew_be #[Q, num_queries, ptr+4, ..] + mem_storew_le #[Q, num_queries, ptr+4, ..] dup.4 sub.1 #[num_queries-1, Q, num_queries, ptr+4, ..] swap.5 #[num_queries, Q, num_queries-1, ptr+4, ..] @@ -43,7 +44,7 @@ pub proc preprocess movdn.5 #=> [X, layer_ptr, layer_ptr, g] - adv_push.1 + adv_push mul.2 sub.1 movdn.4 @@ -55,7 +56,7 @@ pub proc preprocess dup.5 u32wrapping_add.4 swap.6 - mem_storew_be + mem_storew_le dup.4 sub.1 swap.5 @@ -70,7 +71,7 @@ pub proc preprocess movdn.5 #=> [X, remainder_poly_ptr, remainder_poly_ptr, layer_ptr, g] - adv_push.1 + adv_push dup mul.2 exec.constants::set_remainder_poly_size sub.1 @@ -83,7 +84,7 @@ pub proc preprocess dup.5 u32wrapping_add.4 swap.6 - mem_storew_be + mem_storew_le dup.4 sub.1 swap.5 @@ -100,37 +101,42 @@ end #! Checks that, for a query with index p at layer i, the folding procedure to create layer (i + 1) #! was performed correctly. This also advances layer_ptr by 8 to point to the next query layer. #! -#! Input: [layer_ptr, layer_ptr, poe, p, e1, e0, layer_ptr, rem_ptr, x, x, x, x, x, x, x, x, ...] -#! Output: [is_not_last_layer, layer_ptr+8, layer_ptr+8, poe^4, f_pos, ne1, ne0, layer_ptr+8, rem_ptr, x, x, x, x, x, x, x, x, ...] +#! Input: [layer_ptr, layer_ptr, poe, p, e0, e1, layer_ptr, rem_ptr, x, x, x, x, x, x, x, x, ...] +#! Output: [is_not_last_layer, layer_ptr+8, layer_ptr+8, poe^4, f_pos, ne0, ne1, layer_ptr+8, rem_ptr, x, x, x, x, x, x, x, x, ...] #! -#! Cycles: 83 +#! Cycles: 99 @locals(12) pub proc verify_query_layer - # load layer commitment C as well as [a0, a1, t_depth, d_size] (7 cycles) + # load layer commitment C as well as [d_size, t_depth, a0, a1] (7 cycles) swapdw movup.8 add.4 - mem_loadw_be # load [a0, a1, t_depth, d_size] from layer_ptr + 4 + mem_loadw_le # load [d_size, t_depth, a0, a1] from layer_ptr + 4 swapw movup.8 - mem_loadw_be # load C from layer_ptr - # => [C, d_size, t_depth, a1, a0, poe, p, e1, e0, layer_ptr, rem_ptr, ...] + mem_loadw_le # load C from layer_ptr + # => [C, d_size, t_depth, a0, a1, poe, p, e0, e1, layer_ptr, rem_ptr, ...] # verify Merkle auth path for (index = f_pos, depth = t_depth, Root = C) (19 cycles) - swapw.2 # [poe, p, e1, e0, d_size, t_depth, a1, a0, C, layer_ptr, rem_ptr, ...] - swap # [p, poe, e1, e0, d_size, t_depth, a1, a0, C, layer_ptr, rem_ptr, ...] - movup.4 # [d_size, p, poe, e1, e0, t_depth, a1, a0, C, layer_ptr, rem_ptr, ...] - u32divmod # p and d_size must be u32 values + swapw.2 # [poe, p, e0, e1, d_size, t_depth, a0, a1, C, layer_ptr, rem_ptr, ...] + swap # [p, poe, e0, e1, d_size, t_depth, a0, a1, C, layer_ptr, rem_ptr, ...] + movup.4 # [d_size, p, poe, e0, e1, t_depth, a0, a1, C, layer_ptr, rem_ptr, ...] + + sub.1 # mask = d_size - 1 + dup.1 + u32and # [f_pos, p, poe, e0, e1, t_depth, a0, a1, C, layer_ptr, rem_ptr, ...] + dup.5 loc_store.0 + # => [f_pos, p, poe, e0, e1, t_depth, a0, a1, C, layer_ptr, rem_ptr, ...] movup.5 movupw.2 dup.5 - movup.5 # [t_depth, f_pos, C, f_pos, d_seg, poe, e1, e0, a1, a0, layer_ptr, rem_ptr, ...] - mtree_get # [V, C, f_pos, d_seg, poe, e1, e0, a1, a0, layer_ptr, rem_ptr, ...] + + movup.5 # [t_depth, f_pos, C, f_pos, p, poe, e0, e1, a0, a1, layer_ptr, rem_ptr, ...] + mtree_get # [V, C, f_pos, p, poe, e0, e1, a0, a1, layer_ptr, rem_ptr, ...] adv.push_mapval swapw - # => [V, C, f_pos, d_seg, poe, e1, e0, a1, a0, layer_ptr, rem_ptr, ...] - # where f_pos = p % d_size and d_seg = p / 4 + # => [C, V, f_pos, p, poe, e0, e1, a0, a1, layer_ptr, rem_ptr, ...] # unhash V and save the pre-image in locaddr.0 and locaddr.4; we don't clear values of C # because adv_pipe overwrites the first 8 elements of the stack (15 cycles) @@ -141,9 +147,10 @@ pub proc verify_query_layer padw adv_pipe exec.poseidon2::permute - # => [T2, T1, T0, ptr, V, f_pos, d_seg, poe, e1, e0, a1, a0, layer_ptr, rem_ptr, ..] + # => [T0, T1, T2, ptr, V, f_pos, p, poe, e0, e1, a0, a1, layer_ptr, rem_ptr, ..] - # assert T1 == V (16 cycles) + # assert T0 == V (16 cycles) + swapw swapw.3 drop movup.3 @@ -154,30 +161,50 @@ pub proc verify_query_layer movup.9 assert_eq - # load (v7, ..v0) from memory (8 cycles) - exec.constants::tmp3 - mem_loadw_be - swapw + # load (v0, ..v7) from memory (8 cycles) exec.constants::tmp4 - mem_loadw_be - # => [v7, ..., v0, f_pos, d_seg, poe, e1, e0, a1, a0, layer_ptr, rem_ptr, ...] + mem_loadw_le + swapw + exec.constants::tmp3 + mem_loadw_le + # => [v0, ..., v7, f_pos, p, poe, e0, e1, a0, a1, layer_ptr, rem_ptr, ...] + + # the FRI proof is queried in domain order, but fri_ext2fold4 expects an index whose low + # two bits select the bit-reversed position inside the four-element folded row. Build that + # synthetic index as (4 * f_pos) + rev_2(p >> t_depth). + dup.9 loc_load.0 u32shr + # => [p >> t_depth, v0, ..., v7, f_pos, p, poe, e0, e1, a0, a1, layer_ptr, rem_ptr, ...] + dup push.1 u32and u32shl.1 + # => [2 * bit0, p >> t_depth, v0, ..., v7, f_pos, p, poe, e0, e1, a0, a1, layer_ptr, rem_ptr, ...] + swap push.2 u32and u32shr.1 + # => [bit1, 2 * bit0, v0, ..., v7, f_pos, p, poe, e0, e1, a0, a1, layer_ptr, rem_ptr, ...] + add + # => [rev_2(p >> t_depth), v0, ..., v7, f_pos, p, poe, e0, e1, a0, a1, layer_ptr, rem_ptr, ...] + dup.9 mul.4 add + # => [p_for_fold, v0, ..., v7, f_pos, p, poe, e0, e1, a0, a1, layer_ptr, rem_ptr, ...] + movdn.9 + # => [v0, ..., v7, f_pos, p_for_fold, p, poe, e0, e1, a0, a1, layer_ptr, rem_ptr, ...] + movup.10 + # => [p, v0, ..., v7, f_pos, p_for_fold, poe, e0, e1, a0, a1, layer_ptr, rem_ptr, ...] + drop + # => [v0, ..., v7, f_pos, p_for_fold, poe, e0, e1, a0, a1, layer_ptr, rem_ptr, ...] # fold by 4 (1 cycle) fri_ext2fold4 - # => [x, x, x, x, x, x, x, x, x, x, layer_ptr + 8, poe^4, f_pos, ne1, ne0, rem_ptr, ...] + # => [x, x, x, x, x, x, x, x, x, x, layer_ptr + 8, poe^4, f_pos, ne0, ne1, rem_ptr, ...] # prepare for next iteration (10 cycles) swapdw - # => [x, x, layer_ptr + 8, poe^4, f_pos, ne1, ne0, rem_ptr, x, x, x, x, x, x, x, x, ...] - dup.2 # [layer_ptr+8, x, x, layer_ptr+8, poe^4, f_pos, ne1, ne0, rem_ptr, ] - movdn.7 # [x, x, layer_ptr+8, poe^4, f_pos, ne1, ne0, layer_ptr+8, rem_ptr, ...] + # => [x, x, layer_ptr + 8, poe^4, f_pos, ne0, ne1, rem_ptr, x, x, x, x, x, x, x, x, ...] + dup.2 # [layer_ptr+8, x, x, layer_ptr+8, poe^4, f_pos, ne0, ne1, rem_ptr, ] + movdn.7 # [x, x, layer_ptr+8, poe^4, f_pos, ne0, ne1, layer_ptr+8, rem_ptr, ...] drop - drop # [layer_ptr+8, poe^4, f_pos, ne1, ne0, layer_ptr+8, rem_ptr, ...] - dup # [layer_ptr+8, layer_ptr+8, poe^4, f_pos, ne1, ne0, layer_ptr+8, rem_ptr, ...] - dup.7 # [rem_ptr, layer_ptr+8, layer_ptr+8, poe^4, f_pos, ne1, ne0, layer_ptr+8, rem_ptr, ...] - dup.1 # [layer_ptr+8, rem_ptr, layer_ptr+8, layer_ptr+8, poe^4, f_pos, ne1, ne0, layer_ptr+8, rem_ptr, ...] + drop # [layer_ptr+8, poe^4, f_pos, ne0, ne1, layer_ptr+8, rem_ptr, ...] + dup # [layer_ptr+8, layer_ptr+8, poe^4, f_pos, ne0, ne1, layer_ptr+8, rem_ptr, ...] + dup.7 # [rem_ptr, layer_ptr+8, layer_ptr+8, poe^4, f_pos, ne0, ne1, layer_ptr+8, rem_ptr, ...] + dup.1 # [layer_ptr+8, rem_ptr, layer_ptr+8, layer_ptr+8, poe^4, f_pos, ne0, ne1, layer_ptr+8, rem_ptr, ...] neq - # => [is_not_last_layer, layer_ptr+8, layer_ptr+8, poe^4, f_pos, ne1, ne0, layer_ptr+8, rem_ptr, x, x, x, x, x, x, x, x, ...] + # => [is_not_last_layer, layer_ptr+8, layer_ptr+8, poe^4, f_pos, ne0, ne1, layer_ptr+8, rem_ptr, x, x, x, x, x, x, x, x, ...] end #! Verifies one FRI query. @@ -187,17 +214,17 @@ end #! This procedure is exactly the same as `verify_query_128` except for the remainder polynomial check, #! thus any change to one procedure will imply an equivalent change to the other one. #! -#! Input: [poe, p, e1, e0, layer_ptr, rem_ptr, ...] +#! Input: [poe, p, e0, e1, layer_ptr, rem_ptr, ...] #! Output: [x, x, x, x, x, x, x, x, x, x, x, x, ...] (12 "garbage" elements) #! -#! - poe is g^p. +#! - poe is g^rev(p). #! - p is a query index at the first layer. #! - (e0, e1) is an extension field element corresponding to the value of the first layer at index p. #! - layer_ptr is the memory address of the layer data (Merkle tree root, alpha etc.) for the next #! layer. #! - rem_ptr is the memory address of the remainder polynomial. #! -#! Cycles: 107 + num_layers * 83 +#! Cycles: 107 + num_layers * 80 pub proc verify_query_64 # prepare stack to be in a form that leverages the fri_ext2fold4 instruction output stack state @@ -211,29 +238,29 @@ pub proc verify_query_64 dup movup.3 neq - # => [?, layer_ptr, layer_ptr, poe, p, e1, e0, layer_ptr, rem_ptr, 0, 0, 0, 0, 0, 0, 0, 0, ...] + # => [?, layer_ptr, layer_ptr, poe, p, e0, e1, layer_ptr, rem_ptr, 0, 0, 0, 0, 0, 0, 0, 0, ...] # verify correctness of layer folding while.true exec.verify_query_layer end - # => [rem_ptr, rem_ptr, poe^(2^n), f_pos, ne1, ne0, rem_ptr, rem_ptr, x, x, x, x, x, x, x, x, ...] + # => [rem_ptr, rem_ptr, poe^(2^n), f_pos, ne0, ne1, rem_ptr, rem_ptr, x, x, x, x, x, x, x, x, ...] - movup.2 mul.7 - exec.constants::tmp2 mem_store - # => [rem_ptr, rem_ptr, f_pos, ne1, ne0, rem_ptr, rem_ptr, x, x, x, x, x, x, x, x, ...] + movup.2 + push.0.0.0 movup.3 exec.constants::tmp2 mem_storew_le dropw + # => [rem_ptr, rem_ptr, f_pos, ne0, ne1, rem_ptr, rem_ptr, x, x, x, x, x, x, x, x, ...] - push.0 exec.constants::tmp1 mem_loadw_be - # => [P, ne1, ne0, rem_ptr, rem_ptr, x, x, x, x, x, x, x, x, ...] + push.0 exec.constants::tmp1 mem_loadw_le + # => [P, ne0, ne1, rem_ptr, rem_ptr, x, x, x, x, x, x, x, x, ...] swapw swapdw - # => [x, x, x, x, x, x, x, x, ne1, ne0, rem_ptr, rem_ptr, P, ...] + # => [x, x, x, x, x, x, x, x, ne0, ne1, rem_ptr, rem_ptr, P, ...] exec.helper::evaluate_fri_remainder_poly_max_degree_plus_1_half - # => [x, x, x, x, x, x, x, x, ne1, ne0, rem_ptr, rem_ptr, P, ...] + # => [x, x, x, x, x, x, x, x, ne0, ne1, rem_ptr, rem_ptr, P, ...] swapdw - # => [ne1, ne0, rem_ptr, rem_ptr, P, x, x, x, x, x, x, x, x, ...] + # => [ne0, ne1, rem_ptr, rem_ptr, P, x, x, x, x, x, x, x, x, ...] movup.6 assert_eq movup.5 assert_eq # => [X, x, x, x, x, x, x, x, x, ...] @@ -246,17 +273,17 @@ end #! This procedure is exactly the same as `verify_query_64` except for the remainder polynomial check, #! thus any change to one procedure will imply an equivalent change to the other one. #! -#! Input: [poe, p, e1, e0, layer_ptr, rem_ptr, ...] +#! Input: [poe, p, e0, e1, layer_ptr, rem_ptr, ...] #! Output: [x, x, x, x, x, x, x, x, x, x, x, x, ...] (12 "garbage" elements) #! -#! - poe is g^p. +#! - poe is g^rev(p). #! - p is a query index at the first layer. #! - (e0, e1) is an extension field element corresponding to the value of the first layer at index p. #! - layer_ptr is the memory address of the layer data (Merkle tree root, alpha etc.) for the next #! layer. #! - rem_ptr is the memory address of the remainder polynomial. #! -#! Cycles: 140 + num_layers * 83 +#! Cycles: 140 + num_layers * 80 pub proc verify_query_128 # prepare stack to be in a form that leverages the fri_ext2fold4 instruction output stack state @@ -270,28 +297,28 @@ pub proc verify_query_128 dup movup.3 neq - # => [?, layer_ptr, layer_ptr, poe, p, e1, e0, layer_ptr, rem_ptr, 0, 0, 0, 0, 0, 0, 0, 0, ...] + # => [?, layer_ptr, layer_ptr, poe, p, e0, e1, layer_ptr, rem_ptr, 0, 0, 0, 0, 0, 0, 0, 0, ...] # verify correctness of layer folding while.true exec.verify_query_layer end - # => [rem_ptr, rem_ptr, poe^(2^n), f_pos, ne1, ne0, rem_ptr, rem_ptr, x, x, x, x, x, x, x, x, ...] + # => [rem_ptr, rem_ptr, poe^(2^n), f_pos, ne0, ne1, rem_ptr, rem_ptr, x, x, x, x, x, x, x, x, ...] - movup.2 mul.7 - exec.constants::tmp2 mem_store - # => [rem_ptr, rem_ptr, f_pos, ne1, ne0, rem_ptr, rem_ptr, x, x, x, x, x, x, x, x, ...] + movup.2 + push.0.0.0 movup.3 exec.constants::tmp2 mem_storew_le dropw + # => [rem_ptr, rem_ptr, f_pos, ne0, ne1, rem_ptr, rem_ptr, x, x, x, x, x, x, x, x, ...] - push.0 exec.constants::tmp1 mem_loadw_be - # => [P, ne1, ne0, rem_ptr, rem_ptr, x, x, x, x, x, x, x, x, ...] + push.0 exec.constants::tmp1 mem_loadw_le + # => [P, ne0, ne1, rem_ptr, rem_ptr, x, x, x, x, x, x, x, x, ...] swapw swapdw - # => [x, x, x, x, x, x, x, x, ne1, ne0, rem_ptr, rem_ptr, P, ...] + # => [x, x, x, x, x, x, x, x, ne0, ne1, rem_ptr, rem_ptr, P, ...] exec.helper::evaluate_fri_remainder_poly_max_degree_plus_1 - # => [x, x, x, x, x, x, x, x, ne1, ne0, rem_ptr, rem_ptr, P, ...] + # => [x, x, x, x, x, x, x, x, ne0, ne1, rem_ptr, rem_ptr, P, ...] swapdw - # => [ne1, ne0, rem_ptr, rem_ptr, P, x, x, x, x, x, x, x, x, ...] + # => [ne0, ne1, rem_ptr, rem_ptr, P, x, x, x, x, x, x, x, x, ...] movup.6 assert_eq movup.5 assert_eq # => [X, x, x, x, x, x, x, x, x, ...] @@ -307,7 +334,7 @@ end #! Input: [query_ptr, layer_ptr, rem_ptr, g, ...] #! Output: [...] #! -#! - query_ptr is a pointer to a list of tuples of the form (e0, e1, p, poe) where poe is equal +#! - query_ptr is a pointer to a list of tuples of the form (poe, p, e0, e1) where poe is equal #! to g^p with g being the initial FRI domain generator. p is the query index at the first layer #! and (e0, e1) is an extension field element corresponding to the value of the first layer at index p. #! - layer_ptr is a pointer to the first layer commitment denoted throughout the code by C. @@ -326,15 +353,15 @@ end #! #! This means for example that: #! 1. rem_ptr - 1 points to the last (alpha0, alpha1, t_depth, d_size) tuple. -#! 2. layer_ptr - 1 points to the last (e0, e1, p, poe) tuple. +#! 2. layer_ptr - 1 points to the last (poe, p, e0, e1) tuple. #! -#! Cycles: 24 + num_queries * (107 + num_layers * 83) +#! Cycles: 24 + num_queries * (107 + num_layers * 80) @locals(4) proc verify_64 # store [query_ptr, layer_ptr, rem_ptr, g] to keep track of all queries # (3 cycles) - loc_storew_be.0 + loc_storew_le.0 # [(query_ptr == layer_ptr), query_ptr, layer_ptr, rem_ptr, g] # (4 cycles) @@ -346,14 +373,14 @@ proc verify_64 # a pointer to the evaluation point and a pointer to the location of the polynomial. push.0.0 exec.constants::tmp2 exec.constants::get_remainder_poly_address - exec.constants::tmp1 mem_storew_be + exec.constants::tmp1 mem_storew_le movup.4 while.true - # load [e0, e1, p, poe] from memory i.e. next query data (7 cycles) + # load [poe, p, e0, e1] from memory i.e. next query data (7 cycles) movup.4 - mem_loadw_be - # => [poe, p, e1, e0, layer_ptr, rem_ptr, g, ...] + mem_loadw_le + # => [poe, p, e0, e1, layer_ptr, rem_ptr, g, ...] # we now have everything to verify query p exec.verify_query_64 @@ -362,9 +389,9 @@ proc verify_64 # => [x, x, x, x, x, x, x, x, x, x, x, x, g, ...] dropw drop # => [x, x, x, x, x, x, x, g, ...] - loc_loadw_be.0 # load [query_ptr, layer_ptr, rem_ptr, g] + loc_loadw_le.0 # load [query_ptr, layer_ptr, rem_ptr, g] add.4 - loc_storew_be.0 # store [query_ptr + 4, layer_ptr, rem_ptr, g] + loc_storew_le.0 # store [query_ptr + 4, layer_ptr, rem_ptr, g] swapw # => [x, x, x, x, query_ptr + 4, layer_ptr, rem_ptr, g, ...] dup.5 @@ -386,7 +413,7 @@ end #! Input: [query_ptr, layer_ptr, rem_ptr, g, ...] #! Output: [...] #! -#! - query_ptr is a pointer to a list of tuples of the form (e0, e1, p, poe) where poe is equal +#! - query_ptr is a pointer to a list of tuples of the form (poe, p, e0, e1) where poe is equal #! to g^p with g being the initial FRI domain generator. p is the query index at the first layer #! and (e0, e1) is an extension field element corresponding to the value of the first layer at index p. #! - layer_ptr is a pointer to the first layer commitment denoted throughout the code by C. @@ -405,15 +432,15 @@ end #! #! This means for example that: #! 1. rem_ptr - 1 points to the last (alpha0, alpha1, t_depth, d_size) tuple. -#! 2. layer_ptr - 1 points to the last (e0, e1, p, poe) tuple. +#! 2. layer_ptr - 1 points to the last (poe, p, e0, e1) tuple. #! -#! Cycles: 24 + num_queries * (140 + num_layers * 83) +#! Cycles: 24 + num_queries * (140 + num_layers * 80) @locals(4) proc verify_128 # store [query_ptr, layer_ptr, rem_ptr, g] to keep track of all queries # (3 cycles) - loc_storew_be.0 + loc_storew_le.0 # [(query_ptr == layer_ptr), query_ptr, layer_ptr, rem_ptr, g] # (4 cycles) @@ -425,14 +452,14 @@ proc verify_128 # a pointer to the evaluation point and a pointer to the location of the polynomial. push.0.0 exec.constants::tmp2 exec.constants::get_remainder_poly_address - exec.constants::tmp1 mem_storew_be + exec.constants::tmp1 mem_storew_le movup.4 while.true - # load [e0, e1, p, poe] from memory i.e. next query data (7 cycles) + # load [poe, p, e0, e1] from memory i.e. next query data (7 cycles) movup.4 - mem_loadw_be - # => [poe, p, e1, e0, layer_ptr, rem_ptr, g, ...] + mem_loadw_le + # => [poe, p, e0, e1, layer_ptr, rem_ptr, g, ...] # we now have everything to verify query p exec.verify_query_128 @@ -441,9 +468,9 @@ proc verify_128 # => [x, x, x, x, x, x, x, x, x, x, x, x, g, ...] dropw drop # => [x, x, x, x, x, x, x, g, ...] - loc_loadw_be.0 # load [query_ptr, layer_ptr, rem_ptr, g] + loc_loadw_le.0 # load [query_ptr, layer_ptr, rem_ptr, g] add.4 - loc_storew_be.0 # store [query_ptr + 4, layer_ptr, rem_ptr, g] + loc_storew_le.0 # store [query_ptr + 4, layer_ptr, rem_ptr, g] swapw # => [x, x, x, x, query_ptr + 4, layer_ptr, rem_ptr, g, ...] dup.5 @@ -464,8 +491,8 @@ end #! #! Cycles: #! -#! Polynomial degree less than 64: 24 + num_queries * (107 + num_layers * 83) -#! Polynomial degree less than 128: 24 + num_queries * (140 + num_layers * 83) +#! Polynomial degree less than 64: 24 + num_queries * (107 + num_layers * 80) +#! Polynomial degree less than 128: 24 + num_queries * (140 + num_layers * 80) pub proc verify # Get domain generator and pointer to the remainder codeword # (4 cycles) diff --git a/crates/lib/core/asm/pcs/fri/helper.masm b/crates/lib/core/asm/pcs/fri/helper.masm index 2c63e93912..afd4f52f76 100644 --- a/crates/lib/core/asm/pcs/fri/helper.masm +++ b/crates/lib/core/asm/pcs/fri/helper.masm @@ -104,11 +104,11 @@ end #! #! Input: [...] #! Output: [...] -#! Cycles: 21 + 83 * num_fri_layers +#! Cycles: 21 + 225 * num_fri_layers pub proc load_fri_layer_commitments # We need to store the current FRI layer LDE domain size and its logarithm. padw exec.constants::get_lde_domain_info_word - exec.constants::tmp1 mem_storew_be + exec.constants::tmp1 mem_storew_le # => [Y, ...] where `Y` is as "garbage" word # Address containing the first layer commitment @@ -129,42 +129,42 @@ pub proc load_fri_layer_commitments dup.5 add.4 swap.6 - mem_storew_be + mem_storew_le #=> [COM, num_layers, ptr_layer + 4, y, y, ...] - # Reseed - exec.random_coin::reseed + # Reseed with commitment and absorb per-round PoW witness in one shot. + adv_push + exec.random_coin::reseed_with_felt # => [num_layers, ptr_layer + 4, y, y, ...] + # Verify per-round FRI folding PoW and sample folding challenge in one shot. + # Reads folding_pow_bits from memory. Bypasses buffer API since sponge state + # is known after reseed_with_felt. + exec.random_coin::sample_folding_pow_and_ext + #=> [a0, a1, num_layers, ptr_layer + 4, y, y, ...] padw - exec.random_coin::get_rate_1 - #=> [R1, ZERO, num_layers, ptr_layer + 4, y, y, ... ] - push.0.0 - exec.constants::tmp1 mem_loadw_be - # => [lde_size, log2(lde_size), lde_generator, 0, a1, a0, Y, num_layers, ptr_layer + 4, y, y, ...] + exec.constants::tmp1 mem_loadw_le + # => [lde_size, log2(lde_size), lde_generator, 0, a0, a1, Y, num_layers, ptr_layer + 4, y, y, ...] # Compute and save to memory new lde_size and its new logarithm div.4 swap sub.2 swap - exec.constants::tmp1 mem_storew_be - # => [lde_size / 4, log2(lde_size) - 2, lde_generator, 0, a1, a0, num_layers, ptr_layer + 4, y, y, ...] + exec.constants::tmp1 mem_storew_le + # => [lde_size / 4, log2(lde_size) - 2, lde_generator, 0, a0, a1, num_layers, ptr_layer + 4, y, y, ...] # Move the pointer higher up the stack movup.2 drop movup.2 drop - swapw - dropw - # => [lde_size, log2(lde_size), a1, a0, num_layers, ptr_layer + 4, y, y, Y, ...] - - # Save [a0, a1, log2(lde_size) - 2, lde_size / 4] in memory next to the layer commitment + # => [lde_size / 4, log2(lde_size) - 2, a0, a1, num_layers, ptr_layer + 4, y, y, ...] + # Save [lde_size / 4, log2(lde_size) - 2, a0, a1] in memory next to the layer commitment dup.5 add.4 swap.6 - mem_storew_be + mem_storew_le swapw - # => [num_layers, ptr_layer + 8, y, y, lde_size / 4, log2(lde_size) - 2, a1, a0, ...] + # => [num_layers, ptr_layer + 8, y, y, lde_size / 4, log2(lde_size) - 2, a0, a1, ...] # Decrement the FRI layer counter sub.1 @@ -191,15 +191,6 @@ end #! 2- Remainder polynomial of degree less #! than 128: 191 pub proc load_and_verify_remainder - # Load remainder commitment and save it at `TMP1` - padw - adv_loadw - exec.constants::tmp1 mem_storew_be - #=> [COM, ...] - - # Reseed with remainder commitment - exec.random_coin::reseed - #=> [...] # `adv_pipe` the remainder codeword ## Get the numbers of FRI layers @@ -219,40 +210,36 @@ pub proc load_and_verify_remainder eq if.true # Remainder polynomial degree less than 64 - padw padw padw - # => [Y, Y, 0, 0, 0, 0 remainder_poly_ptr, remainder_size, y, y] + # Load the random coin state as the initial sponge state. + push.0 exec.constants::random_coin_output_len_ptr mem_store + push.0 exec.constants::random_coin_input_len_ptr mem_store + exec.random_coin::load_random_coin_state + # => [R0, R1, C, remainder_poly_ptr, remainder_size, y, y] # adv_load remainder polynomial exec.load_fri_remainder_poly_max_degree_plus_1_half - # Compare Remainder_poly_com with the read commitment - exec.constants::tmp1 mem_loadw_be - movup.4 - assert_eq - movup.3 - assert_eq - movup.2 - assert_eq - assert_eq + # Update the random coin state with the remainder polynomial digest. + exec.random_coin::store_random_coin_state + push.0 exec.constants::random_coin_input_len_ptr mem_store + push.8 exec.constants::random_coin_output_len_ptr mem_store else # Remainder polynomial degree less than 128 - padw padw padw - # => [Y, Y, 0, 0, 0, 0 remainder_poly_ptr, remainder_size, y, y] + # Load the random coin state as the initial sponge state. + push.0 exec.constants::random_coin_output_len_ptr mem_store + push.0 exec.constants::random_coin_input_len_ptr mem_store + exec.random_coin::load_random_coin_state + # => [R0, R1, C, remainder_poly_ptr, remainder_size, y, y] # adv_load remainder polynomial exec.load_fri_remainder_poly_max_degree_plus_1 - # => [Y, Remainder_poly_com, Y, remainder_poly_ptr, remainder_size, y, y] - - # Compare Remainder_poly_com with the read commitment - exec.constants::tmp1 mem_loadw_be - movup.4 - assert_eq - movup.3 - assert_eq - movup.2 - assert_eq - assert_eq + # => [R0, R1, C, remainder_poly_ptr, remainder_size, y, y] + + # Update the random coin state with the remainder polynomial digest. + exec.random_coin::store_random_coin_state + push.0 exec.constants::random_coin_input_len_ptr mem_store + push.8 exec.constants::random_coin_output_len_ptr mem_store end dropw dropw diff --git a/crates/lib/core/asm/stark/constants.masm b/crates/lib/core/asm/stark/constants.masm index 770942651d..0c92cac6c8 100644 --- a/crates/lib/core/asm/stark/constants.masm +++ b/crates/lib/core/asm/stark/constants.masm @@ -2,7 +2,7 @@ # ================================================================================================= # General constants -const ROOT_UNITY = 7277203076849721926 +const ROOT_UNITY = 1753635133440165772 const DOMAIN_OFFSET = 7 const DOMAIN_OFFSET_INV = 2635249152773512046 @@ -13,14 +13,9 @@ const NUM_AUX_TRACE_COEFS = 2 const BLOWUP_FACTOR = 8 const BLOWUP_FACTOR_LOG = 3 -# Number of fixed length public inputs with padding (in field elements) -# This is composed of the input/output operand stacks (16 * 2) and the program digest (4) and four -# zeros for padding to the next multiple of 4. Note that, then, the fixed length public inputs -# which are stored as extension field elements will be double-word aligned. -const NUM_FIXED_LEN_PUBLIC_INPUTS = 40 - -# Op label for kernel procedures table messages -const KERNEL_OP_LABEL = 48 +# FRI parameters (hardcoded; future versions may make these configurable) +const LOG_FINAL_DEGREE = 7 +const FRI_FOLD_ARITY = 4 # MEMORY POINTERS # ================================================================================================= @@ -30,10 +25,11 @@ const KERNEL_OP_LABEL = 48 ## of constant size. ### Addresses to store the LDE domain parameters +### The info word layout is [lde_size, log(lde_size), lde_g, 0]. const LDE_DOMAIN_INFO_PTR = 3223322624 -const LDE_DOMAIN_GEN_PTR = 3223322625 -const LDE_DOMAIN_LOG_SIZE_PTR = 3223322626 -const LDE_DOMAIN_SIZE_PTR = 3223322627 +const LDE_DOMAIN_SIZE_PTR = 3223322624 +const LDE_DOMAIN_LOG_SIZE_PTR = 3223322625 +const LDE_DOMAIN_GEN_PTR = 3223322626 ### Address to store the number of FRI queries const NUM_QUERIES_PTR = 3223322628 @@ -58,9 +54,6 @@ const FRI_QUERIES_ADDRESS_PTR = 3223322633 ### Address to store the logarithm of the execution trace length const TRACE_LENGTH_LOG_PTR = 3223322634 -### Address to store the number of grinding bits -const GRINDING_FACTOR_PTR = 3223322635 - ### Addresses to store the commitments to main, auxiliary and constraints composition polynomials traces const MAIN_TRACE_COM_PTR = 3223322636 const AUX_TRACE_COM_PTR = 3223322640 @@ -78,9 +71,6 @@ const ALPHA_DEEP_ND_PTR = 3223322656 ### Address to store the fixed terms, across all queries, of the DEEP queries. const OOD_FIXED_TERM_HORNER_EVALS_PTR = 3223322660 -### Address storing a pointer to the number of public inputs (in field elements) -const NUM_PUBLIC_INPUTS_PTR = 3223322664 - ### Address storing trace domain generator const TRACE_DOMAIN_GENERATOR_PTR = 3223322665 @@ -101,6 +91,11 @@ const TMP2 = 3223322684 const TMP3 = 3223322688 const TMP4 = 3223322692 +### gamma = beta^MAX_MESSAGE_WIDTH for per-bus domain separation. +### Stored as [gamma0, gamma1, 0, 0] (one extension field element, word-aligned). +### Computed once in generate_aux_randomness, read by reduce_kernel_digests. +const BUS_GAMMA_PTR = 3223322696 + ### Address to the word holding the non-deterministically loaded 2 random challenges, which will be ### checked for correctness once we receive the commitment to the auxiliary trace and are able to ### generate the auxiliary randomness @@ -118,34 +113,75 @@ const NUM_ACE_INPUTS_PTR = 3223322721 const NUM_ACE_GATES_PTR = 3223322722 const MAX_CYCLE_LEN_LOG_PTR = 3223322723 +### Addresses to store proof-of-work bit counts. +### query_pow_bits: PoW before query index sampling (PCS_PARAMS.query_pow_bits) +### deep_pow_bits: PoW before DEEP challenge sampling (PCS_PARAMS.deep.deep_pow_bits) +### folding_pow_bits: PoW per FRI folding round (PCS_PARAMS.fri.folding_pow_bits), same for all layers +const QUERY_POW_BITS_PTR = 3223322724 +const DEEP_POW_BITS_PTR = 3223322725 +const FOLDING_POW_BITS_PTR = 3223322726 + ### Addresses of the digests of dynamically executed procedures const DYNAMIC_PROCEDURE_0_PTR = 3223322728 const DYNAMIC_PROCEDURE_1_PTR = 3223322732 const DYNAMIC_PROCEDURE_2_PTR = 3223322736 const DYNAMIC_PROCEDURE_3_PTR = 3223322740 +const DYNAMIC_PROCEDURE_4_PTR = 3223322744 + +### Random coin buffers +const RANDOM_COIN_INPUT_BUF_PTR = 3223322748 +const RANDOM_COIN_INPUT_LEN_PTR = 3223322756 +const RANDOM_COIN_OUTPUT_LEN_PTR = 3223322757 ## ACE related ## Starts at address 3225419776 = 2**31 + 2**30 + 2**22 and the memory region grows backward -## and forward and is of variable length in both directions. -## In the backward direction, the size is determined by the size of the fixed public inputs and -## the number of (groups) of variable length inputs. +## and forward, forming the ACE READ section consumed by `eval_circuit`. +## +## In the backward direction, the size is determined by the fixed-length public inputs (FLPI) +## and the variable-length public input reductions (VLPI). These regions are laid out by +## `compute_and_store_public_inputs_address` in `stark/public_inputs.masm`. ## -## In the forward direction, the size is determined by the number of OOD evaluations, which itself -## is a function of the number of columns in all traces, the size of the ACE circuit description, -## and the number of auxiliary ACE inputs, which is fixed to 12 base field elements. +## In the forward direction, the size is determined by the OOD evaluations, aux bus boundary +## values, stark variables, and circuit constants. +## +## ACE READ section layout (low address -> high address): +## +## pi_ptr --> [ FLPI (m EF) ] fixed-length public inputs +## [ VLPI reductions (k words) ] k groups, word-aligned (per-instance) +## anchor --> [ aux_rand (1 word) ] AUX_RAND_ELEM_PTR (this address) +## [ OOD evaluations ] OOD_EVALUATIONS_PTR +## [ aux bus boundary ] AUX_BUS_BOUNDARY_PTR +## [ stark vars ] AUXILIARY_ACE_INPUTS_PTR +## [ constants ] ACE_CIRCUIT_STREAM_PTR +## ... EVAL section follows ... +## +## The FLPI and VLPI pointers are dynamic (stored at PUBLIC_INPUTS_ADDRESS_PTR and +## VARIABLE_LEN_PUBLIC_INPUTS_ADDRESS_PTR). All other pointers are fixed constants. +## +## Relationship to ACE codegen: Each VLPI group occupies 1 word (4 base felts = 2 EF +## slots) due to word-alignment, so `k` groups map to `k * 2` EF slots in AceConfig. ### We use 2 extension field elements for a total of 4 base field elements. const AUX_RAND_ELEM_PTR = 3225419776 -### OOD evaluations require a total of (80 + 8) * 2 * 2 field elements for current and next trace -### polynomials and 8 * 2 * 2 field elements for current and next constraint composition polynomials +### OOD evaluations require a total of (72 + 16 + 16) * 2 * 2 field elements for current and next: +### - 72 main trace columns (padded) +### - 16 aux trace base columns (aux width * extension degree) +### - 16 quotient chunk base columns (8 chunks * extension degree) const OOD_EVALUATIONS_PTR = 3225419780 # AUX_RAND_ELEM_PTR + 4 -### We need to allocate for 12 field -const AUXILIARY_ACE_INPUTS_PTR = 3225420164 # AUXILIARY_ACE_INPUTS_PTR + (80 + 8 + 8) * 2 * 2 +### Auxiliary bus boundary values (2 extension field elements = 4 base elements). +### TODO(#3032): The second value is always zero (placeholder for trace splitting). +const AUX_BUS_BOUNDARY_PTR = 3225420196 # OOD_EVALUATIONS_PTR + (72 + 16 + 16) * 2 * 2 + +### Auxiliary inputs for ACE (stark vars), 10 extension field elements = 20 base elements. +const AUXILIARY_ACE_INPUTS_PTR = 3225420200 # AUX_BUS_BOUNDARY_PTR + 4 + +### Address at the start of the memory region holding the arithmetic circuit description (constants + ops). +const ACE_CIRCUIT_STREAM_PTR = 3225420220 # AUXILIARY_ACE_INPUTS_PTR + 20 -### Address at the start of the memory region holding the arithmetic circuit for constraint evaluation -const ACE_CIRCUIT_PTR = 3225420176 # AUXILIARY_ACE_INPUTS_PTR + 12 +### Address at the start of the evaluation-gates portion of the arithmetic circuit (EVAL section). +const ACE_CIRCUIT_PTR = 3225420820 # ACE_CIRCUIT_STREAM_PTR + num_const_felts ## FRI ## @@ -214,18 +250,31 @@ pub proc get_blowup_factor_log push.BLOWUP_FACTOR_LOG end +pub proc get_log_final_degree + push.LOG_FINAL_DEGREE +end + +pub proc get_fri_fold_arity + push.FRI_FOLD_ARITY +end + #! Store details about the LDE domain. #! #! The info stored is `[lde_size, log(lde_size), lde_g, 0]`. pub proc set_lde_domain_info_word - push.LDE_DOMAIN_INFO_PTR mem_storew_be + push.LDE_DOMAIN_INFO_PTR mem_storew_le end #! Load details about the LDE domain. #! #! The info stored is `[lde_size, log(lde_size), lde_g, 0]`. pub proc get_lde_domain_info_word - push.LDE_DOMAIN_INFO_PTR mem_loadw_be + push.LDE_DOMAIN_INFO_PTR mem_loadw_le +end + +#! Returns log(lde_size), i.e., the depth of the LDE domain Merkle tree. +pub proc get_lde_domain_depth + push.LDE_DOMAIN_LOG_SIZE_PTR mem_load end pub proc set_lde_domain_generator @@ -236,14 +285,6 @@ pub proc get_lde_domain_generator push.LDE_DOMAIN_GEN_PTR mem_load end -pub proc set_lde_domain_log_size - push.LDE_DOMAIN_LOG_SIZE_PTR mem_store -end - -pub proc get_lde_domain_log_size - push.LDE_DOMAIN_LOG_SIZE_PTR mem_load -end - pub proc set_lde_domain_size push.LDE_DOMAIN_SIZE_PTR mem_store end @@ -308,12 +349,28 @@ pub proc get_trace_length_log push.TRACE_LENGTH_LOG_PTR mem_load end -pub proc set_grinding_factor - push.GRINDING_FACTOR_PTR mem_store +pub proc set_query_pow_bits + push.QUERY_POW_BITS_PTR mem_store end -pub proc get_grinding_factor - push.GRINDING_FACTOR_PTR mem_load +pub proc get_query_pow_bits + push.QUERY_POW_BITS_PTR mem_load +end + +pub proc set_deep_pow_bits + push.DEEP_POW_BITS_PTR mem_store +end + +pub proc get_deep_pow_bits + push.DEEP_POW_BITS_PTR mem_load +end + +pub proc set_folding_pow_bits + push.FOLDING_POW_BITS_PTR mem_store +end + +pub proc get_folding_pow_bits + push.FOLDING_POW_BITS_PTR mem_load end pub proc main_trace_com_ptr @@ -347,10 +404,6 @@ pub proc ood_fixed_term_horner_evaluations_ptr push.OOD_FIXED_TERM_HORNER_EVALS_PTR end -pub proc num_public_inputs_ptr - push.NUM_PUBLIC_INPUTS_PTR -end - pub proc set_trace_domain_generator push.TRACE_DOMAIN_GENERATOR_PTR mem_store end @@ -398,6 +451,22 @@ pub proc tmp4 push.TMP4 end +pub proc random_coin_input_buf_ptr + push.RANDOM_COIN_INPUT_BUF_PTR +end + +pub proc random_coin_input_len_ptr + push.RANDOM_COIN_INPUT_LEN_PTR +end + +pub proc random_coin_output_len_ptr + push.RANDOM_COIN_OUTPUT_LEN_PTR +end + +pub proc bus_gamma_ptr + push.BUS_GAMMA_PTR +end + pub proc aux_rand_nd_ptr push.AUX_RAND_ND_PTR end @@ -418,10 +487,18 @@ pub proc ood_evaluations_ptr push.OOD_EVALUATIONS_PTR end +pub proc aux_bus_boundary_ptr + push.AUX_BUS_BOUNDARY_PTR +end + pub proc auxiliary_ace_inputs_ptr push.AUXILIARY_ACE_INPUTS_PTR end +pub proc ace_circuit_stream_ptr + push.ACE_CIRCUIT_STREAM_PTR +end + pub proc get_arithmetic_circuit_ptr push.ACE_CIRCUIT_PTR end @@ -450,10 +527,14 @@ pub proc get_procedure_digest_process_public_inputs_ptr push.DYNAMIC_PROCEDURE_3_PTR end +pub proc get_procedure_digest_observe_aux_trace_ptr + push.DYNAMIC_PROCEDURE_4_PTR +end + # HELPER # ================================================================================================= #! Overwrites the top stack word with zeros. pub proc zeroize_stack_word - exec.zero_word_ptr mem_loadw_be + exec.zero_word_ptr mem_loadw_le end diff --git a/crates/lib/core/asm/stark/deep_queries.masm b/crates/lib/core/asm/stark/deep_queries.masm index 49b3bb5ffa..0ae8743482 100644 --- a/crates/lib/core/asm/stark/deep_queries.masm +++ b/crates/lib/core/asm/stark/deep_queries.masm @@ -1,22 +1,26 @@ use miden::core::stark::constants +use miden::core::stark::utils #! Takes a query index and computes x := offset * domain_gen^index. It also computes the denominators #! (x - z) and (x - gz). #! -#! Input: [Y, Y, index, ...] -#! Output: [Z, Y, x, index, ...] +#! Input: [Y, Y, index, query_ptr, ...] +#! Output: [Z, Y, x, index, query_ptr, ...] #! #! where: -#! - Z := [-gz1, x -gz0, -z1, x - z0] +#! - Z := [x - z0, -z1, x - gz0, -gz1] +#! - x := offset * domain_gen^natural_index #! - Y is a "garbage" word -#! -#! Cycles: 58 proc compute_denominators - # Compute x = offset * domain_gen^index + # Compute x = offset * domain_gen^natural_index + # The natural (un-reversed) index is stored at query_ptr + 2 in memory, + # placed there by generate_list_indices to avoid a costly bit_reverse_len call here. exec.constants::get_lde_domain_info_word - #=> [lde_size, depth, domain_gen, 0, Y, index, ...] + #=> [lde_size, depth, domain_gen, 0, Y, index, query_ptr, ...] movup.2 - dup.8 + #=> [domain_gen, lde_size, depth, 0, Y, index, query_ptr, ...] + dup.9 add.2 mem_load + #=> [natural_index, domain_gen, lde_size, depth, 0, Y, index, query_ptr, ...] exp.u32 exec.constants::get_domain_offset mul #=> [x, lde_size, depth, 0, Y, index, ...] @@ -25,62 +29,71 @@ proc compute_denominators movdn.3 #=> [lde_size, depth, 0, x, Y, index, ...] push.0 - exec.constants::tmp1 mem_loadw_be - #=> [-z0, -gz0, -gz1, -z1, x, Y, index, ...] + exec.constants::tmp1 mem_loadw_le + #=> [-z0, -z1, -gz0, -gz1, x, Y, index, ...] + # Compute denominators and place x after Y for word alignment. + # The movup.4 dup movdn.9 moves x past the Y word while keeping a copy on top. dup.4 add - #=> [x-z0, -gz0, -gz1, -z1, x, Y, index, ...] - movdn.3 - #=> [-gz0, -gz1, -z1, x-z0, x, Y, index, ...] - + #=> [x - z0, -z1, -gz0, -gz1, x, Y, index, ...] movup.4 dup movdn.9 - #=> [x, -gz0, -gz1, -z1, x-z0, Y, x, index, ...] - - add swap - #=> [-gz1, x - gz0, -z1, x-z0, Y, x, index, ...] + #=> [x, x - z0, -z1, -gz0, -gz1, Y, x, index, ...] + movup.3 add + #=> [x - gz0, x - z0, -z1, -gz1, Y, x, index, ...] + movdn.2 + #=> [x - z0, -z1, x - gz0, -gz1, Y, x, index, ...] end #! Computes the DEEP query. #! #! Input: [Z, X, Y, W, query_ptr, ...] -#! Ouput: [eval1, eval0, Y, query_ptr, ...] +#! Output: [eval0, eval1, Y, query_ptr, ...] #! #! where: #! -#! 1. X is [q_x_at_alpha_1, q_x_at_alpha_0, q_x_at_alpha_1, q_x_at_alpha_0] -#! 2. W is [q_gz_1, q_gz_0, q_z_1, q_z_0] +#! 1. X is [q_x_at_alpha_0, q_x_at_alpha_1, q_x_at_alpha_0, q_x_at_alpha_1] +#! 2. W is [q_z_0, q_z_1, q_gz_0, q_gz_1] #! -#! Cycles: 62 +#! Cycles: 54 proc divide_and_add swapw #=> [X, Z, Y, W, query_ptr, ...] dupw.3 #=> [W, X, Z, Y, query_ptr, ...] - #=> [q_gz_1, q_gz_0, q_z_1, q_z_0, q_x_at_alpha_1, q_x_at_alpha_0, q_x_at_alpha_1, q_x_at_alpha_0, Z, Y, query_ptr, ...] + #=> [q_z_0, q_z_1, q_gz_0, q_gz_1, q_x_at_alpha_0, q_x_at_alpha_1, q_x_at_alpha_0, q_x_at_alpha_1, Z, Y, query_ptr, ...] - movup.5 movup.5 - movup.5 movup.5 - #=> [q_z_1, q_z_0, q_x_at_alpha_1, q_x_at_alpha_0, p_gz_1, p_gz_0, q_x_at_alpha_1, q_x_at_alpha_0, Z, Y, query_ptr, ...] + movdn.5 movdn.5 + #=> [q_gz_0, q_gz_1, q_x_at_alpha_0, q_x_at_alpha_1, q_z_0, q_z_1, q_x_at_alpha_0, q_x_at_alpha_1, Z, Y, query_ptr, ...] ext2add - #=> [num0_1, num0_0, p_gz_1, p_gz_0, q_x_at_alpha_1, q_x_at_alpha_0, Z, Y, query_ptr, ...] + #=> [num_gz_0, num_gz_1, q_z_0, q_z_1, q_x_at_alpha_0, q_x_at_alpha_1, Z, Y, query_ptr, ...] - movdn.9 movdn.9 - #=> [p_gz_1, p_gz_0, q_x_at_alpha_1, q_x_at_alpha_0, Z, num0_1, num0_0, Y, query_ptr, ...] + swap movdn.9 movdn.8 + #=> [q_z_0, q_z_1, q_x_at_alpha_0, q_x_at_alpha_1, Z, num_gz_0, num_gz_1, Y, query_ptr, ...] ext2add - #=> [num1_1, num1_0, Z, num0_1, num0_0, Y, query_ptr, ...] + #=> [num_z_0, num_z_1, Z, num_gz_0, num_gz_1, Y, query_ptr, ...] movup.3 movup.3 ext2div - #=> [res1_1, res1_0, z0_1, z0_0, num0_1, num0_0, Y, query_ptr, ...] + #=> [res_z_0, res_z_1, gz0_0, gz0_1, num_gz_0, num_gz_1, Y, query_ptr, ...] movdn.5 movdn.5 - #=> [z0_1, z0_0, num0_1, num0_0, res1_1, res1_0, Y, query_ptr, ...] + #=> [gz0_0, gz0_1, num_gz_0, num_gz_1, res_z_0, res_z_1, Y, query_ptr, ...] ext2div - #=> [res0_1, res0_0, res1_1, res1_0, Y, query_ptr, ...] + #=> [res_gz_0, res_gz_1, res_z_0, res_z_1, Y, query_ptr, ...] + + # Multiply res_gz by challenge_points (beta) for point batching. + # DEEP formula: Q(X) = res_z + beta * res_gz + # beta is stored at deep_rand_coef_ptr (positions 0,1). + exec.constants::deep_rand_coef_ptr mem_load + exec.constants::deep_rand_coef_ptr add.1 mem_load + swap + #=> [beta0, beta1, res_gz_0, res_gz_1, res_z_0, res_z_1, Y, query_ptr, ...] + ext2mul + #=> [beta_res_gz_0, beta_res_gz_1, res_z_0, res_z_1, Y, query_ptr, ...] ext2add - # => [eval1, eval0, Y, query_ptr, ...] + # => [eval0, eval1, Y, query_ptr, ...] end #! Prepares the stack for the computation of the DEEP composition polynomial FRI queries. @@ -103,9 +116,9 @@ pub proc prepare_stack_deep_queries_computation exec.constants::get_fri_queries_address # => [query_ptr, ...] - padw exec.constants::ood_fixed_term_horner_evaluations_ptr mem_loadw_be - # => [q_gz_1, q_gz_0, q_z_1, q_z_0, query_ptr, ...] - # => [W, query_ptr, ...] where W is [q_gz_1, q_gz_0, q_z_1, q_z_0] + padw exec.constants::ood_fixed_term_horner_evaluations_ptr mem_loadw_le + # => [q_z_0, q_z_1, q_gz_0, q_gz_1, query_ptr, ...] + # => [W, query_ptr, ...] where W is [q_z_0, q_z_1, q_gz_0, q_gz_1] # Get pointer to help test for the last query to be processed exec.constants::fri_com_ptr @@ -118,25 +131,26 @@ pub proc prepare_stack_deep_queries_computation push.0.0 exec.constants::deep_rand_alpha_nd_ptr exec.constants::current_trace_row_ptr - exec.constants::tmp2 mem_storew_be + exec.constants::tmp2 mem_storew_le # Compute the negations of z and gz where z is the OOD point # We do it here as this computation is common to all queries. - exec.constants::z_ptr mem_loadw_be - # => [zN_1, zN_0, z1, z0, query_ptr, query_end_ptr, W, query_ptr, ...] + exec.constants::z_ptr mem_loadw_le + # => [zN_0, zN_1, z0, z1, query_ptr, query_end_ptr, W, query_ptr, ...] drop drop neg swap neg - # => [-z0, -z1, query_ptr, query_end_ptr, W, query_ptr, ...] - dup.1 exec.constants::get_trace_domain_generator mul - # => [-gz1, -z0, -z1, query_ptr, query_end_ptr, W, query_ptr, ...] - swap - # => [-z0, -gz1, -z1, query_ptr, query_end_ptr, W, query_ptr, ...] - dup exec.constants::get_trace_domain_generator mul - # => [-gz0, -z0, -gz1, -z1, query_ptr, query_end_ptr, W, query_ptr, ...] swap - # => [-z0, -gz0, -gz1, -z1, query_ptr, query_end_ptr, W, query_ptr, ...] + # => [-z0, -z1, query_ptr, query_end_ptr, W, query_ptr, ...] + dup + exec.constants::get_trace_domain_generator mul + # => [-gz0, -z0, -z1, query_ptr, query_end_ptr, W, query_ptr, ...] + dup.2 + exec.constants::get_trace_domain_generator mul + # => [-gz1, -gz0, -z0, -z1, query_ptr, query_end_ptr, W, query_ptr, ...] + movdn.3 movdn.2 + # => [-z0, -z1, -gz0, -gz1, query_ptr, query_end_ptr, W, query_ptr, ...] # Save to temporary location `tmp1` for later use when computing the denominators - exec.constants::tmp1 mem_storew_be + exec.constants::tmp1 mem_storew_le # => [Y, query_ptr, query_end_ptr, W, query_ptr, ...] end @@ -162,15 +176,15 @@ pub proc compute_deep_query # # Cycles: 58 exec.compute_denominators - #=> [Z, X, x, index, query_ptr, query_end_ptr, W, query_ptr, ...] where Z := [-gz1, x - gz0, -z1, x - z0] + #=> [Z, X, x, index, query_ptr, query_end_ptr, W, query_ptr, ...] # 2) Compute final result # # Cycles: 62 exec.divide_and_add - #=> [eval1, eval0, x, index, query_ptr, query_end_ptr, W, query_ptr, ...] + #=> [eval0, eval1, x, index, query_ptr, query_end_ptr, W, query_ptr, ...] - # 3) Store [poe, index, eval_1, eval_0] where poe := g^index = x / offset and prepare stack + # 3) Store [poe, index, eval0, eval1] where poe := g^index = x / offset and prepare stack # for next iteration. ## a) Compute poe @@ -178,14 +192,14 @@ pub proc compute_deep_query ## Cycles: 4 movup.3 movup.3 exec.constants::get_domain_offset_inv mul - #=> [poe, index, eval1, eval0, query_ptr, query_end_ptr, W, query_ptr, ...] + #=> [poe, index, eval0, eval1, query_ptr, query_end_ptr, W, query_ptr, ...] - ## b) Store [eval0, eval1, index, poe] + ## b) Store [poe, index, eval0, eval1] ## ## Cycles: 5 dup.4 add.4 swap.5 - mem_storew_be - #=> [poe, index, eval1, eval0, query_ptr+1, query_end_ptr, W, query_ptr, ...] + mem_storew_le + #=> [poe, index, eval0, eval1, query_ptr+4, query_end_ptr, W, query_ptr, ...] ## c) Prepare stack for next iteration ## @@ -197,9 +211,11 @@ end #! Computes the DEEP composition polynomial FRI queries. #! -#! Input: [...] -#! Output: [...] -proc compute_deep_composition_polynomial_queries +#! Inputs: [...] +#! Outputs: [...] +#! +#! Invocation: exec +pub proc compute_deep_composition_polynomial_queries # Prepare the stack for the core procedure computing the queries exec.prepare_stack_deep_queries_computation # => [Y, query_ptr, query_end_ptr, W, query_ptr] diff --git a/crates/lib/core/asm/stark/mod.masm b/crates/lib/core/asm/stark/mod.masm index e0018c35a3..5affb40db9 100644 --- a/crates/lib/core/asm/stark/mod.masm +++ b/crates/lib/core/asm/stark/mod.masm @@ -5,20 +5,18 @@ use miden::core::stark::verifier #! The purpose of the following verifier is to serve as a generic core around which a specific #! verifier can be built. It expects the following parameters on the stack from the caller: #! -#! 1. `[D0, D1, D2, D3]` which are respectively the digests for dynamic execution of procedures -#! i. `compute_deep_composition_polynomial_queries` -#! ii. `execute_constraint_evaluation_check` -#! iii. `process_row_ood_evaluations` -#! iv. `process_public_inputs` -#! 2. `num_constraints` which is the number of constraints in the AIR -#! 3. `trace_info` which is a field element encoding the layout of the AIR -#! 4. `num_fixed_len_pi` is the number of fixed length public inputs of the AIR +#! 1. `[D0, D1, D2, D3, D4]` which are respectively the digests for dynamic execution of procedures +#! D0. `observe_aux_trace` +#! D1. `process_public_inputs` +#! D2. `process_row_ood_evaluations` +#! D3. `execute_constraint_evaluation_check` +#! D4. `compute_deep_composition_polynomial_queries` +#! 2. Per-proof parameter: `log(trace_length)` +#! 3. `[rd0, rd1, rd2, rd3]`: RELATION_DIGEST = hash(PROTOCOL_ID, CIRCUIT_COMMITMENT), +#! a compile-time constant that binds the Fiat-Shamir transcript to the AIR instance. #! -#! In addition to the above parameters, the verifier expects the following auxiliary proof parameters: -#! -#! 1. `log(trace_length)`, the logarithm base 2 of the trace length -#! 2. `num_queries`, the number of FRI queries -#! 3. `grinding`, the number of bits of grinding i.e., proof-of-work +#! Precondition: security parameters (num_queries, query_pow_bits, deep_pow_bits, +#! folding_pow_bits) must already be stored in memory before calling this procedure. #! #! The following simplifying assumptions are currently made and hardcoded: #! @@ -29,6 +27,6 @@ use miden::core::stark::verifier #! Similarly, elements of the auxiliary trace are quadratic extension field elements. The random #! values for computing random linear combinations are also in this extension field. #! -#! Inputs: [D3, D2, D1, D0, log(trace_length), num_queries, grinding, num_constraints, trace_info, num_fixed_len_pi] +#! Inputs: [D0, D1, D2, D3, D4, log(trace_length), rd0, rd1, rd2, rd3] #! Outputs: [] pub use verifier::verify diff --git a/crates/lib/core/asm/stark/ood_frames.masm b/crates/lib/core/asm/stark/ood_frames.masm index 81da520020..35b63dc300 100644 --- a/crates/lib/core/asm/stark/ood_frames.masm +++ b/crates/lib/core/asm/stark/ood_frames.masm @@ -5,11 +5,11 @@ use miden::core::stark::random_coin #! #! This also computes Q^z(alpha) and Q^gz(alpha) where: #! -#! Q^z(alpha) = (q_z_0, q_z_1) = \sum_{i=0}^{n+m+l} S_i * alpha^i +#! Q^z(alpha) = (q_z_0, q_z_1) = \sum_{i=0}^{n+m+l} S_i * alpha^{n+m+l-i} #! #! and #! -#! Q^gz(alpha) = (q_gz_0, q_gz_1) = \sum_{i=0}^{n+m+l} T_i * alpha^i +#! Q^gz(alpha) = (q_gz_0, q_gz_1) = \sum_{i=0}^{n+m+l} T_i * alpha^{n+m+l-i} #! #! where: #! @@ -36,12 +36,12 @@ pub proc load_and_horner_eval_ood_frames # `core::stark::random_coin::generate_deep_composition_random_coefficients` ## Load the random challenge non-deterministically - adv_push.2 - # => [alpha_1, alpha_0] + adv_push adv_push + # => [alpha_0, alpha_1] # Save the random challenge - dup.1 dup.1 - exec.constants::deep_rand_alpha_nd_ptr mem_storew_be + push.0.0 movup.3 movup.3 + exec.constants::deep_rand_alpha_nd_ptr mem_storew_le # => [Y] # --- Compute Q^z(alpha) -------------------------------------------------- @@ -58,53 +58,56 @@ pub proc load_and_horner_eval_ood_frames ## 2) Process the fully aligned OOD `current` evaluations at z of the execution trace ## and constraints polynomials evaluations. - ## Note that, by the assumption on the widths of committed traces, the capacity portion - ## of the sponge state is always initialized to `[0, 0, 0, 0]`. + ## We load the random coin state and overwrite the rate with OOD blocks; capacity carries over. - ### a) Set up the hasher state - padw padw - # => [ZERO, 0, 0, 0, 0, U, Y] - movupw.3 - # => [Y, ZERO, 0, 0, 0, 0, U] + ### a) Load the random coin state as the initial sponge state. + push.0 exec.constants::random_coin_output_len_ptr mem_store + push.0 exec.constants::random_coin_input_len_ptr mem_store + exec.random_coin::load_random_coin_state + # => [R0, R1, C, ood_frame_ptr, alpha_ptr, 0, 0] ### b) Process the `current` OOD evaluations exec.process_row_ood_evaluations - # => [Y, Y, C, ood_frame_ptr, alpha_ptr, acc1, acc0] + # => [Y, Y, C, ood_frame_ptr, alpha_ptr, acc0, acc1] ### c) Save -Q^z(alpha) swapw.3 - # => [ood_frame_ptr, alpha_ptr, acc1, acc0, Y, C, Y] + # => [ood_frame_ptr, alpha_ptr, acc0, acc1, Y, C, Y] movup.3 neg movup.3 neg push.0.0 - exec.constants::ood_fixed_term_horner_evaluations_ptr mem_storew_be - # => [0, 0, -acc1, -acc0, ood_frame_ptr, alpha_ptr, Y, C, Y] + movup.2 + movup.3 + swap.1 + exec.constants::ood_fixed_term_horner_evaluations_ptr mem_storew_le + dropw + push.0.0 + movdn.3 + movdn.3 + # => [ood_frame_ptr, alpha_ptr, 0, 0, Y, C, Y] # --- Compute Q^gz(alpha) ------------------------------------------------- - # Reset the Horner accumulator - movdn.5 movdn.5 drop drop - # => [ood_frame_ptr, alpha_ptr, 0, 0, Y, C, Y] - # Load the `next` trace polynomials OOD evaluations. swapw.3 # => [Y, Y, C, ood_frame_ptr, alpha_ptr, 0, 0] exec.process_row_ood_evaluations - # => [Y, D, C, ood_frame_ptr, alpha_ptr, acc1, acc0] + # => [R0, R1, C, ood_frame_ptr, alpha_ptr, acc0, acc1] - # Reseed with the digest of the OOD evaluations - swapw - exec.random_coin::reseed - # => [Y, C, ood_frame_ptr, alpha_ptr, acc1, acc0] + # Update the random coin state with the OOD stream digest. + exec.random_coin::store_random_coin_state + push.0 exec.constants::random_coin_input_len_ptr mem_store + push.8 exec.constants::random_coin_output_len_ptr mem_store + # => [ood_frame_ptr, alpha_ptr, acc0, acc1] - # Negate Q^z(alpha) and save it - dropw dropw drop drop - # => [acc1, acc0] - neg - exec.constants::ood_fixed_term_horner_evaluations_ptr add.3 mem_store - # => [acc0] + # Negate Q^gz(alpha) and save it + drop drop + # => [acc0, acc1] neg exec.constants::ood_fixed_term_horner_evaluations_ptr add.2 mem_store + # => [acc1] + neg + exec.constants::ood_fixed_term_horner_evaluations_ptr add.3 mem_store # => [] end @@ -115,8 +118,8 @@ end #! into the hasher state and simultaneously computing a random linear combination using Horner #! evaluation. #! -#! Inputs: [R2, R1, C, ptr, acc1, acc0] -#! Outputs: [R2, R1, C, ptr, acc1`, acc0`] +#! Inputs: [R0, R1, C, ptr, acc0, acc1] +#! Outputs: [R0, R1, C, ptr, acc0`, acc1`] proc process_row_ood_evaluations exec.constants::get_procedure_digest_process_row_ood_evaluations_ptr dynexec end diff --git a/crates/lib/core/asm/stark/public_inputs.masm b/crates/lib/core/asm/stark/public_inputs.masm index fb8c2468d8..c9b7ad1a13 100644 --- a/crates/lib/core/asm/stark/public_inputs.masm +++ b/crates/lib/core/asm/stark/public_inputs.masm @@ -2,87 +2,100 @@ use miden::core::stark::constants #! Processes the public inputs. #! +#! This is a generic dispatch procedure that calls the instance-specific implementation +#! via `dynexec`. The instance-specific implementation loads fixed-length and variable-length +#! public inputs from the advice stack, reduces the variable-length inputs using auxiliary +#! randomness, and stores everything into the ACE READ section. +#! #! This involves: #! #! 1. Loading from the advice stack the fixed-length public inputs and storing them in memory -#! starting from the address pointed to by `public_inputs_address_ptr`. +#! starting from the address pointed to by `public_inputs_address_ptr`. #! 2. Loading from the advice stack the variable-length public inputs, storing them temporarily -#! in memory, and then reducing them to an element in the challenge field using the auxiliary -#! randomness. This reduced value is then used to impose a boundary condition on the relevant -#! auxiliary column. -#! -#! Note that the fixed length public inputs are stored as extension field elements while -#! the variable length ones are stored as base field elements. -#! Note also that, while loading the above, we compute the hash of the public inputs. The hashing -#! starts with capacity registers of the hash function set to `C` that is the result of hashing -#! the proof context. +#! in memory, and then reducing them to an element in the challenge field using the auxiliary +#! randomness. This reduced value is then used to impose boundary conditions on the relevant +#! auxiliary columns. #! -#! The output D, that is the digest of the above hashing, is then used in order to reseed -#! the random coin. +#! Note that the fixed-length public inputs are stored as extension field elements while +#! the variable-length ones are stored as base field elements, because the ACE circuit operates +#! only on extension field elements and the latter inputs are not direct inputs to the circuit, +#! i.e., only their reduced values are. +#! Both fixed-length and variable-length public inputs are absorbed into the Fiat-Shamir +#! transcript via direct sponge absorption during loading. #! #! It is worth noting that: #! -#! 1. Only the fixed-length public inputs are stored for the lifetime of the verification procedure. -#! The variable-length public inputs are stored temporarily, as this simplifies the task of -#! reducing them using the auxiliary randomness. On the other hand, the resulting values from -#! the aforementioned reductions are stored right after the fixed-length public inputs. These -#! are stored in a word-aligned manner and padded with zeros if needed. -#! 2. The public inputs address is computed in such a way so as we end up with the following -#! memory layout: +#! 1. Only the fixed-length public inputs are stored for the lifetime of the verification +#! procedure. The variable-length public inputs are stored temporarily, as this simplifies +#! the task of reducing them using the auxiliary randomness. The resulting values from the +#! reductions are stored right after the fixed-length public inputs, in a word-aligned +#! manner and padded with zeros if needed. +#! 2. The public inputs address is computed so that we end up with the following memory layout: #! -#! [..., a_0...a_{m-1}, b_0...b_{n-1}, alpha0, alpha1, beta0, beta1, OOD-evaluations-start, ...] +#! [..., a_0..a_{m-1}, b_0..b_{n-1}, beta0, beta1, alpha0, alpha1, OOD-start, ...] #! #! where: #! -#! 1. [a_0...a_{m-1}] are the fixed-length public inputs stored as extension field elements. This -#! section is double-word-aligned. -#! 2. [b_0...b_{n-1}] are the results of reducing the variable length public inputs using +#! a) [a_0..a_{m-1}] are the fixed-length public inputs stored as extension field elements. +#! This section is double-word-aligned. +#! b) [b_0..b_{n-1}] are the results of reducing the variable-length public inputs using #! auxiliary randomness. This section is word-aligned. -#! 3. [alpha0, alpha1, beta0, beta1] is the auxiliary randomness. -#! 4. `OOD-evaluations-start` is the first field element of the section containing the OOD -#! evaluations. -#! 3. Note that for each bus message in a group in the variable length public inputs, each -#! message is expected to be padded to the next multiple of 8 and provided in reverse order. -#! This has the benefit of making the reduction using the auxiliary randomness more efficient -#! using `horner_eval_base`. -#! -#! -#! Input: [C, ...] -#! Output: [...] -proc process_public_inputs +#! c) [beta0, beta1, alpha0, alpha1] is the auxiliary randomness. +#! d) OOD-start is the first field element of the section containing the OOD evaluations. +#! 3. For each bus message in a group in the variable-length public inputs, each message is +#! expected to be padded to the next multiple of 8 and provided in reverse order. This has +#! the benefit of making the reduction using the auxiliary randomness more efficient using +#! `horner_eval_base`. +#! +#! Inputs: [...] +#! Outputs: [...] +#! +#! Invocation: exec +pub proc process_public_inputs exec.constants::get_procedure_digest_process_public_inputs_ptr dynexec end -#! Computes the address where the public inputs are to be stored and returns it. +#! Computes the addresses where the public inputs are to be stored. +#! +#! In order to call `eval_circuit`, we need to lay out the inputs to the constraint evaluation +#! circuit in a contiguous region of memory (called READ section in the ACE chiplet documentation) +#! right before the region storing the circuit description (called EVAL section). #! -#! In order to be able to call `eval_circuit`, we need to layout the inputs to -#! the constraint evaluation circuit in a contiguous region of memory (called `READ` section -#! in the ACE chiplet documentation) right before the region of memory storing the circuit -#! description (called `EVAL` section in the ACE chiplet documentation). #! As the number of public inputs is a per-instance parameter, while the sizes of the OOD -#! evaluation frames and the number of auxiliary random values are fixed, we can lay out -#! the public inputs right before the auxiliary random values and OOD evaluations. -#! Hence the address where public inputs are stored is computed using a negative offset -#! from the address where the OOD are stored. -#! We compute two pointers, one to the public inputs and the other is for the portion -#! within the public inputs region storing the variable length public inputs. This will be -#! the region storing, temporarily, the variable length public inputs that are to be reduced -#! by the auxiliary randomness and, permanently, the results of the aforementioned reductions. -#! -#! Input: [num_var_len_pi_groups, num_fixed_len_pi, ...] -#! Output: [...] -proc compute_and_store_public_inputs_address +#! evaluation frames and the number of auxiliary random values are fixed, we lay out the public +#! inputs right before the auxiliary random values and OOD evaluations. +#! Hence the address where public inputs are stored is computed using a negative offset from the +#! address where the OOD evaluations are stored. +#! +#! We compute two pointers: +#! var_len_ptr = OOD_EVALUATIONS_PTR - 4 - num_var_len_pi_groups * 4 +#! pi_ptr = var_len_ptr - num_fixed_len_pi * 2 +#! +#! The `* 4` for VLPI groups provides word-alignment (each group uses 4 base felts = 2 EF +#! slots, even though the reduced value is only 1 EF). The `* 2` for FLPI converts the base +#! felt count to EF slots (each base felt is stored as [val, 0]). +#! +#! The `-4` accounts for the auxiliary randomness word [beta0, beta1, alpha0, alpha1] at +#! AUX_RAND_ELEM_PTR (4 base felts between var_len_ptr and OOD_EVALUATIONS_PTR). +#! +#! The var_len_ptr is the region that will temporarily store the variable-length public inputs +#! and permanently store the results of reducing them by the auxiliary randomness. +#! +#! Inputs: [num_var_len_pi_groups, num_fixed_len_pi, ...] +#! Outputs: [...] +#! +#! Invocation: exec +pub proc compute_and_store_public_inputs_address # 1) Get a pointer to where OOD evaluations are stored exec.constants::ood_evaluations_ptr # => [ood_evals_ptr, num_var_len_pi_groups, num_fixed_len_pi, ...] # 2) Compute the pointer to the reductions of the variable length public inputs # - # We need to account for the number of variable-length - # public inputs groups. For each group we allocate 2 slots and we pad with zeros so that - # things are word aligned. As of now, we only have one group. - # We also need to account for the auxiliary randomness i.e., 4 base field elements. - sub.4 # 2 auxiliary random values + # We need to account for the number of variable-length public inputs groups. + # For each group we allocate a word (4 base elements = 2 EF slots) for word-alignment. + # We also need to account for the auxiliary randomness (4 base elements for alpha/beta). + sub.4 swap mul.4 sub # subtract number of variable length public input groups, with padding for word-alignment # => [res_var_len_pi_reductions_ptr, num_fixed_len_pi, ...] @@ -101,66 +114,78 @@ proc compute_and_store_public_inputs_address exec.constants::variable_length_public_inputs_address_ptr mem_store end -#! Loads 8 base field elements from the advice stack and saves them as extension field elements. +#! Loads 8 base field elements from the advice stack, stores them as extension field elements +#! in memory, and returns the original base element words in the rate positions for absorption +#! by the caller via `poseidon2::permute`. +#! +#! The procedure does NOT absorb the elements into the transcript -- the caller is responsible +#! for calling `poseidon2::permute` after this procedure to complete the absorption. #! +#! Inputs: [Y, Y, C, ptr, ...] +#! Outputs: [A0, A1, C, ptr + 16, ..] #! -#! Input: [Y, Y, C, ptr, ...] -#! Output: [A1, A0, C, ptr + 16, ..] -proc load_base_store_extension_double_word +#! where A0 and A1 are the original base element words (from advice), positioned in the rate +#! slots so that a subsequent `poseidon2::permute` absorbs them into the sponge state. +#! +#! Invocation: exec +pub proc load_base_store_extension_double_word # 1) Load the first 4 base elements from the advice stack and save them temporarily adv_loadw - exec.constants::tmp1 mem_storew_be + exec.constants::tmp1 mem_storew_le # 2) Represent the first 4 base field elements as elements in the quadratic extension field swapw exec.constants::zeroize_stack_word # => [0, 0, 0, 0, a3, a2, a1, a0, C, ptr, ...] - movdn.6 - # => [0, 0, 0, a3, a2, a1, 0, a0, C, ptr, ...] - movdn.4 - # => [0, 0, a3, a2, 0, a1, 0, a0, C, ptr, ...] - movdn.2 - # => [0, a3, 0, a2, 0, a1, 0, a0, C, ptr, ...] + movdn.7 + # => [0, 0, 0, a3, a2, a1, a0, 0, C, ptr, ...] + movdn.5 + # => [0, 0, a3, a2, a1, 0, a0, 0, C, ptr, ...] + movdn.3 + # => [0, a3, a2, 0, a1, 0, a0, 0, C, ptr, ...] + swap + # => [a3, 0, a2, 0, a1, 0, a0, 0, C, ptr, ...] # 3) Save the first 2 extension field elements - swapw dup.12 - mem_storew_be + mem_storew_le # 4) Load the second 4 base elements from the advice stack and save them temporarily adv_loadw - exec.constants::tmp2 mem_storew_be + exec.constants::tmp2 mem_storew_le swapw - # => [0, a3, 0, a2, a7, a6, a5, a4, C, ptr, ...] + # => [a3, 0, a2, 0, a7, a6, a5, a4, C, ptr, ...] # 5) Save the second 2 extension field elements dup.12 add.4 - mem_storew_be + mem_storew_le # 6) Represent the second 4 base field elements as elements in the quadratic extension field exec.constants::zeroize_stack_word # => [0, 0, 0, 0, a7, a6, a5, a4, C, ptr, ...] - movdn.6 - movdn.4 - movdn.2 - # => [0, a7, 0, a6, 0, a5, 0, a4, C, ptr, ...] + movdn.7 + movdn.5 + movdn.3 + swap + # => [a7, 0, a6, 0, a5, 0, a4, 0, C, ptr, ...] # 7) Save the third 2 extension field elements - # We also load the first 4 base elements as a word for use by `poseidon2::permute` - swapw + # We also load the second 4 base elements into the R2 rate position. dup.12 add.8 - mem_storew_be - exec.constants::tmp1 mem_loadw_be + mem_storew_le + exec.constants::tmp2 mem_loadw_le swapw # 8) Save the fourth 2 extension field elements - # We also load the second 4 base elements as a word for use by `poseidon2::permute` and update the pointer + # We also load the first 4 base elements into the R1 rate position and update the pointer. + # This ordering (first word on top = R1, second word below = R2) matches the Rust + # challenger's absorption order: first 4 elements -> rate[0..3], next 4 -> rate[4..7]. dup.12 add.16 swap.13 add.12 - mem_storew_be - exec.constants::tmp2 mem_loadw_be - # => [a7, a6, a5, a4, a3, a2, a1, a0, C, ptr, ...] + mem_storew_le + exec.constants::tmp1 mem_loadw_le + # => [a3, a2, a1, a0, a7, a6, a5, a4, C, ptr + 16, ...] end diff --git a/crates/lib/core/asm/stark/random_coin.masm b/crates/lib/core/asm/stark/random_coin.masm index 0b8d736c02..f510d0e8bd 100644 --- a/crates/lib/core/asm/stark/random_coin.masm +++ b/crates/lib/core/asm/stark/random_coin.masm @@ -1,48 +1,25 @@ -#! Disclaimer: most of the procedures in this file assume that the input pointers are word-aligned. +#! Random coin for the STARK verifier, built on a Poseidon2 sponge. +#! +#! The sponge state is stored in memory as three words: rate R1 (r1_ptr), rate R2 (r2_ptr), +#! and capacity C (c_ptr). R1 and R2 are contiguous (r2_ptr = r1_ptr + 4), so rate elements +#! 0..7 can be addressed as r1_ptr + index. +#! +#! Sampling uses an output_len counter that tracks how many rate elements remain. Each +#! permutation sets output_len=8; each sample_felt decrements it by 1 and reads +#! rate[output_len - 1]. Absorption (reseed_direct, reseed_with_felt, etc.) writes directly +#! to rate memory and permutes, bypassing any input buffer. use miden::core::crypto::hashes::poseidon2 use miden::core::stark::constants use miden::core::stark::utils - -#! Helper procedure to compute addition of two words component-wise. -#! Input: [b3, b2, b1, b0, a3, a2, a1, a0] -#! Output: [c3, c2, c1, c0] -#! -#! Cycles: 16 -proc add_two_words - movup.3 - movup.7 - add - #=> [c0, b3, b2, b1, a3, a2, a1] - - movup.3 - movup.6 - add - #=> [c1, c0, b3, b2, a3, a2] - - movup.3 - movup.5 - add - #=> [c2, c1, c0, b3, a3] - - movup.3 - movup.4 - add - #=> [c3, c2, c1, c0] -end - -#! Return the first half of the rate portion of the random coin state -#! -#! The random coin uses Poseidon2 to generate data. The Poseidon2 state is composed of 3 -#! words, 2 words for the rate, and 1 word for the capacity. This procedure -#! returns the first word of the Poseidon2 state. +#! Return the first half of the rate portion of the random coin state. #! #! Input: [...] #! Output: [R1, ...] #! Cycles: 6 pub proc get_rate_1 - padw exec.constants::r1_ptr mem_loadw_be + padw exec.constants::r1_ptr mem_loadw_le end #! Store the first half of the rate portion of the random coin state. @@ -51,20 +28,16 @@ end #! Output: [...] #! Cycles: 6 pub proc set_rate_1 - exec.constants::r1_ptr mem_storew_be dropw + exec.constants::r1_ptr mem_storew_le dropw end -#! Return the second half of the rate portion of the random coin state -#! -#! The random coin uses Poseidon2 to generate data. The Poseidon2 state is composed of 3 -#! words, 2 words for the rate, and 1 word for the capacity. This procedure -#! returns the first word of the Poseidon2 state. +#! Return the second half of the rate portion of the random coin state. #! #! Input: [...] #! Output: [R2, ...] #! Cycles: 6 pub proc get_rate_2 - padw exec.constants::r2_ptr mem_loadw_be + padw exec.constants::r2_ptr mem_loadw_le end #! Store the second half of the rate portion of the random coin state. @@ -73,20 +46,16 @@ end #! Output: [...] #! Cycles: 6 pub proc set_rate_2 - exec.constants::r2_ptr mem_storew_be dropw + exec.constants::r2_ptr mem_storew_le dropw end -#! Return the capacity portion of the random coin state -#! -#! The random coin uses Poseidon2 to generate data. The Poseidon2 state is composed of 3 -#! words, 2 words for the rate, and 1 word for the capacity. This procedure -#! returns the first word of the Poseidon2 state. +#! Return the capacity portion of the random coin state. #! #! Input: [...] #! Output: [C, ...] #! Cycles: 6 pub proc get_capacity - padw exec.constants::c_ptr mem_loadw_be + padw exec.constants::c_ptr mem_loadw_le end #! Set the capacity portion of the random coin state. @@ -95,205 +64,379 @@ end #! Output: [...] #! Cycles: 6 pub proc set_capacity - exec.constants::c_ptr mem_storew_be dropw + exec.constants::c_ptr mem_storew_le dropw end #! Load the random coin state on the stack. #! #! Input: [...] -#! Output: [R2, R1, C, ...] +#! Output: [R0, R1, C, ...] #! Cycles: 18 pub proc load_random_coin_state exec.get_capacity - exec.get_rate_1 exec.get_rate_2 + exec.get_rate_1 end #! Store the random coin state to memory. #! -#! Input: [R2, R1, C, ...] +#! Input: [R0, R1, C, ...] #! Output: [...] #! Cycles: 18 pub proc store_random_coin_state - exec.set_rate_2 exec.set_rate_1 + exec.set_rate_2 exec.set_capacity end -#! Initializes the seed for randomness generation by computing the hash of the proof context using -#! the trace length, number of queries, the number of bits of grinding. -#! Currently, this part, as well as the rest of the STARK verifier assumes a blowup factor -#! equal to 8. -#! The ouput of this procedure is the capacity portion of the state after applying `poseidon2::permute`. +#! Sample a single base field element from the transcript. #! -#! Input: [log(trace_length), num_queries, grinding, num_constraints, trace_info, num_fixed_len_pi, ...] -#! Output: [C, ...] -#! Cycles: 210 +#! SAFETY: Requires output_len > 0. All call sites in the recursive verifier guarantee this +#! invariant because every sponge permutation sets output_len=8 and at most 8 elements are +#! consumed before the next permutation. An assertion guards against caller bugs. +#! +#! Input: [...] +#! Output: [x, ...] +pub proc sample_felt + exec.constants::random_coin_output_len_ptr mem_load + dup push.0 neq assert.err="sample_felt: output buffer is empty" + sub.1 + dup exec.constants::random_coin_output_len_ptr mem_store + + exec.constants::r1_ptr add mem_load +end + +#! Sample a quadratic extension field element from the transcript. +#! +#! Input: [...] +#! Output: [x0, x1, ...] +pub proc sample_ext + exec.sample_felt + exec.sample_felt + swap +end + +#! Sample a number of bits from the transcript. +#! +#! Input: [bits, ...] +#! Output: [value, ...] +pub proc sample_bits + dup + pow2 + u32assert u32overflowing_sub.1 assertz + # => [mask, bits, ...] + + exec.sample_felt + u32split + swap + drop + # => [lo, mask, bits, ...] + u32and + swap + drop +end + +#! Initializes the random coin state with domain-separated Fiat-Shamir (DSFS) seeding, +#! then derives trace domain parameters. +#! +#! Implements the transcript initialization: +#! +#! Use the caller-supplied RELATION_DIGEST as initial sponge capacity, +#! absorb PCS parameters into the rate, and permute. +#! Rate layout: R1 = [nq, query_pow_bits, deep_pow_bits, folding_pow_bits] +#! R2 = [log_blowup, log_final_degree, fold_arity, 0] +#! +#! RELATION_DIGEST = hash(PROTOCOL_ID, CIRCUIT_COMMITMENT) is a compile-time constant +#! computed once per AIR and pushed by the caller (the specific verifier). +#! +#! Currently assumes a blowup factor equal to 8. +#! +#! Precondition: num_queries, query_pow_bits, deep_pow_bits, and folding_pow_bits must +#! already be stored in memory before calling this procedure. +#! +#! Input: [log(trace_length), rd0, rd1, rd2, rd3, ...] +#! Output: [...] pub proc init_seed - # Save the parameters in memory for later use + # Save log(trace_length) in memory for later use. dup exec.constants::set_trace_length_log - dup.1 exec.constants::set_number_queries - dup.2 exec.constants::set_grinding_factor - # Pre-load constants used by poseidon2::permute into memory and initialize the state of the random coin to zeros. - # Since memory beyond 3 * 2^30 does not have any special meaning, we can use the memory region - # starting from address 2^32 - 1 in decreasing order to hold constants that are used throughout - # the `verify` procedure. + # Initialize the zero word and buffers to zero. padw - exec.constants::zero_word_ptr mem_storew_be - exec.constants::c_ptr mem_storew_be - exec.constants::r1_ptr mem_storew_be - exec.constants::r2_ptr mem_storew_be + exec.constants::zero_word_ptr mem_storew_le dropw - #=> [log(trace_length), num_queries, grinding, num_constraints, trace_info, num_fixed_len_pi, ...] + push.0 exec.constants::random_coin_input_len_ptr mem_store + push.0 exec.constants::random_coin_output_len_ptr mem_store + #=> [log(tl), rd0, rd1, rd2, rd3, ...] + + # ---- RELATION_DIGEST + PCS_PARAMS ---- + + # Build the sponge state [R1, R2, C] for hperm: + # R1 = [nq, query_pow_bits, deep_pow_bits, folding_pow_bits] + # R2 = [log_blowup, log_final_degree, fold_arity, 0] + # C = [rd0, rd1, rd2, rd3] (RELATION_DIGEST) + # + # Drop log(tl) from the stack (saved in memory, not part of Phase 1 rate). + + drop + #=> [rd0, rd1, rd2, rd3, ...] + + # Build R1 from security parameters stored in memory. + exec.constants::get_folding_pow_bits + exec.constants::get_deep_pow_bits + exec.constants::get_query_pow_bits + exec.constants::get_number_queries + #=> [nq, query_pow, deep_pow, folding_pow, rd0, rd1, rd2, rd3, ...] + # ^-- R1 ^-- C (digest) + + # Build R2 = [log_blowup, log_final_degree, fold_arity, 0] + push.0 + exec.constants::get_fri_fold_arity + exec.constants::get_log_final_degree + exec.constants::get_blowup_factor_log + #=> [log_blowup, log_final_deg, fold_arity, 0, nq, query_pow, deep_pow, folding_pow, rd0, rd1, rd2, rd3, ...] + # ^-- R2 ^-- R1 ^-- C - # Create the initial seed for randomness generation from proof context + swapw + #=> [nq, query_pow, deep_pow, folding_pow, log_blowup, log_final_deg, fold_arity, 0, rd0, rd1, rd2, rd3, ...] + # ^-- R1 ^-- R2 ^-- C - ## Compute trace_length + # Permute and store the transcript state after absorbing protocol parameters. + exec.poseidon2::permute + #=> [R1', R2', C', ...] + + exec.store_random_coin_state + #=> [...] + + push.0 exec.constants::random_coin_input_len_ptr mem_store + push.8 exec.constants::random_coin_output_len_ptr mem_store + #=> [...] + + # ---- Derive trace domain parameters ---- + # + # Reload log(trace_length) from memory (it was saved earlier) and derive + # trace_length, LDE domain size, LDE generator, and trace generator. + + exec.constants::get_trace_length_log + #=> [log(trace_length), ...] + + ## Compute trace_length = 2^log(trace_length) dup pow2 - dup - u32test - assert.err="range check failed: trace length" - #=> [trace_length, log(trace_length), num_queries, grinding, num_constraints, trace_info, num_fixed_len_pi, ...] + u32test assert.err="trace length overflows u32" + #=> [trace_length, log(trace_length), ...] - ## Save the trace length and its log to memory - dup.0 exec.constants::set_trace_length - #=> [trace_length, log(trace_length), num_queries, grinding, num_constraints, trace_info, num_fixed_len_pi, ...] + ## Save the trace length to memory + dup exec.constants::set_trace_length + #=> [trace_length, log(trace_length), ...] ## Compute log size of LDE domain swap exec.constants::get_blowup_factor_log add - #=> [log(lde_size), trace_length, num_queries, grinding, num_constraints, trace_info, num_fixed_len_pi, ...] + #=> [log(lde_size), trace_length, ...] ## Compute size of LDE domain dup pow2 - #=> [lde_size, log(lde_size), trace_length, num_queries, grinding, num_constraints, trace_info, num_fixed_len_pi, ...] + #=> [lde_size, log(lde_size), trace_length, ...] # Compute lde_domain generator dup.1 exec.utils::compute_lde_generator movdn.2 - #=> [lde_size, log(lde_size), lde_g, trace_length, num_queries, grinding, num_constraints, trace_info, num_fixed_len_pi, ...] + #=> [lde_size, log(lde_size), lde_g, trace_length, ...] push.0 movdn.3 - #=> [lde_size, log(lde_size), lde_g, 0, trace_length, num_queries, grinding, num_constraints, trace_info, num_fixed_len_pi, ...] + #=> [lde_size, log(lde_size), lde_g, 0, trace_length, ...] # Save `[0, lde_g, log(lde_size), lde_size]` exec.constants::set_lde_domain_info_word - #=> [lde_size, log(lde_size), lde_g, 0, trace_length, num_queries, grinding, num_constraints, trace_info, num_fixed_len_pi, ...] + #=> [lde_size, log(lde_size), lde_g, 0, trace_length, ...] # clean stack drop drop - #=> [lde_g, 0, trace_length, num_queries, grinding, num_constraints, trace_info, num_fixed_len_pi, ...] + #=> [lde_g, 0, trace_length, ...] # Compute trace generator `trace_g` = `lde_g^blowup_factor` repeat.3 dup mul end - #=> [trace_g, 0, trace_length, num_queries, grinding, num_constraints, trace_info, num_fixed_len_pi, ...] + #=> [trace_g, 0, trace_length, ...] # Save `trace_g` to memory exec.constants::set_trace_domain_generator - #=> [0, trace_length, num_queries, grinding, num_constraints, trace_info, num_fixed_len_pi, ...] + #=> [0, trace_length, ...] - # clean stack - drop - #=> [trace_length, num_queries, grinding, num_constraints, trace_info, num_fixed_len_pi, ...] - - # Construct the proof context - exec.build_proof_context - # => [num_queries, grinding, proof_options, num_constraints, modulus1, modulus0, trace_length, trace_info, num_fixed_len_pi, ...] - - # We get the number of the variable length public inputs section non-deterministically so that - # we can initialize the capacity portion of the sponge state. The total number of public inputs - # is easily derived using an addition. - movup.8 - # => [num_fixed_len_pi, num_queries, grinding, proof_options, num_constraints, modulus1, modulus0, trace_length, trace_info, ...] - adv_push.1 add - dup exec.constants::num_public_inputs_ptr mem_store - u32divmod.8 - # => [rem, quo, num_queries, grinding, proof_options, num_constraints, modulus1, modulus0, trace_length, trace_info, ...] - - # Hash proof context - swap drop - push.0.0.0 - movdnw.2 - # => [B, A, 0, 0, 0, c, ...] + # Clean up the stack. + drop drop +end + +#! Observe the single AIR instance shape and discard the instance challenge. +#! +#! miden-lifted-stark 0.24 observes each log(trace_length) after public inputs and then samples +#! one extension-field instance challenge before absorbing the main trace commitment. The VM +#! recursive verifier only supports one AIR instance, so this helper observes the stored +#! log(trace_length), performs the partial-rate duplexing, and marks two base-field outputs as +#! consumed without materializing the unused extension element. +#! +#! SAFETY: +#! 1. input_len=0 (asserted). +#! 2. The current random coin state has just absorbed the public inputs. +#! 3. On exit: input_len=0, output_len=6. +#! +#! Input: [...] +#! Output: [...] +pub proc observe_trace_height_and_discard_instance_challenge + exec.constants::random_coin_input_len_ptr mem_load + # => [input_len, ...] + assertz.err="observe_trace_height_and_discard_instance_challenge: input buffer must be empty" + # => [...] + + # observing clears the output buffer. + push.0 exec.constants::random_coin_output_len_ptr mem_store + # => [...] + + # observe log(trace_length) into rate[0], leaving rate[1..7] and capacity unchanged. + exec.constants::get_trace_length_log + # => [log(trace_length), ...] + exec.constants::r1_ptr mem_store + # => [...] + exec.load_random_coin_state + # => [R1, R2, C, ...] exec.poseidon2::permute - dropw - dropw - # => [C, ...] + # => [R1', R2', C', ...] + exec.store_random_coin_state + # => [...] + + push.0 exec.constants::random_coin_input_len_ptr mem_store + # => [...] + push.6 exec.constants::random_coin_output_len_ptr mem_store + # => [...] end -#! Builds the proof context. +#! Reseed with a commitment word and absorb an additional single felt, then permute. +#! +#! Writes the commitment word to rate[0..3] and the felt to rate[4], leaving rate[5..7] +#! unchanged from the previous permutation, then permutes. Used in the FRI layer loop +#! where each round absorbs a layer commitment plus a PoW nonce felt. #! -#! Input: [trace_length, num_queries, grinding, num_constraints, trace_info, ...] -#! Output: [num_queries, grinding, proof_options, num_constraints, modulus1, modulus0, trace_length, trace_info, ...] -proc build_proof_context - ## trace layout info, which is the concatenation as u8-s of: - ## 1. main segment width - ## 2. num auxiliary segments, which always 1 - ## 3. auxiliary segment width - ## 4. number of auxiliary random values - ## 5. trace length (this is already on the stack) +#! SAFETY: +#! 1. input_len=0 (asserted). +#! 2. On exit: input_len=0, output_len=8 (fresh permutation output). +#! +#! Input: [felt, w0, w1, w2, w3, ...] +#! Output: [...] +pub proc reseed_with_felt + # Assert input buffer is empty. + exec.constants::random_coin_input_len_ptr mem_load + assertz.err="reseed_with_felt: input buffer must be empty" + + # Write the felt to rate[4] (= r2_ptr position 0), since we can only modify one + # element of R2 and need the rest from memory. + exec.constants::r2_ptr mem_store + # => [w0, w1, w2, w3, ...] + + # Build sponge state [R1, R2, C] on the stack directly. + # R1 = commitment word (already on the stack). + # R2 and C are loaded from memory. + exec.get_capacity + exec.get_rate_2 + # => [R2, C, R1, ...] + movupw.2 + # => [R1, R2, C, ...] - movup.4 - swap - ## field modulus bytes (2 field elements) - push.0x01 # lower half of the modulus - push.0xffffffff # upper half of the modulus - ## field extension and FRI parameters - ## field extension degree || FRI folding factor || FRI remainder polynomial max degree || blowup factor - push.0x02047f08 - # => [proof_options, modulus1, modulus0, trace_length, trace_info, num_queries, grinding, num_constraints, ...] - movup.6 - movup.6 - # => [num_queries, grinding, proof_options, modulus1, modulus0, trace_length, trace_info, num_constraints, ...] - - movup.7 - movdn.3 - # => [num_queries, grinding, proof_options, num_constraints, modulus1, modulus0, trace_length, trace_info, ...] + exec.poseidon2::permute + exec.store_random_coin_state + + # Mark output buffer as full. + push.8 exec.constants::random_coin_output_len_ptr mem_store end -#! Reseed the random coin with `DATA` +#! Reseed by writing a word directly to rate[0..3] and permuting. #! -#! Input: [DATA, ...] -#! Ouput: [...] -#! Cycles: 54 -pub proc reseed - # Load previous state and update it - # -------------------------------------------------------------------------------------------- - exec.get_rate_1 - # => [R1, DATA, ...] (6 cycles) - - exec.add_two_words - # => [R1, ...] (16 cycles) +#! Overwrites rate[0..3] with the given word, leaves rate[4..7] unchanged from the +#! previous permutation, then permutes. This is the standard overwrite-and-permute +#! absorption pattern for a single word. +#! +#! SAFETY: +#! 1. input_len=0 (asserted). +#! 2. The word to absorb is on top of the stack. +#! 3. On exit: input_len=0, output_len=8 (fresh permutation output). +#! +#! Input: [w0, w1, w2, w3, ...] +#! Output: [...] +pub proc reseed_direct + # Assert input buffer is empty. + exec.constants::random_coin_input_len_ptr mem_load + assertz.err="reseed_direct: input buffer must be empty" - exec.get_capacity - swapw - exec.get_rate_2 - # => [R2, R1, C, ...] (13 cycles) + # Write the word to rate[0..3] and consume it from the stack. + exec.set_rate_1 + # Permute (rate[4..7] and capacity from memory are unchanged). + exec.load_random_coin_state exec.poseidon2::permute - # => [R2', R1', C`, ...] (1 cycles) + exec.store_random_coin_state - # Save the new state to memory - # -------------------------------------------------------------------------------------------- - exec.constants::r2_ptr mem_storew_be - dropw - exec.constants::r1_ptr mem_storew_be - dropw - exec.constants::c_ptr mem_storew_be - dropw - # => [...] (18 cycles) + # Fresh output available. + push.8 exec.constants::random_coin_output_len_ptr mem_store end +#! Verify per-round FRI folding proof-of-work and sample one extension field element, +#! reading rate elements directly instead of going through `sample_felt`. +#! +#! Reads rate[7] (grinding), rate[6] and rate[5] (ext element) from r2_ptr memory, +#! matching what `sample_felt` would return at output_len=8,7,6. +#! +#! The folding PoW bit count is read from memory (set by load_security_params). +#! When folding_pow_bits=0 the check is trivially satisfied (mask=0). +#! +#! Equivalent to: `get_folding_pow_bits sample_bits assertz; sample_ext` +#! +#! SAFETY: +#! 1. MUST be called immediately after `reseed_with_felt` with no intervening +#! random coin operations (output_len=8, input_len=0 guaranteed). +#! 2. Sets output_len=5 on exit (3 elements consumed), input_len=0 unchanged. +#! 3. folding_pow_bits must already be stored in memory. +#! +#! Input: [...] +#! Output: [a0, a1, ...] +pub proc sample_folding_pow_and_ext + # Assert precondition: input buffer must be empty. + exec.constants::random_coin_input_len_ptr mem_load + assertz.err="sample_folding_pow_and_ext: input buffer must be empty" + + exec.constants::r2_ptr + # => [r2, ...] + + # Grinding check: read rate[7], extract low 32 bits, mask with 2^folding_pow_bits - 1. + dup add.3 mem_load + u32split swap drop + # => [lo, r2, ...] + + exec.constants::get_folding_pow_bits + pow2 + u32assert u32overflowing_sub.1 assertz + # => [mask, lo, r2, ...] + + u32and + assertz.err="per-round FRI folding grinding check failed" + # => [r2, ...] + + # Ext element: read rate[6] (first sampled) and rate[5] (second sampled) + # sample_ext does: sample_felt -> rate[6], sample_felt -> rate[5], swap -> [rate[6], rate[5]] + dup add.2 mem_load + swap add.1 mem_load + # => [rate[5], rate[6], ...] -- but sample_ext swaps, so final is [rate[6], rate[5]] + swap + # => [rate[6], rate[5], ...] = [a0, a1, ...] + + # Update output_len to 5 (consumed rate[7], rate[6], rate[5]) + push.5 exec.constants::random_coin_output_len_ptr mem_store +end # COEFFICIENT GENERATION # ============================================================================================= @@ -305,39 +448,53 @@ end #! has the form `h(m) = alpha + \sum_{i=0}^{|m| - 1} m_i * beta^i` for a message `m`. #! #! As these random challenges have already been used non-deterministically in prior computations, we -#! also check that the generated challenges matche the non-deterministically provided one. +#! also check that the generated challenges match the non-deterministically provided one. #! #! Input: [...] #! Output: [...] #! Cycles: 20 pub proc generate_aux_randomness - padw exec.constants::r1_ptr mem_loadw_be - exec.constants::aux_rand_elem_ptr mem_storew_be - #=> [beta1, beta0, alpha1, alpha0, ...] - padw exec.constants::aux_rand_nd_ptr mem_loadw_be - # => [alpha1, alpha0, beta1, beta0, beta1, beta0, alpha1, alpha0, ...] + exec.sample_ext + exec.sample_ext + # => [beta0, beta1, alpha0, alpha1, ...] - movup.6 assert_eq.err="comparison failed: aux randomness" - movup.5 assert_eq.err="comparison failed: aux randomness" - # => [beta1, beta0, beta1, beta0, ...] + exec.constants::aux_rand_elem_ptr mem_storew_le + # => [beta0, beta1, alpha0, alpha1, ...] - movup.2 assert_eq.err="comparison failed: aux randomness" - assert_eq.err="comparison failed: aux randomness" + # Pad with zeros, load with mem_loadw_le overwriting the padding so that we can compare + padw + # => [0, 0, 0, 0, beta0, beta1, alpha0, alpha1, ...] + exec.constants::aux_rand_nd_ptr mem_loadw_le + # => [nd_beta0, nd_beta1, nd_alpha0, nd_alpha1, beta0, beta1, alpha0, alpha1, ...] + + # Assert sampled values match the non-deterministically provided ones. + # Comparison order: beta0, beta1, alpha0, alpha1 (memory offset 0, 1, 2, 3). + movup.4 assert_eq.err="aux randomness mismatch at element 0 (beta0)" + movup.3 assert_eq.err="aux randomness mismatch at element 1 (beta1)" + movup.2 assert_eq.err="aux randomness mismatch at element 2 (alpha0)" + assert_eq.err="aux randomness mismatch at element 3 (alpha1)" #=> [...] end -#! Draw constraint composition random coefficient and save it at `compos_coef_ptr`. +#! Draw constraint composition random coefficient and save it at `compos_coef_ptr`. #! #! Input: [...] #! Output: [...] #! Cycles: 13 pub proc generate_constraint_composition_coefficients + # Sample alpha (constraint folding challenge). + exec.sample_ext + push.0.0 + movup.3 + movup.3 exec.constants::composition_coef_ptr - padw exec.constants::r1_ptr mem_loadw_be - # => [y, y, alpha1, alpha0, compos_coef_ptr, ...] where y is a "garbage" value - movup.4 mem_storew_be dropw - #=> [...] + mem_storew_le dropw + + # Sample beta (multi-AIR accumulation challenge) to keep transcript in sync. + # For a single AIR, beta is unused but must be sampled from the random coin. + exec.sample_ext + drop drop end #! Draw deep composition polynomial random coefficient and save it at `deep_rand_coef_ptr`. @@ -349,19 +506,28 @@ end #! Output: [...] #! Cycles: 22 pub proc generate_deep_composition_random_coefficients - padw exec.constants::r1_ptr mem_loadw_be - # => [y, y, alpha1, alpha0, ...] where y is a "garbage" value - push.0.0 - exec.constants::deep_rand_alpha_nd_ptr mem_loadw_be - drop drop - # => [alpha1_nd, alpha0_nd, alpha1, alpha0, ...] where y is a "garbage" value + # Sample challenge_columns (deep alpha) for batching columns. + exec.sample_ext + padw + exec.constants::deep_rand_alpha_nd_ptr mem_loadw_le + # => [alpha0_nd, alpha1_nd, 0, 0, alpha0, alpha1, ...] - dup.2 assert_eq - dup.2 assert_eq - push.0.0 + dup.4 assert_eq + dup.4 assert_eq exec.constants::deep_rand_coef_ptr - mem_storew_be + mem_storew_le dropw + + # Sample challenge_points (deep beta) for batching evaluation points. + # p3-miden's DEEP formula weights the gz term by beta: + # Q(X) = [f(z)-f(X)]/(z-X) + beta * [f(gz)-f(X)]/(gz-X) + exec.sample_ext + # => [beta0, beta1, ...] + + # Store [beta0, beta1, alpha0, alpha1] at deep_rand_coef_ptr. + # (alpha was already stored at positions 2,3 by the mem_storew_le above) + exec.constants::deep_rand_coef_ptr mem_store + exec.constants::deep_rand_coef_ptr add.1 mem_store #=> [...] end @@ -370,7 +536,7 @@ end # ============================================================================================= #! Generate the OOD challenge point `z = (z0, z1)` and compute `z^N` where N is -#! the trace length. The resulting word `[(z_1, z_0)^N, z1, z0]` is stored in the +#! the trace length. The resulting word `[(z_0, z_1)^N, z0, z1]` is stored in the #! global memory address `exec.z_ptr` reserved for it. #! #! Input: [X, ...] @@ -378,31 +544,30 @@ end #! Note: The top word on the stack is consumed by this procedure. #! Cycles: 21 + 10 * log(N) pub proc generate_z_zN - # Load z (first two felts of the random coin state) and log trace length N - exec.constants::r1_ptr mem_loadw_be - drop drop + # Sample z and load log trace length N + exec.sample_ext exec.constants::get_trace_length_log - # => [log(trace_len), z_1, z_0, ...] + # => [log(trace_len), z_0, z_1, ...] dup.2 dup.2 - # => [z_1, z_0, log(trace_len), z_1, z_0, ...] + # => [z_0, z_1, log(trace_len), z_0, z_1, ...] # Compute z^N using the fact that z^N = z^(2^log(N)) # Loop starts with `i=log(trace_len)` push.1 while.true dup.1 dup.1 ext2mul - # => [(z_1, z_0)^n, i, z_1, z_0, ...] + # => [(z_0, z_1)^n, i, z_0, z_1, ...] dup.2 sub.1 swap.3 push.1 neq - # => [b, (z_1, z_0)^n, i-1, z_1, z_0, ...] + # => [b, (z_0, z_1)^n, i-1, z_0, z_1, ...] end movup.2 drop - # => [(z_1, z_0)^n, z_1, z_0, ...] + # => [(z_0, z_1)^n, z_0, z_1, ...] # Store z and z^N - exec.constants::z_ptr mem_storew_be + exec.constants::z_ptr mem_storew_le dropw end @@ -410,330 +575,182 @@ end # INDEX GENERATION # ============================================================================================= -# Helper function for generating a list of indices that takes a word of random felts and saves -# to memory region (referenced by `ptr`) 4 random integers in the range 0..=(mask+1). -# `depth` is saved next to each of the 4 integers for use in subsequent steps. -# -# Input: [R, ptr, mask, depth, ...] -# Output:[R, ptr+16, mask, depth, ...] -# -# Cycles: 100 -proc generate_four_integers - # Get the first random felt - dup.3 # [r0, R1, ptr, mask, depth, ...] - u32split swap # [r0_lo, r0_hi, R1, ptr, mask, depth, ...] - dup.7 # [mask, r0_lo, r0_hi, R1, ptr, mask, depth, ...] - u32and # [r, r0_hi, R1, ptr, mask, depth, ...] - dup.8 swap # [r, depth, r0_hi, R1, ptr, mask, depth, ...] - push.0 movdn.3 # [r, depth, r0_hi, 0, R1, ptr, mask, depth, ...] - - # Store and update pointer - dup.8 add.4 swap.9 # [ptr, r, depth, r0_hi, 0, R1, ptr + 4, mask, depth, ...] - mem_storew_be - dropw # [R1, ptr + 4, mask, depth, ...] - - # Get the second random felt - dup.2 # [r1, R1, ptr+4, mask, depth, ...] - u32split swap # [r1_lo, r1_hi, R1, ptr+4, mask, depth, ...] - dup.7 # [mask, r1_lo, r1_hi, R1, ptr+4, mask, depth, ...] - u32and # [r, r1_hi, R1, ptr+4, mask, depth, ...] - dup.8 swap # [r, depth, r1_hi, R1, ptr+4, mask, depth, ...] - push.0 movdn.3 # [r, depth, r1_hi, 0, R1, ptr+4, mask, depth, ...] - - # Store and update pointer - dup.8 add.4 swap.9 # [ptr, r, depth, r1_hi, 0, R1, ptr+8, mask, depth, ...] - mem_storew_be - dropw # [R1, ptr + 8, mask, depth, ...] - - # Get the third random felt - dup.1 - u32split swap - dup.7 - u32and - dup.8 swap - push.0 movdn.3 - - # Store and update pointer - dup.8 add.4 swap.9 - mem_storew_be - dropw - - # Get the fourth random felt - dup - u32split swap - dup.7 - u32and - dup.8 swap - push.0 movdn.3 - - # Store and update pointer - dup.8 add.4 swap.9 - mem_storew_be - dropw -end - -# Helper function for generating a list of indices. It takes a word of random felts and saves -# to a memory region, referenced by `ptr`, 3 random integers in the range 0..=(mask+1). This procedure -# is used to generate a list of random indices that are used in FRI. Moreover, this procedure -# is called first, and right after the PoW check, thus the first element in the rate portion of -# the state is discarded. -# `depth` is saved next to each of the 3 integers for use in subsequent steps. -# -# Input: [R, ptr, mask, depth, ...] -# Output:[R, ptr + 12, mask, depth, ...] -# -# Cycles: 75 -proc generate_three_integers - # Get the second random felt - dup.2 # [r0, R1, ptr, mask, depth, ...] - u32split swap # [r0_lo, r0_hi, R1, ptr, mask, depth, ...] - dup.7 # [mask, r0_lo, r0_hi, R1, ptr, mask, depth, ...] - u32and # [r, r0_hi, R1, ptr, mask, depth, ...] - dup.8 swap # [r, depth, r0_hi, R1, ptr, mask, depth, ...] - push.0 movdn.3 # [r, depth, r0_hi, 0, R1, ptr, mask, depth, ...] - - # Store and update pointer - dup.8 add.4 swap.9 # [ptr, r, depth, r0_hi, 0, R1, ptr + 4, mask, depth, ...] - mem_storew_be - dropw # [R1, ptr + 4, mask, depth, ...] - - # Get the second random felt - dup.1 # [r1, R1, ptr, mask, depth, ...] - u32split swap # [r1_lo, r1_hi, R1, ptr, mask, depth, ...] - dup.7 # [mask, r1_lo, r1_hi, R1, ptr, mask, depth, ...] - u32and # [r, r1_hi, R1, ptr, mask, depth, ...] - dup.8 swap # [r, depth, r1_hi, R1, ptr, mask, depth, ...] - push.0 movdn.3 # [r, depth, r1_hi, 0, R1, ptr, mask, depth, ...] - - # Store and update pointer - dup.8 add.4 swap.9 # [ptr, r, depth, r1_hi, 0, R1, ptr + 4, mask, depth, ...] - mem_storew_be - dropw # [R1, ptr + 4, mask, depth, ...] - - # Get the third random felt - dup.0 - u32split swap - dup.7 - u32and - dup.8 swap - push.0 movdn.3 - - # Store and update pointer - dup.8 add.4 swap.9 - mem_storew_be - dropw -end - #! Generate a list of `num_queries` number of random indices in the range -#! [0, lde_size] and store it in memory starting from `query_ptr`. -#! The list is stored as `(r, depth, y, y)` where `depth` is `log(lde_domain_size)`. -#!`depth` is needed when computing the deep queries. +#! [0, lde_size) and store it in memory starting from `query_ptr`. +#! The list is stored as `(index, depth, index, 0)` where `index` is the sampled domain-order +#! index and `depth` is `log(lde_domain_size)`, which is needed when computing the DEEP queries. #! -#! Input: [query_ptr, num_queries, ...] -#! Output: [...] +#! Reads rate elements directly from memory (decrementing from output_len-1 down to 0), +#! permuting when the rate is exhausted, rather than calling sample_felt per query. #! -#! Cycles: 267 + q * 236 + r * 29 where q = num_queries / 8 and r = num_queries % 8 +#! Input: [...] +#! Output: [...] #! -#! NOTE: This procedure is called first, and right after the PoW check, thus the first element -#! in the rate portion of the state is discarded. -#! NOTE: The cycles count can be estimated, using the fact that r < 8, via the more compact formula -#! 470 + 236 * (num_queries / 8) +#! NOTE: This procedure is called right after the PoW check. The PoW check consumes one +#! rate element via sample_bits, leaving output_len = 7. pub proc generate_list_indices - # Get the number of query indices we need to generate and the address to where we need - # to store them at. exec.constants::get_number_queries exec.constants::get_fri_queries_address #=> [query_ptr, num_queries, ...] - # Create mask - exec.constants::get_lde_domain_log_size - exec.constants::get_lde_domain_size - sub.1 - #=> [mask, depth, query_ptr, num_queries, ...] where depth = log(lde_size) - - # Get address holding the integers (this will later hold the FRI queries) - movup.2 - #=> [query_ptr, mask, depth, num_queries, ...] - - # Load the first half of the rate portion of the state of the random coin. We discard the first - # element as it is used for PoW and use the remaining the 3. - exec.get_rate_1 - #=> [R1, query_ptr, mask, depth, num_queries, ...] - exec.generate_three_integers - #=> [R1, query_ptr+12, mask, depth, num_queries, ...] - - - # Load the second half of the rate portion of the state of the random coin. - exec.constants::r2_ptr mem_loadw_be - #=> [R2, query_ptr+12, mask, depth, num_queries, ...] - exec.generate_four_integers - #=> [R2, query_ptr+26, mask, depth, num_queries, ..., ...] - - # Squeeze - exec.constants::c_ptr mem_loadw_be - exec.get_rate_1 - exec.get_rate_2 - exec.poseidon2::permute - #=> [R2', R1, C, query_ptr+26, mask, depth, num_queries, ...] - - # Save the new state - exec.constants::r2_ptr mem_storew_be - dropw - # => [R1, C] - exec.constants::r1_ptr mem_storew_be - swapw - # => [C, R1] - exec.constants::c_ptr mem_storew_be - dropw - #=> [R1, query_ptr+26, mask, depth, num_queries, ...] - - - # Use `num_queries` to iterate. - - ## Subtract the 7 elements we have already generated above. - movup.7 - push.7 sub - #=> [num_queries-7, R1, query_ptr+26, mask, depth, ...] - - ## Divide by 8 to get the number of iterations - u32assert u32divmod.8 - #=> [num_queries_remainder, num_queries_quotient, X, query_ptr+26, mask, depth, ...] - - ## Save remainder for later use - movdn.8 - #=> [num_queries_quotient, X, query_ptr+26, mask, depth, num_queries_remainder, ...] - - ## Use `quotient` to iterate - dup movdn.8 - #=> [num_queries_quotient, X, query_ptr+26, mask, depth, num_queries_quotient, num_queries_remainder, ...] - - push.0 neq + exec.constants::get_lde_domain_depth + #=> [depth, query_ptr, num_queries, ...] + + # Pre-compute pow2_shift = 2^(32 - depth) and mask = 2^depth - 1. + # pow2_shift is kept for stack shape compatibility with the old bit-reversal path. + dup push.32 swap u32wrapping_sub pow2 + #=> [pow2_shift, depth, query_ptr, num_queries, ...] + swap dup pow2 u32assert u32overflowing_sub.1 assertz + #=> [mask, depth, pow2_shift, query_ptr, num_queries, ...] + + # Rearrange to loop layout: [query_ptr, num_queries, mask, depth, pow2_shift, ...] + movup.3 movup.4 swap + #=> [query_ptr, num_queries, mask, depth, pow2_shift, ...] + + # Load current output_len from random coin state (7 after PoW). + # Assert it is nonzero: this procedure expects a freshly permuted sponge with at least + # one element already consumed (by the PoW check). A zero output_len would mean the + # sponge was never permuted or was fully drained, which is a caller bug. + exec.constants::random_coin_output_len_ptr mem_load + dup push.0 neq assert.err="generate_list_indices: output_len must be nonzero" + #=> [output_len, query_ptr, num_queries, mask, depth, pow2_shift, ...] + + # Stack layout during loop: + # pos 0: output_len (rate elements remaining before next permute) + # pos 1: query_ptr (advances by 4 each iteration) + # pos 2: num_queries (decrements to 0) + # pos 3: mask (constant) + # pos 4: depth (constant, needed for inclusion in the stored word) + # pos 5: pow2_shift (constant, needed for bit_reverse) + + dup.2 push.0 neq while.true - #=> [X, query_ptr', mask, depth, num_remaining_iterations, remainder, ...] - - exec.generate_four_integers - #=> [X, query_ptr'+16, mask, depth, num_remaining_iterations, remainder, ...] - - exec.constants::r2_ptr mem_loadw_be - exec.generate_four_integers - #=> [R2, query_ptr'+32, mask, depth, num_remaining_iterations, remainder, ...] - - # Squeeze - exec.constants::c_ptr mem_loadw_be - exec.get_rate_1 - exec.get_rate_2 - exec.poseidon2::permute - #=> [R2, R1, C, query_ptr'+32, mask, depth, num_remaining_iterations, remainder, ...] - - # Save the new state - exec.constants::r2_ptr mem_storew_be + # --- Ensure rate has an element; permute if exhausted --- + dup push.0 eq + if.true + drop + exec.load_random_coin_state + exec.poseidon2::permute + exec.store_random_coin_state + push.8 + end + #=> [output_len, query_ptr, num_queries, mask, depth, pow2_shift, ...] + + # --- Read rate element at index (output_len - 1) --- + sub.1 + #=> [idx, query_ptr, num_queries, mask, depth, pow2_shift, ...] + # R1 and R2 are contiguous in memory (R1_PTR, R1_PTR+4 = R2_PTR), so + # rate[idx] is simply at R1_PTR + idx. + dup exec.constants::r1_ptr add mem_load + #=> [felt, idx, query_ptr, num_queries, mask, depth, pow2_shift, ...] + + # --- Extract masked index: lo 32 bits AND mask --- + u32split swap drop + #=> [lo, idx, query_ptr, num_queries, mask, depth, pow2_shift, ...] + dup.4 u32and + #=> [natural_index, idx, query_ptr, num_queries, mask, depth, pow2_shift, ...] + + # --- Prepare domain-order query word --- + # 0.24 LMCS trees are indexed by domain order, so the Merkle index and the DEEP + # evaluation index are both the sampled natural index. + dup.5 swap dup movdn.2 + #=> [natural_index, depth, natural_index, idx, query_ptr, num_queries, mask, depth, pow2_shift, ...] + + # --- Store [index, depth, index, 0] at query_ptr --- + push.0 movdn.3 + #=> [natural_index, depth, natural_index, 0, idx, query_ptr, num_queries, mask, depth, pow2_shift, ...] + dup.5 + #=> [query_ptr, natural_index, depth, natural_index, 0, idx, query_ptr, num_queries, mask, depth, pow2_shift, ...] + mem_storew_le dropw - #=> [R1, C, query_ptr'+32, mask, depth, num_remaining_iterations, remainder, ...] - exec.constants::r1_ptr mem_storew_be - swapw - #=> [C, R1, query_ptr'+32, mask, depth, num_remaining_iterations, remainder, ...] - exec.constants::c_ptr mem_storew_be - dropw - #=> [R1, query_ptr'+32, mask, depth, num_remaining_iterations, remainder, ...] + #=> [idx, query_ptr, num_queries, mask, depth, pow2_shift, ...] - movup.7 sub.1 dup movdn.8 - #=> [num_remaining_iterations-1, R1, query_ptr'+32, mask, depth, num_remaining_iterations-1, remainder, ...] + # --- Advance query_ptr, decrement num_queries --- + swap add.4 swap + #=> [idx, query_ptr', num_queries, mask, depth, pow2_shift, ...] + movup.2 sub.1 movdn.2 + #=> [idx, query_ptr', num_queries-1, mask, depth, pow2_shift, ...] - push.0 neq + # --- Check loop condition --- + # idx is our output_len for next iteration (already decremented). + dup.2 push.0 neq end - #=> [R1, query_ptr', mask, depth, 0, remainder, ...] - - ## Use remainder - ## Note: we rename the `remainder` variable to `num_queries`, as it now indicates the number of - ## queries left. - - ### Put the remaining number of queries to generate in the appropriate stack position - movup.8 movdn.7 - #=> [R1, query_ptr', mask, depth, num_queries, ...] - ### Load the second half of the rate portion of the state of the random coin. - padw exec.constants::r2_ptr mem_loadw_be - #=> [R2, R1, query_ptr, mask, depth, num_queries, ...] + # --- Restore random coin output_len so subsequent operations see correct state --- + # pos 0 = output_len (remaining), store it back. + exec.constants::random_coin_output_len_ptr mem_store + #=> [query_ptr, num_queries, mask, depth, pow2_shift, ...] - ### Iterate over remainder - dup.11 sub.1 swap.12 - #=> [num_queries, R2, R1, query_ptr, mask, depth, num_queries-1, ...] + # Also clear the input_len to 0 (should already be 0, but it is better to be safe). + push.0 exec.constants::random_coin_input_len_ptr mem_store - neq.0 - while.true - #=> [R2, R1, query_ptr, mask, depth, num_queries, ...] - movup.7 - u32split swap # [r0_lo, r0_hi, R2, r3, r2, r1, ptr, mask, depth, num_queries, ...] - dup.10 # [mask, r0_lo, r0_hi, R2, r3, r2, r1, ptr, mask, depth, num_queries, ...] - u32and # [r, r0_hi, R2, r3, r2, r1, ptr, mask, depth, num_queries, ...] - dup.11 swap # [r, depth, r0_hi, R2, r3, r2, r1, ptr, mask, depth, num_queries, ...] - push.0 movdn.3 # [r, depth, r0_hi, 0, R2, r3, r2, r1, ptr, mask, depth, num_queries, ...] - - # Store and update pointer - dup.11 add.4 swap.12 # [ptr, r, depth, r0_hi, 0, R2, r3, r2, r1, ptr + 4, mask, depth, num_queries, ...] - mem_storew_be - drop drop drop # [x, R2, r3, r2, r1, ptr + 1, mask, depth, num_queries, ...] - dup.11 sub.1 swap.12 - #=> [num_queries, x, R2, r3, r2, r1, ptr + 1, mask, depth, num_queries-1, ...] - push.0 neq - end - #=> [R2, R1, query_ptr, mask, depth, 0, ...] - - dropw dropw dropw drop + dropw drop end # PROOF-OF-WORK CHECK # ============================================================================================= -#! Check that the Proof-of-Work contained in the nonce is equal to the required number -#! of bits prescribed by grinding bits. The grinding factor is assumed to be less than 32. +#! Verify a proof-of-work witness given pow_bits on the stack. #! -#! Input: [...] +#! When pow_bits != 0, reads the nonce from advice, writes it to rate[0], permutes, +#! and checks that the low pow_bits of the output are zero. +#! When pow_bits == 0, consumes the witness (must be zero) without affecting the transcript. +#! +#! Used by check_query_pow (query phase) and check_deep_pow (DEEP phase). +#! FRI folding PoW uses a separate path (sample_folding_pow_and_ext) because the +#! witness is bundled with the commitment reseed. +#! +#! SAFETY: Requires input_len=0. +#! +#! Input: [pow_bits, ...] #! Output: [...] -#! Cycles: 73 -pub proc check_pow - # Load the grinding factor - exec.constants::get_grinding_factor - - # Compute the mask. - pow2 - u32assert u32overflowing_sub.1 assertz.err="range check failed: pow" - #=> [mask, ...] - - # Load Capacity portion - exec.get_capacity - #=> [C, mask, ...] - - # Load first half of rate portion and add pow witness to first element of rate - exec.get_rate_1 - adv_push.1 - dup.4 - add - swap.4 - drop - - # Load the second half of rate portion and apply the permutation - padw - exec.constants::r2_ptr mem_loadw_be - exec.poseidon2::permute - #=> [R2, R1, C, mask, ...] +proc check_pow + dup + push.0 neq + if.true + adv_push + # Assert input buffer is empty, then write nonce directly to rate[0] and permute. + exec.constants::random_coin_input_len_ptr mem_load + assertz.err="check_pow: input buffer must be empty" + exec.constants::r1_ptr mem_store + exec.load_random_coin_state + exec.poseidon2::permute + exec.store_random_coin_state + push.8 exec.constants::random_coin_output_len_ptr mem_store + # sample_bits reads from fresh output (no duplex triggered). + exec.sample_bits + assertz.err="proof-of-work check failed" + else + # Consume witness to keep advice layout, but do not affect transcript. + adv_push + assertz.err="proof-of-work nonce must be zero when grinding factor is zero" + drop + end +end - # Save the new random coin state - exec.constants::r2_ptr mem_storew_be - dropw - exec.constants::r1_ptr mem_storew_be - swapw - exec.constants::c_ptr mem_storew_be - dropw - drop drop drop - #=> [R10, mask] +#! Check the DEEP proof-of-work. +#! +#! Called before sampling DEEP composition polynomial challenges. +#! +#! SAFETY: Requires input_len=0. +#! +#! Input: [...] +#! Output: [...] +pub proc check_deep_pow + exec.constants::get_deep_pow_bits + exec.check_pow +end - # Make sure the PoW is valid - u32split - drop - u32and - assertz.err="range check failed: pow" - drop - #=> [...] +#! Check the query proof-of-work. +#! +#! Called after loading the FRI remainder, before sampling query indices. +#! +#! SAFETY: Requires input_len=0 (guaranteed after load_and_verify_remainder). +#! +#! Input: [...] +#! Output: [...] +pub proc check_query_pow + exec.constants::get_query_pow_bits + exec.check_pow end diff --git a/crates/lib/core/asm/stark/utils.masm b/crates/lib/core/asm/stark/utils.masm index e3340fdc3f..5083997d1f 100644 --- a/crates/lib/core/asm/stark/utils.masm +++ b/crates/lib/core/asm/stark/utils.masm @@ -18,128 +18,315 @@ end #! Validates the inputs to the recursive verifier. #! -#! Input: [log(trace_length), num_queries, grinding, ...] -#! Output: [log(trace_length), num_queries, grinding, ...] +#! Checks log(trace_length) from the stack and security parameters from memory. +#! The security parameters must already be stored in memory before calling this +#! procedure (done by the specific verifier's load_security_params). #! -#! Cycles: 45 +#! Input: [log(trace_length), ...] +#! Output: [log(trace_length), ...] pub proc validate_inputs - # 1) Assert that all inputs are u32 so that we can use u32 operations in what follows - push.0 - dupw - u32assertw - # => [0, log(trace_length), num_queries, grinding, 0, log(trace_length), num_queries, grinding, ...] + # 1) Assert log(trace_length) is u32 + dup u32assert # 2) Assert that the trace length is at most 29. The 2-adicity of our field is 32 and since # the blowup factor is 8, we need to make sure that the LDE size is at most 2^32. # We also check that the trace length is greater than the minimal length supported i.e., 2^6. - drop - dup u32lt.30 assert.err="range check failed: input bounds" - u32gt.5 assert.err="range check failed: input bounds" + dup u32lt.30 assert.err="log(trace_length) must be less than 30" + u32gt.5 assert.err="log(trace_length) must be greater than 5" # 3) Assert that the number of FRI queries is at most 150. This restriction is a soft one # and is due to the memory layout in the `constants.masm` files but can be updated # therein. # We also make sure that the number of FRI queries is at least 7. - dup u32lt.151 assert.err="range check failed: input bounds" - u32gt.6 assert.err="range check failed: input bounds" + exec.constants::get_number_queries + dup u32lt.151 assert.err="num_queries must be less than 151" + u32gt.6 assert.err="num_queries must be greater than 6" + + # 4) Assert that PoW bit counts are less than 32 (must fit in u32 bit masking) + exec.constants::get_query_pow_bits + u32lt.32 assert.err="query_pow_bits must be less than 32" - # 4) Assert that the grinding factor is at most 31 - u32lt.32 assert.err="range check failed: input bounds" + exec.constants::get_deep_pow_bits + u32lt.32 assert.err="deep_pow_bits must be less than 32" - # 5) Clean up the stack - drop + exec.constants::get_folding_pow_bits + u32lt.32 assert.err="folding_pow_bits must be less than 32" end -#! Sets up auxiliary inputs to the arithmetic circuit for the constraint evaluation check. +#! Reverse the lowest `bits` bits of `index` using parallel bit-swap. +#! `pow2_shift` must equal 2^(32 - bits); the caller pre-computes it once. +#! +#! The algorithm has two parts: +#! +#! 1) Left-shift: multiply index by pow2_shift = 2^(32-bits) to place the `bits` +#! meaningful bits into the top of a 32-bit word. Since index < 2^bits, the +#! product is always < 2^32 so u32wrapping_mul is exact. #! -#! These inputs are: +#! 2) Full 32-bit reversal via 5 parallel swap steps. Each step k (for k=1,2,4,8,16) +#! swaps every adjacent group of k bits. A mask isolates the even-positioned +#! groups; the odd-positioned groups are the complement. Shifting each half by +#! k positions and combining swaps all groups simultaneously. After all 5 steps, +#! bit position i has moved to position 31-i, which (because of the initial +#! left-shift) is exactly position (bits-1-i) of the original -- i.e., the +#! reversed index. No final shift is needed. +#! +#! The two halves never overlap, so XOR = OR = ADD; we use XOR (1 cycle vs 3 for +#! u32wrapping_add). +#! +#! Input: [index, pow2_shift, ...] +#! Output: [rev_index, ...] +#! Cycles: 78 +pub proc bit_reverse_len_parallel + u32wrapping_mul + + # Step 1: swap adjacent bits + # x = ((x >> 1) & 0x55555555) ^ ((x & 0x55555555) << 1) + dup u32shr.1 push.0x55555555 u32and + swap push.0x55555555 u32and u32shl.1 + u32xor + #=> [x1, ...] + + # Step 2: swap bit pairs + # x = ((x >> 2) & 0x33333333) ^ ((x & 0x33333333) << 2) + dup u32shr.2 push.0x33333333 u32and + swap push.0x33333333 u32and u32shl.2 + u32xor + #=> [x2, ...] + + # Step 3: swap nibbles + # x = ((x >> 4) & 0x0F0F0F0F) ^ ((x & 0x0F0F0F0F) << 4) + dup u32shr.4 push.0x0F0F0F0F u32and + swap push.0x0F0F0F0F u32and u32shl.4 + u32xor + #=> [x3, ...] + + # Step 4: swap bytes + # x = ((x >> 8) & 0x00FF00FF) ^ ((x & 0x00FF00FF) << 8) + dup u32shr.8 push.0x00FF00FF u32and + swap push.0x00FF00FF u32and u32shl.8 + u32xor + #=> [x4, ...] + + # Step 5: swap halfwords + # x = (x >> 16) ^ (x << 16) (no mask needed, both halves fit in 16 bits) + dup u32shr.16 + swap u32shl.16 + u32xor + #=> [rev_index, ...] +end + +#! Sets up the stark-vars region of the ACE circuit input layout. #! -#! 1) OOD evaluation point z, -#! 2) random challenge used in computing the DEEP composition polynomial, -#! 3) z^N where N is the execution trace length -#! 4) z^k where k = min_num_cycles = trace_len / max_cycle_len and max_cycle_len is the longest cycle -#! among all the cycles of periodic columns. -#! 5) g^{-1} where g is the trace domain generator. +#! The stark-vars block is 10 EF slots (5 words) laid out as: #! -#! The only input to this procedure is the log2 of the max cycle length across all periodic columns. +#! Word 0 (slots 0-1): alpha, z^N (EF: composition challenge, trace-length power) +#! Word 1 (slots 2-3): z_k, is_first (EF: periodic eval point, first-row selector) +#! Word 2 (slots 4-5): is_last, is_transition (EF: last-row selector, transition selector) +#! Word 3 (slots 6-7): gamma, weight0 (EF: batching challenge; base as EF: barycentric weight) +#! Word 4 (slots 8-9): f, s0 (base as EF: chunk shift ratio h^N, first shift) #! #! Input: [max_cycle_len_log, ...] #! Output: [...] pub proc set_up_auxiliary_inputs_ace - padw exec.constants::composition_coef_ptr mem_loadw_be + # ================================================================== + # Phase 1: alpha, z^N -> Word 0 (z_k and z remain on stack) + # ================================================================== - # z and z^N - push.0.0 exec.constants::z_ptr mem_loadw_be - # => [(z_1, z_0)^n, z_1, z_0, alpha1, alpha0, max_cycle_len_log, ...] + padw exec.constants::composition_coef_ptr mem_loadw_le + # => [alpha0, alpha1, 0, 0, max_cycle_len_log, ...] + movup.3 movup.3 + push.0.0 exec.constants::z_ptr mem_loadw_le + # => [z_n_0, z_n_1, z_0, z_1, alpha0, alpha1, max_cycle_len_log, ...] + + # Compute z_k = z^(N / max_cycle_len) via repeated squaring. exec.constants::get_trace_length_log movup.7 sub - # => [log(min_num_cycles), (z_1, z_0)^n, z_1, z_0, alpha1, alpha0, ...] where min_num_cycles = trace_len / max_cycle_len + # => [k, z_n_0, z_n_1, z_0, z_1, alpha0, alpha1, ...] + # where k = log(trace_len) - log(max_cycle_len) dup.4 dup.4 - # => [z_1, z_0, k, (z_1, z_0)^n, z_1, z_0, alpha1, alpha0, ...] where k = min_num_cycles + # => [z_0, z_1, k, z_n_0, z_n_1, z_0, z_1, alpha0, alpha1, ...] push.1 while.true dup.1 dup.1 - # => [z_1, z_0, z_1, z_0, k, (z_1, z_0)^n, z_1, z_0, alpha1, alpha0, ...] where k = min_num_cycles ext2mul - # => [z_exp_1, z_exp_0, k, (z_1, z_0)^n, z_1, z_0, alpha1, alpha0, ...] where k = min_num_cycles dup.2 sub.1 swap.3 push.1 neq end movup.2 drop - # => [z_k_1, z_k_0, (z_1, z_0)^n, z_1, z_0, alpha1, alpha0, ...] where k = min_num_cycles + # => [z_k_0, z_k_1, z_n_0, z_n_1, z_0, z_1, alpha0, alpha1, ...] + + # Rearrange for Word 0 = [alpha0, alpha1, z_n_0, z_n_1] + movup.3 movup.3 + # => [z_n_0, z_n_1, z_k_0, z_k_1, z_0, z_1, alpha0, alpha1, ...] + movup.7 movup.7 + # => [alpha0, alpha1, z_n_0, z_n_1, z_k_0, z_k_1, z_0, z_1, ...] + + exec.constants::auxiliary_ace_inputs_ptr + mem_storew_le + drop drop + # => [z_n_0, z_n_1, z_k_0, z_k_1, z_0, z_1, ...] + + # ================================================================== + # Phase 2: is_first, is_last, is_transition -> Words 1-2 + # ================================================================== + + # Compute vanishing = z^N - 1 (z^N is still on the stack from Phase 1). + sub.1 + # => [van_0, van_1, z_k_0, z_k_1, z_0, z_1, ...] + + # is_first = vanishing * inv(z - 1) + dup.5 dup.5 + # => [z_0, z_1, van_0, van_1, z_k_0, z_k_1, z_0, z_1, ...] + sub.1 ext2inv + # => [inv_z1_0, inv_z1_1, van_0, van_1, z_k_0, z_k_1, z_0, z_1, ...] + dup.3 dup.3 + # => [van_0, van_1, inv_z1_0, inv_z1_1, van_0, van_1, z_k_0, z_k_1, z_0, z_1, ...] + ext2mul + # => [is_first_0, is_first_1, van_0, van_1, z_k_0, z_k_1, z_0, z_1, ...] + # Store Word 1: [z_k_0, z_k_1, is_first_0, is_first_1] + movup.5 movup.5 + # => [z_k_0, z_k_1, is_first_0, is_first_1, van_0, van_1, z_0, z_1, ...] + exec.constants::auxiliary_ace_inputs_ptr add.4 + mem_storew_le + dropw + # => [van_0, van_1, z_0, z_1, ...] + + # is_transition = z - g^{-1} (g_inv is base-field, only coord 0 changes) exec.constants::get_trace_domain_generator inv - # => [g^-1, z_k_1, z_k_0, (z_1, z_0)^n, z_1, z_0, alpha1, alpha0, ...] where k = min_num_cycles - movdn.2 - push.0 - movdn.2 - # => [z_k_1, z_k_0, 0, g^-1, (z_1, z_0)^n, z_1, z_0, alpha1, alpha0, ...] where k = min_num_cycles + # => [g_inv, van_0, van_1, z_0, z_1, ...] + movup.3 swap sub + # => [is_trans_0, van_0, van_1, z_1, ...] + movup.3 + swap + # => [is_trans_0, is_trans_1, van_0, van_1, ...] - exec.constants::get_trace_domain_generator - inv dup mul - push.0 - # => [0, g^-2, z_k_1, z_k_0, 0, g^-1, (z_1, z_0)^n, z_1, z_0, alpha1, alpha0, ...] where k = min_num_cycles + # is_last = vanishing * inv(is_transition) + dup.1 dup.1 + # => [is_trans_0, is_trans_1, is_trans_0, is_trans_1, van_0, van_1, ...] + ext2inv + # => [inv_t_0, inv_t_1, is_trans_0, is_trans_1, van_0, van_1, ...] + movup.5 movup.5 + # => [van_0, van_1, inv_t_0, inv_t_1, is_trans_0, is_trans_1, ...] + ext2mul + # => [is_last_0, is_last_1, is_trans_0, is_trans_1, ...] - # Save [z_k_0, z_k_1, g^-2, 0] + # Store Word 2: [is_last_0, is_last_1, is_trans_0, is_trans_1] exec.constants::auxiliary_ace_inputs_ptr add.8 - mem_storew_be + mem_storew_le dropw - # => [0, g^-1, (z_1, z_0)^n, z_1, z_0, alpha1, alpha0, ...] + # => [...] - # Save [(z_0, z_1)^n, g^-1, 0] - exec.constants::auxiliary_ace_inputs_ptr add.4 - mem_storew_be + # ================================================================== + # Phase 3: f, s0, weight0, gamma -> Words 3-4 + # ================================================================== + + # Compute s0 = offset^N + push.0.7 + exec.constants::get_trace_length + exp.u32 + # => [s0, 0, ...] + + # Compute f = h^N (chunk shift ratio between cosets) + push.0 + exec.constants::get_lde_domain_generator + exec.constants::get_trace_length + exp.u32 + # => [f, 0, s0, 0, ...] + + # Compute weight0 = 1 / (8 * s0^7) + dup.2 dup + mul + # => [s0^2, f, 0, s0, 0, ...] + dup dup mul + # => [s0^4, s0^2, f, 0, s0, 0, ...] + mul + # => [s0^6, f, 0, s0, 0, ...] + dup.3 mul + mul.8 inv + # => [weight0, f, 0, s0, 0, ...] + + # Store Word 4: [f, 0, s0, 0] + movdn.4 + # => [f, 0, s0, 0, weight0, ...] + exec.constants::auxiliary_ace_inputs_ptr add.16 + mem_storew_le dropw + # => [weight0, ...] - # Save [alpha0, alpha1, z_0, z_1] - exec.constants::auxiliary_ace_inputs_ptr - mem_storew_be + # Store Word 3: [gamma_0, gamma_1, weight0, 0] + # weight0 is still on the stack -- sample gamma and assemble the word. + exec.sample_gamma + # => [gamma_0, gamma_1, weight0, ...] + push.0 movdn.3 + # => [gamma_0, gamma_1, weight0, 0, ...] + exec.constants::auxiliary_ace_inputs_ptr add.12 + mem_storew_le dropw - # => [...] end -#! Executes the constraints evalution check. +#! Sample the batching challenge gamma (EF element). #! -#! Input: [...] -#! Output: [...] -proc execute_constraint_evaluation_check +#! gamma batches the constraint evaluation with the auxiliary trace boundary checks: +#! output = constraint_check + gamma * product_check + gamma^2 * sum_check +#! +#! WORKAROUND (unsound): Reads gamma directly from the sponge rate buffer without +#! consuming it. This gives gamma == deep_alpha (the next challenge that will be +#! properly sampled in generate_deep_composition_random_coefficients). Using the +#! same value for both is unsound. +#! +#! TODO: Replace with a proper `sample_ext` call once the Rust-side +#! StarkTranscript is updated to draw gamma between OOD and DEEP phases. +#! +#! Input: [...] +#! Output: [gamma_0, gamma_1, ...] +proc sample_gamma + # Assert output_len == 8 so the rate buffer indices are correct. + exec.constants::random_coin_output_len_ptr mem_load push.8 assert_eq + # Read the top 2 elements of the sponge rate buffer. + exec.constants::r1_ptr add.7 mem_load + exec.constants::r1_ptr add.6 mem_load + swap +end + +#! Executes the constraints evaluation check. +#! +#! Inputs: [...] +#! Outputs: [...] +#! +#! Invocation: exec +pub proc execute_constraint_evaluation_check exec.constants::get_procedure_digest_execute_constraint_evaluation_check_ptr dynexec end +#! Observes the auxiliary trace: draws aux randomness, reseeds with the aux trace commitment, +#! and absorbs aux trace boundary values into the transcript. +#! +#! For AIRs without an auxiliary trace, the implementation should be a no-op. +#! +#! Inputs: [...] +#! Outputs: [...] +#! +#! Invocation: exec +pub proc observe_aux_trace + exec.constants::get_procedure_digest_observe_aux_trace_ptr dynexec +end + #! Stores digests of dynamically executed procedures. #! -#! Input: [D3, D2, D1, D0, ...] +#! Input: [D0, D1, D2, D3, D4, ...] #! Output: [...] pub proc store_dynamically_executed_procedures - exec.constants::get_procedure_digest_process_public_inputs_ptr mem_storew_be dropw - exec.constants::get_procedure_digest_process_row_ood_evaluations_ptr mem_storew_be dropw - exec.constants::get_procedure_digest_execute_constraint_evaluation_check_ptr mem_storew_be dropw - exec.constants::get_procedure_digest_compute_deep_composition_polynomial_queries_ptr mem_storew_be dropw + exec.constants::get_procedure_digest_observe_aux_trace_ptr mem_storew_le dropw + exec.constants::get_procedure_digest_process_public_inputs_ptr mem_storew_le dropw + exec.constants::get_procedure_digest_process_row_ood_evaluations_ptr mem_storew_le dropw + exec.constants::get_procedure_digest_execute_constraint_evaluation_check_ptr mem_storew_le dropw + exec.constants::get_procedure_digest_compute_deep_composition_polynomial_queries_ptr mem_storew_le dropw # => [...] end diff --git a/crates/lib/core/asm/stark/verifier.masm b/crates/lib/core/asm/stark/verifier.masm index 99bd0b9794..f4ddf96e06 100644 --- a/crates/lib/core/asm/stark/verifier.masm +++ b/crates/lib/core/asm/stark/verifier.masm @@ -13,21 +13,18 @@ use miden::core::stark::utils #! The purpose of the following verifier is to serve as a generic core around which a specific #! verifier can be built. It expects the following parameters on the stack from the caller: #! -#! 1. `[D0, D1, D2, D3]` which are respectively the digests for dynamic execution of procedures -#! i. `compute_deep_composition_polynomial_queries` -#! ii. `execute_constraint_evaluation_check` -#! iii. `process_row_ood_evaluations` -#! iv. `process_public_inputs` -#! 2. `num_constraints` which is the number of constraints in the AIR -#! 3. `trace_info` which is a field element encoding the layout of the AIR -#! 4. `num_fixed_len_pi` is the number of fixed length public inputs of the AIR -#! 5. `is_aux_trace` flag indicating the existence of an auxiliary segment in this AIR +#! 1. `[D0, D1, D2, D3, D4]` which are the digests for dynamic execution of: +#! D0. `observe_aux_trace` +#! D1. `process_public_inputs` +#! D2. `process_row_ood_evaluations` +#! D3. `execute_constraint_evaluation_check` +#! D4. `compute_deep_composition_polynomial_queries` +#! 2. Per-proof parameter: `log(trace_length)` +#! 3. `[rd0, rd1, rd2, rd3]`: RELATION_DIGEST = hash(PROTOCOL_ID, CIRCUIT_COMMITMENT), +#! a compile-time constant that binds the Fiat-Shamir transcript to the AIR instance. #! -#! In addition to the above parameters, the verifier expects the following auxiliary proof parameters: -#! -#! 1. `log(trace_length)`, the logarithm base 2 of the trace length -#! 2. `num_queries`, the number of FRI queries -#! 3. `grinding`, the number of bits of grinding i.e., proof-of-work +#! Precondition: security parameters (num_queries, query_pow_bits, deep_pow_bits, +#! folding_pow_bits) must already be stored in memory before calling this procedure. #! #! The following simplifying assumptions are currently made and hardcoded: #! @@ -38,66 +35,55 @@ use miden::core::stark::utils #! Similarly, elements of the auxiliary trace are quadratic extension field elements. The random #! values for computing random linear combinations are also in this extension field. #! -#! Inputs: [D3, D2, D1, D0, log(trace_length), num_queries, grinding, num_constraints, trace_info, num_fixed_len_pi, is_aux_trace] +#! Inputs: [D0, D1, D2, D3, D4, log(trace_length), rd0, rd1, rd2, rd3] #! Outputs: [] pub proc verify #============================================================================================== - # I) Hash proof context and hash-&-load public inputs + # I) Observe proof context and load public inputs #============================================================================================== # Store digests of dynamically executed procedures exec.utils::store_dynamically_executed_procedures - # => [log(trace_length), num_queries, grinding, num_constraints, trace_info, num_fixed_len_pi, is_aux_trace, ...] + # => [log(trace_length), rd0, rd1, rd2, rd3] # Validate inputs - # - # Cycles: 45 exec.utils::validate_inputs - # => [log(trace_length), num_queries, grinding, num_constraints, trace_info, num_fixed_len_pi, is_aux_trace, ...] + # => [log(trace_length), rd0, rd1, rd2, rd3] - # Initialize the seed using proof context - # - # Cycles: 210 + # Initialize sponge with DSFS seeding and derive trace domain parameters. + # Consumes [log(tl), rd0, rd1, rd2, rd3]. Security params are read from memory. exec.random_coin::init_seed - # => [C, is_aux_trace, ...] + # => [...] - # Load public inputs + # Load and observe public inputs exec.public_inputs::process_public_inputs - # => [is_aux_trace, ...] + # => [...] + + # Observe the AIR instance shape and discard the unused instance challenge. + exec.random_coin::observe_trace_height_and_discard_instance_challenge + # => [...] + + # Load main trace commitment and re-seed with it. + # + # SAFETY: reseed_direct bypasses the duplex input buffer and requires input_len=0. + # The preceding trace-height observation helper guarantees this postcondition. + padw adv_loadw + exec.constants::main_trace_com_ptr mem_storew_le + # => [main_trace_commitment, ...] + exec.random_coin::reseed_direct + # => [...] + #============================================================================================== - # II) Generate the auxiliary trace random elements if auxiliary segment exists + # II) Observe auxiliary trace #============================================================================================== - # Load main trace commitment and re-seed with it - # - # Cycles: 56 - padw - adv_loadw - exec.constants::main_trace_com_ptr mem_storew_be - # => [main_trace_commitment, is_aux_trace, ...] - exec.random_coin::reseed - # => [is_aux_trace, ...] - - # If auxiliary segment exists, generate auxiliary randomness and reseed with commitment - # to auxiliary segment - if.true - # Draw random ExtFelt for the auxiliary trace - # - # Cycles: 12 - exec.random_coin::generate_aux_randomness - # => [...] - - # Reseed with auxiliary trace commitment - # - # Cycles: 64 - padw - adv_loadw - exec.constants::aux_trace_com_ptr mem_storew_be - exec.random_coin::reseed - # => [...] - end + # The AIR-specific implementation handles: drawing aux randomness, reseeding with the + # aux trace commitment, and absorbing aux trace boundary values into the transcript. + # For AIRs without an auxiliary trace, the implementation is a no-op. + exec.utils::observe_aux_trace + # => [...] #============================================================================================== # III) Draw constraint composition coefficients @@ -112,13 +98,14 @@ pub proc verify # and generate the Out-of-Domain (OOD) challenge z #============================================================================================== - # Reseed with constraint composition polynomial commitment + # Reseed with constraint composition polynomial commitment. # - # Cycles: 88 + 18 * log(trace_length) - padw - adv_loadw - exec.constants::composition_poly_com_ptr mem_storew_be - exec.random_coin::reseed + # SAFETY: reseed_direct requires input_len=0 (see SAFETY note above for rationale). + # Guaranteed here because generate_constraint_composition_coefficients only samples + # (decrements output_len) and never observes (input_len stays 0). + padw adv_loadw + exec.constants::composition_poly_com_ptr mem_storew_le + exec.random_coin::reseed_direct exec.random_coin::generate_z_zN # => [...] @@ -126,12 +113,14 @@ pub proc verify # V) Read the OOD frames for the main trace, auxiliary trace and the trace of evaluations # of H over the LDE domain. This also computes some values needed for the computation # of the DEEP queries. + # + # Cycles: 307 #============================================================================================== exec.ood_frames::load_and_horner_eval_ood_frames #============================================================================================== - # VI) Constraint evaluation check + # VI) Draw gamma for reduced_aux_values batching and evaluate constraints #============================================================================================== exec.utils::execute_constraint_evaluation_check @@ -141,11 +130,12 @@ pub proc verify #============================================================================================== #============================================ - # 1) Draw random coefficients for computing - # DEEP composition polynomial. + # 1) Check DEEP PoW and draw random + # coefficients for DEEP composition + # polynomial. #============================================ - # Cycles: 14 + exec.random_coin::check_deep_pow exec.random_coin::generate_deep_composition_random_coefficients #============================================ @@ -157,7 +147,7 @@ pub proc verify # - Number of FRI layers. #============================================ - # Cycles: 77 + # Cycles: 45 exec.helper::generate_fri_parameters # => [...] @@ -167,7 +157,7 @@ pub proc verify # computing the degree respecting projection #============================================ - # Cycles: 40 + 108 * num_fri_layers + # Cycles: 21 + 225 * num_fri_layers exec.helper::load_fri_layer_commitments # => [...] @@ -177,19 +167,16 @@ pub proc verify #============================================ # Cycles: - # 1- Remainder polynomial of degree less - # than 64: 157 - # 2- Remainder polynomial of degree less - # than 128: 191 + # 1- Remainder polynomial of degree less than 64: 156 + # 2- Remainder polynomial of degree less than 128: 188 exec.helper::load_and_verify_remainder # => [...] #============================================ - # 5) Check PoW nonce + # 5) Check FRI Queries PoW nonce #============================================ - # Cycles: 78 - exec.random_coin::check_pow + exec.random_coin::check_query_pow # => [...] #============================================ @@ -201,11 +188,11 @@ pub proc verify # the first layer commitment and the total number of queries. exec.helper::compute_query_pointer - # Draw random query indices + # Cycles: ~134 * num_queries exec.random_coin::generate_list_indices # => [...] - # Compute deep composition polynomial queries + # Cycles: ~348 * num_queries exec.deep_queries::compute_deep_composition_polynomial_queries # => [...] @@ -216,7 +203,7 @@ pub proc verify # Call FRI verifier # # Cycles: - # 1- Remainder of size 64: 18 + num_queries * (107 + num_layers * 83) - # 2- Remainder of size 128: 18 + num_queries * (140 + num_layers * 83) + # 1- Remainder of size 64: 22 + num_queries * (43 + num_layers * 93) + # 2- Remainder of size 128: 22 + num_queries * (75 + num_layers * 93) exec.frie2f4::verify end diff --git a/crates/lib/core/asm/sys/mod.masm b/crates/lib/core/asm/sys/mod.masm index f34f819685..0a0c8c7426 100644 --- a/crates/lib/core/asm/sys/mod.masm +++ b/crates/lib/core/asm/sys/mod.masm @@ -12,7 +12,7 @@ @locals(4) pub proc truncate_stack() # save the first word to memory and bring elements to be dropped to the top of the stack - loc_storew_be.0 dropw movupw.3 + loc_storew_le.0 dropw movupw.3 # => [X, B, C, D, ...] # until stack depth greater than 16, keep dropping extra elements @@ -26,7 +26,7 @@ pub proc truncate_stack() # => [X, B, C, D, ...] # bring the previously saved word back onto the stack - loc_loadw_be.0 + loc_loadw_le.0 # => [A, B, C, D, ...] end @@ -38,12 +38,12 @@ end #! Logs a precompile commitment and removes the helper words produced by `log_precompile`. #! #! Input: `[COMM, TAG, ...]` -#! Output: Stack without the three helper words `[R1, R0, CAP_NEXT]`. +#! Output: Stack without the three helper words `[R0, R1, CAP_NEXT]`. #! Cycles: 1 (plus cost of the underlying `log_precompile` instruction). pub proc log_precompile_request padw movdnw.2 # => [COMM, TAG, PAD, ...] log_precompile - # => [R1, R0, CAP_NEXT, ...] + # => [R0, R1, CAP_NEXT, ...] dropw dropw dropw end diff --git a/crates/lib/core/asm/sys/vm/aux_trace.masm b/crates/lib/core/asm/sys/vm/aux_trace.masm new file mode 100644 index 0000000000..f1919ceec7 --- /dev/null +++ b/crates/lib/core/asm/sys/vm/aux_trace.masm @@ -0,0 +1,56 @@ +use miden::core::crypto::hashes::poseidon2 +use miden::core::stark::constants +use miden::core::stark::random_coin + +#! Observes the auxiliary trace for the Miden VM AIR. +#! +#! Draws auxiliary randomness, reseeds the transcript with the auxiliary trace commitment, +#! and absorbs the boundary values (2 extension field elements = 4 base field elements = 1 word). +#! TODO(#3032): the second value is always zero (placeholder for trace splitting). +#! +#! The advice provider must supply exactly 2 words in order: +#! [commitment, W0] +#! +#! The commitment is stored at aux_trace_com_ptr and the boundary values at +#! aux_bus_boundary_ptr. +#! +#! Precondition: input_len=0 (guaranteed by the preceding reseed_direct in the generic verifier). +#! Postcondition: input_len=0, output_len=8. +#! +#! Input: [...] +#! Output: [...] +pub proc observe_aux_trace + # Draw random extension field elements for the auxiliary trace. + exec.random_coin::generate_aux_randomness + # => [...] + + # Assert precondition: input buffer must be empty. + exec.constants::random_coin_input_len_ptr mem_load + assertz.err="observe_aux_trace: input buffer must be empty" + + # Reseeding clears the output buffer. + push.0 exec.constants::random_coin_output_len_ptr mem_store + + # --- Single permutation: Absorb [COM, W0] --- + + padw adv_loadw + exec.constants::aux_trace_com_ptr mem_storew_le + # => [COM, ...] + + padw adv_loadw + exec.constants::aux_bus_boundary_ptr mem_storew_le + # => [W0, COM, ...] + + swapw + exec.random_coin::get_capacity + movdnw.2 + exec.poseidon2::permute + # => [R1', R2', C', ...] + + # Store final sponge state. + exec.random_coin::store_random_coin_state + # => [...] + + # Mark output buffer as full (8 elements available for sampling). + push.8 exec.constants::random_coin_output_len_ptr mem_store +end diff --git a/crates/lib/core/asm/sys/vm/constraints_eval.masm b/crates/lib/core/asm/sys/vm/constraints_eval.masm index 93fbb8ee07..6185d8c3cd 100644 --- a/crates/lib/core/asm/sys/vm/constraints_eval.masm +++ b/crates/lib/core/asm/sys/vm/constraints_eval.masm @@ -5,30 +5,23 @@ use miden::core::stark::utils # CONSTANTS # ================================================================================================= -# Number of constraints, both boundary and transitional -const NUM_CONSTRAINTS = 6 - -# Number of inputs to the constraint evaluation circuit -const NUM_INPUTS_CIRCUIT = 244 +# Number of READ variables (inputs + constants) for the constraint evaluation circuit. +# Breakdown: 270 READ slots + 302 constants = 572 +# This value must match AceConfig and the layout in `constants.masm`. +# If NUM_VAR_LEN_PI_GROUPS changes, this must be regenerated via ace-codegen. +const NUM_INPUTS_CIRCUIT = 562 # Number of evaluation gates in the constraint evaluation circuit -const NUM_EVAL_GATES_CIRCUIT = 108 +const NUM_EVAL_GATES_CIRCUIT = 5524 # Max cycle length for periodic columns -const MAX_CYCLE_LEN_LOG = 3 - -# --- constant getters -------------------------------------------------------- - -proc get_num_constraints - push.NUM_CONSTRAINTS -end +const MAX_CYCLE_LEN_LOG = 4 # ERRORS # ================================================================================================= const ERR_FAILED_TO_LOAD_CIRCUIT_DESCRIPTION = "failed to load the circuit description for the constraints evaluation check" - # CONSTRAINT EVALUATION CHECKER # ================================================================================================= @@ -36,17 +29,17 @@ const ERR_FAILED_TO_LOAD_CIRCUIT_DESCRIPTION = "failed to load the circuit descr #! chiplet. #! #! The circuit description is hardcoded into the verifier using its commitment, which is computed as -#! the sequential hash of its description using Poseidon2 hasher. The circuit description, containing both -#! constants and evaluation gates description, is stored at the contiguous memory region starting -#! at `ACE_CIRCUIT_PTR`. The variable part of the circuit input is stored at the contiguous memory +#! the sequential hash of its description using Poseidon2 hasher. The circuit description, +#! containing both constants and evaluation gates description, is stored starting at +#! `ACE_CIRCUIT_STREAM_PTR` (right after the circuit inputs). The evaluation gates portion begins at +#! `ACE_CIRCUIT_PTR`. The variable part of the circuit input is stored at the contiguous memory #! region starting at `pi_ptr`. The (variable) inputs to the circuit are laid out such that the #! aforementioned memory regions are together contiguous with the (variable) inputs section. #! #! Inputs: [] #! Outputs: [] pub proc execute_constraint_evaluation_check() - # Compute and store at the appropriate memory location the auxiliary inputs needed by - # the arithmetic circuit. + # Compute and store all stark vars at the appropriate memory location. push.MAX_CYCLE_LEN_LOG exec.utils::set_up_auxiliary_inputs_ace # => [] @@ -81,9 +74,9 @@ end proc load_ace_circuit_description push.CIRCUIT_COMMITMENT adv.push_mapval - exec.constants::get_arithmetic_circuit_ptr + exec.constants::ace_circuit_stream_ptr padw padw padw - repeat.14 + repeat.765 adv_pipe exec.poseidon2::permute end @@ -93,121 +86,773 @@ proc load_ace_circuit_description # => [] end - # CONSTRAINT EVALUATION CIRCUIT DESCRIPTION # ================================================================================================= adv_map CIRCUIT_COMMITMENT = [ - 1, - 0, - 0, - 0, - 2305843126251553075, - 114890375379, - 2305843283017859381, - 2305843266911732021, - 1152921616275996777, - 2305843265837990197, - 1152921614128513127, - 2305843319525081397, - 1152921611981029477, - 2305843318451339573, - 1152921609833545827, - 2305843317377597749, - 1152921607686062177, - 2305843316303855925, - 1152921605538578527, - 1152921604464836831, - 1152921614128513128, - 1152921602317353060, - 1152921601243611234, - 1152921600169869408, - 1152921599096127582, - 1152921598022385920, - 2305843101555490908, - 1152921604464836735, - 1152921614128513129, - 1152921593727418468, - 1152921592653676642, - 1152921591579934816, - 1152921590506192990, - 1152921776263528702, - 270582939757, - 1152921587284967502, - 1152921586211225679, - 1152921611981029479, - 1152921584063742050, - 1152921582990000224, - 1152921581916258398, - 1152921580842516556, - 2305843084375621707, - 1152921609833545829, - 1152921577621291104, - 1152921576547549278, - 315680096365, - 1152921574400065828, - 314606354541, - 1152921572252581952, - 1152921571178840130, - 2305843074711945285, - 1152921607686062179, - 1152921567957614686, - 1152921566883872830, - 2305843070416977980, - 1152921605538578529, - 1152921563662647358, - 2305843067195752504, - 1152921571178840159, - 2305843065048268853, - 2305843063974527060, - 53687091285, - 333933707485, - 117037858930, - 118111600754, - 120259084402, - 117037858929, - 1152921557220196467, - 2305843055384592490, - 1152921553998970927, - 1152921548630261805, - 1152921547556519982, - 1152921546482778154, - 1152921628087156851, - 1152921544335294771, - 1152921544335294579, - 1152921542187811039, - 2305843045720916004, - 1152921542187810931, - 1152921538966585392, - 2305843042499690529, - 1152921551851487278, - 1152921535745359902, - 2305843039278465062, - 1152921538966585459, - 1152921532524134623, - 1152921551851487279, - 1152921530376650777, - 2305843033909755931, - 1152921625939673300, - 2305843031762272469, - 1152921526081683569, - 2305843029614788822, - 1152921523934199921, - 2305843027467305175, - 1152921521786716273, - 2305843025319821528, - 1152921519639232625, - 2305843023172337881, - 1152921517491748977, - 2305843021024854234, - 1152921515344265329, - 2305843018877370587, - 1152921548630261804, - 1152921512123039752, - 6442450966, - 1152921509975556101, - 1152921508901814276, - 1152921507828072451, - 1152921506754330626, - 1152921505680588801 + 17293822565076172801,0,0,0,11529215043384115201,0,299140176084720,0, + 1152921504339460096,0,72039928838487824,0,1152903912152367104,0,18374422528162594833,0, + 1152921573057888240,0,71758595593666800,0,18446480251047444721,0,1152921504337362944,0, + 18374668818767151377,0,1152939096524455936,0,72356588187222032,0,1152921435618934800,0, + 18374950426885684977,0,10376293539045703681,0,1224679958200254480,0,18446744069413535745,0, + 1080600096228311280,0,18446726477228539905,0,1153185451552472816,0,18446744000695107601,0, + 1080881438063066896,0,1081127728667623440,0,1048576,0,1225278234257456880,0, + 17592186044416,0,1152622510189117680,0,68719476720,0,1224996617548988688,0, + 256,0,4294967296,0,72057594037927936,0,281474976645120,0, + 1152921504338411520,0,18446744069414584065,0,18446744065119617025,0,18374686475376656385,0, + 18446462594437939201,0,13506450331346961525,0,1220060926486833092,0,15289945474699020367,0, + 10080285661408854814,0,7056201302604023426,0,13870961636502358441,0,11181970014612250858,0, + 2263989043493551858,0,7021945588023361315,0,3637755601080351657,0,11994061785393688135,0, + 15933964477054035317,0,14303114990560505081,0,13712991196315763967,0,5649818220516819012,0, + 2281722520371668701,0,16179464883396004044,0,5508577990254168895,0,12900944264650033356,0, + 1790798523172755581,0,648527659962338404,0,7000883374074734167,0,11976864282148750745,0, + 4345701392714390734,0,14648803090404994705,0,2559539914729344226,0,8063653970832556457,0, + 8752889350027678997,0,5399077151114037649,0,14286750482834966066,0,9533880535744934927,0, + 9040200629101104401,0,8830665781029957836,0,14880754969559215189,0,10115872490820423390,0, + 122922138494589770,0,6049475111361333809,0,3816230378359147739,0,16485436779640540592,0, + 15999160671148163603,0,7793391273136215850,0,7375453422563383092,0,15727465800456661448,0, + 17604474207884486051,0,16311278769261608080,0,12229019500121537086,0,5115474250774582499,0, + 9853196461104309197,0,17881666388449638104,0,16666394781378211508,0,13485721503250451362,0, + 17538579226039010365,0,9324358263331059291,0,9431224685432275531,0,14352769487075254372,0, + 10394000667754223111,0,3863742218954159982,0,9189088713770063131,0,17882368282699348817,0, + 2669874548580171960,0,11609388145590593001,0,3715890505894502683,0,9146314019201542231,0, + 9494531110289004550,0,1215846508483385725,0,10769472835802134382,0,15120084924436367840,0, + 2409854718166686917,0,12611807655159677898,0,6194600797308869879,0,15985800743640437130,0, + 13706629396021380488,0,17226312540324137322,0,17076998920676414740,0,10714455172347297500,0, + 10737646911324969129,0,15549715087232586323,0,14098088243370493341,0,12378208969032677709,0, + 7362195708571034250,0,1942698693963992628,0,7528813266379185038,0,9937467207233454003,0, + 16664378465012507901,0,4872475500441857048,0,14329983667734104309,0,5783837547550234175,0, + 17085344416645756047,0,14235112306529067868,0,13792136309666777285,0,6563429178210015618,0, + 6034349441124231390,0,11452553603455937636,0,2866957227454593452,0,9124371651607698999,0, + 4056726964389686874,0,681014837720862499,0,3303119831890681118,0,12294872131488898818,0, + 9562093600544865194,0,10290167051015114909,0,3610766868984241006,0,7399723478196938523,0, + 7940490424257645340,0,7566343854685332757,0,3118114980642221848,0,36505548729526372,0, + 14881263750443725044,0,2471080946433257851,0,7229836574508822565,0,10172039981998141256,0, + 1266061798995870870,0,13696472808521858472,0,8172540520828620197,0,6066700792379843120,0, + 2902435192254421716,0,17243161309620410771,0,11566354596024378109,0,18436205014769240465,0, + 12942016006619377473,0,4428364532927351915,0,17550708978324807967,0,3227074310485866338,0, + 10526784394206789892,0,1012812621152338313,0,10627553279586214293,0,13544218254559197214,0, + 3366616676571496961,0,1185926521574269147,0,2797137607232632471,0,7378476058878128673,0, + 11472823999425505273,0,6426770371114890086,0,8344543475752135508,0,2037711414516144606,0, + 1002212915765425025,0,15429253385178963727,0,1884175150292008318,0,8517525717352190773,0, + 17078912966192349589,0,3702396818487532663,0,16813028956792564865,0,11770956504672294412,0, + 15502925789736377359,0,10108618202177051889,0,10058246739382562279,0,2898550573977775146,0, + 15414823412825521822,0,13635735147884026055,0,8534910183325198132,0,6894925738120887046,0, + 1155604511900039128,0,14183576722912116648,0,17276011797343470775,0,11800013335275200655,0, + 17472205982442522728,0,4695754115444372153,0,5532398984513739978,0,5543895808451907073,0, + 12763612101924866144,0,3932388051002360716,0,12567328766287897212,0,1898697119458861645,0, + 2757139537974467281,0,9066915857827737439,0,3122781916728353510,0,7367915640346560395,0, + 9477007979080135218,0,10093927718065036845,0,7537861698812080491,0,15882320805449904668,0, + 7372913098978788409,0,14188709260829449414,0,6664771524923680343,0,4438926477479481854,0, + 17369996407673990512,0,3917705574714323619,0,2778663024013093070,0,6365225074103382184,0, + 6394114259051379208,0,1544555490264202584,0,15044592435296754555,0,4793660808636315108,0, + 14101374348988450957,0,12906295516933811002,0,16165137851232782658,0,2914102009105693254,0, + 16882131584667299040,0,7993232952439841307,0,4805821119940375546,0,17571690224505910672,0, + 281377096927929017,0,16140901060737761281,0,2305843008676823041,0,2097152,0, + 18446708885042495489,0,137438953440,0,18446744069412487169,0,35184372088832,0, + 18446743931975630881,0,1,0,65535,0,3,0, + 9,0,27,0,81,0,243,0, + 729,0,2187,0,16,0,8,0, + 7,0,4,0,18446462594437873665,0,18446744069414584320,0, + 281474976710656,0,2,0,4294967295,0,65536,0, + 128,0,5,0,6,0,18446744069414584319,0, + 9223372034707292161,0,9223372034707292160,0,18446744069414584318,0,18446744069414584317,0, + 13835058052060938241,0,4611686017353646080,0,17850970025369572891,0,0,1, + 18,0,22,0,19,0,87,0, + 84,0,85,0,108,0,13,0, + 4294967294,0,2147483648,0,104,0,88,0, + 14,0,92,0,10,0,11,0, + 12,0,15,0,17,0,20,0, + 21,0,1073741824,0,1152921504606846976,0,23,0, + 24,0,25,0,1152927754858010309,2305848939489793725,1152927433809204933,2305848937342310077, + 1152927431661721285,2305848935194826429,1152927429514237637,2305848933047342781,1152927427366753989,2305848930899859133,1152927425219270341,2305848928752375485, + 1152927423071786693,2305848926604891837,1152927420924303045,2305848924457408189,1152927418776819397,2305848922309924541,1152927416629335749,2305848920162440893, + 1152927414481852101,2305848918014957245,1152927412334368453,2305848915867473597,1152927410186884805,2305848913719989949,1152927408039401157,2305848911572506301, + 1152927405891917509,2305848909425022653,1152927737678141125,2305848907277538990,1152927401596950213,2305848905130055343,1152927399449466565,2305848902982571696, + 1152927397301982917,2305848900835088049,1152927395154499269,2305848898687604402,1152927393007015621,2305848896540120755,1152927390859531973,1152927389785790149, + 2305848893318895284,1152927387638306501,2305848891171411637,1152927385490822853,2305848889023927990,1152927383343339205,2305848886876444343,1152927381195855557, + 2305848884728960696,1152927379048371909,2305848882581477049,1152927376900888261,2305848880433993402,1152927374753404613,2305848878286509755,1152927721572013765, + 2305848876139026079,1152927370458437317,2305848873991542432,1152927368310953669,2305848871844058785,1152927366163470021,2305848869696575138,1152927364015986373, + 2305848867549091491,1152927361868502725,2305848865401607844,1152927359721019077,2305848863254124221,1152927357573535429,2305848861106640549,1152927355426051781, + 2305848858959156902,1152927353278568133,2305848856811673255,1152927351131084485,2305848854664189608,1152927348983600837,2305848852516705961,1152927346836117189, + 2305848850369222314,1152927344688633541,2305848848221738667,1152927342541149893,2305848846074255020,1152927711908337349,2305848843926771366,1152927338246182597, + 2305848841779287702,1152927336098698949,2305848839631804072,1152927333951215301,2305848837484320407,1152927331803731653,2305848835336836778,1152927329656248005, + 2305848833189353112,1152927327508764357,2305848831041869465,1152927325361280709,2305848828894385818,1152927323213797061,2305848826746902175,1152927321066313413, + 2305848824599418523,1152927318918829765,2305848822451934881,1152927316771346117,2305848820304451228,1152927314623862469,2305848818156967587,1152927312476378821, + 2305848816009483933,1152927310328895173,2305848813862000317,1152927694728468165,2305848811714516614,1152927306033927877,2305848809567032967,1152927303886444229, + 2305848807419549320,1152927301738960581,2305848805272065673,1152927299591476933,2305848803124582026,1152927297443993285,2305848800977098379,1152927295296509637, + 2305848798829614732,1152927293149025989,2305848796682131085,1152927291001542341,2305848794534647438,1152927288854058693,2305848792387163791,1152927286706575045, + 2305848790239680144,1152927284559091397,2305848788092196497,1152927282411607749,2305848785944712850,1152927280264124101,2305848783797229203,1152927278116640453, + 2305848781649745556,1152927677548598981,2305848779502261878,1152927273821673157,2305848777354778231,1152927271674189509,2305848775207294584,1152927269526705861, + 2305848773059810937,1152927267379222213,2305848770912327290,1152927265231738565,2305848768764843643,1152927263084254917,2305848766617359996,1152927260936771269, + 2305848764469876349,1152927258789287621,2305848762322392702,1152927256641803973,2305848760174909055,1152927254494320325,2305848758027425408,1152927252346836677, + 2305848755879941761,1152927250199353029,2305848753732458114,1152927248051869381,2305848751584974467,1152927245904385733,2305848749437490820,1152927660368729797, + 2305848747290007142,1152927241609418437,2305848745142523495,1152927239461934789,2305848742995039848,1152927237314451141,2305848740847556201,1152927235166967493, + 2305848738700072554,1152927233019483845,2305848736552588907,1152927230872000197,2305848734405105260,1152927228724516549,2305848732257621613,1152927226577032901, + 2305848730110137966,1152927224429549253,2305848727962654319,1152927222282065605,2305848725815170672,1152927220134581957,2305848723667687025,1152927217987098309, + 2305848721520203378,1152927215839614661,2305848719372719731,1152927213692131013,2305848717225236084,1152927643188860613,2305848715077752406,1152927209397163717, + 2305848712930268759,1152927207249680069,2305848710782785112,1152927205102196421,2305848708635301465,1152927202954712773,2305848706487817818,1152927200807229125, + 2305848704340334171,1152927198659745477,2305848702192850524,1152927196512261829,2305848700045366877,1152927194364778181,2305848697897883230,1152927192217294533, + 2305848695750399583,1152927190069810885,2305848693602915936,1152927187922327237,2305848691455432289,1152927185774843589,2305848689307948642,1152927183627359941, + 2305848687160464995,1152927181479876293,2305848685012981348,1152927626008991429,2305848682865497670,1152927177184908997,2305848680718014023,1152927175037425349, + 2305848678570530376,1152927172889941701,2305848676423046729,1152927170742458053,2305848674275563082,1152927168594974405,2305848672128079435,1152927166447490757, + 2305848669980595788,1152927164300007109,2305848667833112141,1152927162152523461,2305848665685628494,1152927160005039813,2305848663538144847,1152927157857556165, + 2305848661390661200,1152927155710072517,2305848659243177553,1152927153562588869,2305848657095693906,1152927151415105221,2305848654948210259,1152927149267621573, + 2305848652800726612,1152927608829122245,2305848650653242934,1152927144972654277,2305848648505759287,1152927142825170629,2305848646358275640,1152927140677686981, + 2305848644210791993,1152927138530203333,2305848642063308346,1152927136382719685,2305848639915824699,1152927134235236037,2305848637768341052,1152927132087752389, + 2305848635620857405,1152927129940268741,2305848633473373758,1152927127792785093,2305848631325890111,1152927125645301445,2305848629178406464,1152927123497817797, + 2305848627030922817,1152927121350334149,2305848624883439170,1152927119202850501,2305848622735955523,1152927117055366853,2305848620588471876,1152927591649253061, + 2305848618440988198,1152927112760399557,2305848616293504551,1152927110612915909,2305848614146020904,1152927108465432261,2305848611998537257,1152927106317948613, + 2305848609851053610,1152927104170464965,2305848607703569963,1152927102022981317,2305848605556086316,1152927099875497669,2305848603408602669,1152927097728014021, + 2305848601261119022,1152927095580530373,2305848599113635375,1152927093433046725,2305848596966151728,1152927091285563077,2305848594818668081,1152927089138079429, + 2305848592671184434,1152927086990595781,2305848590523700787,1152927084843112133,2305848588376217140,1152927574469383877,2305848586228733462,1152927080548144837, + 2305848584081249815,1152927078400661189,2305848581933766168,1152927076253177541,2305848579786282521,1152927074105693893,2305848577638798874,1152927071958210245, + 2305848575491315227,1152927069810726597,2305848573343831580,1152927067663242949,2305848571196347933,1152927065515759301,2305848569048864286,1152927063368275653, + 2305848566901380639,1152927061220792005,2305848564753896992,1152927059073308357,2305848562606413345,1152927056925824709,2305848560458929698,1152927054778341061, + 2305848558311446051,1152927052630857413,2305848556163962404,1152927557289514693,2305848554016478726,1152927048335890117,2305848551868995079,1152927046188406469, + 2305848549721511432,1152927044040922821,2305848547574027785,1152927041893439173,2305848545426544138,1152927039745955525,2305848543279060491,1152927037598471877, + 2305848541131576844,1152927035450988229,2305848538984093197,1152927033303504581,2305848536836609550,1152927031156020933,2305848534689125903,1152927029008537285, + 2305848532541642256,1152927026861053637,2305848530394158609,1152927024713569989,2305848528246674962,1152927022566086341,2305848526099191315,1152927020418602693, + 2305848523951707668,1152927540109645509,2305848521804223990,1152927016123635397,2305848519656740343,1152927013976151749,2305848517509256696,1152927011828668101, + 2305848515361773049,1152927009681184453,2305848513214289402,1152927007533700805,2305848511066805755,1152927005386217157,2305848508919322108,1152927003238733509, + 2305848506771838461,1152927001091249861,2305848504624354814,1152926998943766213,2305848502476871167,1152926996796282565,2305848500329387520,1152926994648798917, + 2305848498181903873,1152926992501315269,2305848496034420226,1152926990353831621,2305848493886936579,1152926988206347973,2305848491739452932,1152927522929776325, + 2305848489591969254,1152926983911380677,2305848487444485607,1152926981763897029,2305848485297001960,1152926979616413381,2305848483149518313,1152926977468929733, + 2305848481002034666,1152926975321446085,2305848478854551019,1152926973173962437,2305848476707067372,1152926971026478789,2305848474559583725,1152926968878995141, + 2305848472412100078,1152926966731511493,2305848470264616431,1152926964584027845,2305848468117132784,1152926962436544197,2305848465969649137,1152926960289060549, + 2305848463822165490,1152926958141576901,2305848461674681843,1152926955994093253,2305848459527198196,1152927505749907141,2305848457379714518,1152926951699125957, + 2305848455232230871,1152926949551642309,2305848453084747224,1152926947404158661,2305848450937263577,1152926945256675013,2305848448789779930,1152926943109191365, + 2305848446642296283,1152926940961707717,2305848444494812636,1152926938814224069,2305848442347328989,1152926936666740421,2305848440199845342,1152926934519256773, + 2305848438052361695,1152926932371773125,2305848435904878048,1152926930224289477,2305848433757394401,1152926928076805829,2305848431609910754,1152926925929322181, + 2305848429462427107,1152926923781838533,2305848427314943460,1152927763447944901,1152927504676164532,2305848424093717972,1152926918413128628,2305848421946234324, + 1152926916265644980,2305848419798750676,1152926914118161332,2305848417651267028,1152926911970677684,2305848415503783380,1152926909823194036,2305848413356299732, + 1152926907675710388,2305848411208816084,1152927497159971764,2305848409061332430,1152926903380743092,2305848406913848783,1152926901233259444,2305848404766365140, + 1152926899085775796,2305848402618881488,1152926896938292148,2305848400471397841,1152926894790808500,2305848398323914194,1152926892643324852,2305848396176430547, + 5991479383910,1152926889422100326,5991479383890,1152926887274616658,1152926888348358343,2305848389733979028,2305849419452389222,5991479382929, + 1152926881905906577,1152926884053391047,2305848384365269903,2305849307783239422,5991479382924,1152926876537198438,1152926875463456450,1152926878684681927, + 2305848377922818953,1152927824651229010,1152926871168489154,1152926872242230983,2305848373627851653,5378372801996,1152926866873521918,1152926865799780034, + 1152926867947263687,2305848368259142528,1152926866873521898,1152926861504812738,1152926862578554567,2305848363964175228,5991479383909,1152926857209845605, + 1152926856136102786,1152926858283587271,2305848358595466103,1152927935246635906,5991479383908,1152926850767394660,1152926849693651828,1152926852914878151, + 2305848352153015153,1152927934172894068,5991479383907,1152926844324943715,1152926843251200878,1152926846472427207,2305848345710564203,1152927933099152238, + 5991479383906,1152926837882492770,1152926836808749928,1152926840029976263,2305848339268113253,6430639789821,1152926832513782644,1152926831440041666, + 1152926833587525319,2305848333899404128,6429566047996,1152926827145073518,1152926826071332546,1152926828218816199,2305848328530695003,6428492306171, + 1152926821776364392,1152926820702623426,1152926822850107079,2305848323161985878,1152927932025410408,6427418564346,1152926815333913427,1152926814260172482, + 1152926817481397959,2305848316719534928,1152927761300461414,1152926811038947015,2305848313498309453,1152927761300461394,1152926807817721543,2305848310277083978, + 1152927761300460409,1152926804596496071,2305848307055858503,1152927761300460403,1152926801375270599,2305848303834633028,1152927761300460397,1152926798154045127, + 2305848300613407553,1152927761300460391,1152926794932819655,2305848297392182078,1152927991081211588,1152926791711594183,2305848294170956603,2305849495688058316, + 5282809780017,1152926786342885058,1152926788490368711,2305848288802247478,6474663204300,1152927981417535375,1152926780974175027,1152927959942697777, + 6477884429772,1152926777752949554,6478958171596,1152926775605465902,1152926774531725181,2305848278064829232,5282809780016,1152926771310498602, + 1152926770236757698,1152926783121659591,2305848272696120103,6476810687948,1152926765941790607,1152926764868047667,1152926763794306940,1152926762720565040, + 1152926761646823106,1152926767015532231,2305848264106185503,2305848267327410992,2305848261958701867,6475736946124,1152926755204371236,1152926754130630542, + 1152926753056888700,2305848256589992731,5246302557644,6485400622896,1152926748761920277,1152926747688179394,1152926758425597639,2305848250147541778, + 6471441979183,1152926743393211178,1152926742319470274,1152926744466953927,2305848244778832653,6470368237358,1152926738024502058,1152926736950761154, + 1152926739098244807,2305848239410123528,6469294495533,1152926732655792938,1152926731582052034,1152926733729535687,2305848234041414403,6468220753708, + 1152926727287083818,1152926726213342914,1152926728360826567,2305848228672705278,2305848256589992746,5217311528396,6484326881071,1152926719770891002, + 1152926718697150146,1152926722992117447,2305848221156512503,6483253139246,1152926714402181882,1152926713328441026,1152926715475924679,2305848215787803378, + 6482179397421,1152926709033472762,1152926707959731906,1152926710107215559,2305848210419094253,6481105655596,1152926703664763642,1152926702591022786, + 1152926704738506439,2305848205050385128,1152927937394120388,1152926699369797319,2305848201829159653,5990405642087,1152926695074830019,1152926696148571847, + 2305848197534192353,6432787273471,5991479382750,1152926689706119902,5989331899102,1152926687558636252,5988258157278,1152926685411152602, + 5987184415454,1152926683263668952,5986110673630,1152926681116185302,5985036931806,1152926678968701652,5983963189982,1152926676821218002, + 5982889448158,1152926674673734352,1152926673599993538,1152926691853604551,2305848176059355853,6473589462476,1152926669305025331,6472515720652, + 1152926667157541577,1152926754130629423,1152926665010057927,1152926663936316205,1152927977122566858,1152926661788832563,1152926764868048785,1152926659641348802, + 2305848163174453956,1152926665010059154,1152926656420124541,1152926755204372368,1152926654272640913,1152926653198897965,1152926652125157245,2305848155658261181, + 2305848154584519359,1152926653198899090,1152926647830189949,1152926669305026446,1152926645682705096,1152927982491276082,1152926643535221427,1152926642461480850, + 2305848145994584757,1152926764868048782,1152926639240255356,1152926780974176142,1152926637092771708,2305848140625875629,2305848139552133807,2305848138478391991, + 6466073269708,1152926631724061463,2305848135257166640,2305848134183424680,1152927978196308787,1152926627429094088,1152926626355352262,1152926625281610541, + 1152926659641348807,1152926666083799854,2305848126667231903,1152926644608963270,1152926754130630545,1152926618839159475,2305848122372264604,2305848121298522781, + 1152926654272639791,1152926614544192179,1152926644608963259,2305848117003555478,1152926644608963265,2305848114856071828,2305848113782330008,1152926608101742482, + 2305848111634846368,1152926764868047663,1152926604880515746,1152926603806775186,1152926626355352366,1152926601659291538,2305848105192395404,2305848104118653583, + 1152926626355352242,1152926597364323117,1152926597364324242,2305848099823686278,1152926614544192301,1152926593069356925,1152926614544193426,1152926590921873277, + 2305848094454977154,2305848093381235332,2305848092307493512,1152927970680115991,1152926604880515885,1152926584479422333,2305848088012526204,2305848086938784555, + 2305848085865042557,2305848084791300772,1152926579110713107,1152927958868955812,1152927957795213943,2305848080496333428,5070208897653,1152926573742003906, + 1152926670378768071,2305848076201366128,1152926663936317330,2305848074053882564,1152926618839159495,1152926567299552045,2305848070832657004,1152926567299553170, + 2305848068685173353,1152926614544192199,1152926561930842925,2305848065463947879,1152926561930844050,2305848063316464228,1152926653198897863,1152926556562133805, + 2305848060095238754,1152926556562134930,2305848057947755103,5158255727197,2305848055800271524,1152926625281611666,2305848053652787872,1152926618839159458, + 1152926546898457389,2305848050431562329,1152926546898458514,2305848048284078678,1152926614544192162,1152926541529748269,2305848045062853204,1152926541529749394, + 2305848042915369553,1152926626355352251,1152926536161039149,2305848039694144079,1152926536161040274,2305848037546660428,5119601021514,2305848035399176823, + 2305848034325434971,1152927978196309902,1152926527571104456,1152926526497362630,1152926525423620909,1152926525423622034,2305848027882984003,1152926526497362587, + 1152926521128653613,2305848024661758529,1152926521128654738,2305848022514274878,1152926526497362583,1152926515759944493,2305848019293049404,1152926515759945618, + 2305848017145565753,1152926526497362619,1152926510391235373,2305848013924340279,1152926510391236498,2305848011776856628,1152926526497362574,1152926505022526253, + 2305848008555631154,1152926505022527378,2305848006408147503,1152926526497362625,1152926499653817133,2305848003186922029,1152926499653818258,2305848001039438378, + 1152926526497362734,1152926494285108013,2305847997818212904,1152926494285109138,2305847995670729253,1152926526497362610,1152926488916398893,2305847992449503779, + 1152926488916400018,2305847990302020128,1152926659641350034,1152926483547690877,2305847987080794654,1152926608101741357,2305847984933311003,2305847983859569223, + 1152926478178981650,1152926550119683962,1152927956721472072,2305847979564601878,1152926479252723579,2305847977417118228,4967129682455,1152926470662788802, + 1152926570520778439,2305847973122150928,1152926604880515783,1152926466367820589,1152926660715090714,2305847968827183628,2305847967753441883,1152926626355352257, + 1152926460999111469,1152926660715090734,2305847963458474503,1152926643535221442,2305847961310990853,1152926623134128018,4949949813251,2305847958089765448, + 2305847957016023561,1152926604880515778,2305847954868539929,2305847953794798079,1152926448114210577,1152926462072854393,1152927955647730176,2305847949499830778, + 1152926449187952506,2305847947352347128,4937064911355,1152926440598017730,1152926467441563335,2305847943057379828,2305847966679700127,1152926622060386194, + 4930622461628,2305847938762412544,2305847937688670705,1152926623134126893,4926327494332,2305847934467445245,2305847933393703405,1152926427713115920, + 1152926436303050616,1152927954573988334,2305847929098736103,1152926428786857849,2305847926951252453,4916663816680,1152926420196923074,1152926437376792263, + 2305847922656285153,1152926643535221447,2305847920508801694,1152926644608963374,1152926604880515763,1152926412680730514,2305847916213834204,2305847915140092381, + 1152926754130629427,1152926408385763196,2305847911918866904,2305847910845125105,1152926601659290413,1152926619912902546,4898410205651,2305847906550157806, + 2305847905476415956,1152926622060385069,4894115239612,2305847902255190506,2305847901181448655,1152926395500861199,1152926405164537719,1152927953500246480, + 2305847896886481353,1152926396574603128,2305847894738997703,4884451561930,1152926387984668354,1152926416975697607,2305847890444030403,2305847909771383452, + 1152926617765418898,4878009112252,2305847886149063120,2305847885075321280,1152926619912901421,4873714144956,2305847881854095820,2305847880780353980, + 1152926375099766542,1152926383689701238,1152927952426504637,2305847876485386678,1152926376173508471,2305847874337903028,4864050467255,1152926367583573698, + 1152926384763442887,2305847870042935728,2305847888296546970,1152926613470451602,4857608017596,2305847865747968445,2305847864674226605,1152926617765417773, + 4853313050300,2305847861453001145,2305847860379259305,1152926354698671885,1152926363288606581,1152927951352762794,2305847856084292003,1152926355772413814, + 2305847853936808353,4843649372580,1152926347182479042,1152926364362348231,2305847849641841053,2305847867895452310,1152926612396709778,4837206922940, + 2305847845346873770,2305847844273131930,1152926613470450477,4832911955644,2305847841051906470,2305847839978164630,1152926334297577228,1152926342887511924, + 1152927950279020951,2305847835683197328,1152926335371319157,2305847833535713678,4823248277905,1152926326781384386,1152926343961253575,2305847829240746378, + 1152926412680729389,2305847827093262997,4909147623814,2305847824945779098,1152926460999112594,1152926610249226130,4812510859651,2305847820650811799, + 2305847819577069956,1152926612396708653,4808215893692,2305847816355844499,2305847815282102655,1152926309601515275,1152926319265191795,1152927949205279104, + 2305847810987135353,1152926310675257204,2305847808839651703,4798552215930,1152926302085322434,1152926323560158919,2305847804544684403,2305847823872037523, + 2305847802397200768,1152926610249225005,4791036024508,2305847799175975292,2305847798102233455,1152926292421646090,1152926297790355314,1152927948131537280, + 2305847793807266153,1152926293495388019,2305847791659782503,4781372346730,1152926284905453250,1152926298864096967,2305847787364815203,1152927836462387563, + 1152927948131537264,1152927947057795456,2305847783069847903,1152926293495388018,2305847780922364253,4770634928480,1152926274168035010,1152926281684227783, + 2305847776627396953,1152927835388645739,1152927947057795440,1152927945984053632,2305847772332429653,1152927948131537260,2305847770184946003,4759897510230, + 1152926263430616770,1152926270946809543,2305847765889978703,1152926665010058029,1152926259135649661,2305847762668753372,1152926413754472338,4751307575626, + 2305847759447527792,2305847758373785984,2305847757300044140,1152926251619456775,1152926253766940527,1152927944910311808,2305847753005076803,1152927947057795436, + 2305847750857593153,4740570157380,1152926244103263938,1152926260209391303,2305847746562625853,1152927833241162053,1152927944910311751,1152927943836569984, + 2305847742267658553,1152927945984053612,2305847740120174903,4729832739130,1152926233365845698,1152926240882038471,2305847735825207603,1152927832167420229, + 1152927943836569927,1152927942762828160,2305847731530240303,1152927944910311788,2305847729382756653,4719095320880,1152926222628427458,1152926230144620231, + 2305847725087789353,2305847758373785964,1152926218333460228,1152927942762828103,1152927943836569964,2305847719719080228,4709431644453,1152926212964751042, + 1152926219407201991,2305847715424112928,5981815707499,1152926208669783748,1152926209743525575,2305847711129145628,1152926208669783747,1152926205448558279, + 2305847707907920153,1152927940615345860,1152926202227332807,2305847704686694678,1152927940615345859,1152926199006107335,2305847701465469203,6437082240771, + 2305848267327410986,4689030550988,2305849473139480453,1152926191489913623,4685809324302,1152926189342429456,1152926667157542797,1152926187194946355, + 1152926660715091855,1152926185047463824,2305847688580567304,2305847687506825855,1152926654272640910,1152926180752496508,2305847684285600380,2305847683211858554, + 2305847682138116356,1152927939541602589,1152926175383785727,2305847678916890890,1152926187194947470,2305847676769407516,2305847675695665662,4665408229628, + 5981815707395,1152926167867592975,2305847671400698104,1152926165720110786,1152926195784881863,2305847668179472628,4670776939980,1152926161425142045, + 1152926162498885319,2305847663884505328,6486474364674,1152926157130174713,1152926156056434370,1152926158203918023,2305847658515796203,1152926176457529092, + 1152926151761465585,1152926150687725250,1152926152835208903,2305847653147087078,1152926524349880083,1152926146392757954,1152926147466499783,2305847648852119778, + 6454262109971,1152926142097789506,1152926141024048834,1152926143171532487,2305847643483410653,6453188368147,1152926136729080383,1152926135655339714, + 1152926137802823367,2305847638114701528,6452114626323,1152926131360371261,1152926130286630594,1152926132434114247,2305847632745992403,6451040884499, + 1152926125991662138,1152926124917921474,1152926127065405127,2305847627377283278,6449967142675,1152926120622953016,1152926119549212354,1152926121696696007, + 2305847622008574153,6448893400851,1152926115254243893,1152926114180503234,1152926116327986887,2305847616639865028,6447819659027,1152926109885534771, + 1152926108811794114,1152926110959277767,2305847611271155903,6446745917203,1152926104516825648,1152926103443084994,1152926105590568647,2305847605902446778, + 6444598433555,1152926099148116526,1152926098074375874,1152926100221859527,2305847600533737653,6442450949907,1152926093779407403,1152926092705666754, + 1152926094853150407,2305847595165028528,6440303466259,1152926088410698281,1152926087336957634,1152926089484441287,2305847589796319403,6438155982611, + 1152926083041989158,1152926081968248514,1152926084115732167,2305847584427610278,6486474364691,1152926077673280031,1152926076599539394,1152926078747023047, + 2305847579058901153,1152926136729080332,1152926072304572098,1152926073378313927,2305847574763933853,6454262109970,1152926068009603596,1152926066935862978, + 1152926069083346631,2305847569395224728,1152926131360371180,1152926062640895682,1152926063714637511,2305847565100257428,1152926125991662030,1152926058345928386, + 1152926059419670215,2305847560805290128,1152926120622952891,1152926054050961090,1152926055124702919,2305847556510322828,1152926115254243752,1152926049755993794, + 1152926050829735623,2305847552215355528,1152926109885534613,1152926045461026498,1152926046534768327,2305847547920388228,1152926104516825470,1152926041166059202, + 1152926042239801031,2305847543625420928,6445672175379,1152926036871090542,1152926035797350082,1152926037944833735,2305847538256711803,6454262109969, + 1152926031502381570,1152926030428640962,1152926032576124615,2305847532888002678,6454262109968,1152926026133672432,1152926025059931842,1152926027207415495, + 2305847527519293553,6454262109967,1152926020764963282,1152926019691222722,1152926021838706375,2305847522150584428,6454262109966,1152926015396254143, + 1152926014322513602,1152926016469997255,2305847516781875303,6454262109965,1152926010027545004,1152926008953804482,1152926011101288135,2305847511413166178, + 6454262109964,1152926004658835865,1152926003585095362,1152926005732579015,2305847506044457053,6454262109963,1152925999290126722,1152925998216386242, + 1152926000363869895,2305847500675747928,1152926120622952839,1152925993921418946,1152925994995160775,2305847496380780628,6448893400850,1152925989626450311, + 1152925988552709826,1152925990700193479,2305847491012071503,6447819659025,1152925984257741191,1152925983184000706,1152925985331484359,2305847485643362378, + 6446745917200,1152925978889032071,1152925977815291586,1152925979962775239,2305847480274653253,1152926020764963207,1152925973520324290,1152925974594066119, + 2305847475979685953,6453188368142,1152925969225355655,1152925968151615170,1152925970299098823,2305847470610976828,6452114626317,1152925963856646535, + 1152925962782906050,1152925964930389703,2305847465242267703,6451040884492,1152925958487937415,1152925957414196930,1152925959561680583,2305847459873558578, + 1152926413754471213,1152925953119228029,1152925952045487810,1152925954192971463,2305847454504849453,6444598433554,1152925947750518831,1152925946676778690, + 1152925948824262343,2305847449136140328,6443524691729,1152925942381809711,1152925941308069570,1152925943455553223,2305847443767431203,6442450949904, + 1152925937013100591,1152925935939360450,1152925938086844103,2305847438398722078,1152925953119227994,1152925931644393154,1152925932718134983,2305847434103754778, + 6453188368138,1152925927349424175,1152925926275684034,1152925928423167687,2305847428735045653,6452114626313,1152925921980715055,1152925920906974914, + 1152925923054458567,2305847423366336528,6451040884488,1152925916612005935,1152925915538265794,1152925917685749447,2305847417997627403,6441377208083, + 1152925911243297097,1152925910169556674,1152925912317040327,2305847412628918278,6440303466258,1152925905874587977,1152925904800847554,1152925906948331207, + 2305847407260209153,6439229724433,1152925900505878857,1152925899432138434,1152925901579622087,2305847401891500028,6438155982608,1152925895137169737, + 1152925894063429314,1152925896210912967,2305847396522790903,6454262109959,1152925889768460617,1152925888694720194,1152925890842203847,2305847391154081778, + 6453188368134,1152925884399751497,1152925883326011074,1152925885473494727,2305847385785372653,6452114626309,1152925879031042377,1152925877957301954, + 1152925880104785607,2305847380416663528,6451040884484,1152925873662333257,1152925872588592834,1152925874736076487,2305847375047954403,1152926642461479725, + 1152925868293623933,1152925867219883714,1152925869367367367,2305847369679245278,1152925868293623850,1152925862924916418,1152925863998658247,2305847365384277978, + 1152925868293623845,1152925858629949122,1152925859703690951,2305847361089310678,1152925868293623840,1152925854334981826,1152925855408723655,2305847356794343378, + 6441377208079,1152925850040012768,1152925848966272706,1152925851113756359,2305847351425634253,6440303466254,1152925844671303648,1152925843597563586, + 1152925845745047239,2305847346056925128,6439229724429,1152925839302594528,1152925838228854466,1152925840376338119,2305847340688216003,6438155982604, + 1152925833933885408,1152925832860145346,1152925835007628999,2305847335319506878,1152925868293623898,1152925828565178050,1152925829638919879,2305847331024539578, + 1152925868293623831,1152925824270210754,1152925825343952583,2305847326729572278,1152925868293623826,1152925819975243458,1152925821048985287,2305847322434604978, + 1152925868293623821,1152925815680276162,1152925816754017991,2305847318139637678,6449967142663,1152925811385307104,1152925810311567042,1152925812459050695, + 2305847312770928553,6448893400838,1152925806016597984,1152925804942857922,1152925807090341575,2305847307402219428,6447819659013,1152925800647888864, + 1152925799574148802,1152925801721632455,2305847302033510303,6446745917188,1152925795279179744,1152925794205439682,1152925796352923335,2305847296664801178, + 5991479383931,1152925789910472571,1152925788836729351,1152925787762988738,1152925790984214215,2305847290222350228,1152927956721473403,6454262109644, + 1152925782394279802,2305847285927382929,4275639949075,1152925779173052935,1152925778099312322,1152925784541763271,2305847280558673803,1152927957795215227, + 1152925782394279801,2305847277337448328,4267050014482,1152925770583118343,1152925769509377730,1152925774878086855,2305847271968739203,1152925788836729219, + 1152925765214410434,1152925766288152263,2305847267673771903,1152927953500247931,2305847265526288271,4255238854419,1152925758771958147,1152925757698217666, + 1152925761993184967,2305847260157579128,1152927952426506107,2305847258010095495,4247722661650,1152925751255765379,1152925750182024898,1152925754476992199, + 2305847252641386353,1152927951352764283,1152925782394279800,2305847249420160878,4239132727057,1152925742665830787,1152925741592090306,1152925746960799431, + 2305847244051451753,1152927950279022459,1152925782394279799,2305847240830226278,4230542792464,1152925734075896195,1152925733002155714,1152925738370864839, + 2305847235461517153,1152925782394279798,2305847233314033544,4223026599695,1152925726559703427,1152925725485962946,1152925729780930247,2305847227945324378, + 1152925782394279797,2305847225797840785,4215510406926,1152925719043510659,1152925717969770178,1152925722264737479,2305847220429131603,1152927955647731579, + 1152925782394279796,2305847217207906128,4206920472333,1152925710453576067,1152925709379835586,1152925714748544711,2305847211839197003,1152927954573989755, + 1152925782394279795,2305847208617971528,4198330537740,1152925701863641475,1152925700789900994,1152925706158610119,2305847203249262403,1152925789910471328, + 1152925696494933698,1152925697568675527,2305847198954295103,1152926466367821714,6484326881043,1152925691126222652,1152925690052482754,1152925693273708231, + 2305847192511844153,6483253139218,1152925685757513532,1152925684683773634,1152925686831257287,2305847187143135028,6482179397393,1152925680388804412, + 1152925679315064514,1152925681462548167,2305847181774425903,6481105655568,1152925675020095292,1152925673946355394,1152925676093839047,2305847176405716778, + 6437082240787,1152925669651386913,1152925668577646274,1152925670725129927,2305847171037007653,1152926654272639795,1152925664282679164,1152925663208937154, + 6445672175371,1152925661061451552,1152925665356420807,2305847163520814878,6444598433546,1152925656766484256,1152925657840228039,2305847159225847578, + 6443524691721,1152925652471516960,1152925653545260743,2305847154930880278,6442450949896,1152925648176549664,1152925649250293447,2305847150635912978, + 2305848989955659631,4139274737415,1152925642807840544,1152925644955326151,2305847145267203853,2305848989955659630,4133906028294,1152925637439131424, + 1152925639586617031,2305847139898494728,6439229724421,1152925633144164128,1152925634217907911,2305847135603527428,6438155982596,1152925628849196832, + 1152925629922940615,2305847131308560128,1152926604880517010,1152925624554231677,1152926142097790658,1152925622406745852,1152925625627973319,2305847124866109178, + 6453188368146,1152925618111780546,1152925617038036732,1152925619185522375,2305847119497400053,6452114626321,1152925612743071426,1152925611669327612, + 1152925613816813255,2305847114128690928,6451040884496,1152925607374362306,1152925606300618492,1152925608448104135,2305847108759981803,6449967142671, + 1152925602005653186,1152925600931909372,1152925603079395015,2305847103391272678,6448893400846,1152925596636944066,1152925595563200252,1152925597710685895, + 2305847098022563553,6447819659021,1152925591268234946,1152925590194491132,1152925592341976775,2305847092653854428,6446745917196,1152925585899525826, + 1152925584825782012,1152925586973267655,2305847087285145303,1152925661061453506,1152925580530814716,1152925581604558535,2305847082990178003,1152925656766486210, + 1152925576235847420,1152925577309591239,2305847078695210703,1152925652471518914,1152925571940880124,1152925573014623943,2305847074400243403,1152925648176551618, + 1152925567645912828,1152925568719656647,2305847070105276103,6441377208071,1152925563350947522,1152925562277203708,1152925564424689351,2305847064736566978, + 6440303466246,1152925557982238402,1152925556908494588,1152925559055980231,2305847059367857853,1152927973901342601,1152927972827600776,1152925551539787201, + 2305847055072890554,1152925549392303981,1152927972827600777,2305847051851665077,1152925546171078508,1152925545097336257,2305847048630439606,1152927958868957065, + 2305847046482955953,2305847045409216378,4035121780613,1152925538654883580,1152925553687271111,2305847041114246828,1152925546171078509,1152925549392303980, + 2305847037893021353,1152927958868957064,2305847035745537703,4025458104196,1152925528991207164,1152925535433660103,2305847031450570403,1152925549392304009, + 1152925546171078536,1152925523622499777,2305847027155603104,1152925521475016581,1152925549392304008,1152925546171078537,2305847022860635803,1152925517180049284, + 1152925516106307009,2305847019639410332,1152925549392303993,2305847017491926678,1152927955647731593,2305847015344443028,2305847014270703479,4003983267719, + 1152925507516370684,1152925525769983687,2305847009975733903,1152925517180049285,1152925521475016580,2305847006754508428,1152925546171078521,2305847004607024778, + 1152927955647731592,2305847002459541128,3992172107654,1152925495705210620,1152925504295147207,2305846998164573828,1152925521475016583,1152925517180049286, + 1152925490336503233,2305846993869606529,1152925549392303990,2305846991722122878,1152927952426506121,2305846989574639228,2305846988500899700,3978213463813, + 1152925481746568898,1152925480672825084,1152925492483987143,2305846983132188278,1152925517180049287,1152925521475016582,2305846979910962803,1152925546171078518, + 2305846977763479153,1152927952426506120,2305846975615995503,3965328561924,1152925468861667010,1152925467787923196,1152925477451601607,2305846970247286378, + 1152926659641348909,1152925463492958077,1152925462419214075,1152925464566699719,2305846964878577253,1152925462419214070,1152925459197990599,2305846961657351778, + 1152925462419214065,1152925455976765127,2305846958436126303,1152925462419214060,1152925452755539655,2305846955214900828,1152925462419214055,1152925449534314183, + 2305846951993675353,1152925462419214050,1152925446313088711,2305846948772449878,1152925462419214045,1152925443091863239,2305846945551224403,1152925462419214040, + 1152925439870637767,2305846942329998928,1152925462419214036,1152925436649412295,2305846939108773453,1152925462419214032,1152925433428186823,2305846935887547978, + 1152925462419214028,1152925430206961351,2305846932666322503,1152925462419214024,1152925426985735879,2305846929445097028,1152925462419214019,1152925423764510407, + 2305846926223871553,1152925462419214014,1152925420543284935,2305846923002646078,1152927957795215240,1152925416248317377,2305846919781420720,2305846918707678897, + 2305846917633939321,3907346503557,1152925410879606374,1152925417322059463,2305846913338969653,1152927957795215241,2305846911191486118,2305846910117744295, + 2305846909044004728,3898756568964,1152925402289671782,1152925407658383047,2305846904749035053,1152925549392304005,1152925546171078532,1152925396920964545, + 2305846900454067754,1152927954573989769,1152927953500247944,1152925392625997249,2305846896159100454,2305846895085358631,2305846894011619189,3883724183301, + 1152925387257288386,1152925386183544422,1152925399068448455,2305846888642907678,1152925546171078533,1152925549392304004,2305846885421682203,1152927953500247945, + 1152927954573989768,2305846882200456728,2305846881126714905,2305846880052975476,3869765539588,1152925373298644674,1152925372224900710,1152925382962321095, + 2305846874684263953,1152926603806774061,5991479383823,1152925366856193807,1152925365782449678,1152925369003677383,2305846868241813003,5991479383822, + 1152925361487484686,1152925360413740558,1152925362561226439,2305846862873103878,5991479383821,1152925356118775565,1152925355045031438,1152925357192517319, + 2305846857504394753,5991479383820,1152925350750066444,1152925349676322318,1152925351823808199,2305846852135685628,2305849346437945103,2305846849988204301, + 2305846848914462476,5991479381495,1152925342160129550,1152925346455099079,2305846844619492853,1152927483201328903,2305849346437945102,2305846841398269709, + 1152927839683614154,2305846839250783728,2305846838177041906,3827889608562,1152925331422711310,1152925338938906311,2305846833882074603,1152927482127587086, + 2305846831734593295,1152927481053845261,2305846829587107303,1152927479980103436,2305846827439623653,3817152190218,1152925320685293070,1152925328201488071, + 2305846823144656353,1152927948131538698,3811783481221,1152925315316583950,1152925317464069831,2305846817775947228,1152927968532633477,5991479381465, + 1152925309947874830,1152925312095360711,2305846812407238103,1152927968532633454,3801046062985,1152925304579165710,1152925306726651591,2305846807038528978, + 1152927968532633453,3795677353864,1152925299210456590,1152925301357942471,2305846801669819853,4044785457031,1152925294915489294,1152925295989233351, + 2305846797374852553,4041564231558,1152925290620521998,1152925291694266055,2305846793079885253,2305849351806654227,2305849461328320379,6452114626427, + 1152925284178073481,6451040884602,1152925282030589832,1152925280956847553,2305846784489950655,2305846783416208833,3773128773058,1152925276661878286, + 1152925287399298759,2305846779121241528,2305849350732912402,2305849460254578554,1152925284178073480,1152925282030589833,2305846773752532403,2305846772678790580, + 3762391354805,1152925265924460046,1152925273440655047,2305846768383823278,2305849349659170577,2305849457033353079,6447819659127,1152927482127587209, + 1152925258408267177,6446745917302,1152927482127587208,1152925255187041702,1152925254113301953,2305846757646405031,2305846756572663210,3746285227435, + 1152925249818332686,1152925262703236807,2305846752277695903,2305849348585428752,2305849455959611254,1152925255187041705,1152925256260783528,2305846746908986778, + 2305846745835244955,3735547809180,1152925239080914446,1152925246597109447,2305846741540277653,2305849337848010502,2305849349659170579,6340445476627, + 1152925232638465927,6339371734802,1152925230490982278,1152925229417240001,2305846732950343055,2305846731876601233,3721589165458,1152925225122270734, + 1152925235859691207,2305846727581633928,2305849336774268677,2305849348585428754,1152925232638465926,1152925230490982279,2305846722212924803,2305846721139182980, + 3710851747205,1152925214384852494,1152925221901047495,2305846716844215678,1152927842904840059,1152927841831098231,2305846713622990203,1152927840757356409, + 2305846711475506553,1152927839683614581,2305846709328022903,3699040589680,1152925202573692430,1152925211163629255,2305846705033055603,1152927842904840058, + 1152927841831098230,2305846701811830128,1152927840757356408,2305846699664346478,1152927839683614580,2305846697516862828,3687229429615,1152925190762532366, + 1152925199352469191,2305846693221895528,1152927948131538801,3681860720395,1152925185393823246,1152925187541309127,2305846687853186403,1152927838609872651, + 3676492011272,1152925180025114126,1152925182172600007,2305846682484477278,2305848989955659628,3671123302153,1152925174656405006,1152925176803890887, + 2305846677115768153,6445672175367,1152925170361437710,1152925171435181767,2305846672820800853,2305849462402062203,3661459625747,1152925164992729687, + 1152925163918988994,1152925167140214471,2305846666378349903,2305849463475803923,1152925159624020586,1152925158550279874,1152925160697763527,2305846661009640778, + 4269197498131,1152925154255311445,1152925153181570754,1152925155329054407,2305846655640931653,1152927958868956947,5991479381314,1152925147812860520, + 1152925146739119810,1152925149960345287,2305846649198480703,2305849463475803596,3637837305619,1152925141370409573,1152925140296668866,1152925143517894343, + 2305846642756029753,1152925788836729443,1152925137075443399,2305846639534804278,5991479381324,1152925132780476098,1152925131706733155,1152925133854217927, + 2305846634166095153,1152925788836729426,1152925128485508807,2305846630944869678,5991479383930,1152925124190541690,1152925123116798546,1152925125264283335, + 2305846625576160553,1152925154255312578,1152925118821831250,1152925119895574215,2305846621281193253,1152925788836729424,1152925115600606919,2305846618059967778, + 1152925123116798544,1152925112379381447,2305846614838742303,4269197495634,3603477567251,1152925107010672322,1152925105936929360,1152925109158155975, + 2305846608396291353,1152926549045941954,6453188368251,1152925100568221459,1152925099494477078,1152925102715705031,2305846601953840403,1152925100568221577, + 3590592665036,3589518923539,1152925093052026134,1152925096273254087,2305846595511389453,1152926569447036610,1152925088757058882,1152925089830803143, + 2305846591216422153,4037269263820,3579855247123,1152925083388349706,1152925085535835847,2305846585847713028,1152926415901955986,1152925079093384898, + 1152927957795215226,3572339054354,1152925075872156928,1152925080167126727,2305846578331520253,1152925124190541587,2305846576184038860,3565896603529, + 1152925069429705984,1152925072650933959,2305846571889069303,1152927956721473417,3560527894289,1152925064060996864,1152925066208483015,2305846566520360178, + 1152927478906361616,2305846564372879123,3554085443448,1152925057618545920,1152925060839773895,2305846560077909228,5991479383827,1152925053323581203, + 1152925052249836800,1152925054397322951,2305846554709200103,1152926411606988482,1152925047954870495,1152925049028613831,2305846550414232803,1152925047954870007, + 1152925044733646535,2305846547193007328,1152927955647731578,1152925040438678977,2305846543971782545,3533684348689,1152925037217451236,1152925041512421063, + 2305846539676814553,2305849460254578553,1152925032922484050,4278861171925,3535831829716,3525094414096,1152925028627516644,1152925033996228295, + 2305846531086879953,1152926614544192194,2305846528939397630,2305846527865655812,1152927476758878086,2305846525718173575,3515430737339,1152925018963842949, + 3513283253708,1152927476758878088,2305846520349464457,1152925014668872903,1152925013595131084,1152925025406293703,2305846516054494403,1152926660715090630, + 2305846513907012094,2305846512833270278,2305846511759527118,2305846510685786628,1152925005005199042,3510062028563,1152925002857712827,1152925010373908167, + 2305846505317076153,3515430737682,1152924998562745531,1152924999636489927,2305846501022108853,1152927479980103558,1152927971753858716,2305846497800883397, + 2305846496727141554,3486439708539,1152924989972812286,1152924995341522631,2305846492432174253,3487513447762,1152924985677843648,1152924986751588039, + 2305846488137206953,2305846670673319801,3487513447590,1152924980309135878,1152924982456620743,2305846482768497828,2305846513907012102,1152924976014169990, + 1152924977087911623,2305846478473530528,1152926618839159490,1152924971719202498,2305849350732912507,1152927847199807132,3463891127451,3462817388410, + 1152924966350490780,1152924972792944327,2305846468809854103,1152924970645458152,1152924963129267911,2305846465588628628,3510062028562,1152924958834298012, + 1152924959908042439,2305846461293661328,3486439706504,1152924954539330766,1152924955613075143,2305846456998694028,2305847278411192185,3486439705737, + 1152924949170622980,1152924951318107847,2305846451629984903,1152926653198897858,1152924944875656898,1152927846126065531,2305846447335020307,3437047584634, + 1152924940580686979,1152924945949398727,2305846443040050303,6341519218554,3510062025852,1152924935211977859,1152924937359464135,2305846437671341178, + 6342592960379,2305846524644431308,3425236421751,1152924928769526915,1152924931990755015,2305846431228890228,1152926658567608002,3515430737683, + 1152924923400817777,1152924925548304071,2305846425860181103,1152924924474559633,1152924920179594951,2305846422638955628,1152927967458891460,1152924916958369479, + 2305846419417730153,5991479383939,1152924912663402371,1152924913737144007,2305846415122762853,5991479383835,1152924908368433849,1152924907294693058, + 1152924909442176711,2305846409754053728,1152924908368433837,1152924902999725762,1152924904073467591,2305846405459086428,5991479383954,1152924898704758674, + 1152924899778500295,2305846401164119128,5991479383953,1152924894409791377,1152924895483532999,2305846396869151828,5991479383952,1152924890114824080, + 1152924891188565703,2305846392574184528,5991479383951,1152924885819856783,1152924886893598407,2305846388279217228,5991479383950,1152924881524889486, + 1152924882598631111,2305846383984249928,5991479383949,1152924877229922189,1152924878303663815,2305846379689282628,5991479383948,1152924872934954892, + 1152924874008696519,2305846375394315328,1152926661788833678,3364033140605,1152924869713729223,2305846371099348028,1152927977122568077,3359738173308, + 1152924865418761927,2305846366804380728,6455335851916,6456409590837,1152924858976311186,1152924861123794631,2305846361435671603,1152927983565019004, + 1152924855755085511,2305846358214446128,1152927982491277180,1152924852533860039,2305846354993220653,1152925788836729471,1152924849312634567,2305846351771995178, + 1152927971753857658,1152924846091409095,2305846348550769703,1152926583405680518,1152924842870183623,2305846345329544228,1152927969606374010,1152924839648958151, + 2305846342108318753,1152927968532632186,1152924836427732679,2305846338887093278,1152925789910470914,1152924833206507207,2305846335665867803,5991479383943, + 1152924828911538434,1152924829985281735,2305846331370900503,1152927958868957062,1152924824616571671,1152924825690314439,2305846327075933203,1152926751983146690, + 1152927867600901908,6364067796428,1152927869748382734,1152924817100377103,1152924816026635280,6471441979171,1152924813879151627,1152924821395347143, + 2305846316338514953,6470368237346,1152924809584184331,1152924810657928903,2305846312043547653,6469294495521,1152924805289217035,1152924806362961607, + 2305846307748580353,6468220753696,1152924800994249739,1152924802067994311,2305846303453613053,6467147011871,1152924796699282443,1152924797773027015, + 2305846299158645753,1152927869748385575,1152924792404315151,5991479380981,1152924790256833195,1152924789183092418,1152924793478059719,2305846291642452978, + 1152927967458891458,6350109153154,5991479380974,1152924782740638702,1152924781666896879,1152924785961866951,2305846284126260203,4977867101644, + 1152924777371932555,1152924776298187758,1152924775224445935,1152924778445674183,2305846277683809253,2305848142773359289,2305846275536327196,1152924769855736813, + 1152924768781997762,1152924772003223239,2305846271241358303,6365141538252,1152924764487027726,1152924763413285903,1152924764487030567,1152924761265802255, + 2305846264798907354,1152924759118318574,1152924758044579522,1152924765560772295,2305846260503940053,1152927966385148695,1152924754823354055,2305846257282714578, + 1152927855789741955,3279207536076,1152924749454642127,2305846252987747297,1152927475685136163,3241626572683,2305849370060265252,2305849371134004169, + 2305846247619038152,2305846246545299238,2305846245471554502,2305846244397815591,2305846243324070852,2305846242250331944,2305846241176587202,2305849375428971457, + 2305846239029103552,2305849376502713279,3227667925962,1152924731201031116,1152924730127292098,1152924751602128583,2305846232586652603,1152924759118321547, + 1152924725832324995,1152924724758582978,1152924726906066631,2305846227217943478,1152927853642255330,1152924720463615682,1152924721537357511,2305846222922976178, + 4977867099118,1152924716168648473,1152924715094906755,1152924714021164738,1152924717242390215,2305846216480525228,3211561801164,2305849469918254540, + 3204045608729,1152924707578710953,1152924706504972059,1152924705431230339,1152924704357488322,1152924710799939271,2305846206816848803,5991479383937, + 1152924700062521217,5974299514753,1152924697915034527,5989331900289,1152924695767550877,5978594482049,1152924693620067227,5970004547457, + 1152924691472583577,5968930805633,1152924689325099927,5979668223873,1152924687177616277,5980741965697,1152924685030132627,1152924701136262855, + 2305846187489495953,5991479383936,1152924680735168384,1152924681808910023,2305846183194528653,5991479383935,1152924676440201087,1152924677513942727, + 2305846178899561353,5991479383934,1152924672145233790,1152924673218975431,2305846174604594053,6459630818764,1152924667850266495,1152924666776524670, + 6458557076940,1152924664629037954,1152924663555299198,2305846167088401280,6457483335116,1152924660334070657,2305846163867175804,2305846162793437056, + 3152505998306,1152924668924008135,2305846159572208503,3266322634188,2305849467770771328,2305846156350986110,1152924650670394228,1152924653891622599, + 2305846153129757553,1152924658186590087,1152924647449171655,2305846149908532078,1152924658186590086,1152924644227946183,2305846146687306603,1152924658186590085, + 1152924641006720711,2305846143466081128,1152924658186590084,1152924637785495239,2305846140244855653,1152924661407815561,1152924634564269767,2305846137023630178, + 1152924661407815560,1152924631343044295,2305846133802404703,1152924665702782858,1152924628121818823,2305846130581179228,6480031913771,1152924623826851715, + 1152924622753109698,1152924624900593351,2305846125212470103,2305849489245607356,3113851295531,1152924617384399533,1152924616310658754,1152924619531884231, + 2305846118770019153,1152927984638759595,1152924613089433287,2305846115548793678,1152926654272640893,1152927959942698894,2305846112327568203,2305848088012526379, + 2305846110180084553,2305846109106344732,2305846108032604035,5991479380805,1152924609868207815,2305846104811375428,5991479382699,1152924598057047747, + 1152924599130789575,2305846100516408128,5835786819020,5803574561597,1152924592688338770,1152924591614596965,1152924594835822279,2305846094073957178, + 1152924593762080594,1152924587319629668,1152924588393371335,2305846089778989878,1152924587319629667,1152924584098404039,2305846086557764403,1152927914845541750, + 2305849435558516578,2305849433411032928,2305846082262797103,2305846081189058401,2305846080115313455,2305849431263549278,2305849429116065628,2305846076894087978, + 2305846075820349277,2305846074746604330,2305846073672862507,2305849426968581978,2305849424821098328,2305846070451637028,2305846069377898329,2305846068304153380, + 2305846067230411557,2305846066156669739,2305846065082930431,1152924559402339101,1152924558328597277,1152924558328597276,1152924556181113627,2305849434484774752, + 2305846058640476972,2305849430189807452,2305846056492993319,2305846055419251479,2305849425894840152,2305846053271767841,2305846052198026004,2305846051124284183, + 2305846050050544865,1152924544369953551,1152924543296211727,1152924543296211726,1152924541148728077,2305846044681833241,2305846081189058399,2305846042534349614, + 2305846075820349275,2305846040386865961,2305846039313124104,2305846069377898327,2305846037165640483,2305846036091898629,2305846035018156808,2305846033944417475, + 1152924528263826176,1152924527190084352,1152924527190084351,1152924525042600702,2305849436632258402,2305846027501964041,2305849432337291102,2305846025354480391, + 2305846024280738554,2305849428042323802,2305846022133254916,2305846021059513079,2305846019985771258,2305846018912031909,1152924513231440626,1152924512157698802, + 1152924512157698801,1152924510010215152,2305846013543320316,2305846012469578506,2305846011395836683,2305846010322094858,2305846066156669734,2305846008174613639, + 1152924502494022376,1152924501420280552,1152924501420280551,1152924499272796902,2305846051124284181,2305846001732162665,1152924496051571426,1152924494977829602, + 1152924494977829601,1152924492830345952,2305845996363451108,2305846035018156806,2305845994215969867,1152924488535378651,1152924487461636827,1152924487461636826, + 1152924485314153177,2305846019985771256,2305845987773518893,1152924482092927701,1152924481019185877,1152924481019185876,1152924478871702227,2305845982404807383, + 2305845981331065565,2305845980257323742,2305845979183581917,2305845978109840106,2305846066156669728,2305845975962358799,1152924470281767626,1152924469208025802, + 1152924469208025801,1152924467060542152,2305846051124284178,2305845969519907825,1152924463839316676,1152924462765574852,1152924462765574851,1152924460618091202, + 2305845964151196358,2305846035018156803,2305845962003715027,1152924456323123901,1152924455249382077,1152924455249382076,1152924453101898427,2305846019985771253, + 2305845955561264053,1152924449880672951,1152924448806931127,1152924448806931126,1152924446659447477,2305845950192552633,2305845949118810815,2305845948045068992, + 2305845946971327167,2305845945897585356,2305845944823843562,2934536410874,1152924438069513008,1152924580877178567,2305845940528876203,2305846028575705852, + 2305845938381392619,2305845988847258327,2305845936233908942,2305845935160167079,2305845956635003577,2305845933012683440,2305845931938941604,2305845930865199783, + 2920577767161,1152924424110869296,1152924434848290503,2305845926570232478,2305846011395836654,2305845924422748909,2305845980257323729,2305845922275265232, + 2305845921201523354,2305845948045068979,2305845919054039730,2305845917980297879,2305845916906556058,2906619123448,1152924410152225584,1152924420889646791, + 2305845912611588753,2305846059714218777,2305845910464105115,2305846002805902052,2305845908316621465,2305845907242879629,2305845970593647302,2305845905095395990, + 2305845904021654154,2305845902947912333,2892660479735,1152924396193581872,1152924406931003079,2305845898652945028,2305845944823843533,2887291770614, + 1152924390824872752,1152924392972359367,2305845893284235903,2305845930865199781,2881923061493,1152924385456163632,1152924387603650247,2305845887915526778, + 2305845916906556056,2876554352372,1152924380087454512,1152924382234941127,2305845882546817653,2305845902947912331,2871185643251,1152924374718745392, + 1152924376866232007,2305845877178108528,2305845944823843503,2865816934130,1152924369350036272,1152924371497522887,2305845871809399403,2305845930865199778, + 2860448225009,1152924363981327152,1152924366128813767,2305845866440690278,2305845916906556053,2855079515888,1152924358612618032,1152924360760104647, + 2305845861071981153,2305845902947912328,2849710806767,1152924353243908912,1152924355391395527,2305845855703272028,1152927914845541721,2305849436632257791, + 1152924347875199576,1152924346801457752,1152924346801457751,1152924344653974102,2305849435558515937,1152924342506490451,1152924341432748627,1152924341432748626, + 1152924339285264977,2305845842818370132,2305849434484774083,1152924336064039501,1152924334990297677,1152924334990297676,1152924332842814027,2305849433411032229, + 1152924330695330376,1152924329621588552,1152924329621588551,1152924327474104902,2305845831007210057,2305845829933468238,2305845828859726415,2305845827785984590, + 2305849432337290375,1152924321031653951,1152924319957912127,1152924319957912126,1152924317810428477,2305849431263548521,1152924315662944826,1152924314589203002, + 1152924314589203001,1152924312441719352,2305845815974824507,2305849430189806667,1152924309220493876,1152924308146752052,1152924308146752051,1152924305999268402, + 2305849429116064813,1152924303851784751,1152924302778042927,1152924302778042926,1152924300630559277,2305845804163664432,2305845803089922613,2305845802016180790, + 2305845800942438965,2305845799868697152,2305849428042322959,1152924293114366501,1152924292040624677,1152924292040624676,1152924289893141027,2305849426968581105, + 1152924287745657376,1152924286671915552,1152924286671915551,1152924284524431902,2305845788057537057,2305849425894839251,1152924281303206426,1152924280229464602, + 1152924280229464601,1152924278081980952,2305849424821097397,1152924275934497301,1152924274860755477,1152924274860755476,1152924272713271827,2305845776246376982, + 2305845775172635163,2305845774098893340,2305845773025151515,2305845771951409702,2305845770877667904,2760590235386,1152924264123337305,1152924350022686407, + 2305845766582700553,2305845836375919177,2305845764435216961,2305845809532373552,2305845762287733288,2305845761213991429,2305845781615086102,2305845759066507790, + 2305845757992765954,2305845756919024133,2746631591673,1152924250164693593,1152924260902115015,2305845752624056828,2305845828859726404,2305845750476573251, + 2305845802016180779,2305845748329089578,2305845747255347704,2305845774098893329,2305845745107864080,2305845744034122229,2305845742960380408,2732672947960, + 1152924236206049881,1152924246943471303,2305845738665413103,2305845848187079252,2305845736517929465,2305845821343533627,2305845734370445815,2305845733296703979, + 2305845793426246177,2305845731149220340,2305845730075478504,2305845729001736683,2718714304247,1152924222247406169,1152924232984827591,2305845724706769378, + 2305845770877667879,2713345595126,1152924216878697049,1152924219026183879,2305845719338060253,2305845756919024131,2707976886005,1152924211509987929, + 1152924213657474759,2305845713969351128,2305845742960380406,2702608176884,1152924206141278809,1152924208288765639,2305845708600642003,2305845729001736681, + 2697239467763,1152924200772569689,1152924202920056519,2305845703231932878,2305845770877667853,2691870758642,1152924195403860569,1152924197551347399, + 2305845697863223753,2305845756919024128,2686502049521,1152924190035151449,1152924192182638279,2305845692494514628,2305845742960380403,2681133340400, + 1152924184666442329,1152924186813929159,2305845687125805503,2305845729001736678,2675764631279,1152924179297733209,1152924181445220039,2305845681757096378, + 1152927914845541691,2838973388645,1152924173929023927,1152924176076510919,2305845676388387253,1152927472463910757,2305849435558516581,2305845673167162158, + 2305845672093420328,2305845671019678498,2305845669945936306,2305845668872197345,1152924163191605676,1152924162117863852,1152924162117863851,1152924159970380202, + 2654289794916,1152924157822896567,1152924170707801799,2305845660282259878,1152927472463910756,2305845669945939809,2305845657061037924,1152927929877927356, + 2305845654913550766,1152927471390168927,2305845652766067118,2305845651692325279,2305845650618583457,1152927927730443722,2305845648471099822,1152927926656701888, + 2305845646323616174,2305845645249874329,1152927470316427100,2305845643102390702,1152927469242685275,2305845640954907054,2305845639881165204,2305845638807423382, + 2305845637733681563,1152927468168943450,2305845635586197934,1152927467095201625,2305845633438714286,2305845632364972429,1152927466021459800,2305845630217488814, + 1152927920214250964,2305845628070005166,2305845626996263304,2305845625922521482,2305845624848779663,2305845623775037859,2305845622701298883,1152924117020707201, + 1152924115946965377,1152924115946965376,1152924113799481727,2608118896483,1152924111651998135,1152924154601674439,2305845614111361403,1152927472463910755, + 2305845623775037858,2305845610890139491,1152924149232965052,2305845608742652291,1152924147085481397,2305845606595168643,2305845605521426804,2305845604447684982, + 1152924142790514122,2305845602300201347,1152924140643030464,2305845600152717699,2305845599078975854,1152924137421804980,2305845596931492227,1152924135274321331, + 2305845594784008579,2305845593710266729,2305845592636524907,2305845591562783088,1152924129905612210,2305845589415299459,1152924127758128561,2305845587267815811, + 2305845586194073954,1152924124536903088,2305845584046590339,1152924122389419476,2305845581899106691,2305845580825364829,2305845579751623007,2305845578677881188, + 2305845577604139384,2567316707066,1152924070849808823,1152924108430776007,2305845573309172053,2305845577604139383,2561947997945,1152924065481099703, + 1152924067628586695,2305845567940462928,1152924103062066620,2305845565792979288,2555505547000,1152924059038648759,1152924062259877575,2305845561498011978, + 1152924100914582965,2305845559350528344,2549063096055,1152924052596197815,1152924055817426631,2305845555055561028,1152924096619615690,2305845552908077400, + 2542620645110,1152924046153746871,1152924049374975687,2305845548613110078,1152924094472132032,2305845546465626456,2536178194165,1152924039711295927, + 1152924042932524743,2305845542170659128,1152924091250906548,2305845540023175512,2529735743220,1152924033268844983,1152924036490073799,2305845535728208178, + 1152924089103422899,2305845533580724568,2523293292275,1152924026826394039,1152924030047622855,2305845529285757228,1152924083734713778,2305845527138273624, + 2516850841330,1152924020383943095,1152924023605171911,2305845522843306278,1152924081587230129,2305845520695822680,2510408390385,1152924013941492151, + 1152924017162720967,2305845516400855328,1152924078366004656,2305845514253371736,2503965939440,1152924007499041207,1152924010720270023,2305845509958404378, + 1152924076218521044,2305845507810920792,2497523488495,1152924001056590263,1152924004277819079,2305845503515953428,1152927914845541661,2305848969554564962, + 1152923995687880976,1152923994614139152,1152923994614139151,1152923992466655502,2486786070373,1152923990319171857,1152923997835368135,2305845492778535178, + 2305845668872197375,1152923986024204551,1152923984950462727,1152923984950462726,1152923982802979077,2305845657061037281,1152923980655495426,1152923979581753602, + 1152923979581753601,1152923977434269952,2305845480967375107,2305845653839811779,1152923974213044476,1152923973139302652,1152923973139302651,1152923970991819002, + 2305845651692328101,1152923968844335351,1152923967770593527,1152923967770593526,1152923965623109877,2305845469156215032,2305845468082473213,2305845467008731390, + 2305845465934989565,2305845647397360775,1152923959180658926,1152923958106917102,1152923958106917101,1152923955959433452,2305845645249877097,1152923953811949801, + 1152923952738207977,1152923952738207976,1152923950590724327,2305845454123829482,2305845642028651595,1152923947369498851,1152923946295757027,1152923946295757026, + 1152923944148273377,2305845639881167917,1152923942000789726,1152923940927047902,1152923940927047901,1152923938779564252,2305845442312669407,2305845441238927588, + 2305845440165185765,2305845439091443940,2305845438017702127,2305845634512458767,1152923931263371476,1152923930189629652,1152923930189629651,1152923928042146002, + 2305845632364975089,1152923925894662351,1152923924820920527,1152923924820920526,1152923922673436877,2305845426206542032,2305845629143749587,1152923919452211401, + 1152923918378469577,1152923918378469576,1152923916230985927,2305845626996265909,1152923914083502276,1152923913009760452,1152923913009760451,1152923910862276802, + 2305845414395381957,2305845413321640138,2305845412247898315,2305845411174156490,2305845410100414677,2305845409026672879,2398739240698,1152923902272342289, + 1152923987097949895,2305845404731705528,2305845474524924152,2305845402584221936,2305845447681378527,2305845400436738263,2305845399362996404,2305845419764091077, + 2305845397215512765,2305845396141770929,2305845395068029108,2384780596985,1152923888313698577,1152923899051120327,2305845390773061803,2305845467008731379, + 2305845388625578226,2305845440165185754,2305845386478094553,2305845385404352679,2305845412247898304,2305845383256869055,2305845382183127204,2305845381109385383, + 2370821953272,1152923874355054865,1152923885092476615,2305845376814418078,2305845486336084227,2305845374666934440,2305845459492538602,2305845372519450790, + 2305845371445708954,2305845431575251152,2305845369298225315,2305845368224483479,2305845367150741658,2356863309559,1152923860396411153,1152923871133832903, + 2305845362855774353,2305845409026672854,2351494600438,1152923855027702033,1152923857175189191,2305845357487065228,2305845395068029106,2346125891317, + 1152923849658992913,1152923851806480071,2305845352118356103,2305845381109385381,2340757182196,1152923844290283793,1152923846437770951,2305845346749646978, + 2305845367150741656,2335388473075,1152923838921574673,1152923841069061831,2305845341380937853,2305845409026672828,2330019763954,1152923833552865553, + 1152923835700352711,2305845336012228728,2305845395068029103,2324651054833,1152923828184156433,1152923830331643591,2305845330643519603,2305845381109385378, + 2319282345712,1152923822815447313,1152923824962934471,2305845325274810478,2305845367150741653,2313913636591,1152923817446738193,1152923819594225351, + 2305845319906101353,1152927918066767698,1152923814225516231,2305845316684875878,1152927916993025874,1152923811004290759,2305845313463650403,1152927915919284050, + 1152923807783065287,2305845310242424928,2305848877212767606,2305845308094944571,2305845307021202717,6414533662446,1152923800266868827,1152923799193130834, + 1152923804561839815,2305845301652490328,6320044381644,1152923794898163558,1152923793824421610,1152923792750676059,1152923795971905223,2305845295210039378, + 6298569545164,1152923788455712594,1152923787381966939,1152923789529454279,2305845289841330253,1152927935246636902,5991479380042,1152923782013261508, + 1152923784160745159,2305845284472621128,1152926856136103782,1152923778792036039,2305845281251395653,1152926849693652838,1152923775570810567,2305845278030170178, + 1152926843251201894,1152923772349585095,2305845274808944703,5991479383892,1152923768054617940,1152923766980876134,1152923769128359623,2305845269440235578, + 1152927760226719590,1152923762685908734,6430639789516,6429566047692,1152923759464679477,6318970639820,6317896897996,1152923756243454002, + 1152923755169712179,1152923754095970358,1152923763759650503,2305845256555333678,1152923760538425188,1152923757317199612,5991479380010,1152923747653519403, + 1152923746579777590,1152923750874748615,2305845249039140903,1152923749801006932,1152923742284814182,1152923743358555847,2305845244744173603,1152923749801006931, + 1152923737989846886,1152923739063588551,2305845240449206303,1152923793824421733,1152923734768621255,2305845237227980828,1152923758390937660,1152923730473650260, + 1152923731547395783,2305845232933013528,5991479380016,1152923726178686821,1152923725104941110,1152923727252428487,2305845227564304403,1152923759464683365, + 6428492305868,1152923719736231952,1152923718662494038,1152923717588752230,1152923721883719367,2305845220048111628,1152923718662494035,1152923713293784934, + 1152923714367526599,2305845215753144328,1152923756243457789,6316823156172,1152923707925071877,1152923706851330102,6300717028812,1152923704703846402, + 6418828629746,1152923702556362752,1152923710072559303,2305845205015726078,6417754887921,1152923698261395456,1152923699335141063,2305845200720758778, + 6416681146096,1152923693966428160,1152923695040173767,2305845196425791478,6415607404271,1152923689671460864,1152923690745206471,2305845192130824178, + 2305849437706000228,1152927933099153252,2179695904751,1152923683229013861,1152923682155272038,2305849312078206702,2305845184614635347,2174327199574, + 1152923677860300779,1152923686450239175,2305845180319664103,5991479383891,1152923673565337427,1152923672491591659,1152923674639079111,2305845174950954978, + 1152923681081530202,1152923669270369991,2305845171729729503,1152923681081530201,1152923666049144519,2305845168508504028,1152923681081530200,1152923662827919047, + 2305845165287278553,1152923681081530199,1152923659606693575,2305845162066053078,6412386178508,2305849326036850428,1152927821430003452,2148557391826, + 1152923652090500861,1152923651016755290,1152923649943013331,1152923648869271603,1152923647795533670,1152923656385468103,2305845150254893003,1152923758390941542, + 1152923643500562387,1152923642426820559,6299643287379,1152923640279336902,1152923644574308039,2305845142738700228,6315749414646,1152923635984373587, + 2305845139517478650,2129230042978,1152923632763144134,1152923637058115271,2305845135222507453,6314675672821,1152923628468180819,2305845132001285881, + 2121713850209,1152923625246951366,1152923629541922503,2305845127706314678,6313601930996,1152923620951988051,2305845124485093112,2114197657440, + 1152923617730758598,1152923622025729735,2305845120190121903,6312528189171,1152923613435795283,2305845116968900343,2106681464671,1152923610214565830, + 1152923614509536967,2305845112673929128,1152927822503745277,1152923605919598596,1152923604845860588,2305845108378965845,2098091529965,1152923601624631350, + 1152923606993344199,2305845104083994528,1152923719736231987,1152923597329667926,1152923596255926118,1152923598403409607,2305845098715285403,1152923597329667923, + 1152923591960958822,1152923593034700487,2305845094420318103,1152923758390941539,1152927915919284052,1152923586592245652,1152923585518507878,1152923588739733191, + 2305845087977867153,5347234288514,1152923581223539570,1152923582297282247,2305845083682899853,6317896898404,1152923576928572312,1152923575854827406, + 1152923578002314951,2305845078314190728,5991479383905,1152923571559864161,1152923570486118286,1152923572633605831,2305845072945481603,5991479383904, + 1152923566191155040,1152923565117409166,1152923567264896711,2305845067576772478,5991479383903,1152923560822445919,1152923559748700046,1152923561896187591, + 2305845062208063353,5991479383902,1152923555453736798,1152923554379990926,1152923556527478471,2305845056839354228,5991479383901,1152923550085027677, + 1152923549011281806,1152923551158769351,2305845051470645103,5991479383900,1152923544716318556,1152923543642572686,1152923545790060231,2305845046101935978, + 5991479383899,1152923539347609435,1152923538273863566,1152923540421351111,2305845040733226853,5991479383898,1152923533978900314,1152923532905154446, + 1152923535052641991,2305845035364517728,2305846025354483551,2305845033217034077,2305845032143296352,2305845031069550427,2305845029995812705,2019708376931, + 1152923523241481126,1152923522167736206,1152923529683932871,2305845024627099478,2305846022133258075,2305845022479615827,2305845021405878108,2305845020332132177, + 2305845019258394461,2008970958690,1152923512504062886,1152923511430317966,1152923518946514631,2305845013889681228,1152927922361734054,1152923507135350670, + 1152923508209096391,2305845009594713928,1152927486422554467,2305849320668141302,2305845006373492471,2305845005299746627,2305845004226008824,2305845003152262977, + 2305845002078525177,2305845001004779333,1990717347579,1152923494250451864,1152923493176706958,1152923503914129095,2305844995636070203,1152927486422554466, + 2305849316373174002,2305844992414848755,2305844991341102902,2305844990267365108,2305844989193619252,2305844988119881461,2305844987046135608,1976758703866, + 1152923480291808152,1152923479218063246,1152923489955485383,2305844981677426478,6306085738328,1152923474923099032,1152923473849354126,1152923475996841671, + 2305844976308717353,1152927922361734595,1152927923435476830,2305844973087491877,1152927924509218655,2305844970940008228,2305844969866266402,1152927925582960480, + 2305844967718782753,2305844966645040927,1152927926656702305,2305844964497557278,2305844963423815462,2305849428042323806,1962800056090,2305844960202589977, + 2305849429116065631,2305844970940008227,1947767670551,2305844955907622680,2305844954833880852,2305849430189807456,2305844967718782752,1942398961426, + 2305844950538913555,2305844949465171727,2305849431263549281,2305844964497557277,1937030252301,2305844945170204430,1954210121482,1152923438415877988, + 2305844941948978971,1931661547352,1152923435194648462,1152923470628132551,2305844937654011653,5340791837556,1152923430899684204,1152923431973426887, + 2305844933359044353,1152923430899684198,1152923427678459591,2305844930137818878,1152923430899681146,1152923424457234119,2305844926916593403,1152923430899681141, + 1152923421236008647,2305844923695367928,1152927928804185954,1152923416941037314,1152923418014783175,2305844919400400628,1152927927730444130,1152923412646070018, + 1152923413719815879,2305844915105433328,1152923581223540477,1152923408351103025,6315749414348,1152923406203619332,6311454447052,6312528188876, + 1152923402982393577,1897301808588,1152923400834909930,2305844904368019195,1152923398687430388,1152923397613684460,1152923409424848583,2305844900073047778, + 1152923404056139511,1888711873996,1152923392244975338,2305844895778084603,1152923390097495795,1152923389023749868,1152923394392463047,2305844891483113178, + 1152923402982397686,1880121939404,1152923383655040746,2305844887188150011,1152923381507561202,1152923380433815276,1152923385802528455,2305844882893178578, + 1152927816061294327,1871532004812,1152923375065106154,2305844878598215419,1152923372917626609,1152923371843880684,1152923377212593863,2305844874303243978, + 1152926851841136322,1152923367548913713,6426344822521,1152923365401433838,5991479379652,1152923363253946052,1152923362180204230,1152923368622659271, + 2305844864639567553,1859720844748,1152923357885236933,1152923356811495110,1152923358958982855,2305844859270858428,6425271080696,1152923352516531950, + 5991479379640,1152923350369044152,1152923349295302334,1152923348221560518,1152923353590273735,2305844850680923828,1846835942860,1152923343926593209, + 1152923342852851390,1152923341779109574,1152923345000339143,2305844844238472878,1152923343926593214,1832877299437,1152923336410400454,1152923338557888199, + 2305844838869763753,1152923364327687877,1152923351442785977,6422049855221,1152923329967949489,2305844833501054629,1152923327820465854,2305844831353570982, + 1152927808545101242,2305844829206091504,1818918651552,1152923322451756742,1152923333189179079,2305844824911120028,1152923329967953646,1813549946316, + 2305845212531918863,1152923316009305752,1152923314935568109,1152923313861822150,1152923319230535367,2305844816321185428,1152927806397618012,1804960012020, + 1152923308493113060,1152923307419371206,1152923310640600775,2305844809878734478,1152927806397618011,1798517561075,1152923302050662108,1152923300976920262, + 1152923304198149831,2305844803436283528,1152927806397618010,1792075110130,1152923295608211156,1152923294534469318,1152923297755698887,2305844796993832578, + 1152927806397618009,1785632659185,1152923289165760204,1152923288092018374,1152923291313247943,2305844790551381628,1152923430899685116,1152923283797051396, + 5991479383802,1152923281649567352,1152923284870796999,2305844784108930678,5334349386606,1152923277354603366,1152923278428346055,2305844779813963378, + 1152923277354600324,1152923274133378759,2305844776592737903,1152923277354604283,1152923269838411618,1152923270912153287,2305844772297770603,1152926845398685378, + 1152923265543440388,1152927820356261730,1152923263395956327,1152923266617185991,2305844765855319653,1152927930951669602,1152923259100989043,1152923260174735047, + 2305844761560352353,6314675672524,1152923254806026081,1152923253732280043,1152923252658538087,1152923255879767751,2305844755117901403,1152923264469698283, + 1152923248363570873,1152923249437316807,2305844750822934103,6423123597046,1152923244068603480,1152923245142349511,2305844746527966803,6426344822220, + 1152923239773640128,2305844743306745695,2305844742233003873,1731945567991,1152923235478668888,1152923240847382215,2305844737938032203,2305844744380483152, + 2305844735790552820,2305844734716811105,1724429375324,1152923227962476120,1152923232257447623,2305844730421839428,2040109471577,1152923223667508816, + 1152923222593767027,1152923224741254855,2305844725053130303,1152923254806025966,1152927813913810681,2305844721831904828,6414533658170,1152923215077574224, + 1152923214003832423,1152923219372545735,2305844716463195703,1152923277354604385,1152927926656702301,5991479379507,1152923207561385821,1152923206487639604, + 1152923210782611143,2305844708947002928,1152927918066767709,2305844706799523672,1152927918066767704,1152927916993025879,1152923198971450817,2305844702504551979, + 1692217116204,1152923195750221363,2305844699283326504,1688995895131,1152923192528995892,1152923203266418375,2305844694988359203,1152927916993025885, + 2305844692840879959,1152927916993025880,1152927918066767703,2305844689619650078,1679332214303,1152923182865319475,2305844686398424604,1676110993242, + 1152923179644094004,1152923189307774663,2305844682103457303,1152923264469702394,2305844679955973740,1152923174275384912,1152923176422872775,2305844676734748178, + 1152923174275389275,1152923171054163655,2305844673513522703,1152923174275389274,1152923167832938183,2305844670292297228,1152923174275389276,1152923164611712711, + 2305844667071071753,1152927463873976144,2305844664923592529,1152923159243003588,1152923161390487239,2305844661702362628,1152927993228695451,1152923154948036507, + 1152923153874294683,1152923152800552859,1152923151726811035,1152923150653069211,1152923149579327387,1152923148505585563,1152923147431843739,1152923146358101915, + 1152923145284360091,1152923144210618267,1152923143136876443,1152923142063134619,1152923140989392795,1152927462800229875,2305844643448756122,1152927993228695443, + 2305844641301272363,2305844640227526129,5991479379438,2305848096602460853,2305844637006303929,2305844635932562042,1152923130251970029,2305844633785079244, + 1152923154948036475,2305844631637591535,2305844630563849713,5991479379429,1152923123809522304,2305844627342624232,1152923153874294680,2305844625195140591, + 1152923152800552839,2305844623047656928,1152923151726811014,2305844620900173278,2305844619826431473,1152923150653069207,1152923149579327382,2305844616605205978, + 1152923148505585557,2305844614457722328,1152923147431843732,2305844612310238678,2305844611236496859,5991479379411,1152923104482169643,2305844608015271394, + 1152923152800552811,2305844605867787744,1152923151726810986,2305844603720304078,2305844602646562289,2305844601572820436,5991479379402,1152923094818493212, + 2305844598351594960,1152927993228695339,2305844596204115859,1152923154948036486,2305844594056627653,2305844592982885873,5991479379394,6464999527884, + 6463925781952,1152923084081074967,1152923083007329729,2305844586540434887,1152923153874294576,2305844584392951235,1152923152800552707,2305844582245467578, + 1152923151726810882,2305844580097983928,2305844579024242161,1152923150653069103,1152923149579327278,2305844575803016628,1152923148505585453,2305844573655532978, + 1152923147431843628,2305844571508049328,2305844570434307509,5991479379373,1152923063679979788,2305844567213082044,1152927993228695330,2305844565065602859, + 2305844563991856625,2305844565065602963,2305844561844372977,1152923056163784103,5991479379364,1152923054016303789,2305844557549405610,1152927461726488051, + 2305844555401926554,2305844554328184713,2305844554328184712,1152923047573849502,2305844554328184711,1152923045426365852,2305844554328184710,1152923043278882202, + 5991479379352,1152923041131401922,2305844544664503713,1152923139915650506,2305844542517024666,2305844541443282824,1152927993228695431,2305844539295794578, + 2305844538222052804,1152923153874294661,2305844536074569103,2305844541443282699,1152927993228695306,2305844532853343628,1152923154948036361,2305844530705859978, + 1152923153874294536,2305844528558376328,1152923022877787533,5991479379333,1152926643535221549,1152923019656566653,1152923018582820228,2305844522115925397, + 2305844554328184679,5991479379327,2305844518894704076,1152923013214111104,1152927801028908462,2305844515673478889,1152927910550574510,2305844513525995343, + 2305844512452249093,1152927908403090862,2305844510304769869,2305844509231023479,1152927906255607214,2305844507083544395,2305844506009798004,1152927904108123566, + 2305844503862318921,2305844502788572529,1152927901960639918,2305844500641093447,2305844499567347054,1152927899813156270,2305844497419867973,2305844496346121579, + 1486058685818,1152922989591790972,2305844634858820224,2305844492051157803,2305844490977415964,1578400482659,4685809321314,1553704420773, + 1152922982075601581,2305844485608703329,1152923047573853630,1544040744285,1152922977780630939,1541893260635,1152922975633147289,1539745776985, + 1152922973485667010,2305844477018768734,1152923022877791678,2305844474871285133,1152922969190696322,2305844472723801430,1152922967043212669,1152927938467857792, + 2305844469502575953,1459215140198,1152922962748249794,1152923156021778119,2305844465207608653,6263136060933,1152922958453282499,1152922959527024327, + 2305844460912641353,1152923139915650492,2305844458765162394,2305844457691420555,1152927993228695434,2305844455543932228,1152923154948036489,2305844453396448578, + 1152923153874294664,2305844451248964928,1152923152800552747,2305844449101481278,2305844448027739646,2305844457691420551,1152927993228695430,2305844444806513978, + 1152923154948036485,2305844442659030328,1152923153874294660,2305844440511546678,2305844439437804861,1152922933757216059,5991479379250,1152922931609735861, + 2305844435142841804,1152927958868957067,1152927971753856912,2305844431921612078,2305844430847870277,1152927958868957066,1152925782394279814,2305844427626644778, + 1152922921946060699,2305844425479161131,1152925782394279813,2305844423331679920,1152922917651088897,2305844421184193830,1152925782394279812,2305844419036712614, + 1152922913356121600,2305844416889226530,2305844415815484733,5991479379229,1152922909061157506,2305844412594259247,2305844448027739645,5991479379225, + 1152927958868955776,2305844408299294978,1152922902618703128,2305844406151808282,5991479379260,2305846110180086576,2305844402930586401,1152922897249994003, + 2305844400783099156,1152924818174118927,1152922894028770268,1388348184012,1152922894028773160,1386200696076,1152927868674640911,1152922888660061148, + 1382979470602,1152922888660064040,1380831986951,1152922884365092350,2305844387898197308,1152923150653069191,2305844385750713603,5991479379201, + 1152922878996386583,2305844382529488143,1152927460652746227,2305844380382009242,2305844379308267307,5991479383938,1152922872553936795,2305844376087037179, + 1152923154948036490,2305844373939553528,5974299514754,1152922867185227675,2305844370718328059,2305844369644586305,1152922863963997430,5989331900290, + 1152922861816518555,2305844365349618939,1152923154948036488,2305844363202135278,1152922857521546481,5978594482050,1152922855374067611,2305844358907167995, + 1152923154948036487,2305844356759684328,1152922851079095531,5970004547458,1152922848931616667,2305844352464717051,2305844351390975428,1152922845710386405, + 5968930805634,1152922843562907547,2305844347096007931,2305844346022266167,1152922840341677280,5979668223874,1152922838194198427,2305844341727298811, + 1152923154948036484,2305844339579815128,1152922833899226331,5991479379157,1152922831751747456,2305844335284847870,5991479379179,1152922828530518906, + 2305844332063622354,5991479379190,1152922825309293437,2305844328842396879,2305844379308267411,1152927993228695426,2305844325621171403,1152926482473948947, + 2305846236881619915,1152922817793100776,2305844321326204104,1152922815645615617,2305844319178720457,5991479379139,1152924783814383491,1152922811350648002, + 2305844314883753164,1152922809203164536,2305844438364063035,1152922807055684277,2305844310588789378,2305844309515044118,2305844308441302289,5247376295097, + 2305844368570844406,1152922800613229804,2305844304146334961,1152922798465746150,2305844301998851307,1152922796318262497,2305844299851367653,1152922794170778844, + 2305844297703884000,1152922792023295190,2305844295556400347,1152922789875816320,2305844293408916664,1152922798465747834,2305844291261433003,2305844290187692925, + 1306743801000,1278826513598,1152922782359623362,1152922955232057031,2305844284818982053,1152923007845406403,1152922779138397895,2305844281597756578, + 1152923139915650488,2305844279450277786,2305844278376535851,1152923154948036491,1152923153874294666,2305844275155305628,1152923152800552841,2305844273007821978, + 1152923151726811016,2305844270860338328,2305844269786596610,1152923149579327366,2305844267639112853,1152923148505585541,2305844265491629203,1152923147431843716, + 2305844263344145553,1152927459579004408,2305844261196661903,2305844260122920093,5991479379084,1152922753368593077,2305844256901699020,1152927458505262584, + 2305844254754210959,2305844253680469149,5991479379078,1152922746926142082,2305844250459243657,1152927457431520760,2305844248311760015,2305844247238018205, + 5991479379072,1152922740483691136,2305844244016792707,2305844262270403741,5991479379068,1152922736188723897,2305844239721825405,1152927456357778936, + 2305844237574341775,2305844236500599965,1152927455284037107,2305844234353121178,1152927454210299803,2305844232205637424,1152923154948036505,2305844230058148978, + 1152927453136553472,2305844227910665328,2305844226836923508,1152922721156334710,5991479379052,1152922719008854832,2305844222541956217,1152927452062811640, + 2305844220394472591,2305844219320730781,1152923139915650496,2305844217173251994,2305844216099510155,2305844215025763651,2305844213952021825,2305844212878279999, + 1152922707197690982,5991479379039,1152922705050211105,2305844208583312489,1152923139915650497,2305844206435833754,2305844205362091819,2305844204288345231, + 5991479379032,1152922697534018221,2305844201067119708,1152923139915650498,2305844198919640986,2305849489245607372,2305844196772152403,2305844195698410646, + 5991479379024,1152922688944083735,2305844192477185109,1152927450989069816,2305844190329701533,1152927449915327987,2305844188182222746,1152927993228695419, + 2305844186034739096,2305844184960992369,2305844183887250505,1152923153874294667,1152923152800552842,2305844180666025028,1152923151726811017,2305844178518541378, + 1152923150653069192,2305844176371057728,2305844175297315909,1152922669616727115,5991479379004,1152922667469247098,2305844171002348621,1152927448841586168, + 2305844168854865053,1152922663174276157,1152922662100534381,5991479378997,1152922659953054507,2305844163486155833,2305844278376535945,1152923153874294650, + 2305844160264930791,1152923152800552825,2305844158117446703,1152923151726811000,2305844155969963053,1152923150653069175,2305844153822479403,1152923149579327350, + 2305844151674995753,1152923148505585525,2305844149527512103,1152923147431843700,2305844147380028453,1152923146358101875,2305844145232544803,1152923145284360050, + 2305844143085061153,1152923144210618225,2305844140937577503,1152923143136876400,2305844138790093853,2305844137716352049,1152923139915650487,2305844135568873370, + 2305849478508189132,2305844133421384728,1152923154948036371,1152923153874294546,2305844130200159253,1152923152800552721,2305844128052675603,1152923151726810896, + 2305844125905191953,1152923150653069071,2305844123757708303,1152923149579327246,2305844121610224653,1152923148505585421,2305844119462741003,1152923147431843596, + 2305844117315257353,1152923146358101771,2305844115167773703,1152923145284359946,2305844113020290053,1152923144210618121,2305844110872806403,1152923143136876296, + 2305844108725322753,2305844107651580950,1152922601970992154,5991479378941,1152922599823511883,2305844103356613682,1152923139915650505,2305844101209135002, + 1152927993228695414,2305844099061651337,2305844097987904504,2305844096914162731,1152927478906361719,2305844094766684041,5991479378930,2305844092619195475, + 1152923154948036469,1152923153874294644,2305844089397969903,1152923152800552819,2305844087250486253,1152923151726810994,2305844085103002603,2305844084029260784, + 1152922578348671988,5991479378919,1152922576201192125,2305844079734293498,1152927447767844339,2305844077586814874,2305844076513068022,2305844075439326251, + 1152922569758737384,1152927446694102515,2305844072218105754,2305844093692937207,2305844070070617053,1152923154948036465,1152923153874294640,2305844066849391578, + 1152923152800552815,2305844064701907928,1152923151726810990,2305844062554424278,2305844061480682459,1152922555800093663,1152927483201329015,2305844058259462025, + 5991479378896,2305844056111973459,2305844055038231567,1152922549357642706,5991479378892,1152922547210162646,2305844050743264228,1152927445620360691, + 2305844048595785626,1152923153874294547,2305844046448297030,2305844045374555079,5991479378884,1152926667157541578,1152922537546486579,1152922536472744635, + 1152922535399004050,1152922534325257155,2305844037858362313,2305844160264930374,2305844035710878836,5991479378875,1152926186121204526,1152922527882811282, + 1152922526809064378,2305844030342169533,1152923152800552722,2305844028194685894,1152923151726810897,2305844026047202228,1152923150653069072,2305844023899718578, + 2305844022825976901,5991479378863,1152922527882810157,1152922514997904302,2305844018531009462,1152927444546618867,2305844016383530906,2305844015309784134, + 2305844158117446704,2305844013162300460,2305844012088558634,2305844011014816680,5991479378852,1152926186121204402,1152922503186748205,1152922502113002403, + 2305844005646107563,1152927993228695407,2305844003498629016,2305844002424882289,2305844001351140425,2305844000277398448,2305848987808175983,1152922493523072923, + 2305843997056178072,2305843995982431345,2305843994908689481,1152923153874294543,1152923152800552718,2305843991687463828,1152923151726810893,2305843989539980178, + 1152923150653069068,2305843987392496528,2305843986318754709,1152922480638165914,5991479378828,1152926618839160722,1152922477416945533,1152922476343198603, + 2305843979876303775,2305844001351140265,2305843977728820144,2305843994908689321,2305843975581336462,1152922469900747653,5991479378818,1152926618839159597, + 1152922466679527293,1152922465605780353,2305843969138885511,1152923153874292959,1152923152800550647,2305843965917660028,1152923151726808818,2305843963770176378, + 1152923150653066989,2305843961622692728,2305843960548950939,1152923153874292456,1152923152800550627,2305843957327725428,1152923151726808798,2305843955180241778, + 1152923150653066969,2305843953032758128,2305843951959016341,1152922446278427509,1152927993228695406,2305843948737795992,2305843947664049265,2305843946590307241, + 2305843945516565424,1152922439835976556,2305848987808175982,1152922437688498075,2305843941221603224,2305843940147856497,2305843939074114473,2305843938000372622, + 1152922432319783782,5991479378783,1152922430172303137,2305843933705405309,1152923153874294665,2305843931557921641,2305843930484179911,2305849449517159884, + 1152922423729854363,2305843927262959512,2305843926189212785,2305843925115471167,2305843924041728967,1152922418361140057,5991479378770,1152922416213659388, + 2305843919746761564,2305843946590307401,1152923152800552840,2305843916525536091,1152923151726811015,2305843914378052428,1152923150653069190,2305843912230568778, + 2305843911156826958,5991479378759,1152922404402499174,2305843907935601487,1152923139915650499,2305843905788123034,2305843904714376264,1152923154948036474, + 2305843902566892353,2305843901493150662,5991479378750,1152926186121204411,1152922393665082157,1152922392591336253,2305843896124441412,2305843904714380748, + 2305843893976958024,2305843892903215936,2305843891829474246,5991479378741,1152922393665083282,1152922384001401652,2305843887534506809,1152927443472877043, + 2305843885387028378,2305843884313286553,1152927993228695448,2305843882165797678,2305843881092056551,2305843880018314288,2305843878944572462,5991479378729, + 1152927983565017902,1152922371116504957,1152922370042757928,2305843873575863089,1152923146358101896,2305843871428379683,1152923145284360071,2305843869280895778, + 1152923144210618246,2305843867133412128,1152923143136876421,2305843864985928478,2305843863912186929,1152922358231598078,5991479378714,1152922356084114818, + 2305843859617219364,1152922353936631157,5142149600956,5087388762901,5085241279252,5146444563219,1152922721156339134,1226213163793, + 1152922346420441904,2305843849953542930,1152922707197695422,1209033294605,1152922342125474593,2305843845658575630,5133559661322,5247376294665, + 1152922669616731582,1180042265351,1152922335683023482,2305843839216124680,1158567428871,1152922332461794413,1157493687042,1152922330314314539, + 2305843833847415556,1152922601970996670,1127428915966,1152922326019346763,2305843829552448255,1152922578348676542,1086626726650,1152922321724379837, + 2305843825257480955,1065151890170,1152922318503150547,1064078148341,1152922316355666893,1050119504627,1152922314208186838,2305843817741288183, + 1029718409968,1022202217199,1010391057134,997506155245,1152922480638170558,989989962475,1152922305618248585,2305843809151353580, + 1152922469900752318,967441384167,1152922301323281279,2305843804856386280,1152922446278432190,950261514979,1152922297028313959,940597838561, + 1152922294880830304,934155387615,1152922292733349665,2305843796266451684,1152922418361144766,920196743899,1152922288438382332,2305843791971484380, + 3957812363992,887984489175,879394554582,865435910869,853624750846,1152922280922187138,2305843784455291604,774167855894, + 1152922277700966082,1152922775917172423,2305843780160324303,1152923004624180931,1152922274479740615,2305843776939098828,1152927442399135219,2305843774791620506, + 2305843773717878681,1152927993228695404,2305843771570389703,1152923154948036458,2305843769422906053,5991479378627,1152922262668579065,2305843766201685452, + 2305843773717878634,1152927993228695300,2305843762980455103,1152923154948036354,2305843760832971453,5991479378619,2305847687506825858,2305843757611750016, + 2305843756538007810,2305843755464266364,2305843754390524538,1152922248709935358,1152922247636189882,2305843751169295040,2305843761906714052,5991479378609, + 1152926175383786283,1152922242267480752,2305843745800585906,1152922240119997810,743029346553,737660633771,732291924652,1152922235825034946, + 1152922271258515143,2305843738284393128,1152923001402955459,1152922232603809479,2305843735063167653,2305844278376534840,1152923154948036450,1152923153874294625, + 2305843730768200353,1152923152800552800,2305843728620716703,1152923151726810975,2305843726473233053,1152923150653069150,2305843724325749403,1152923149579327325, + 2305843722178265753,1152923148505585500,2305843720030782103,1152923147431843675,2305843717883298453,1152923146358101850,2305843715735814803,1152923145284360025, + 2305843713588331153,1152923144210618200,2305843711440847503,1152923143136876375,2305843709293363853,2305843708219622050,5991479378570,1152923759464679498, + 1152922200391550991,1152922199317813076,1152922198244065929,2305843701777176012,2305844205362090808,2305843699629687443,5991479378562,1152922199317809107, + 1152922191801614977,2305843695334720132,1152927993228695382,2305843693187240760,2305843692113495032,2175400941398,680752321996,1152922184285427554, + 1152922185359169374,2305843686744785528,1152922181064197633,1152922184285427553,1152922185359169373,2305843682449818228,1152922176769230336,2305843680302334581, + 1152922184285427552,1152922185359169372,2305843677081109103,1152922171400521215,2305843674933625456,1152922184285427551,1152922185359169371,2305843671712399978, + 1152922166031812094,2305843669564916331,2305843668491174523,5991479378533,1152922200391554915,1152922160663107412,1152922159589360228,2305843663122465406, + 2305843692113495010,2305843660974981734,5991479378526,1152923783087003492,1152922153146910735,1152922152073172820,1152922150999425629,2305843654532530784, + 2305843692113495005,2305843652385047142,5991479378518,1152922153146914659,1152922144556980052,1152922143483232853,2305843647016338008,2305843692113495123, + 2305843644868854427,5991479378511,1152923760538425190,1152922137040783412,1152922135967041551,1152922134893298254,2305843638426403409,2305844134495130424, + 2305843636278919819,5991479378503,1152922135967045475,1152922128450852692,1152922127377105478,2305843630910210633,2305843904714381156,1152927993228695395, + 2305843627688985153,2305843626615243425,1152923153874294616,2305843624467759678,5991479378492,6431713531340,6410238689850,1152922115565950821, + 609885356601,5385888994764,1152922112344719927,1152922111270978107,2305843614804083266,1152922542915196771,1152922728672528399,2305843611582857778, + 6427418564044,1152922104828527152,1152922682501633891,1152922510702938127,2305843606214148653,1152922100533565282,2305843604066665006,2305843602992928609, + 1152927927730443708,2305843600845444960,2305843599771703135,1152922094091114395,2305843597624214056,1152923154948036445,2305843595476730403,6424197338572, + 1152922088722405212,6423123596748,1152922086574916127,1152922086574917411,2305843589034279453,1152922088722405210,1152922082279954270,2305843585813053979, + 1152927922361735007,1152922079058728798,2305843582591828504,1152922076911240704,1152922075837497903,2305843579370603041,1152923153874294620,1152923152800552795, + 2305843576149377553,1152923151726810970,2305843574001893903,1152923150653069145,2305843571854410253,1152922066173826914,2305843569706926610,5991479378441, + 1152922114492208996,557272007224,1152922060805112328,2305843564338217523,2305843884313286494,1152927993228695392,2305843561116992003,1152923154948036447, + 2305843558969508353,2305849430189807052,2305849423747356108,546534588926,1152922050067695104,2305843553600799231,1152922051141436927,2305843551453315578, + 5991479378424,1152922061878859619,539018396167,1152922042551506786,1152922041477759479,2305843545010864644,2305844644522497946,2305843542863386464, + 1152927993228695391,2305843540715897328,1152923154948036446,2305843538568413678,1152923153874294621,2305843536420930028,2305844216099510112,2305843534273446383, + 2305843533199704557,2305843532125962731,1152922026445373930,5991479378405,1152922043625248610,518617301494,1152922022150406628,2305843525683511794, + 1152922020002923887,2305843696408461958,2305843522462286434,2305843521388544602,2305843520314802771,2305843519241060939,2305843518167319108,2305843517093577269, + 2305843516019835398,2305843514946093556,1152922026445379006,1152922030740346721,2305843511724868053,1152922006044279266,2305843509577384406,499289948639, + 1152922002823059138,1152922229382584007,2305843505282417103,1152922998181729987,1152921999601833671,2305843502061191628,1152927441325393395,2305843499913713562, + 1152927993228695381,1152923154948036438,2305843496692482503,2305843495618740680,1152923149579327326,1152923148505585501,2305843492397515203,1152923147431843676, + 2305843490250031553,1152923146358101851,2305843488102547903,2305843487028806084,5991479378364,1152922152073167481,1152921979200733627,2305843482733843916, + 1152923153874294626,1152923152800552801,2305843479512613303,1152923151726810976,2305843477365129653,1152923150653069151,2305843475217646003,2305843474143904196, + 5991479378352,1152922152073167482,1152921966315831727,2305843469848936888,1152922144556974713,1152921963094606267,2305843466627711404,1152922144556974714, + 1152921959873380783,2305843463406485929,2305843540715902816,2305843461259002349,2305843460185261129,1152923153874294619,1152923152800552794,2305843456964034978, + 1152923151726810968,2305843454816551328,1152923150653069143,2305843452669067678,2305843451595325859,5991479378331,1152922042551502416,1152921943767253402, + 2305843447300358566,1152927440251656022,2305843445152880473,2305849431263548876,1152927439177908628,2305843441931649429,1152921936251061760,2305843439784165796, + 2305843438710424519,5991479378319,1152922042551506785,1152921930882351502,2305843434415456663,2305844554328184664,2305844554328184663,1152921926587384202, + 2305844554328184660,1152921924439900552,2305844554328184659,1152921922292416902,1152927915919283648,2305843424751781279,1152921919071191428,5991479378305, + 1152921916923707910,2305843420456812939,1152921914776225132,2305843470922678714,458487759228,455266533755,439160406394,426275504505, + 1152921926587389374,423054279031,1152921906186289543,420906795381,1152921904038805893,418759311731,1152921901891322242,416611828081, + 1152921899743838726,2305843403276943736,392989507965,1152921896522618562,1152921996380608199,2305843398981976428,1152922994960504515,1152921893301393095, + 2305843395760750953,1152927438104167923,2305843393613272986,2305843392539531102,2305843391465783810,1152923154948036444,2305843389318300003,2305843388244558242, + 2305843387170816417,1152923154948036441,2305843385023332707,2305843383949591101,1152923152800552791,2305843381802107228,1152921876121518431,2305843390392041926, + 1152923153874294613,2305843377507139928,1152923152800552788,2305843375359656278,1152921869679067481,5991479378259,1152921867531583989,2305843371064694220, + 1152927437030426099,2305843368917211034,2305843367843469154,1152927993228695393,2305843365695979853,1152923154948036448,2305843363548496203,1152923153874294623, + 2305843361401012553,1152923152800552798,2305843359253528903,1152923151726810973,2305843357106045253,1152923150653069148,2305843354958561603,1152923149579327323, + 2305843352811077953,1152923148505585498,2305843350663594303,1152923147431843673,2305843348516110653,1152923146358101848,2305843346368627003,1152923145284360023, + 2305843344221143353,5991479378231,1152921837466814538,2305843340999917904,1152927435956684275,2305843338852439962,2305843337778698082,2305843336704950604, + 2305843335631208778,2305843334557466952,2305843333483725126,2305843332409983300,2305843331336241474,2305843330262499648,2305843329188757822,2305843328115015996, + 2305843327041274170,2305843325967532344,5991479378214,1152921819213203400,2305843322746306868,1152921837466815280,2305843320598823203,2296733767116, + 1152921813844498258,1152921812770750757,2305843316303855905,1152921810623268201,1152921876121524051,1152923239773640532,6426344816922,1152921806328299871, + 2305843309861404955,1152921804180816212,6426344822460,1152921802033332569,2305843305566437654,1152921799885849077,2305843303418955850,2305843302345213896, + 6414533662396,1152921795590884144,2305843299123986704,1152921795590881567,2305843296976503053,286689067292,1152921790222177986,1152921890080167623, + 2305843292681535753,1152922991739279043,1152921787000952519,2305843289460310278,6529424037755,1152921782705985220,1152921783779727047,2305843285165342978, + 6528350295930,1152921778411017924,1152921779484759751,2305843280870375678,6527276554105,1152921774116050628,1152921775189792455,2305843276575408378, + 6526202812280,1152921769821083332,1152921770894825159,2305843272280441078,6525129070455,1152921765526116036,1152921766599857863,2305843267985473778, + 6524055328630,1152921761231148740,1152921762304890567,2305843263690506478,6522981586805,1152921756936181444,1152921758009923271,2305843259395539178, + 6521907844980,1152921752641214148,1152921753714955975,2305843255100571878,6520834103155,1152921748346246852,1152921749419988679,2305843250805604578, + 6519760361330,1152921744051279556,1152921745125021383,2305843246510637278,6518686619505,1152921739756312260,1152921740830054087,2305843242215669978, + 6517612877680,1152921735461344964,1152921736535086791,2305843237920702678,6516539135855,1152921731166377668,1152921732240119495,2305843233625735378, + 6515465394030,1152921726871410372,1152921727945152199,2305843229330768078,6514391652205,1152921722576443076,1152921723650184903,2305843225035800778, + 6513317910380,1152921718281475780,1152921719355217607,2305843220740833478,6512244168571,1152921713986508483,1152921715060250311,2305843216445866178, + 6511170426746,1152921709691541187,1152921710765283015,2305843212150898878,6510096684921,1152921705396573891,1152921706470315719,2305843207855931578, + 6509022943096,1152921701101606595,1152921702175348423,2305843203560964278,6507949201271,1152921696806639299,1152921697880381127,2305843199265996978, + 6506875459446,1152921692511672003,1152921693585413831,2305843194971029678,6505801717621,1152921688216704707,1152921689290446535,2305843190676062378, + 6504727975796,1152921683921737411,1152921684995479239,2305843186381095078,6503654233971,1152921679626770115,1152921680700511943,2305843182086127778, + 6502580492146,1152921675331802819,1152921676405544647,2305843177791160478,6501506750321,1152921671036835523,1152921672110577351,2305843173496193178, + 6500433008496,1152921666741868227,1152921667815610055,2305843169201225878,6499359266671,1152921662446900931,1152921663520642759,2305843164906258578, + 6498285524846,1152921658151933635,1152921659225675463,2305843160611291278,6497211783021,1152921653856966339,1152921654930708167,2305843156316323978, + 6496138041196,1152921649561999043,1152921650635740871,2305843152021356678,6251324905158,1152927757005493950,1152927758079235775,139586442950, + 1152921644193289919,1152921643119548095,136365217478,1152921640972064447,1152921639898322623,133143992006,1152921637750838975,1152921636677097151, + 129922766534,1152921634529613503,1152921633455871679,126701541062,1152921631308388031,1152921630234646207,123480315590,1152921628087162559, + 1152921627013420735,120259090118,1152921624865937087,1152921623792195263,1152927895518188974,2305843124104075073,1152927893370705326,2305843121956591423, + 1152927891223221678,2305843119809107773,1152927889075738030,2305843117661624123,1152927886928254382,2305843115514140473,1152927884780770734,2305843113366656823, + 1152927882633287086,2305843111219173173,1152927880485803438,2305843109071689523,1152921638824575104,1152921602317353082,1152921601243611255,1152921600169869428, + 1152921599096127601,1152921598022385774,1152921596948649664,1152921595874902122,1152921638824575107,1152921593727418490,1152921592653676663,1152921591579934836, + 1152921590506193009,1152921589432451182,1152921588358709377,1152921587284967528,2305843090818072660,1152921642045800579,1152921584063742074,1152921582990000247, + 1152921581916258420,1152921580842516593,1152921579768774766,1152921578695032958,1152921577621291110,2305843081154396235,1152921584063742077,1152921574400065655, + 1152921573326323828,1152921572252582001,1152921571178840174,1152921570105098363,1152921569031356516,2305843072564461634,1152921574400065658,1152921565810131060, + 1152921564736389233,1152921563662647406,1152921562588905592,1152921561515163746,2305843065048268858,1152921565810131063,1152921558293938289,1152921557220196462, + 1152921556146454645,1152921555072712800,2305843058605817907,1152921558293938292,1152921551851487342,1152921550777745522,1152921549704003678,2305843053237108781, + 1152921551851487345,1152921546482778223,1152921545409036380,2305843048942141480,5991479383750,1152921542187810852,36507222148,2305849499983025865, + 2305849542932694341,1152928037252110235,2305843041425948703,1152928036178363905,2305843039278465053,1152928035104622080,2305843037130981403,2305843036057240979, + 1152921531450394003,2305849504277988755,1152927998597404571,2305843031762272278,1152927997523658241,2305843029614788628,1152927996449916416,2305843027467304978, + 1152921521786716184,1152921529302914494,2305843024246079503,1152921521786716183,1152921517491748896,2305843021024854029,1152927759152971786,2305843018877370401, + 1152927759152977601,1152921512123045576,2305843015656144904,1152921509975556101,1152921508901814276,1152921507828072451,1152921506754330626,1152921505680588801 ] diff --git a/crates/lib/core/asm/sys/vm/deep_queries.masm b/crates/lib/core/asm/sys/vm/deep_queries.masm index f2ea0e28dc..028e019428 100644 --- a/crates/lib/core/asm/sys/vm/deep_queries.masm +++ b/crates/lib/core/asm/sys/vm/deep_queries.masm @@ -74,22 +74,22 @@ end #! 3. alpha is the randomness used in order to build the DEEP polynomial. #! #! Inputs: [Y, query_ptr] -#! Outputs: [Y, q_x_at_alpha_1, q_x_at_alpha_0, q_x_at_alpha_1, q_x_at_alpha_0, index, query_ptr] +#! Outputs: [Y, q_x_at_alpha_0, q_x_at_alpha_1, q_x_at_alpha_0, q_x_at_alpha_1, index, query_ptr] #! #! where: #! - Y is a "garbage" word. proc load_query_row # Process the main segment of the execution trace portion of the query exec.process_main_segment_execution_trace - #=> [Y, ptr_x, ptr_alpha_inv, acc1, acc0, depth, index, query_ptr] + #=> [Y, ptr_x, ptr_alpha_inv, acc0, acc1, depth, index, query_ptr] # Process the auxiliary segment of the execution trace portion of the query exec.process_aux_segment_execution_trace - #=> [Y, ptr_x, ptr_alpha_inv, acc1, acc0, depth, index, query_ptr] + #=> [Y, ptr_x, ptr_alpha_inv, acc0, acc1, depth, index, query_ptr] # Process the constraints composition polys trace portion of the query exec.process_constraints_composition_poly_trace - #=> [Y, q_x_at_alpha_1, q_x_at_alpha_0, q_x_at_alpha_1, q_x_at_alpha_0, index, query_ptr] + #=> [Y, q_x_at_alpha_0, q_x_at_alpha_1, q_x_at_alpha_0, q_x_at_alpha_1, index, query_ptr] end # MAIN TRACE SEGMENT PROCESSING @@ -98,28 +98,28 @@ end #! Handles the logic for processing the main segment of the execution trace. #! #! Inputs: [Y, query_ptr] -#! Output: [Y, ptr_x, ptr_alpha_inv, acc1, acc0, depth, index, query_ptr] +#! Output: [Y, ptr_x, ptr_alpha_inv, acc0, acc1, depth, index, query_ptr] proc process_main_segment_execution_trace # Load the query index - dup.4 mem_loadw_be + dup.4 mem_loadw_le #=> [index, depth, y, y, query_ptr] where y are "garbage" values here and throughout # Get commitment to main segment of the execution trace movdn.3 movdn.2 push.0.0 - exec.constants::main_trace_com_ptr mem_loadw_be + exec.constants::main_trace_com_ptr mem_loadw_le #=>[MAIN_TRACE_TREE_ROOT, depth, index, query_ptr] # Use the commitment to get the leaf and save it dup.5 dup.5 mtree_get - exec.constants::tmp3 mem_storew_be + exec.constants::tmp3 mem_storew_le adv.push_mapval #=>[LEAF_VALUE, MAIN_TRACE_TREE_ROOT, depth, index, query_ptr] - exec.constants::tmp2 mem_loadw_be + exec.constants::tmp2 mem_loadw_le swapw - #=>[LEAF_VALUE, ptr_x, ptr_alpha_inv, acc1, acc0, depth, index, query_ptr] + #=>[LEAF_VALUE, ptr_x, ptr_alpha_inv, acc0, acc1, depth, index, query_ptr] # Load the values of the main segment of the execution trace at the current query. We also # compute their hash and the value of their random linear combination using powers of a @@ -130,10 +130,11 @@ proc process_main_segment_execution_trace #=> [Y, Y, 0, 0, 0, 0, ptr, y, y, y] exec.load_main_segment_execution_trace - #=> [Y, L, C, ptr_x, ptr_alpha_inv, acc1, acc0, depth, index, query_ptr] + #=> [Y, L, C, ptr_x, ptr_alpha_inv, acc0, acc1, depth, index, query_ptr] # Load the leaf value we got using `mtree_get` and compare it against the hash we just computed - exec.constants::tmp3 mem_loadw_be + swapw + exec.constants::tmp3 mem_loadw_le assert_eqw.err=LEAF_VALUE_MISMATCH end @@ -142,9 +143,9 @@ end #! Inputs: [Y, Y, 0, 0, 0, 0, ptr] #! Outputs: [Y, D, C, ptr] #! -#! Cycles: 30 +#! Cycles: 27 proc load_main_segment_execution_trace - repeat.10 + repeat.9 adv_pipe horner_eval_base exec.poseidon2::permute @@ -157,34 +158,35 @@ end #! Handles the logic for processing the auxiliary segment of the execution trace, if such a trace #! exists. #! -#! Inputs: [Y, ptr_x, ptr_alpha_inv, acc1, acc0, depth, index, query_ptr] -#! Output: [Y, ptr_x, ptr_alpha_inv, acc1, acc0, depth, index, query_ptr] +#! Inputs: [Y, ptr_x, ptr_alpha_inv, acc0, acc1, depth, index, query_ptr] +#! Output: [Y, ptr_x, ptr_alpha_inv, acc0, acc1, depth, index, query_ptr] proc process_aux_segment_execution_trace # Load aux trace commitment and get leaf - exec.constants::aux_trace_com_ptr mem_loadw_be + exec.constants::aux_trace_com_ptr mem_loadw_le # Get the leaf against the auxiliary trace commitment for the current query dup.9 dup.9 mtree_get - exec.constants::tmp3 mem_storew_be + exec.constants::tmp3 mem_storew_le adv.push_mapval - #=> [L, R, ptr_x, ptr_alpha_inv, acc1, acc0, depth, index, query_ptr] + #=> [L, R, ptr_x, ptr_alpha_inv, acc0, acc1, depth, index, query_ptr] # Load the values of the auxiliary segment of the execution trace at the current query # Set up the stack - exec.constants::zero_word_ptr mem_loadw_be + exec.constants::zero_word_ptr mem_loadw_le swapw padw - #=> [Y, Y, C, ptr_x, ptr_alpha_inv, acc1, acc0, depth, index, query_ptr] + #=> [Y, Y, C, ptr_x, ptr_alpha_inv, acc0, acc1, depth, index, query_ptr] # Load the first 4 columns as a batch of 4 quadratic extension field elements. exec.load_aux_segment_execution_trace - #=> [Y, D, C, ptr_x, ptr_alpha_inv, acc1, acc0, depth, index, query_ptr] + #=> [Y, D, C, ptr_x, ptr_alpha_inv, acc0, acc1, depth, index, query_ptr] # Load the leaf value we got using `mtree_get` and compare it against the hash we just computed - exec.constants::tmp3 mem_loadw_be + swapw + exec.constants::tmp3 mem_loadw_le assert_eqw.err=LEAF_VALUE_MISMATCH - #=> [Y, ptr_x, ptr_alpha_inv, acc1, acc0, depth, index, query_ptr] + #=> [Y, ptr_x, ptr_alpha_inv, acc0, acc1, depth, index, query_ptr] end #! Loads the portion of the query associated to the auxiliary segment of the execution trace. @@ -196,7 +198,7 @@ end proc load_aux_segment_execution_trace repeat.2 adv_pipe - horner_eval_ext + horner_eval_base exec.poseidon2::permute end end @@ -206,30 +208,31 @@ end #! Handles the logic for processing the constraints composition polynomials trace. #! -#! Inputs: [Y, ptr_x, ptr_alpha_inv, acc1, acc0, depth, index, query_ptr] -#! Output: [Y, q_x_at_alpha_1, q_x_at_alpha_0, q_x_at_alpha_1, q_x_at_alpha_0, index, query_ptr] +#! Inputs: [Y, ptr_x, ptr_alpha_inv, acc0, acc1, depth, index, query_ptr] +#! Output: [Y, q_x_at_alpha_0, q_x_at_alpha_1, q_x_at_alpha_0, q_x_at_alpha_1, index, query_ptr] proc process_constraints_composition_poly_trace # Load the commitment to the constraint trace - exec.constants::composition_poly_com_ptr mem_loadw_be - #=> [R, ptr_x, ptr_alpha_inv, acc1, acc0, depth, index, query_ptr] + exec.constants::composition_poly_com_ptr mem_loadw_le + #=> [R, ptr_x, ptr_alpha_inv, acc0, acc1, depth, index, query_ptr] # Get the leaf against the commitment dup.9 movup.9 mtree_get - exec.constants::tmp3 mem_storew_be + exec.constants::tmp3 mem_storew_le adv.push_mapval - #=>[L, R, ptr_x, ptr_alpha_inv, acc1, acc0, index, query_ptr] + #=>[L, R, ptr_x, ptr_alpha_inv, acc0, acc1, index, query_ptr] # Load the 8 columns as quadratic extension field elements in batches of 4. padw swapw.2 exec.load_constraints_composition_polys_trace - #=> [Y, L, Y, ptr_x, ptr_alpha_inv, acc1, acc0, index, query_ptr] + #=> [Y, L, Y, ptr_x, ptr_alpha_inv, acc0, acc1, index, query_ptr] # Load the leaf value we got using `mtree_get` and compare it against the hash we just computed - exec.constants::tmp3 mem_loadw_be + swapw + exec.constants::tmp3 mem_loadw_le assert_eqw.err=LEAF_VALUE_MISMATCH - #=> [Y, ptr_x, ptr_alpha_inv, acc1, acc0, index, query_ptr] + #=> [Y, ptr_x, ptr_alpha_inv, acc0, acc1, index, query_ptr] # Re-order the stack swapw @@ -247,7 +250,7 @@ end proc load_constraints_composition_polys_trace repeat.2 adv_pipe - horner_eval_ext + horner_eval_base exec.poseidon2::permute end end diff --git a/crates/lib/core/asm/sys/vm/mod.masm b/crates/lib/core/asm/sys/vm/mod.masm index eef1a63efe..556d2d19c4 100644 --- a/crates/lib/core/asm/sys/vm/mod.masm +++ b/crates/lib/core/asm/sys/vm/mod.masm @@ -1,19 +1,74 @@ +use miden::core::sys::vm::aux_trace use miden::core::sys::vm::deep_queries use miden::core::sys::vm::constraints_eval use miden::core::sys::vm::ood_frames use miden::core::sys::vm::public_inputs use miden::core::stark::verifier +use miden::core::stark::constants -# Indicates the existence of auxiliary trace segment. -const IS_AUX_TRACE = 1 +# Acceptable security parameters for Miden VM proof verification. +# These define the security policy enforced by `assert_acceptable_options`. +# If the protocol security level changes, update these constants accordingly. +const ACCEPTABLE_NUM_QUERIES = 27 +const ACCEPTABLE_QUERY_POW_BITS = 16 +const ACCEPTABLE_DEEP_POW_BITS = 12 +const ACCEPTABLE_FOLDING_POW_BITS = 4 -# Main segment width is 80 (0x50) and there are 1 (0x01) auxiliary segments -# of width 8 (0x08) using 16 (0x10) random extension field elements -const TRACE_INFO = 0x50010810 +# RELATION_DIGEST = hash(PROTOCOL_ID, CIRCUIT_COMMITMENT). +# This is a compile-time constant computed once per AIR that binds the Fiat-Shamir +# transcript to the relation (AIR structure + fix protocol parameter choices). +# +# PROTOCOL_ID (defined in circuit_evaluation.rs) implicitly covers every hardcoded +# protocol choice: hash function, field, blowup factor, FRI folding factor, coset +# offset, max remainder degree, etc. It must be bumped when any of these change. +# CIRCUIT_COMMITMENT covers the AIR constraints (via the encoded ACE circuit hash). +const RELATION_DIGEST_0 = 2564365500194292689 +const RELATION_DIGEST_1 = 7963649451118915546 +const RELATION_DIGEST_2 = 13003513905888733288 +const RELATION_DIGEST_3 = 3704785727996306162 + +#! Loads security parameters from the advice stack and stores them in memory. +#! +#! The advice stack must contain, in order: +#! [num_queries, query_pow_bits, deep_pow_bits, folding_pow_bits] +#! +#! After this procedure, all four values are available in memory via the corresponding +#! accessors in constants.masm (get_number_queries, get_query_pow_bits, etc.). +#! +#! Input: [...] +#! Output: [...] +proc load_security_params + adv_push exec.constants::set_number_queries + adv_push exec.constants::set_query_pow_bits + adv_push exec.constants::set_deep_pow_bits + adv_push exec.constants::set_folding_pow_bits +end + +#! Asserts that the security parameters in memory meet the Miden VM security policy. +#! +#! Input: [...] +#! Output: [...] +proc assert_acceptable_options + exec.constants::get_number_queries + push.ACCEPTABLE_NUM_QUERIES assert_eq.err="num_queries does not match acceptable security policy" + + exec.constants::get_query_pow_bits + push.ACCEPTABLE_QUERY_POW_BITS assert_eq.err="query_pow_bits does not match acceptable security policy" + + exec.constants::get_deep_pow_bits + push.ACCEPTABLE_DEEP_POW_BITS assert_eq.err="deep_pow_bits does not match acceptable security policy" + + exec.constants::get_folding_pow_bits + push.ACCEPTABLE_FOLDING_POW_BITS assert_eq.err="folding_pow_bits does not match acceptable security policy" +end #! Verifies a STARK proof attesting to the correct execution of a program in the Miden VM. #! +#! Security parameters (num_queries, query_pow_bits, deep_pow_bits, folding_pow_bits) are +#! loaded from the advice stack, validated against the acceptable security policy, and +#! stored in memory for use by the generic verifier. +#! #! - The public inputs are composed of the input and output stacks, of fixed size equal to 16, as #! well as the program and the kernel procedures digests. #! - There are two trace segments, main and auxiliary. It is assumed that the main trace segment @@ -24,37 +79,21 @@ const TRACE_INFO = 0x50010810 #! Note that, due to the padding of the main trace columns, the number of OOD evaluations per row #! is 80 for the main trace. #! -#! Inputs: [log(trace_length), num_queries, grinding] +#! Inputs: [log(trace_length)] #! Outputs: [] -#! -#! Cycles: -#! 1- Remainder polynomial size 64: -#! 2515 + num_queries * (512 + num_fri_layers * 83) + 108 * num_fri_layers + 10 * log(trace_length) -#! 2- Remainder polynomial size 128: -#! 2540 + num_queries * (541 + num_fri_layers * 83) + 108 * num_fri_layers + 10 * log(trace_length) -#! -#! where num_fri_layers is computed as: -#! -#! 1- If log(trace_length) is even, then num_fri_layers = (log(trace_length) - 6) / 2, where 6 = log2(64), -#! 2- If log(trace_length) is odd, then num_fri_layers = (log(trace_length) - 7) / 2, where 7 = log2(128). pub proc verify_proof - # --- Get constants ------------------------------------------------------- + # --- Load and validate security parameters from advice stack --- - # Flag indicating the existence of auxiliary trace - push.IS_AUX_TRACE movdn.3 - # => [log(trace_length), num_queries, grinding, is_aux_trace] + exec.load_security_params + exec.assert_acceptable_options + # => [log(trace_length)] - # Number of fixed length public inputs - exec.public_inputs::get_num_fixed_len_public_inputs movdn.3 - # => [log(trace_length), num_queries, grinding, num_fixed_len_pi, is_aux_trace] - - # Trace info as one field element - push.TRACE_INFO movdn.3 - # => [log(trace_length), num_queries, grinding, trace_info, num_fixed_len_pi, is_aux_trace] + # --- Get constants ------------------------------------------------------- - # Number of constraints - exec.constraints_eval::get_num_constraints movdn.3 - # => [log(trace_length), num_queries, grinding, num_constraints, trace_info, num_fixed_len_pi, is_aux_trace] + # Push RELATION_DIGEST, then move log(trace_length) back to top. + push.RELATION_DIGEST_3.RELATION_DIGEST_2.RELATION_DIGEST_1.RELATION_DIGEST_0 + movup.4 + # => [log(trace_length), rd0, rd1, rd2, rd3] # --- Load the digests of all dynamically invoked procedures -------------- @@ -62,7 +101,8 @@ pub proc verify_proof procref.constraints_eval::execute_constraint_evaluation_check procref.ood_frames::process_row_ood_evaluations procref.public_inputs::process_public_inputs - # =>[D3, D2, D1, D0, log(trace_length), num_queries, grinding, num_constraints, trace_info, num_fixed_len_pi, is_aux_trace] + procref.aux_trace::observe_aux_trace + # => [D0, D1, D2, D3, D4, log(tl), rd0, rd1, rd2, rd3] # --- Call the core verification procedure from `core-lib` ------------------ diff --git a/crates/lib/core/asm/sys/vm/ood_frames.masm b/crates/lib/core/asm/sys/vm/ood_frames.masm index b74a73f28a..2092c24dfc 100644 --- a/crates/lib/core/asm/sys/vm/ood_frames.masm +++ b/crates/lib/core/asm/sys/vm/ood_frames.masm @@ -8,12 +8,12 @@ use miden::core::crypto::hashes::poseidon2 #! evaluation. #! #! -#! Inputs: [R2, R1, C, ptr, acc1, acc0] -#! Outputs: [R2, R1, C, ptr, acc1`, acc0`] +#! Inputs: [R0, R1, C, ptr, acc0, acc1] +#! Outputs: [R0, R1, C, ptr, acc0`, acc1`] #! -#! Cycles: 72 +#! Cycles: 78 pub proc process_row_ood_evaluations - repeat.24 + repeat.26 adv_pipe horner_eval_ext exec.poseidon2::permute diff --git a/crates/lib/core/asm/sys/vm/public_inputs.masm b/crates/lib/core/asm/sys/vm/public_inputs.masm index d2cac17f52..e948f91442 100644 --- a/crates/lib/core/asm/sys/vm/public_inputs.masm +++ b/crates/lib/core/asm/sys/vm/public_inputs.masm @@ -1,23 +1,45 @@ use miden::core::stark::constants use miden::core::stark::random_coin use miden::core::stark::public_inputs - use miden::core::crypto::hashes::poseidon2 +# PUBLIC INPUTS PROCESSING FOR MIDEN VM RECURSIVE VERIFIER +# ================================================================================================= +# +# This module handles the Miden VM-specific public input processing for the recursive verifier. +# It populates the FLPI and VLPI portions of the ACE READ section (see `stark/constants.masm` +# for the full layout diagram). +# +# Memory layout populated by this module (growing backward from AUX_RAND_ELEM_PTR): +# +# pi_ptr --> [ FLPI: 40 base felts as 40 EF slots ] load_public_inputs +# [ VLPI: reduced kernel value (1 word) ] reduce_variable_length_public_inputs +# anchor --> [ aux_rand: beta0,beta1,alpha0,alpha1 ] (loaded ND here, verified in random_coin) +# +# The FLPI are the input/output stacks (32), program digest (4), and precompile state (4). +# The VLPI reduction is the LogUp kernel ROM boundary correction +# kernel_corr = Σ_i 1 / kernel_proc_message(digest_i) +# (chiplet-side INIT removes; boundary adds). +# +# Advice stack consumption order: +# 1. fixed-length PI (40 base felts) -- load_public_inputs +# 2. num_kernel_proc_digests (1 felt) -- reduce_variable_length_public_inputs +# 3. kernel digests (8 * N base felts) -- reduce_variable_length_public_inputs +# 4. aux randomness (4 base felts) -- reduce_variable_length_public_inputs +# # CONSTANTS # ================================================================================================= -# Number of fixed length public inputs with padding (in field elements) -# This is composed of the input/output operand stacks (16 * 2) and the program digest (4) and four -# zeros for padding to the next multiple of 4. Note that, then, the fixed length public inputs -# which are stored as extension field elements will be double-word aligned. +# Number of fixed length public inputs (in field elements). +# This is composed of the input/output operand stacks (16 * 2), the program digest (4), and the +# precompile transcript state (4). Note that the fixed length public inputs are stored as extension +# field elements and are double-word aligned. const NUM_FIXED_LEN_PUBLIC_INPUTS = 40 -# Number of variable length public input groups +# Number of variable length public input groups. +# The reduced kernel value occupies 1 word (4 base felts) in the ACE READ section. const NUM_VAR_LEN_PI_GROUPS = 1 -# Op label for kernel procedures table messages -const KERNEL_OP_LABEL = 48 # CONSTANTS GETTERS # ================================================================================================= @@ -35,67 +57,47 @@ end #! #! 1. Loading from the advice stack the fixed-length public inputs and storing them in memory #! starting from the address pointed to by `public_inputs_address_ptr`. -#! 2. Loading from the advice stack the variable-length public inputs, storing them temporarily -#! in memory, and then reducing them to an element in the challenge field using the auxiliary -#! randomness. This reduced value is then used to impose a boundary condition on the relevant -#! auxiliary column. -#! -#! Note that the fixed length public inputs are stored as extension field elements while -#! the variable length ones are stored as base field elements. -#! -#! Note also that, while loading the above, we compute the hash of the public inputs. The hashing -#! starts with capacity registers of the hash function set to `C` that is the result of hashing -#! the proof context. +#! 2. Loading kernel procedure digests from the advice stack, reducing them, and storing the +#! reduced result at `variable_length_public_inputs_address_ptr` (in the ACE READ section). +#! 3. Loading the auxiliary randomness from the advice stack so it can be checked later. #! -#! The output D, that is the digest of the above hashing, is then used in order to reseed -#! the random coin. +#! Note that the fixed length public inputs are stored as extension field elements. +#! The kernel digests are temporarily stored in memory starting at +#! `variable_length_public_inputs_address_ptr` during reduction. The final reduced value +#! overwrites the start of this region and remains in the ACE READ section. #! -#! It is worth noting that: +#! POSTCONDITION: random coin input_len=0 on return. #! -#! 1. Only the fixed-length public inputs are stored for the lifetime of the verification procedure. -#! The variable-length public inputs are stored temporarily, as this simplifies the task of -#! reducing them using the auxiliary randomness. On the other hand, the resulting values from -#! the aforementioned reductions are stored right after the fixed-length public inputs. These -#! are stored in a word-aligned manner and padded with zeros if needed. -#! 2. The public inputs address is computed in such a way so as we end up with the following -#! memory layout: +#! The generic verifier (stark/verifier.masm) calls reseed_direct immediately after this +#! procedure, which requires input_len=0. This postcondition holds because: +#! - FLPI (40 base felts) are absorbed in groups of 8 via direct sponge permutation +#! (5 iterations * 8 = 40), bypassing the buffer entirely. +#! - VLPI (kernel digests, each padded to 8 felts) are absorbed via adv_pipe + permute, +#! also bypassing the buffer. +#! - Both paths reset the buffer counters (input_len=0, output_len=8) after completion. #! -#! [..., a_0...a_{m-1}, b_0...b_{n-1}, alpha0, alpha1, beta0, beta1, OOD-evaluations-start, ...] +#! If FLPI size changes from a multiple of 8, or VLPI digest padding changes from 8, +#! this postcondition must be re-verified. #! -#! where: -#! -#! 1. [a_0...a_{m-1}] are the fixed-length public inputs stored as extension field elements. This -#! section is double-word-aligned. -#! 2. [b_0...b_{n-1}] are the results of reducing the variable length public inputs using -#! auxiliary randomness. This section is word-aligned. -#! 3. [alpha0, alpha1, beta0, beta1] is the auxiliary randomness. -#! 4. `OOD-evaluations-start` is the first field element of the section containing the OOD -#! evaluations. -#! 3. Note that for each bus message in a group in the variable length public inputs, each -#! message is expected to be padded to the next multiple of 8 and provided in reverse order. -#! This has the benefit of making the reduction using the auxiliary randomness more efficient -#! using `horner_eval_base`. -#! -#! -#! Input: [C, ...] +#! Input: +#! - Operand stack: [...] +#! - Advice stack: [fixed_len_PI..., num_kernel_proc_digests, +#! kernel_digest_elements..., beta0, beta1, alpha0, alpha1, ...] #! Output: [...] pub proc process_public_inputs # 1) Compute the address where the public inputs will be stored and store it. # This also computes the address where the reduced variable-length public inputs will be stored. exec.get_num_fixed_len_public_inputs push.NUM_VAR_LEN_PI_GROUPS + # => [NUM_VAR_LEN_PI_GROUPS, NUM_FIXED_LEN_PUBLIC_INPUTS, ...] + exec.public_inputs::compute_and_store_public_inputs_address - # => [C, ...] + # => [...] - # 2) Load the public inputs from the advice tape. - # This will also hash them so that we can absorb them into the transcript. + # 2) Load the fixed-length public inputs from the advice tape and observe them. exec.load_public_inputs - # => [D, ...] - - # 3) Absorb into the transcript - exec.random_coin::reseed # => [...] - # 4) Reduce the variable-length public inputs using randomness. + # 3) Load kernel digests, auxiliary randomness, and reduce kernel digests. exec.reduce_variable_length_public_inputs # => [...] end @@ -106,258 +108,331 @@ end #! Loads from the advice stack the public inputs and stores them in memory starting from address #! pointed to by `public_inputs_address_ptr`. #! -#! Note that the public inputs are stored as extension field elements. +#! The public inputs are stored as extension field elements and absorbed into the random coin +#! transcript via direct sponge permutation (bypassing the buffer-based observe API). #! -#! In parallel, it computes the hash of the public inputs being loaded. The hashing starts with -#! capacity registers of the hash function set to `C` resulting from hashing the proof context. -#! The output D is the digest of the hashing of the public inputs. +#! Buffer hygiene: The random coin input/output buffers are flushed before loading the sponge +#! state onto the stack. After the loop, the state is stored back and the buffer counters are +#! reset (input_len=0, output_len=8) so subsequent random coin operations work correctly. #! -#! Inputs: [C, ...] -#! Outputs: [D, ...] +#! Inputs: [...] +#! Outputs: [...] proc load_public_inputs - # 1) Load and hash the fixed length public inputs + # 1) Flush random coin buffers and load sponge state onto the stack. + push.0 exec.constants::random_coin_output_len_ptr mem_store + push.0 exec.constants::random_coin_input_len_ptr mem_store + exec.random_coin::load_random_coin_state + # => [R0, R1, C, ...] + # 2) Place pi_ptr below the 3-word sponge state. exec.constants::public_inputs_address_ptr mem_load - movdn.4 - padw padw + movdn.12 + # => [R0, R1, C, pi_ptr, ...] + + # 3) Load and store the fixed length public inputs. + # Each iteration: load_base_store_extension_double_word loads 8 base elements from advice, + # stores them as 4 EF elements in memory, and returns the original words in the rate + # positions. The subsequent permute absorbs them into the sponge. + # 5 iterations * 8 = 40 = NUM_FIXED_LEN_PUBLIC_INPUTS. repeat.5 exec.public_inputs::load_base_store_extension_double_word exec.poseidon2::permute end + # => [R0', R1', C', pi_ptr + 80, ...] - # 2) Load and hash the variable length public inputs - - ## a) Compute the number of base field elements in total in the variable length public inputs - exec.constants::num_public_inputs_ptr mem_load - exec.get_num_fixed_len_public_inputs - sub - # => [num_var_len_pi, R2, R1, C, ptr, ...] - - ## b) Compute the number of hash iteration needed to hash the variable length public inputs. - ## We also check the double-word alignment. - u32divmod.8 - # => [rem, num_iter, R2, R1, C, ptr, ...] - push.0 assert_eq.err="range check failed: alignment" - # => [num_iter, R2, R1, C, ptr, ...] - - ## c) Prepare the stack for hashing - movdn.13 - # => [R2, R1, C, ptr, num_iter, ...] - dup.13 sub.1 swap.14 - push.0 neq - # => [(num_iter == 0), R2, R1, C, ptr, num_iter - 1, ...] - - ## d) Hash the variable length public inputs - while.true - adv_pipe - exec.poseidon2::permute - # => [R2, R1, C, ptr, num_iter, ...] - dup.13 sub.1 swap.14 - push.0 neq - end - # => [R2, R1, C, ptr, num_iter, ...] - - # 3) Return the final digest - exec.poseidon2::squeeze_digest - # => [D, ptr, num_iter, ...] where D = R1 the digest - movup.4 drop - movup.4 drop - # => [D, ...] + # 4) Store sponge state back to random coin and reset buffer counters. + exec.random_coin::store_random_coin_state + push.0 exec.constants::random_coin_input_len_ptr mem_store + push.8 exec.constants::random_coin_output_len_ptr mem_store + # => [pi_ptr + 80, ...] + + drop end #! Reduces the variable-length public inputs using the auxiliary randomness. #! -#! The procedure non-deterministically loads the auxiliary randomness from the advice tape and -#! stores it at `aux_rand_nd_ptr` so that it can be later checked for correctness. After this, -#! the procedure uses the auxiliary randomness in order to reduce the variable-length public -#! inputs to a single element in the challenge field. The resulting values are then stored -#! contiguously after the fixed-length public inputs. -#! -#! Currently, the only variable-length public inputs are the kernel procedure digests. +#! This procedure: +#! 1. Reads `num_kernel_proc_digests` from the advice stack and stores it temporarily in `tmp3`. +#! 2. Loads kernel procedure digests from the advice stack into memory at +#! `variable_length_public_inputs_address_ptr`, absorbing them into the Fiat-Shamir transcript +#! via the Poseidon2 sponge (one permutation per digest). +#! 3. Loads the auxiliary randomness (alpha, beta) from the advice stack and stores it at +#! `aux_rand_nd_ptr` for later verification. +#! 4. Reduces the kernel digests to a single extension field element using auxiliary randomness. +#! 5. The reduced value is stored at `variable_length_public_inputs_address_ptr` (in the ACE READ +#! section) by `reduce_kernel_digests`. #! #! Input: #! - Operand stack: [...] -#! - Advice stack: [beta0, beta1, alpha0, alpha1, var_len_pi_1_len, ..., var_len_pi_k_len, ...] +#! - Advice stack: [num_kernel_proc_digests, kernel_digest_elements..., +#! beta0, beta1, alpha0, alpha1, ...] #! Output: [...] proc reduce_variable_length_public_inputs - # 1) Load the auxiliary randomness i.e., alpha and beta - # We store them as [beta0, beta1, alpha0, alpha1] since `horner_eval_ext` requires memory + # 1) Read num_kernel_proc_digests from advice and store for later use. + # We use tmp3 because tmp1 and tmp2 are clobbered by reduce_kernel_digests. + adv_push + exec.constants::tmp3 mem_store + # => [...] + + # 2) Load kernel digests from advice into memory, absorbing into the FS transcript. + # Each digest is padded to 8 elements (2 words), loaded via adv_pipe. + # + # The 4-felt zero-pad is a vestige of the old [label, d0..d3] 5-slot encoding: the + # reversed 8-felt layout made `horner_eval_base` + `β*` produce `d0*β..d3*β^4` so the + # label could sit at β^0. The new encoding is just `bus_prefix + d0..d3` at β^0..β^3 + # — the 4 leading zeros are now Horner no-ops. It's kept because adv_pipe / mem_stream + # / Poseidon2 all operate on 8-felt chunks; a future refactor could pack digests + # sequentially (4 felts each) and pair them per adv_pipe / permute iteration to halve + # VLPI memory. + + ## a) Flush random coin buffers and load sponge state onto the stack. + push.0 exec.constants::random_coin_output_len_ptr mem_store + push.0 exec.constants::random_coin_input_len_ptr mem_store + exec.random_coin::load_random_coin_state + # => [R0, R1, C, ...] + + ## b) Place the memory destination pointer at position 12 for adv_pipe. + exec.constants::variable_length_public_inputs_address_ptr mem_load + movdn.12 + # => [R0, R1, C, var_len_ptr, ...] + + ## c) Get num_iterations (= num_kernel_proc_digests). + exec.constants::tmp3 mem_load + # => [num_iter, R0, R1, C, var_len_ptr, ...] + + ## d) Loop: load 2 words (8 felts) per digest from advice to memory via adv_pipe, + ## then absorb into the sponge via poseidon2::permute. + dup push.0 neq + while.true + sub.1 movdn.13 + # => [R0, R1, C, ptr, remaining, ...] + + adv_pipe + # => [W0, W1, C, ptr+8, remaining, ...] + exec.poseidon2::permute + # => [R0', R1', C', ptr+8, remaining, ...] + + movup.13 + # => [remaining, R0', R1', C', ptr+8, ...] + dup push.0 neq + end + # => [0, R0', R1', C', ptr_final, ...] + + ## e) Store sponge state back to random coin and reset buffer counters. + drop + # => [R0', R1', C', ptr_final, ...] + exec.random_coin::store_random_coin_state + push.0 exec.constants::random_coin_input_len_ptr mem_store + push.8 exec.constants::random_coin_output_len_ptr mem_store + # => [ptr_final, ...] + drop + # => [...] + + # 3) Load the auxiliary randomness (alpha and beta) from advice. + # Stored as [beta0, beta1, alpha0, alpha1] since `horner_eval_ext` requires memory # word-alignment. padw adv_loadw - exec.constants::aux_rand_nd_ptr mem_storew_be - # => [alpha1, alpha0, beta1, beta0, ...] + exec.constants::aux_rand_nd_ptr mem_storew_le dropw # => [...] - # 2) Get the pointer to the variable-length public inputs. - # This is also the pointer to the first address at which we will store the results of - # the reductions. + # 4) Compute gamma = beta^16 for per-bus domain separation. + # gamma is needed by reduce_kernel_digests to build bus_prefix = alpha + gamma. + # We compute it here (from the non-deterministic beta) because generate_aux_randomness + # runs later in the protocol. The value is stored at BUS_GAMMA_PTR for reuse. + exec.constants::aux_rand_nd_ptr mem_load + exec.constants::aux_rand_nd_ptr push.1 add mem_load + # => [beta1, beta0, ...] + swap + # => [beta0, beta1, ...] + dup.1 dup.1 ext2mul # beta^2 + dup.1 dup.1 ext2mul # beta^4 + dup.1 dup.1 ext2mul # beta^8 + dup.1 dup.1 ext2mul # beta^16 = gamma + # => [gamma0, gamma1, ...] + push.0.0 movup.3 movup.3 + # => [gamma0, gamma1, 0, 0, ...] + exec.constants::bus_gamma_ptr mem_storew_le + dropw + # => [...] + + # 5) Get the pointer to the variable-length public inputs and reduce kernel digests. + # The reduced value is stored by reduce_kernel_digests at var_len_ptr (in the ACE READ + # section), where it remains accessible via variable_length_public_inputs_address_ptr. exec.constants::variable_length_public_inputs_address_ptr mem_load - dup - # => [next_var_len_pub_inputs_ptr, var_len_pub_inputs_res_ptr, ...] where - # `next_var_len_pub_inputs_ptr` points to the next chunk of variable public inputs to be reduced, - # and `var_len_pub_inputs_res_ptr` points to the next available memory location where the result - # of the reduction can be stored. - # Note that, as mentioned in the top of this module, the variable-length public inputs are only - # stored temporarily and they will be over-written by, among other data, the result of reducing - # the variable public inputs. - - adv_push.1 exec.reduce_kernel_digests - # => [next_var_len_pub_inputs_ptr, var_len_pub_inputs_res_ptr, ...] - - # 3) Clean up the stack. - drop drop + # => [var_len_ptr, ...] + + exec.constants::tmp3 mem_load + # => [num_kernel_proc_digests, var_len_ptr, ...] + + exec.reduce_kernel_digests # => [...] end #! Reduces the kernel procedures digests using auxiliary randomness. #! -#! Inputs: [num_ker_procedures, digests_ptr] -#! Outputs: [next_ptr] +#! Inputs: [num_ker_procedures, digests_ptr, ...] +#! Outputs: [...] #! -#! where `digests_ptr` is a pointer to the kernel procedures digests and `next_ptr` is a pointer to -#! the start of the next group of variable public inputs to be reduced, if such a group exists. +#! where `digests_ptr` is a pointer to the kernel procedures digests. The reduced value +#! `kernel_corr = Σ_i 1 / kernel_proc_message(digest_i)` is stored as +#! [kernel_corr0, kernel_corr1, 0, 0] at the original `digests_ptr`. proc reduce_kernel_digests # Assert that the number of kernel procedures is at most 1023 - dup u32lt.1024 assert.err="range check failed: kernel count" - - # Store number of kernel procedures digests - push.0.0 dup.2 - exec.constants::tmp1 mem_storew_be - # => [num_ker_procedures, 0, 0, num_ker_procedures, digests_ptr, ...] + dup u32lt.1024 assert.err="number of kernel procedures must be less than 1024" - # Load alpha - exec.constants::aux_rand_nd_ptr mem_loadw_be - # => [alpha1, alpha0, beta1, beta0, digests_ptr, ...] + # Save the original digests_ptr in TMP2 so we can store the result there later. + # (mem_stream will advance digests_ptr during the Horner loop.) + dup.1 exec.constants::tmp2 mem_store - # We will keep [beta0, beta1, alpha0 + op_label, alpha1] on the stack so that we can compute - # the final result, where op_label is a unique label to domain separate the interaction with - # the chiplets` bus. - # The final result is then computed as: - # - # alpha + op_label * beta^0 + beta * (r_0 * beta^0 + r_1 * beta^1 + r_2 * beta^2 + r_3 * beta^3) - swap - push.KERNEL_OP_LABEL - add + # Store number of kernel procedures digests at TMP1 as [num_ker, 0, 0, num_ker]. + # We keep only digests_ptr on the stack (dropping the counter word since we read + # it back from TMP1 later). + push.0.0 dup.2 + exec.constants::tmp1 mem_storew_le + dropw + # => [digests_ptr, ...] + + # Load alpha and beta. Pad with 4 zeros (padw) so mem_loadw_le overwrites the + # padding word instead of digests_ptr (which sits at position 4 after padding). + padw + exec.constants::aux_rand_nd_ptr mem_loadw_le + # => [beta0, beta1, alpha0, alpha1, digests_ptr, ...] + + # Compute bus_prefix = alpha + gamma for per-bus domain separation. + # gamma = beta^16 was precomputed and stored at BUS_GAMMA_PTR. + # KERNEL_ROM_INIT = 0, so bus_prefix = alpha + (0+1)*gamma = alpha + gamma. + movup.3 movup.3 + # => [alpha0, alpha1, beta0, beta1, digests_ptr, ...] + exec.constants::bus_gamma_ptr mem_load + # => [gamma0, alpha0, alpha1, beta0, beta1, digests_ptr, ...] + exec.constants::bus_gamma_ptr push.1 add mem_load + # => [gamma1, gamma0, alpha0, alpha1, beta0, beta1, digests_ptr, ...] swap - # => [alpha1, alpha0 + op_label, beta1, beta0, digests_ptr, ...] + # => [gamma0, gamma1, alpha0, alpha1, beta0, beta1, digests_ptr, ...] + ext2add + # => [prefix0, prefix1, beta0, beta1, digests_ptr, ...] # Push the `horner_eval_ext` accumulator push.0.0 - # => [acc1, acc0, alpha1, alpha0 + op_label, beta1, beta0, digests_ptr, ...] + # => [acc0, acc1, prefix0, prefix1, beta0, beta1, digests_ptr, ...] # Push the pointer to the evaluation point beta exec.constants::aux_rand_nd_ptr - # => [beta_ptr, acc1, acc0, alpha1, alpha0 + op_label, beta1, beta0, digests_ptr, ...] + # => [beta_ptr, acc0, acc1, prefix0, prefix1, beta0, beta1, digests_ptr, ...] # Get the pointer to kernel procedures digests movup.7 - # => [digests_ptr, beta_ptr, acc1, acc0, alpha1, alpha0 + op_label, beta1, beta0, ...] + # => [digests_ptr, beta_ptr, acc0, acc1, prefix0, prefix1, beta0, beta1, ...] # Set up the stack for `mem_stream` + `horner_eval_ext` swapw padw padw - # => [Y, Y, alpha1, alpha0 + op_label, beta1, beta0, digests_ptr, beta_ptr, acc1, acc0, ...] + # => [Y, Y, prefix0, prefix1, beta0, beta1, digests_ptr, beta_ptr, acc0, acc1, ...] # where `Y` is a garbage word. # Build a boolean flag for the expression `num_ker_procedures > 0`. - # This will be used to drive the loop reducing the digests - exec.constants::tmp1 mem_loadw_be dup + # Use mem_load (not mem_loadw_le) to read only the counter without polluting the stack. + exec.constants::tmp1 mem_load + # => [num_ker, Y, Y, prefix0, prefix1, beta0, beta1, digests_ptr, beta_ptr, acc0, acc1, ...] push.0 neq while.true - # Compute `acc = ∑ {0≤i<4} digest_ptr[i] ⋅ βⁱ` - # - # Since the width of the digests, plus the op_label, is less than 8, we only need - # to loop once + # Compute `acc = sum {0<=i<4} digest[i] * beta^i` via Horner evaluation. + # The stored 8-felt digest is [0,0,0,0, d3,d2,d1,d0]: the 4 leading zeros are + # Horner no-ops (contribute 0*β^4..0*β^7), so the result is just d0 + d1*β + + # d2*β^2 + d3*β^3 — exactly the β^0..β^3 payload we want. One mem_stream pass. repeat.1 mem_stream horner_eval_base end - # => [Y, Y, alpha1, alpha0 + op_label, beta1, beta0, digests_ptr, beta_ptr, acc1, acc0, ...] + # => [Y, Y, prefix0, prefix1, beta0, beta1, digests_ptr, beta_ptr, acc0, acc1, ...] swapdw - # => [alpha1, alpha0 + op_label, beta1, beta0, digests_ptr, beta_ptr, acc1, acc0, Y, Y, ...] + # => [prefix0, prefix1, beta0, beta1, digests_ptr, beta_ptr, acc0, acc1, Y, Y, ...] movup.7 movup.7 - # => [acc1, acc0, alpha1, alpha0 + op_label, beta1, beta0, digests_ptr, beta_ptr, Y, Y, ...] - - # Compute `tmp = β ⋅ acc = ∑ {0≤i<4} digest_ptr[i] ⋅ βⁱ⁺¹` - dup.5 dup.5 - # => [beta1, beta0, acc1, acc0, alpha1, alpha0 + op_label, beta1, beta0, digests_ptr, beta_ptr, Y, Y, ...] - ext2mul - # => [tmp1, tmp0, alpha1, alpha0 + op_label, beta1, beta0, digests_ptr, beta_ptr, Y, Y, ...] + # => [acc0, acc1, prefix0, prefix1, beta0, beta1, digests_ptr, beta_ptr, Y, Y, ...] - # Compute `term = α + op_label + ∑{i = 0..4} digest_ptr[i] ⋅ βⁱ⁺¹` + # Compute `term = prefix + acc = bus_prefix + sum{i = 0..4} digest[i] * beta^i` dup.3 dup.3 ext2add - # => [term1, term0, alpha1, alpha0 + op_label, beta1, beta0, digests_ptr, beta_ptr, Y, Y, ...] + # => [term0, term1, prefix0, prefix1, beta0, beta1, digests_ptr, beta_ptr, Y, Y, ...] movdn.15 movdn.15 - # => [alpha1, alpha0 + op_label, beta1, beta0, digests_ptr, beta_ptr, Y, Y, term1, term0, ...] + # => [prefix0, prefix1, beta0, beta1, digests_ptr, beta_ptr, Y, Y, term0, term1, ...] push.0 movdn.6 push.0 movdn.6 - # => [alpha1, alpha0 + op_label, beta1, beta0, digests_ptr, beta_ptr, 0, 0, Y, Y, term1, term0, ...] + # => [prefix0, prefix1, beta0, beta1, digests_ptr, beta_ptr, 0, 0, Y, Y, term0, term1, ...] swapdw - # => [Y, Y, alpha1, alpha0 + op_label, beta1, beta0, digests_ptr, beta_ptr, 0, 0, term1, term0, ...] + # => [Y, Y, prefix0, prefix1, beta0, beta1, digests_ptr, beta_ptr, 0, 0, term0, term1, ...] - # Subtract 1 from num_ker_digests - exec.constants::tmp1 mem_loadw_be sub.1 - exec.constants::tmp1 mem_storew_be - - # Compute flag to decide on exiting the loop - dup - push.0 - neq + # Subtract 1 from num_ker_digests and check > 0. + exec.constants::tmp1 mem_load sub.1 + # => [counter-1, D, D, prefix0, prefix1, beta0, beta1, digests_ptr, beta_ptr, 0, 0, ...] + dup exec.constants::tmp1 mem_store + # => [counter-1, D, D, ...] + push.0 neq + # => [flag, D, D, ...] end - # => [Y, Y, alpha1, alpha0 + op_label, beta1, beta0, digests_ptr, beta_ptr, 0, 0, term1, term0, ...] + # => [Y, Y, prefix0, prefix1, beta0, beta1, digests_ptr, beta_ptr, 0, 0, term0, term1, ...] dropw dropw dropw - # => [digests_ptr, beta_ptr, 0, 0, term1, term0, ...] - dup exec.constants::tmp2 mem_store - exec.constants::tmp1 mem_loadw_be drop drop drop - - # We now need to multiply all of the reduced values - # We push the multiplicative identity element, the number of elements to multiply, and a boolean - # flag to enter or not the loop - push.1.0 + # => [digests_ptr_advanced, beta_ptr, 0, 0, termN_0, termN_1, ..., term1_0, term1_1, ...] + drop drop drop drop + # => [termN_0, termN_1, ..., term1_0, term1_1, ...] + + # Read the original num_ker_procedures from TMP1+3 (preserved from initial mem_storew_le). + # TMP1 word was [num_ker, 0, 0, num_ker]; TMP1+3 still holds the original value. + exec.constants::tmp1 push.3 add mem_load + # => [N, termN_0, termN_1, ..., term1_0, term1_1, ...] + + # Accumulate the sum of reciprocals: acc = Σ 1/term_i. + # We push the additive identity element, the number of elements to accumulate, and a boolean + # flag to enter or not the loop. + push.0 + push.0 movup.2 dup push.0 neq - # => [loop, n, acc1, acc0, term1_1, term1_0, ..., termn_1, termn_0, ...] + # => [loop, n, acc0, acc1, term1_0, term1_1, ..., termn_0, termn_1, ...] while.true sub.1 movdn.4 - # => [acc1, acc0, term1_1, term1_0, n - 1, ..., termn_1, termn_0, ...] - ext2mul - # => [acc1', acc0', n - 1, ..., termn_1, termn_0, ...] + # => [acc0, acc1, term1_0, term1_1, n - 1, ..., termn_0, termn_1, ...] + movup.3 movup.3 + # => [term1_0, term1_1, acc0, acc1, n - 1, ...] + ext2inv + # => [inv_t0, inv_t1, acc0, acc1, n - 1, ...] + ext2add + # => [acc0', acc1', n - 1, ..., termn_0, termn_1, ...] movup.2 dup push.0 neq - # => [loop, n - 1, acc1', acc0', term1_1, term1_0, ..., termn_1, termn_0, ...] + # => [loop, n - 1, acc0', acc1', term1_0, term1_1, ..., termn_0, termn_1, ...] end - # => [0, prod1, prod0, ...] where prod is the resulting product + # => [0, sum0, sum1, ...] where sum = Σ 1/term_i - # since we are initializing the bus with "requests", we should invert the reduced result + # kernel_corr = Σ 1/term_i (no negation: chiplet removes, boundary adds). drop - ext2inv - # => [inv_prod1, inv_prod0, ...] + # => [kernel_corr0, kernel_corr1, ...] - # Store the result at `digests_ptr` as `[inv_prod0, inv_prod1, 0, 0]` + # Store the result at `digests_ptr` as `[kernel_corr0, kernel_corr1, 0, 0]` # Note that `digests_ptr` points to the group that we just reduced above and hence it is safe # to overwrite it with the result. - exec.constants::tmp2 mem_load movdn.2 - # => [inv_prod1, inv_prod0, digests_ptr, ...] push.0.0 - # => [0, 0, inv_prod1, inv_prod0, digests_ptr, var_len_pub_inputs_res_ptr, ...] - dup.5 add.4 swap.6 - mem_storew_be + movup.3 + movup.3 + # => [prod0, prod1, 0, 0, ...] + exec.constants::tmp2 mem_load + # => [original_digests_ptr, prod0, prod1, 0, 0, ...] + mem_storew_le dropw - # => [digests_ptr, var_len_pub_inputs_res_ptr, ...] + # => [...] end diff --git a/crates/lib/core/asm/word.masm b/crates/lib/core/asm/word.masm index 3fb72bfae3..bd6acfaf3a 100644 --- a/crates/lib/core/asm/word.masm +++ b/crates/lib/core/asm/word.masm @@ -23,7 +23,7 @@ end #! - `out_ptr` is an element address in memory. #! - Memory layout after the call: `[w0_lo, w0_hi, w1_lo, w1_hi, w2_lo, w2_hi, w3_lo, w3_hi]`. #! -#! Cycles: 8 * (split + store pair) ~= 176 +#! Cycles: 22 pub proc store_word_u32s_le swap u32split # => [w1_lo, w1_hi, w0, w2, w3, out_ptr, ...] @@ -108,7 +108,7 @@ end #! Inputs: [RHS, LHS] #! Outputs: [is_lhs_greater] #! -#! Cycles: 117 +#! Cycles: 133 pub proc gt(rhs: word, lhs: word) -> i1 # Input words are in LE order (word[0] on top) # => [r_0, r_1, r_2, r_3, l_0, l_1, l_2, l_3] @@ -158,7 +158,7 @@ end #! Inputs: [RHS, LHS] #! Outputs: [is_lhs_greater_or_equal] #! -#! Cycles: 118 +#! Cycles: 130 pub proc gte(rhs: word, lhs: word) -> i1 exec.lt not @@ -174,7 +174,7 @@ end #! Inputs: [RHS, LHS] #! Outputs: [is_lhs_lesser] #! -#! Cycles: 117 +#! Cycles: 129 pub proc lt(rhs: word, lhs: word) -> i1 # Input words are in LE order (word[0] on top) # => [r_0, r_1, r_2, r_3, l_0, l_1, l_2, l_3] @@ -224,7 +224,7 @@ end #! Inputs: [RHS, LHS] #! Outputs: [is_lhs_less_or_equal] #! -#! Cycles: 118 +#! Cycles: 134 pub proc lte(rhs: word, lhs: word) -> i1 exec.gt not diff --git a/crates/lib/core/build.rs b/crates/lib/core/build.rs index 7316fd0ac1..b1185df485 100644 --- a/crates/lib/core/build.rs +++ b/crates/lib/core/build.rs @@ -28,14 +28,14 @@ pub struct MarkdownRenderer {} impl MarkdownRenderer { fn write_docs_header(mut writer: &fs::File, ns: &str) { let header = - format!("\n## {}\n| Procedure | Description |\n| ----------- | ------------- |\n", ns); + format!("\n## {ns}\n| Procedure | Description |\n| ----------- | ------------- |\n"); writer.write_all(header.as_bytes()).expect("unable to write header to writer"); } fn write_docs_procedure(mut writer: &fs::File, name: &str, docs: Option<&str>) { if let Some(docs) = docs { let escaped = docs.replace('|', "\\|").replace('\n', "
"); - let line = format!("| {} | {} |\n", name, escaped); + let line = format!("| {name} | {escaped} |\n"); writer.write_all(line.as_bytes()).expect("unable to write func to writer"); } } @@ -137,7 +137,7 @@ fn find_masm_modules(base_dir: &Path, current_dir: &Path) -> io::Result>() .join("::"); - let label = format!("miden::core::{}", module_path); + let label = format!("miden::core::{module_path}"); modules.push((label, path)); } @@ -204,7 +204,9 @@ fn main() -> Result<(), Report> { // or its builder changed: println!("cargo:rerun-if-changed=asm"); println!("cargo:rerun-if-env-changed=MIDEN_BUILD_LIB_DOCS"); - println!("cargo:rerun-if-changed=../assembly/src"); + // NOTE: path is relative to the package root (crates/lib/core/), so we need + // ../../ to reach crates/assembly/src. + println!("cargo:rerun-if-changed=../../assembly/src"); miden_assembly::diagnostics::reporting::set_hook(Box::new(|_| { Box::new(ReportHandlerOpts::new().build()) @@ -245,7 +247,7 @@ fn main() -> Result<(), Report> { .into_diagnostic()?; // Generate documentation - if std::env::var("MIDEN_BUILD_LIB_DOCS").is_ok() { + if env::var("MIDEN_BUILD_LIB_DOCS").is_ok() { build_core_lib_docs(&asm_dir, DOC_DIR_PATH).into_diagnostic()?; } diff --git a/crates/lib/core/docs/collections/mmr.md b/crates/lib/core/docs/collections/mmr.md index c6d5e62a5f..4c55cdae5a 100644 --- a/crates/lib/core/docs/collections/mmr.md +++ b/crates/lib/core/docs/collections/mmr.md @@ -2,9 +2,9 @@ ## miden::core::collections::mmr | Procedure | Description | | ----------- | ------------- | -| get | Loads the leaf at the absolute `pos` in the MMR.

This MMR implementation supports only u32 positions.

Stack transition:
Input: [pos, mmr_ptr, ...]
Output: [N, ...] where `N` is the leaf and `R` is the MMR peak that owns the leaf.

Cycles: 118
| -| num_leaves_to_num_peaks | Given the num_leaves of a MMR returns the num_peaks.

Implemented as counting the number of "1" bits in `num_leaves`.

Input: [num_leaves, ...]
Output: [num_peaks, ...]
Cycles: 69
| +| get | Loads the leaf at the absolute `pos` in the MMR.

This MMR implementation supports only u32 positions.

The position must refer to an existing leaf: `pos < num_leaves`, where `num_leaves` is stored
at `mmr_ptr[0]`. The procedure fails instead of returning an empty or sentinel word when `pos`
is outside the current MMR.

Stack transition:
Input: [pos, mmr_ptr, ...]
Output: [N, ...] where `N` is the leaf and `R` is the MMR peak that owns the leaf.
| +| num_leaves_to_num_peaks | Given the num_leaves of a MMR returns the num_peaks.

Implemented as counting the number of "1" bits in `num_leaves`.

Input: [num_leaves, ...]
Output: [num_peaks, ...]
Cycles: 67
| | num_peaks_to_message_size | Given the num_peaks of a MMR, returns the hasher state size after accounting
for the required padding.

Input: [num_peaks, ...]
Output: [len, ...]
Cycles: 19
| -| unpack | Writes the MMR who's peaks hash to `HASH` to the memory location pointed to by `mmr_ptr`.

Input: [HASH, mmr_ptr, ...]
Output: [...]

Where:
- HASH: is the MMR peak hash, the hash is expected to be padded to an even
length and to have a minimum size of 16 elements
- The advice map must contain a key with HASH, and its value is
`[num_leaves, 0, 0 , 0] \|\| hash_data`, and hash_data is the data used to computed `HASH`
- mmr_ptr: the memory location where the MMR data will be written to,
starting with the MMR forest (its total leaves count) followed by its peaks.
The address is expected to be word-aligned.

Cycles: 164 + 9 * extra_peak_pair cycles
where `extra_peak` is the number of peak pairs in addition to the first
16, i.e. `round_up((num_of_peaks - 16) / 2)`
| -| pack | Computes the hash of the given MMR and copies it to the Advice Map using its hash as a key.

Input: [mmr_ptr, ...]
Output: [HASH, ...]
Cycles: 130 + 3 * num_peaks
| -| add | Adds a new element to the MMR.

This will update the MMR peaks in the VM's memory and the advice provider
with any merged nodes.

Input: [EL, mmr_ptr, ...]
Output: [...]
Cycles: 147 + 39 * peak_merges
| +| unpack | Writes the MMR who's peaks hash to `HASH` to the memory location pointed to by `mmr_ptr`.

Input: [HASH, mmr_ptr, ...]
Output: [...]

Where:
- HASH: is the MMR peak hash, the hash is expected to be padded to an even
length and to have a minimum size of 16 elements
- The advice map must contain a key with HASH, and its value is
`[num_leaves, 0, 0 , 0] \|\| hash_data`, and hash_data is the data used to computed `HASH`
- mmr_ptr: the memory location where the MMR data will be written to,
starting with the MMR forest (its total leaves count) followed by its peaks.
The address is expected to be word-aligned.

Cycles: 162 + 9 * extra_peak_pair cycles
where `extra_peak` is the number of peak pairs in addition to the first
16, i.e. `round_up((num_of_peaks - 16) / 2)`
| +| pack | Computes the hash of the given MMR and copies it to the Advice Map using its hash as a key.

Input: [mmr_ptr, ...]
Output: [HASH, ...]
Cycles: 128 + 3 * num_peaks
| +| add | Adds a new element to the MMR.

This will update the MMR peaks in the VM's memory and the advice provider
with any merged nodes.

Input: [EL, mmr_ptr, ...]
Output: [...]
Cycles: 145 + 39 * peak_merges
| diff --git a/crates/lib/core/docs/collections/smt.md b/crates/lib/core/docs/collections/smt.md index 8f1578ffbb..9f163d5cde 100644 --- a/crates/lib/core/docs/collections/smt.md +++ b/crates/lib/core/docs/collections/smt.md @@ -2,6 +2,6 @@ ## miden::core::collections::smt | Procedure | Description | | ----------- | ------------- | -| get | Returns the value located under the specified key in the Sparse Merkle Tree defined by the
specified root.

If no values had been previously inserted under the specified key, an empty word (i.e.,
[ZERO; 4]) is returned.

Inputs:
Operand stack: [K, R, ...]

Outputs:
Operand stack: [V, R, ...]

Fails if the tree with the specified root does not exits in the VM's advice provider.

Cycles
Leaf empty: 66 cycles
Leaf single: 115 cycles
Leaf multiple, non-empty value: 189 + 3 * pair_count
Leaf multiple, empty value: 186 + 3 * pair_count
| +| get | Returns the value located under the specified key in the Sparse Merkle Tree defined by the
specified root.

If no values had been previously inserted under the specified key, an empty word (i.e.,
[ZERO; 4]) is returned.

Inputs:
Operand stack: [K, R, ...]

Outputs:
Operand stack: [V, R, ...]

Fails if the tree with the specified root does not exits in the VM's advice provider.

Cycles
Leaf empty: 66 cycles
Leaf single: 115 cycles
Leaf multiple, non-empty value: 189 + 6 * pair_count
Leaf multiple, empty value: 186 + 6 * pair_count
| | set | Inserts the specified value under the specified key in a Sparse Merkle Tree defined by the
specified root. If the insert is successful, the old value located under the specified key
is returned via the stack.

If the VALUE is an empty word (i.e., [ZERO; 4]), the new state of the tree is guaranteed to
be equivalent to the state as if the updated value was never inserted.

Inputs:
Operand stack: [V, K, R, ...]
Outputs:
Operand stack: [V_old, R_new, ...]

Fails if the tree with the specified root does not exits in the VM's advice provider.

Cycles
Leaf empty
removal: 74 cycles
insertion: 133 cycles
Leaf single
removal: 227 cycles
insertion (leaf remains single): 205
insertion (leaf becomes multiple): X cycles
Leaf multiple
X cycles
| | peek | Emits the "miden::core::collections::smt::smt_peek" event, which pushes onto the advice stack
the value associated with the specified key in a Sparse Merkle Tree defined by the specified
root.

If no value was previously associated with the specified key, [ZERO; 4] is pushed onto the advice
stack.

Inputs:
Operand stack: [KEY, ROOT]
Advice stack: []

Outputs:
Operand stack: [KEY, ROOT]
Advice stack: [VALUE]

Panics if:
- the tree with the specified root does not exits in the VM's advice provider.

Cycles: 3 cycles
| diff --git a/crates/lib/core/docs/collections/sorted_array.md b/crates/lib/core/docs/collections/sorted_array.md index eb6251acdd..72ff343c72 100644 --- a/crates/lib/core/docs/collections/sorted_array.md +++ b/crates/lib/core/docs/collections/sorted_array.md @@ -2,6 +2,6 @@ ## miden::core::collections::sorted_array | Procedure | Description | | ----------- | ------------- | -| find_word | Finds a value in a sorted array of words.

This function will crash if the following conditions aren't met:
- words must be sorted in non-decreasing order,
- start_ptr, end_ptr are word-aligned
- `start_ptr <= end_ptr`

Input: [VALUE, start_ptr, end_ptr]
Output: [is_value_found, value_ptr, start_ptr, end_ptr]

Cycles:
Value exists: 46 cycles
Value doesn't exist and the array is empty: 25 cycles
Value doesn't exist and is smaller than all elements: 151 cycles
Value doesn't exist and is larger than all elements: 149 cycles
Value doesn't exist: 286 cycles
| -| find_key_value | Finds a key in a sorted array of (key, value) word tuples.

Inputs: [KEY, start_ptr, end_ptr]
Outputs: [is_key_found, key_ptr, start_ptr, end_ptr]

# Panics

Panics if:
- keys are not sorted in non-decreasing order,
- start_ptr is not word-aligned
- end_ptr is not double-word-aligned with the start_ptr:
- `(end_ptr - start_ptr)` must be divisible by 8
- `start_ptr > end_ptr`

Inputs: [KEY, start_ptr, end_ptr]
Output: [is_key_found, key_ptr, start_ptr, end_ptr]
| -| find_half_key_value | Finds a half-key in a sorted array of (key, value) word tuples.

Half-key means that, out of the keys in the array, only half of the key - the most significant
element (prefix) and the second most significant element (suffix) - need to match.

Inputs: [key_suffix, key_prefix, start_ptr, end_ptr]
Output: [is_key_found, key_ptr, start_ptr, end_ptr]

# Panics

Panics if:
- keys are not sorted in non-decreasing order,
- start_ptr is not word-aligned
- end_ptr is not double-word-aligned with the start_ptr:
- `(end_ptr - start_ptr)` must be divisible by 8
- `start_ptr > end_ptr`
| +| find_word | Finds a value in a sorted array of words.

**The input array must be sorted in non-decreasing lexicographic order.** The host event handler validates this and will return an error if the array is not sorted.

Input: [VALUE, start_ptr, end_ptr]
Output: [is_value_found, value_ptr, start_ptr, end_ptr]

# Panics

Panics if:
- start_ptr, end_ptr are not word-aligned
- `start_ptr > end_ptr`

Cycles:
Value exists: 46 cycles
Value doesn't exist and the array is empty: 25 cycles
Value doesn't exist and is smaller than all elements: 151 cycles
Value doesn't exist and is larger than all elements: 149 cycles
Value doesn't exist: 286 cycles
| +| find_key_value | Finds a key in a sorted array of (key, value) word tuples.

**The keys in the array must be sorted in non-decreasing lexicographic order.** The host event handler validates this and will return an error if the keys are not sorted.

Inputs: [KEY, start_ptr, end_ptr]
Outputs: [is_key_found, key_ptr, start_ptr, end_ptr]

# Panics

Panics if:
- start_ptr is not word-aligned
- end_ptr is not double-word-aligned with the start_ptr:
- `(end_ptr - start_ptr)` must be divisible by 8
- `start_ptr > end_ptr`
| +| find_half_key_value | Finds a half-key in a sorted array of (key, value) word tuples.

Half-key means that, out of the keys in the array, only half of the key - the most significant
element (prefix) and the second most significant element (suffix) - need to match.

**The half-keys in the array must be sorted in non-decreasing lexicographic order.** The host event handler validates this and will return an error if the half-keys are not sorted.

Inputs: [key_suffix, key_prefix, start_ptr, end_ptr]
Output: [is_key_found, key_ptr, start_ptr, end_ptr]

# Panics

Panics if:
- start_ptr is not word-aligned
- end_ptr is not double-word-aligned with the start_ptr:
- `(end_ptr - start_ptr)` must be divisible by 8
- `start_ptr > end_ptr`
| diff --git a/crates/lib/core/docs/crypto/aead.md b/crates/lib/core/docs/crypto/aead.md index d1146dad5e..1dcc6bbfa0 100644 --- a/crates/lib/core/docs/crypto/aead.md +++ b/crates/lib/core/docs/crypto/aead.md @@ -4,5 +4,5 @@ AEAD (Authenticated Encryption with Associated Data) implementation using Poseid ## miden::core::crypto::aead | Procedure | Description | | ----------- | ------------- | -| encrypt | Encrypts plaintext data from memory using the `crypto_stream` instruction.

This procedure encrypts plaintext and automatically adds a padding block at the end.
The padding block [1, 0, 0, 0, 0, 0, 0, 0] is written to memory and encrypted, ensuring
proper AEAD operation without requiring the caller to handle padding manually.
This, however, requires the plaintext length to be a multiple of 8. This assumption is made
both in this procedure as well as in the decryption procedure.

Input: [key(4), nonce(4), src_ptr, dst_ptr, num_blocks, ...]
Output: [tag(4), ...]

Where:
- key is the encryption key (4 elements)
- nonce is the initialization vector (4 elements)
- src_ptr points to plaintext in memory (must be word-aligned)
- dst_ptr points to where ciphertext will be written (must be word-aligned)
- num_blocks is the number of 8-element plaintext data blocks (NO padding included)
- tag is the authentication tag returned on stack (4 elements)

Memory Layout:
- Input at src_ptr: [plaintext_block_0(8), ..., plaintext_block_n(8)]
Length: num_blocks * 8 elements (must be multiple of 8)

- Output at dst_ptr: [ciphertext_block_0(8), ..., ciphertext_block_n(8), encrypted_padding(8)]
Length: (num_blocks + 1) * 8 elements
The padding block is automatically added and encrypted

- Standard format: the tag is stored right after ciphertext to create:
[ciphertext_blocks(num_blocks * 8), encrypted_padding(8), tag(4)]
Tag location: dst_ptr + (num_blocks + 1) * 8

Memory Requirements:
- Plaintext must be at word-aligned addresses (addr % 4 == 0)
- Each block is 8 field elements (2 words)
- Blocks must be stored contiguously in memory
- src_ptr and dst_ptr MUST be different (in-place encryption not supported)
This is because crypto_stream reads and writes in the same clock cycle

Padding:
- Padding is AUTOMATIC - caller should NOT pad the plaintext
- The procedure writes [1, 0, 0, 0, 0, 0, 0, 0] to dst_ptr + (num_blocks * 8)
- This padding block is then encrypted along with the data
- For empty plaintext (num_blocks = 0), only the padding block is encrypted

Cycles (estimate): 77 + 2 * n
Where:
- n = number of field elements encrypted (includes the final padding block)
- For num_blocks data blocks: n = 8 * (num_blocks + 1)
| -| decrypt | Decrypts and authenticates ciphertext using non-deterministic advice.

This procedure implements AEAD decryption with automatic tag verification and
automatic padding handling. It mirrors the encrypt procedure's padding behavior.

Decryption Flow:
1. Computes tag location: src_ptr + (num_blocks + 1) * 8
2. Emits event for host to decrypt ciphertext (data blocks + padding block)
3. Loads plaintext data blocks from advice into dst_ptr (num_blocks * 8 elements)
4. Calls encrypt which reads data blocks and adds padding automatically
5. Re-encrypts data + padding to compute authentication tag
6. Compares computed tag with tag from memory at src_ptr + (num_blocks + 1) * 8
7. Halts execution with assertion failure if tags don't match

Input: [key(4), nonce(4), src_ptr, dst_ptr, num_blocks, ...]
Output: [] (empty stack on success, halts on failure)

Where:
- key is the decryption key (4 elements)
- nonce is the initialization vector (4 elements)
- src_ptr points to ciphertext + encrypted_padding + tag in memory (word-aligned)
- dst_ptr points to where plaintext will be written (word-aligned)
- num_blocks is the number of 8-element plaintext data blocks (NO padding)

Memory Layout:
- Input at src_ptr: [ciphertext_blocks(num_blocks * 8), encrypted_padding(8), tag(4)]
The encrypted padding is at: src_ptr + (num_blocks * 8)
The tag is at: src_ptr + (num_blocks + 1) * 8

- Output at dst_ptr: [plaintext_block_0(8), ..., plaintext_block_n(8), padding(8)]
Length: (num_blocks + 1) * 8 elements
The padding block [1, 0, 0, 0, 0, 0, 0, 0] is automatically written
Caller can ignore or remove the padding block if needed

Event: Emits AEAD_DECRYPT event with (nonce, key, src_ptr, dst_ptr, num_blocks)
The host event handler must:
- Read full ciphertext from memory at src_ptr ((num_blocks + 1) * 8 elements)
- Read authentication tag from memory at src_ptr + (num_blocks + 1) * 8
- Decrypt and verify tag using reference implementation
- Extract only data blocks (first num_blocks * 8 elements) from decrypted plaintext
- Insert data blocks (WITHOUT padding) into advice map (keyed by nonce)

Memory Requirements:
- Same as encrypt: word-aligned addresses, contiguous blocks
- src_ptr and dst_ptr MUST be different (in-place operation not supported)

Security:
- Tag verification happens in the MASM procedure via re-encryption
- Execution halts with assertion failure if tag verification fails
- If execution completes successfully, the plaintext at dst_ptr is authenticated

Non-Determinism Soundness:
This procedure uses non-deterministic advice to obtain the plaintext, which is sound
because:
1. The prover provides claimed plaintext via advice (untrusted input)
2. This procedure re-encrypts the claimed plaintext with the same (key, nonce)
3. Due to deterministic encryption, the same plaintext produces the same ciphertext
4. The computed tag cryptographically commits to both plaintext and ciphertext
5. Comparing tags verifies that the claimed plaintext is the unique plaintext that
encrypts to the given ciphertext under the given (key, nonce)

This approach is secure because:
- The MASM procedure verifies the tag when calling the encryption procedure
- The tag acts as a cryptographic commitment
- The deterministic keystream creates a bijection between plaintext and ciphertext
- Any deviation from correct plaintext causes assertion failure

Note: This procedure does NOT remove padding. The caller must handle padding removal.

Cycles (estimate): 177 + 3.5 * n
Where:
- n = number of field elements in the plaintext (excludes the padding block)
- For num_blocks data blocks: n = 8 * num_blocks
| +| encrypt | Encrypts plaintext data from memory using the `crypto_stream` instruction.

This procedure encrypts plaintext and automatically includes a padding block at the end.
The padding block [1, 0, 0, 0, 0, 0, 0, 0] is encrypted without requiring the caller
to write padding into the plaintext buffer manually.
This, however, requires the plaintext length to be a multiple of 8. This assumption is made
both in this procedure as well as in the decryption procedure.

Input: [key(4), nonce(4), src_ptr, dst_ptr, num_blocks, ...]
Output: [tag(4), ...]

Where:
- key is the encryption key (4 elements)
- nonce is the initialization vector (4 elements)
- src_ptr points to plaintext in memory (must be word-aligned)
- dst_ptr points to where ciphertext will be written (must be word-aligned)
- num_blocks is the number of 8-element plaintext data blocks (NO padding included)
- tag is the authentication tag returned on stack (4 elements)

Memory Layout:
- Input at src_ptr: [plaintext_block_0(8), ..., plaintext_block_n(8)]
Length: num_blocks * 8 elements (must be multiple of 8)

- Output at dst_ptr: [ciphertext_block_0(8), ..., ciphertext_block_n(8), encrypted_padding(8)]
Length: (num_blocks + 1) * 8 elements
The padding block is automatically added and encrypted

- Standard format: the tag is stored right after ciphertext to create:
[ciphertext_blocks(num_blocks * 8), encrypted_padding(8), tag(4)]
Tag location: dst_ptr + (num_blocks + 1) * 8

Memory Requirements:
- Plaintext must be at word-aligned addresses (addr % 4 == 0)
- Each block is 8 field elements (2 words)
- Blocks must be stored contiguously in memory

# Panics

Panics if the source and destination memory ranges overlap
(in-place encryption not supported).

Padding:
- Padding is AUTOMATIC - caller should NOT pad the plaintext
- The procedure writes encrypted padding to dst_ptr + (num_blocks * 8)
- The plaintext buffer is not modified
- For empty plaintext (num_blocks = 0), only the padding block is encrypted

Cycles (estimate): 77 + 2 * n
Where:
- n = number of field elements encrypted (includes the final padding block)
- For num_blocks data blocks: n = 8 * (num_blocks + 1)
| +| decrypt | Decrypts and authenticates ciphertext using non-deterministic advice.

This procedure implements AEAD decryption with automatic tag verification. It mirrors
the encrypt procedure's padding behavior while leaving the plaintext output unpadded.

Decryption Flow:
1. Computes tag location: src_ptr + (num_blocks + 1) * 8
2. Emits event for host to decrypt ciphertext (data blocks + padding block)
3. Loads plaintext data blocks from advice into dst_ptr (num_blocks * 8 elements)
4. Calls encrypt which reads data blocks and adds padding automatically
5. Re-encrypts data + padding to compute authentication tag
6. Compares computed tag with tag from memory at src_ptr + (num_blocks + 1) * 8
7. Halts execution with assertion failure if tags don't match

Input: [key(4), nonce(4), src_ptr, dst_ptr, num_blocks, ...]
Output: [] (empty stack on success, halts on failure)

Where:
- key is the decryption key (4 elements)
- nonce is the initialization vector (4 elements)
- src_ptr points to ciphertext + encrypted_padding + tag in memory (word-aligned)
- dst_ptr points to where plaintext will be written (word-aligned)
- num_blocks is the number of 8-element plaintext data blocks (NO padding)

Memory Layout:
- Input at src_ptr: [ciphertext_blocks(num_blocks * 8), encrypted_padding(8), tag(4)]
The encrypted padding is at: src_ptr + (num_blocks * 8)
The tag is at: src_ptr + (num_blocks + 1) * 8

- Output at dst_ptr: [plaintext_block_0(8), ..., plaintext_block_n(8)]
Length: num_blocks * 8 elements
The padding block is authenticated but not written to the plaintext output.

Event: Emits AEAD_DECRYPT event with (key, nonce, src_ptr, dst_ptr, num_blocks)
The host event handler must:
- Read full ciphertext from memory at src_ptr ((num_blocks + 1) * 8 elements)
- Read authentication tag from memory at src_ptr + (num_blocks + 1) * 8
- Decrypt and verify tag using reference implementation
- Extract only data blocks (first num_blocks * 8 elements) from decrypted plaintext
- Insert data blocks (WITHOUT padding) into advice map (keyed by nonce)

Memory Requirements:
- Same as encrypt: word-aligned addresses, contiguous blocks

# Panics

Panics if the source and destination memory ranges overlap
(in-place decryption not supported).

Security:
- Tag verification happens in the MASM procedure via re-encryption
- Execution halts with assertion failure if tag verification fails
- If execution completes successfully, the plaintext at dst_ptr is authenticated

Non-Determinism Soundness:
This procedure uses non-deterministic advice to obtain the plaintext, which is sound
because:
1. The prover provides claimed plaintext via advice (untrusted input)
2. This procedure re-encrypts the claimed plaintext with the same (key, nonce)
3. Due to deterministic encryption, the same plaintext produces the same ciphertext
4. The computed tag cryptographically commits to both plaintext and ciphertext
5. Comparing tags verifies that the claimed plaintext is the unique plaintext that
encrypts to the given ciphertext under the given (key, nonce)

This approach is secure because:
- The MASM procedure verifies the tag when calling the encryption procedure
- The tag acts as a cryptographic commitment
- The deterministic keystream creates a bijection between plaintext and ciphertext
- Any deviation from correct plaintext causes assertion failure

Note: This procedure does not write the padding block to the plaintext output.

Cycles (estimate): 177 + 3.5 * n
Where:
- n = number of field elements in the plaintext (excludes the padding block)
- For num_blocks data blocks: n = 8 * num_blocks
| diff --git a/crates/lib/core/docs/crypto/dsa/ecdsa_k256_keccak.md b/crates/lib/core/docs/crypto/dsa/ecdsa_k256_keccak.md index 493fba3979..82d8e70a92 100644 --- a/crates/lib/core/docs/crypto/dsa/ecdsa_k256_keccak.md +++ b/crates/lib/core/docs/crypto/dsa/ecdsa_k256_keccak.md @@ -4,4 +4,3 @@ | ----------- | ------------- | | verify | Verifies an secp256k1 ECDSA signature compatible with `miden-crypto::ecdsa_k256_keccak`.

This wrapper mirrors the materialization performed in `miden-crypto::ecdsa_k256_keccak`: given
a public key commitment and the original message, it reconstructs the calldata expected by the
precompile (public key bytes, Keccak256(message), signature). The public key and signature are
supplied via the advice stack, and can be obtained with the `ecdsa_k256_keccak` function.

Inputs:
Operand stack: [PK_COMM, MSG, ...]
Advice stack: [PK[9] \| SIG[17] \| ...]
Outputs:
Operand stack: []
Advice stack: []

Where:
- `PK_COMM`: Poseidon2 hash commitment of the 32-byte ECDSA public key
- `MSG`: single word (4 field elements) representing the message to verify
- `PK[9]`: 33-byte public key packed as 9 field elements on advice stack
- `SIG[17]`: 65-byte signature packed as 17 field elements on advice stack

Local memory layout (element addresses):
- locaddr[0 ..9 ] : compressed public key (33 bytes packed as 9 felts)
- locaddr[12..20] : message bytes (MSG written as eight u32 limbs)
- locaddr[20..28] : keccak256(message) digest (8 felts)
- locaddr[28..45] : signature (65 bytes packed as 17 felts)

The procedure traps if:
- The public key does not hash to `PK_COMM` (invalid commitment)
- The signature verification fails
| | verify_prehash | Verifies an ECDSA signature with pre-hashed message using deferred execution.

This procedure is intended for manual signature verification where the caller
has already computed the message digest.

The caller provides the public key, the pre-hashed message digest, and the signature data in
memory. This routine forwards the request to the host precompile and returns the boolean result.
In typical flows the digest is obtained from `keccak256::hash_bytes`, but any 32-byte prehash
is accepted.

Input: `[pk_ptr, digest_ptr, sig_ptr, ...]`
Output: `[result, ...]`

Where:
- `pk_ptr`: word-aligned memory address containing the 33-byte compressed secp256k1 public key
- `digest_ptr`: word-aligned memory address containing the 32-byte message digest
- `sig_ptr`: word-aligned memory address containing the 65-byte signature
- `result`: 1 if the signature is valid, 0 if invalid

All data must be stored in memory as packed u32 values (little-endian), with unused bytes
in the final u32 set to zero.
| -| verify_prehash_impl | Internal implementation of ECDSA signature verification via deferred computation.
This procedure is intended for manual signature verification where the caller
has already computed the message digest.

Emits an event to trigger the precompile handler, reads the verification result from
the advice stack, and computes the commitment and tag for tracking deferred verification.

This procedure mimics the `ecdsa_secp256k1::PublicKey::verify_prehash()` function from
`miden-crypto`, which takes a pre-hashed message that the caller must provide
(e.g. obtained using the keccak256 precompile).

Input: `[pk_ptr, digest_ptr, sig_ptr, ...]`
Output: `[COMM, TAG, result, ...]`

Where:
- `pk_ptr`: word-aligned memory address containing 33-byte public key
- `digest_ptr`: word-aligned memory address containing 32-byte digest
- `sig_ptr`: word-aligned memory address containing 65-byte signature
- `COMM`: commitment to calldata computed as
`Poseidon2(Poseidon2(Poseidon2(pk) \|\| Poseidon2(digest)) \|\| Poseidon2(sig))`
- `TAG`: `[ECDSA_VERIFY_EVENT, result, 0, 0]`
- `result`: 1 if signature is valid, 0 if invalid
| diff --git a/crates/lib/core/docs/crypto/dsa/eddsa_ed25519.md b/crates/lib/core/docs/crypto/dsa/eddsa_ed25519.md index b739a77e72..e2e397507b 100644 --- a/crates/lib/core/docs/crypto/dsa/eddsa_ed25519.md +++ b/crates/lib/core/docs/crypto/dsa/eddsa_ed25519.md @@ -4,4 +4,3 @@ | ----------- | ------------- | | verify | Verifies an Ed25519 EdDSA signature compatible with `miden-crypto::eddsa_25519_sha512`.

This wrapper mirrors the materialization performed in `miden-crypto::eddsa_25519_sha512`: given
a public key commitment and the original message, it reconstructs the calldata expected by the
precompile (public key bytes, SHA512(R \|\| PK \|\| MSG), signature). The public key and signature
are supplied via the advice stack, and can be obtained with the `eddsa_sign` function.

Inputs:
Operand stack: [PK_COMM, MSG, ...]
Advice stack: [PK[8] \| SIG[16] \| ...]
Outputs:
Operand stack: []
Advice stack: []

Where:
- `PK_COMM`: Poseidon2 hash commitment of the 32-byte Ed25519 public key
- `MSG`: single word (4 field elements) representing the message to verify
- `PK[8]`: 32-byte public key packed as 8 field elements on advice stack
- `SIG[16]`: 64-byte signature packed as 16 field elements on advice stack

Local memory layout (element addresses):
- locaddr[0..8]: public key (32 bytes packed as 8 felts)
- locaddr[8..16]: message (32 bytes = 8 felts)
- locaddr[16..32]: signature (64 bytes packed as 16 felts)
- locaddr[32..56]: SHA512 input buffer (R \|\| PK \|\| MSG = 96 bytes = 24 felts)
- locaddr[56..72]: k_digest = SHA512(R \|\| PK \|\| MSG) (64 bytes = 16 felts)

The procedure traps if:
- The public key does not hash to `PK_COMM` (invalid commitment)
- The signature verification fails
| | verify_prehash | Verifies an EdDSA (Ed25519) signature with a pre-computed nonce digest.

This procedure is intended for manual signature verification where the caller
has already computed the message digest.

This procedure uses deferred verification via a precompile. The actual cryptographic
verification is performed by the host, and the result is provided via the advice stack.

Input: `[pk_ptr, k_digest_ptr, sig_ptr, ...]`
Output: `[result, ...]`

Where:
- `pk_ptr`: word-aligned memory address containing the 32-byte Ed25519 public key
- `k_digest_ptr`: word-aligned memory address containing the 64-byte challenge hash `k`
- `sig_ptr`: word-aligned memory address containing the 64-byte Ed25519 signature
- `result`: 1 if the signature is valid, 0 otherwise

All data must be stored in memory as packed u32 field elements (little-endian), with unused limbs
in the final word set to zero.
| -| verify_prehash_impl | Internal implementation of EdDSA verification via deferred computation.

Emits an event to trigger the host precompile, reads the verification result from the
advice stack, and computes the commitment/tag pair used for deferred verification.

Input: `[pk_ptr, k_digest_ptr, sig_ptr, ...]`
Output: `[COMM, TAG, result, ...]`

Where:
- `COMM`: `Poseidon2(Poseidon2(Poseidon2(pk) \|\| Poseidon2(k_digest)) \|\| Poseidon2(sig))`
- `TAG`: `[EDDSA_VERIFY_EVENT, result, 0, 0]`
- `result`: host verification result (1 or 0)
| diff --git a/crates/lib/core/docs/crypto/dsa/falcon512_poseidon2.md b/crates/lib/core/docs/crypto/dsa/falcon512_poseidon2.md index 5d4afba763..e515f746a8 100644 --- a/crates/lib/core/docs/crypto/dsa/falcon512_poseidon2.md +++ b/crates/lib/core/docs/crypto/dsa/falcon512_poseidon2.md @@ -2,7 +2,7 @@ ## miden::core::crypto::dsa::falcon512_poseidon2 | Procedure | Description | | ----------- | ------------- | -| mod_12289 | Given dividend ( i.e. a u64 given by its lower and higher u32 decomposition ) on the stack,
this routine computes c = a % M where M = 12289

Expected stack state

[a_hi, a_lo, ...]

Output stack state looks like

[c, ...] \| c = a % M

Note that it is the responsibility of the calling procedure to ensure that `a_hi` and `a_lo` are
within the appropriate range i.e., they are u32-s.

Cycles: 27
| +| mod_12289 | Given dividend ( i.e. a u64 given by its lower and higher u32 decomposition ) on the stack,
this routine computes c = a % M where M = 12289

Expected stack state

[a_hi, a_lo, ...]

Output stack state looks like

[c, ...] \| c = a % M

Note that it is the responsibility of the calling procedure to ensure that `a_hi` and `a_lo` are
within the appropriate range i.e., they are u32-s.

Cycles: 29
| | hash_to_point | Takes as input a message digest, a nonce of size 40 bytes represented as 8 field elements
and a pointer. The procedure absorbs MSG and NONCE into a fresh Poseidon2 state and squeezes the
coefficients of a polynomial c representing the hash-to-point of (MSG \|\| NONCE). The coefficients
are then saved in the memory region [c_ptr, c_ptr + 512).
This implementation of the `hash_to_point` procedure avoids the rejection-sampling step
required in the per-the-spec algorithm by using the observation on page 31 in
https://falcon-sign.info/falcon.pdf

Input: [c_ptr, MSG, NONCE1, NONCE0, ...]
Output: [...]

Cycles: ~1430
| | load_h_s2_and_product | Takes as input PK, the hash of the coefficients of the polynomial `h` representing the expanded
public key, and a pointer to the memory location where the coefficients of the polynomial `h`
will be stored.
The procedure loads `h` from the advice stack and compares its hash with the provided hash `PK`.
It then loads the polynomial `s2` representing the signature from the advice stack and lays it
in memory right after `h`.
After that, it loads the claimed polynomial `h * s2` in Z_Q[x] where Q is the Miden VM prime
from the advice stack and lays it right after `s2`.
The hash of `h`, `s2` and the claimed product is also computed and the first two field elements
of the digest (i.e., the Fiat-Shamir challenge) are used in order to check that
pi == h * s2 in Z_Q[x] by evaluating both sides at the random point. Note that since we need
to hash the polynomials before computing their evaluations, the procedure receives
the evaluation point non-deterministically so that it can perform the evaluations while hashing
is still going on. After hashing of the polynomials is finished, the procedure checks that
the evaluation point was indeed derived correctly from the hash of all 3 polynomials.

Inputs:
Operand stack: [ptr, PK, ...]
Advice stack: [tau0, tau1, h_0, ..., h_511, s2_0, ..., s2_511, pi_0, ..., pi_1022, ...]
Outputs:
Operand stack: []
Advice stack: []

Cycles: 6780
| | norm_sq | Normalizes an `e` in [0, M) to be in [-(M-1) << 1, (M-1) << 1) and returns its square norm.

We use the following formula to do so:
normalize(e) = e^2 - phi * (2*M*e - M^2) where phi := (e > (M - 1)/2)

The formula implements:

if e > (M-1)/2:
return (M - e)^2
else:
return e^2

The use of the formula avoids using the if-else block.

Input: [e, ...]
Output [norm(e)^2, ...]

Cycles: 20
| diff --git a/crates/lib/core/docs/crypto/hashes/keccak256.md b/crates/lib/core/docs/crypto/hashes/keccak256.md index 411ee3df03..01f20e37cd 100644 --- a/crates/lib/core/docs/crypto/hashes/keccak256.md +++ b/crates/lib/core/docs/crypto/hashes/keccak256.md @@ -5,4 +5,3 @@ | hash_bytes | Computes Keccak256 hash of data stored in memory.

Input: [ptr, len_bytes, ...]
Output: [DIGEST_U32[8], ...]

Where:
- ptr: word-aligned memory address containing INPUT_U32[len_u32] where len_u32=⌈len_bytes/4⌉
- len_bytes: number of bytes to hash
- INPUT_U32[len_u32] ~ INPUT_U8[len_bytes] with u32 packing (unused bytes in final u32 must be 0)
- DIGEST_U32[8] = [d_0, ..., d_7] = Keccak256(INPUT_U8[len_bytes])
| | hash | Computes Keccak256 hash of a single 256-bit input.

Input: [INPUT_U32[8], ...]
Output: [DIGEST_U32[8], ...]

Where
- DIGEST_U32[8] = [d_0, ..., d_7] = Keccak256(INPUT_U8[32])
- INPUT_U32[8] = [i_0, ..., i_7] = [INPUT_LO, INPUT_HI] ~ INPUT_U8[32] with u32 packing
| | merge | Merges two 256-bit digests via Keccak256 hash.

Input: [INPUT_L_U32[8], INPUT_R_U32[8], ...]
Output: [DIGEST_U32[8], ...]

Where
- INPUT_L_U32[8] = [l_0, ..., l_7] = [INPUT_L_LO, INPUT_L_HI] ~ INPUT_L_U8[32]
- INPUT_R_U32[8] = [r_0, ..., r_7] = [INPUT_R_LO, INPUT_R_HI] ~ INPUT_R_U8[32]
- DIGEST_U32[8] = [d_0, ..., d_7] = Keccak256(INPUT_L_U8[32] \|\| INPUT_R_U8[32])
| -| hash_bytes_impl | Internal implementation of memory-based Keccak256 computation via deferred computation.

Emits an event to populate the advice stack with digest and store the preimage for deferred verification.
Returns the commitment to the precompile call and its tag.

Input: [ptr, len_bytes, ...]
Output: [COMM, TAG, DIGEST_U32[8], ...]

Where:
- ptr: word-aligned memory address containing INPUT_U32[len_u32] where len_u32=⌈len_bytes/4⌉
- len_bytes: number of bytes to hash
- COMM: the calldata commitment `Poseidon2(Poseidon2(INPUT_U32[..]) \|\| Poseidon2(DIGEST_U32[..]))` consumed by `log_precompile`
- TAG = [KECCAK_HASH_BYTES_EVENT, len_bytes, 0, 0] encodes the precompile identifier and the byte length as metadata
- DIGEST_U32[8] = [d_0, ..., d_7] = Keccak256(INPUT_U8[len_bytes])
| diff --git a/crates/lib/core/docs/crypto/hashes/poseidon2.md b/crates/lib/core/docs/crypto/hashes/poseidon2.md index 333c7bbcf4..84d41f5910 100644 --- a/crates/lib/core/docs/crypto/hashes/poseidon2.md +++ b/crates/lib/core/docs/crypto/hashes/poseidon2.md @@ -2,16 +2,19 @@ ## miden::core::crypto::hashes::poseidon2 | Procedure | Description | | ----------- | ------------- | -| init_no_padding | Prepares the top of the stack with the hasher initial state.

This procedures does not handle padding, therefore, the user is expected to
consume an amount of data which is a multiple of the rate (2 words).

Input: []
Output: [PERM, PERM, PERM, ...]

Cycles: 12
| +| init_no_padding | Prepares the top of the stack with the hasher initial state.

This procedures does not handle padding, therefore, the user is expected to
consume an amount of data which is a multiple of the rate (2 words).

Input: []
Output: [R0, R1, C, ...]

Where R0, R1, C are three zero words representing the initial Poseidon2 hasher state
(R0 on top of stack).

Cycles: 12
| +| init_with_capacity | Prepares the top of the stack with the hasher initial state, using a caller-supplied capacity
word.

The caller must have placed the capacity word `C` on top of the stack before invoking this
procedure. No padding handling is performed: callers must absorb data which is a multiple of
the rate (2 words), or handle odd-length absorption themselves.

Input: [C, ...]
Output: [R0=0w, R1=0w, C, ...]

Cycles: 8
| | squeeze_digest | Given the hasher state, returns the hash output (digest).

Input: [R0, R1, C, ...]
Output: [DIGEST, ...]

Where:
- `R0` is the first rate word / digest (positions 0-3, on top of stack).
- `R1` is the second rate word (positions 4-7).
- `C` is the capacity word (positions 8-11).
- `DIGEST = R0`.

Cycles: 9
| | copy_digest | Copies the digest to the top of the stack.

It is expected to have the hasher state at the top of the stack at the beginning of the procedure
execution.

Input: [R0, R1, C, ...]
Output: [DIGEST, R0, R1, C, ...]

Where:
- `R0` is the first rate word / digest (positions 0-3, on top of stack).
- `R1` is the second rate word (positions 4-7).
- `C` is the capacity word (positions 8-11).
- `DIGEST = R0`.

Cycles: 4
| | absorb_double_words_from_memory | Hashes the memory `start_addr` to `end_addr` given a Poseidon2 state specified by 3 words.

This requires that `end_addr = start_addr + 8n` where n = {0, 1, 2 ...}, otherwise the procedure
will enter an infinite loop.

Input: [R0, R1, C, start_addr, end_addr, ...]
Output: [R0', R1', C', end_addr, end_addr ...]

Where:
- `R0` is the first rate word / digest (positions 0-3, on top of stack).
- `R1` is the second rate word (positions 4-7).
- `C` is the capacity word (positions 8-11).

Cycles: 4 + 3 * words, where `words` is the `start_addr - end_addr`
| | hash_double_words | Hashes the pairs of words in the memory from `start_addr` to `end_addr`.

This procedure requires that `end_addr = start_addr + 8n` where n = {0, 1, 2 ...} (i.e. we must
always hash some number of double words), otherwise the procedure will enter an infinite loop.

Input: [start_addr, end_addr, ...]
Output: [HASH, ...]

Where:
- `HASH` is the cumulative hash of the provided memory values.

Cycles: 37 + 3 * words, where `words` is the `start_addr - end_addr`
| -| hash_words | Hashes the memory `start_addr` to `end_addr`, handles odd number of elements.

Requires `start_addr ≤ end_addr`, `end_addr` is not inclusive.
Requires `start_addr` and `end_addr` to be word-aligned.

Input: [start_addr, end_addr, ...]
Output: [H, ...]

Cycles:
- even words: 53 cycles + 3 * words
- odd words: 65 cycles + 3 * words
where `words` is the `start_addr - end_addr - 1`
| +| hash_words_with_domain | Hashes the memory `start_addr` to `end_addr` with a domain identifier, handling an odd number
of words.

Requires `start_addr ≤ end_addr`, `end_addr` is not inclusive.
Requires `start_addr` and `end_addr` to be word-aligned.

Input: [domain, start_addr, end_addr, ...]
Output: [H, ...]

Cycles:
- even words: 54 cycles + 3 * words
- odd words: 66 cycles + 3 * words
where `words` is `(end_addr - start_addr) / 4`.
| +| hash_words | Hashes the memory `start_addr` to `end_addr`, handles odd number of elements.

Equivalent to `hash_words_with_domain` with `domain = 0`.

Requires `start_addr ≤ end_addr`, `end_addr` is not inclusive.
Requires `start_addr` and `end_addr` to be word-aligned.

Input: [start_addr, end_addr, ...]
Output: [H, ...]

Cycles:
- even words: 55 cycles + 3 * words
- odd words: 67 cycles + 3 * words
where `words` is `(end_addr - start_addr) / 4`.
| | prepare_hasher_state | Initializes the hasher state required for the `hash_elements_with_state` procedure.

Depending on the provided pad_inputs_flag, this procedure initializes the hasher state using
different values for capacity element:
- If pad_inputs_flag = 1 the capacity element is set to 0. This will essentially "pad" the
hashed values with zeroes to the next multiple of 8.
- If pad_inputs_flag = 0 the capacity element is set to the remainder of the division of
number of hashed elements by 8 (num_elements%8).

Inputs: [ptr, num_elements, pad_inputs_flag]
Outputs: [R0, R1, C, ptr, end_pairs_addr, num_elements%8]

Where:
- ptr is the memory address of the first element to be hashed. This address must be
word-aligned - i.e., divisible by 4.
- num_elements is the number of elements to be hashed.
- pad_inputs_flag is the flag which indicates whether the values which will be hashed should be
padded with zeros to the next multiple of 8.
- R0, R1, C are three words representing the hasher state (R0 on top).
- end_pairs_addr is the memory address at which the pairs of words end.
- num_elements%8 is the number of elements which didn't fit to the word pairs and should be
hashed separately.
| | hash_elements_with_state | Computes hash of Felt values starting at the specified memory address using the provided hasher
state.

This procedure divides the hashing process into two parts: hashing pairs of words using
`absorb_double_words_from_memory` procedure and hashing the remaining values using the `permute`
procedure.

Inputs: [R0, R1, C, ptr, end_pairs_addr, num_elements%8]
Outputs: [HASH]

Where:
- ptr is the memory address of the first element to be hashed. This address must be
word-aligned - i.e., divisible by 4.
- R0, R1, C are three words representing the hasher state (R0 on top).
- end_pairs_addr is the memory address at which the pairs of words end.
- num_elements%8 is the number of elements which didn't fit to the word pairs and should be
hashed separately.
- HASH is the resulting hash of the provided memory values.
| | hash_elements | Computes hash of Felt values starting at the specified memory address.

This procedure divides the hashing process into two parts: hashing pairs of words using
`absorb_double_words_from_memory` procedure and hashing the remaining values using the `permute`
procedure.

Inputs: [ptr, num_elements]
Outputs: [HASH]

Where:
- ptr is the memory address of the first element to be hashed. This address must be
word-aligned - i.e., divisible by 4.
- num_elements is the number of elements to be hashed.
- HASH is the resulting hash of the provided memory values.

Cycles:
- If number of elements divides by 8: 52 cycles + 3 * words
- Else: 185 cycles + 3 * words
where `words` is the number of quads of input values.
| | pad_and_hash_elements | Computes hash of Felt values starting at the specified memory address.

Notice that this procedure essentially pads the elements to be hashed to the next multiple of 8
by setting the capacity element to 0.

This procedure divides the hashing process into two parts: hashing pairs of words using
`absorb_double_words_from_memory` procedure and hashing the remaining values using the `permute`
procedure.

Inputs: [ptr, num_elements]
Outputs: [HASH]

Where:
- ptr is the memory address of the first element to be hashed. This address must be
word-aligned - i.e., divisible by 4.
- num_elements is the number of elements to be hashed.
- HASH is the resulting hash of the provided memory values.

Cycles:
- If number of elements divides by 8: 52 cycles + 3 * words
- Else: 185 cycles + 3 * words
where `words` is the number of quads of input values.
| -| hash | Computes Poseidon2 hash of a single word (256-bit input).

Inputs: [A]
Outputs: [B]

Where:
- A is the word to be hashed.
- B is the resulting hash, computed as `Poseidon2(A)`.

Cycles: 20
| -| merge | Merges two words (256-bit digests) via Poseidon2 hash.

Inputs: [B, A]
Outputs: [C]

Where:
- A and B are the words to be merged.
- C is the resulting hash, computed as `Poseidon2(A \|\| B)`.

Cycles: 16
| +| hash | Computes Poseidon2 hash of a single word (256-bit input).

Inputs: [A]
Outputs: [B]

Where:
- A is the word to be hashed.
- B is the resulting hash, computed as `Poseidon2(A)`.

Cycles: 19
| +| merge | Merges two words (256-bit digests) via Poseidon2 hash.

Inputs: [A, B]
Outputs: [C]

Where:
- A and B are the words to be merged.
- C is the resulting hash, computed as `Poseidon2(A \|\| B)`.

Cycles: 16
| +| merge_in_domain | Merges two words (256-bit digests) via Poseidon2 hash with a domain identifier.

Inputs: [domain, A, B, ...]
Outputs: [C, ...]

Where:
- A and B are the words to be merged (A corresponds to the first rate word).
- C is the resulting hash, computed with capacity `[0, domain, 0, 0]`.

Cycles: 16
| | permute | Performs Poseidon2 permutation on the hasher state.

Inputs: [R0, R1, C]
Outputs: [R0', R1', C']

Where:
- R0, R1, C are three words representing the hasher state (R0 on top).
- R0', R1', C' are the permuted state words.

Cycles: 1
| diff --git a/crates/lib/core/docs/crypto/hashes/sha256.md b/crates/lib/core/docs/crypto/hashes/sha256.md index 66df6c0f04..26fdc27005 100644 --- a/crates/lib/core/docs/crypto/hashes/sha256.md +++ b/crates/lib/core/docs/crypto/hashes/sha256.md @@ -4,6 +4,6 @@ Computes SHA2 small sigma 0.

Input: [x, ...]
Output: [y, ...]

Input: [m0, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13, m14, m15, ...]
Output: [dig0, dig1, dig2, dig3, dig4, dig5, dig6, dig7, ...]

Where: m[0,16) = 32 -bit word

Note, each SHA256 word is 32 -bit wide, so that's how input is expected.
As you've 64 -bytes, consider packing 4 consecutive bytes into single word,
maintaining big endian byte order.

SHA256 digest is represented in terms of eight 32 -bit words ( big endian byte order ).
| -| hash | SHA256 1-to-1 hash: Given 32 -bytes input, computes 32 -bytes SHA256 digest

Expected stack state:

Input: [m0, m1, m2, m3, m4, m5, m6, m7, ...]
Output: [dig0, dig1, dig2, dig3, dig4, dig5, dig6, dig7, ...]

Where: m[0,8) = 32 -bit word

Note, each SHA256 word is 32 -bit wide, so that's how input is expected.
As you've 32 -bytes, consider packing 4 consecutive bytes into single word,
maintaining big endian byte order.

SHA256 digest is represented in terms of eight 32 -bit words ( big endian byte order ).
| -| hash_bytes | Given a memory address and a message length in bytes, compute its sha256 digest

- There must be space for writing the padding after the message in memory
- The padding space after the message must be all zeros before this procedure is called

Input: [addr, len, ...]
Output: [dig0, dig1, dig2, dig3, dig4, dig5, dig6, dig7, ...]
| +| merge | SHA256 2-to-1 hash (merge): Given 64 -bytes input, computes 32 -bytes SHA256 digest

Input: [m0, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13, m14, m15, ...]
Output: [dig0, dig1, dig2, dig3, dig4, dig5, dig6, dig7, ...]

Where: m[0,16) = 32 -bit word

Note, each SHA256 word is 32 -bit wide, so that's how input is expected.
As you've 64 -bytes, consider packing 4 consecutive bytes into single word,
maintaining big endian byte order.

SHA256 digest is represented in terms of eight 32 -bit words ( big endian byte order ).

Panics if:
- any input message word is not a valid 32-bit unsigned integer.

Invocation: exec
| +| hash | SHA256 1-to-1 hash: Given 32 -bytes input, computes 32 -bytes SHA256 digest

Expected stack state:

Input: [m0, m1, m2, m3, m4, m5, m6, m7, ...]
Output: [dig0, dig1, dig2, dig3, dig4, dig5, dig6, dig7, ...]

Where: m[0,8) = 32 -bit word

Note, each SHA256 word is 32 -bit wide, so that's how input is expected.
As you've 32 -bytes, consider packing 4 consecutive bytes into single word,
maintaining big endian byte order.

SHA256 digest is represented in terms of eight 32 -bit words ( big endian byte order ).

Panics if:
- any input message word is not a valid 32-bit unsigned integer.

Invocation: exec
| +| hash_bytes | Given a memory address and a message length in bytes, compute its sha256 digest

- There must be space for writing the padding after the message in memory
- The padding space after the message must be all zeros before this procedure is called

Input: [addr, len, ...]
Output: [dig0, dig1, dig2, dig3, dig4, dig5, dig6, dig7, ...]

Panics if:
- any loaded message word is not a valid 32-bit unsigned integer.
- padding range checks fail.

Invocation: exec
| diff --git a/crates/lib/core/docs/crypto/hashes/sha512.md b/crates/lib/core/docs/crypto/hashes/sha512.md index 6c5db064b2..ccbe3ba4f8 100644 --- a/crates/lib/core/docs/crypto/hashes/sha512.md +++ b/crates/lib/core/docs/crypto/hashes/sha512.md @@ -3,4 +3,3 @@ | Procedure | Description | | ----------- | ------------- | | hash_bytes | Computes SHA512 hash of data stored in memory.

Input: [ptr, len_bytes, ...]
Output: [DIGEST_U32[16], ...]
| -| hash_bytes_impl | Internal implementation of memory-based SHA512 computation via deferred computation.

Emits an event to populate the advice stack with the digest and store the preimage for deferred
verification. Returns the commitment to the calldata and its tag.

Input: [ptr, len_bytes, ...]
Output: [COMM, TAG, DIGEST_U32[16], ...]
| diff --git a/crates/lib/core/docs/math/u256.md b/crates/lib/core/docs/math/u256.md index 9047398768..45c89dd414 100644 --- a/crates/lib/core/docs/math/u256.md +++ b/crates/lib/core/docs/math/u256.md @@ -2,14 +2,14 @@ ## miden::core::math::u256 | Procedure | Description | | ----------- | ------------- | -| wrapping_add | Performs addition of two unsigned 256 bit integers discarding the overflow.
Stack transition looks as follows:
[b0, b1, b2, b3, b4, b5, b6, b7, a0, a1, a2, a3, a4, a5, a6, a7, ...]
-> [c0, c1, c2, c3, c4, c5, c6, c7, ...], where c = (a + b) % 2^256.
| | overflowing_add | Performs addition of two unsigned 256 bit integers preserving the overflow.
Stack transition looks as follows:
[b0, b1, b2, b3, b4, b5, b6, b7, a0, a1, a2, a3, a4, a5, a6, a7, ...]
-> [overflow, c0, c1, c2, c3, c4, c5, c6, c7, ...], where c = (a + b) % 2^256.
| | widening_add | Performs addition of two unsigned 256 bit integers preserving the overflow with sum on top.
Stack transition looks as follows:
[b0, b1, b2, b3, b4, b5, b6, b7, a0, a1, a2, a3, a4, a5, a6, a7, ...]
-> [c0, c1, c2, c3, c4, c5, c6, c7, overflow, ...], where c = (a + b) % 2^256.
| -| wrapping_sub | Performs subtraction of two unsigned 256 bit integers discarding the underflow.
Stack transition looks as follows:
[b0, b1, b2, b3, b4, b5, b6, b7, a0, a1, a2, a3, a4, a5, a6, a7, ...]
-> [c0, c1, c2, c3, c4, c5, c6, c7, ...], where c = (a - b) % 2^256.
| +| wrapping_add | Performs addition of two unsigned 256 bit integers discarding the overflow.
Stack transition looks as follows:
[b0, b1, b2, b3, b4, b5, b6, b7, a0, a1, a2, a3, a4, a5, a6, a7, ...]
-> [c0, c1, c2, c3, c4, c5, c6, c7, ...], where c = (a + b) % 2^256.
| | overflowing_sub | Performs subtraction of two unsigned 256 bit integers preserving the underflow.
Stack transition looks as follows:
[b0, b1, b2, b3, b4, b5, b6, b7, a0, a1, a2, a3, a4, a5, a6, a7, ...]
-> [underflow, c0, c1, c2, c3, c4, c5, c6, c7, ...], where c = (a - b) % 2^256.
| +| wrapping_sub | Performs subtraction of two unsigned 256 bit integers discarding the underflow.
Stack transition looks as follows:
[b0, b1, b2, b3, b4, b5, b6, b7, a0, a1, a2, a3, a4, a5, a6, a7, ...]
-> [c0, c1, c2, c3, c4, c5, c6, c7, ...], where c = (a - b) % 2^256.
| | and | Computes bitwise AND of two unsigned 256 bit integers.
Stack transition looks as follows:
[b0, b1, b2, b3, b4, b5, b6, b7, a0, a1, a2, a3, a4, a5, a6, a7, ...]
-> [c0, c1, c2, c3, c4, c5, c6, c7, ...], where c = a & b.
| | or | Computes bitwise OR of two unsigned 256 bit integers.
Stack transition looks as follows:
[b0, b1, b2, b3, b4, b5, b6, b7, a0, a1, a2, a3, a4, a5, a6, a7, ...]
-> [c0, c1, c2, c3, c4, c5, c6, c7, ...], where c = a \| b.
| | xor | Computes bitwise XOR of two unsigned 256 bit integers.
Stack transition looks as follows:
[b0, b1, b2, b3, b4, b5, b6, b7, a0, a1, a2, a3, a4, a5, a6, a7, ...]
-> [c0, c1, c2, c3, c4, c5, c6, c7, ...], where c = a ^ b.
| | eqz | Returns 1 if the top u256 value is zero; lower stack values are preserved.
Stack transition looks as follows:
[a0, a1, a2, a3, a4, a5, a6, a7, ...] -> [is_zero, ...].
| | eq | Returns 1 if two unsigned 256 bit integers are equal.
Stack transition looks as follows:
[b0, b1, b2, b3, b4, b5, b6, b7, a0, a1, a2, a3, a4, a5, a6, a7, ...] -> [is_equal, ...].
| -| wrapping_mul | Performs multiplication of two unsigned 256 bit integers discarding the overflow.
The input values are assumed to be represented using 32 bit limbs, but this is not checked.
Stack transition looks as follows:
[b0, b1, b2, b3, b4, b5, b6, b7, a0, a1, a2, a3, a4, a5, a6, a7, ...] -> [c0, c1, c2, c3, c4, c5, c6, c7, ...]
where c = (a * b) % 2^256, and a0, b0, and c0 are least significant 32-bit limbs of a, b, and c respectively.
| +| wrapping_mul | Performs multiplication of two unsigned 256 bit integers discarding the overflow.
The input values are assumed to be represented using 32 bit limbs, but this is not checked.
Stack transition looks as follows:
[b0, b1, b2, b3, b4, b5, b6, b7, a0, a1, a2, a3, a4, a5, a6, a7, ...]
-> [c0, c1, c2, c3, c4, c5, c6, c7, ...], where c = (a * b) % 2^256.
| diff --git a/crates/lib/core/docs/math/u64.md b/crates/lib/core/docs/math/u64.md index a7294341d8..b8715e54e0 100644 --- a/crates/lib/core/docs/math/u64.md +++ b/crates/lib/core/docs/math/u64.md @@ -5,19 +5,19 @@ | overflowing_add | Performs addition of two unsigned 64 bit integers preserving the overflow.
The input values are assumed to be represented using 32 bit limbs, but this is not checked.
Stack transition looks as follows:
[b_lo, b_hi, a_lo, a_hi, ...] -> [overflow, c_lo, c_hi, ...], where c = (a + b) % 2^64
This takes 5 cycles.
| | widening_add | Performs addition of two unsigned 64 bit integers preserving the overflow with sum on top.
The input values are assumed to be represented using 32 bit limbs, but this is not checked.
Stack transition looks as follows:
[b_lo, b_hi, a_lo, a_hi, ...] -> [c_lo, c_hi, overflow, ...], where c = (a + b) % 2^64
This takes 6 cycles.
| | wrapping_add | Performs addition of two unsigned 64 bit integers discarding the overflow.
The input values are assumed to be represented using 32 bit limbs, but this is not checked.
Stack transition looks as follows:
[b_lo, b_hi, a_lo, a_hi, ...] -> [c_lo, c_hi, ...], where c = (a + b) % 2^64
This takes 6 cycles.
| -| wrapping_sub | Performs subtraction of two unsigned 64 bit integers discarding the overflow.
The input values are assumed to be represented using 32 bit limbs, but this is not checked.
Stack transition looks as follows:
[b_lo, b_hi, a_lo, a_hi, ...] -> [c_lo, c_hi, ...], where c = (a - b) % 2^64
This takes 11 cycles.
| -| overflowing_sub | Performs subtraction of two unsigned 64 bit integers preserving the overflow.
The input values are assumed to be represented using 32 bit limbs, but this is not checked.
Stack transition looks as follows:
[b_lo, b_hi, a_lo, a_hi, ...] -> [underflow, c_lo, c_hi, ...], where c = (a - b) % 2^64
This takes 15 cycles.
| +| wrapping_sub | Performs subtraction of two unsigned 64 bit integers discarding the overflow.
The input values are assumed to be represented using 32 bit limbs, but this is not checked.
Stack transition looks as follows:
[b_lo, b_hi, a_lo, a_hi, ...] -> [c_lo, c_hi, ...], where c = (a - b) % 2^64
This takes 12 cycles.
| +| overflowing_sub | Performs subtraction of two unsigned 64 bit integers preserving the overflow.
The input values are assumed to be represented using 32 bit limbs, but this is not checked.
Stack transition looks as follows:
[b_lo, b_hi, a_lo, a_hi, ...] -> [underflow, c_lo, c_hi, ...], where c = (a - b) % 2^64
This takes 14 cycles.
| | wrapping_mul | Performs multiplication of two unsigned 64 bit integers discarding the overflow.
The input values are assumed to be represented using 32 bit limbs, but this is not checked.
Stack transition looks as follows:
[b_lo, b_hi, a_lo, a_hi, ...] -> [c_lo, c_hi, ...], where c = (a * b) % 2^64
This takes 15 cycles.
| -| widening_mul | Performs multiplication of two unsigned 64 bit integers preserving the overflow.
The input values are assumed to be represented using 32 bit limbs, but this is not checked.
Stack transition looks as follows:
[b_lo, b_hi, a_lo, a_hi, ...] -> [c_lo, c_mid_lo, c_mid_hi, c_hi, ...], where
c = a * b is represented as a 128-bit value split into 4 32-bit limbs.
This takes 22 cycles.
| -| lt | Performs less-than comparison of two unsigned 64 bit integers.
The input values are assumed to be represented using 32 bit limbs, but this is not checked.
Stack transition looks as follows:
[b_lo, b_hi, a_lo, a_hi, ...] -> [c, ...], where c = 1 when a < b, and 0 otherwise.
This takes 12 cycles.
| +| widening_mul | Performs multiplication of two unsigned 64 bit integers preserving the overflow.
The input values are assumed to be represented using 32 bit limbs, but this is not checked.
Stack transition looks as follows:
[b_lo, b_hi, a_lo, a_hi, ...] -> [c_lo, c_mid_lo, c_mid_hi, c_hi, ...], where
c = a * b is represented as a 128-bit value split into 4 32-bit limbs.
This takes 23 cycles.
| +| lt | Performs less-than comparison of two unsigned 64 bit integers.
The input values are assumed to be represented using 32 bit limbs, but this is not checked.
Stack transition looks as follows:
[b_lo, b_hi, a_lo, a_hi, ...] -> [c, ...], where c = 1 when a < b, and 0 otherwise.
This takes 13 cycles.
| | gt | Performs greater-than comparison of two unsigned 64 bit integers.
The input values are assumed to be represented using 32 bit limbs, but this is not checked.
Stack transition looks as follows:
[b_lo, b_hi, a_lo, a_hi, ...] -> [c, ...], where c = 1 when a > b, and 0 otherwise.
This takes 13 cycles.
| | lte | Performs less-than-or-equal comparison of two unsigned 64 bit integers.
The input values are assumed to be represented using 32 bit limbs, but this is not checked.
Stack transition looks as follows:
[b_lo, b_hi, a_lo, a_hi, ...] -> [c, ...], where c = 1 when a <= b, and 0 otherwise.
This takes 14 cycles.
| | gte | Performs greater-than-or-equal comparison of two unsigned 64 bit integers.
The input values are assumed to be represented using 32 bit limbs, but this is not checked.
Stack transition looks as follows:
[b_lo, b_hi, a_lo, a_hi, ...] -> [c, ...], where c = 1 when a >= b, and 0 otherwise.
This takes 13 cycles.
| -| eq | Performs equality comparison of two unsigned 64 bit integers.
The input values are assumed to be represented using 32 bit limbs, but this is not checked.
Stack transition looks as follows:
[b_lo, b_hi, a_lo, a_hi, ...] -> [c, ...], where c = 1 when a == b, and 0 otherwise.
This takes 5 cycles.
| -| neq | Performs inequality comparison of two unsigned 64 bit integers.
The input values are assumed to be represented using 32 bit limbs, but this is not checked.
Stack transition looks as follows:
[b_lo, b_hi, a_lo, a_hi, ...] -> [c, ...], where c = 1 when a != b, and 0 otherwise.
This takes 5 cycles.
| +| eq | Performs equality comparison of two unsigned 64 bit integers.
The input values are assumed to be represented using 32 bit limbs, but this is not checked.
Stack transition looks as follows:
[b_lo, b_hi, a_lo, a_hi, ...] -> [c, ...], where c = 1 when a == b, and 0 otherwise.
This takes 6 cycles.
| +| neq | Performs inequality comparison of two unsigned 64 bit integers.
The input values are assumed to be represented using 32 bit limbs, but this is not checked.
Stack transition looks as follows:
[b_lo, b_hi, a_lo, a_hi, ...] -> [c, ...], where c = 1 when a != b, and 0 otherwise.
This takes 8 cycles.
| | eqz | Performs comparison to zero of an unsigned 64 bit integer.
The input value is assumed to be represented using 32 bit limbs, but this is not checked.
Stack transition looks as follows:
[a_lo, a_hi, ...] -> [c, ...], where c = 1 when a == 0, and 0 otherwise.
This takes 4 cycles.
| -| min | Compares two unsigned 64 bit integers and drops the larger one from the stack.
The input values are assumed to be represented using 32 bit limbs, but this is not checked.
Stack transition looks as follows:
[b_lo, b_hi, a_lo, a_hi, ...] -> [c_lo, c_hi, ...], where c = min(a, b).
This takes 23 cycles.
| -| max | Compares two unsigned 64 bit integers and drops the smaller one from the stack.
The input values are assumed to be represented using 32 bit limbs, but this is not checked.
Stack transition looks as follows:
[b_lo, b_hi, a_lo, a_hi, ...] -> [c_lo, c_hi, ...], where c = max(a, b).
This takes 24 cycles.
| +| min | Compares two unsigned 64 bit integers and drops the larger one from the stack.
The input values are assumed to be represented using 32 bit limbs, but this is not checked.
Stack transition looks as follows:
[b_lo, b_hi, a_lo, a_hi, ...] -> [c_lo, c_hi, ...], where c = min(a, b).
This takes 27 cycles.
| +| max | Compares two unsigned 64 bit integers and drops the smaller one from the stack.
The input values are assumed to be represented using 32 bit limbs, but this is not checked.
Stack transition looks as follows:
[b_lo, b_hi, a_lo, a_hi, ...] -> [c_lo, c_hi, ...], where c = max(a, b).
This takes 27 cycles.
| | div | Performs division of two unsigned 64 bit integers discarding the remainder.
The input values are assumed to be represented using 32 bit limbs, but this is not checked.
Stack transition looks as follows:
[b_lo, b_hi, a_lo, a_hi, ...] -> [c_lo, c_hi, ...], where c = a // b
This takes 56 cycles.
| | mod | Performs modulo operation of two unsigned 64 bit integers.
The input values are assumed to be represented using 32 bit limbs, but this is not checked.
Stack transition looks as follows:
[b_lo, b_hi, a_lo, a_hi, ...] -> [c_lo, c_hi, ...], where c = a % b
This takes 58 cycles.
| | divmod | Performs divmod operation of two unsigned 64 bit integers.
The input values are assumed to be represented using 32 bit limbs, but this is not checked.
Stack transition looks as follows:
[b_lo, b_hi, a_lo, a_hi, ...] -> [r_lo, r_hi, q_lo, q_hi, ...], where q = a / b, r = a % b.
This takes 54 cycles.
| @@ -25,9 +25,9 @@ | or | Performs bitwise OR of two unsigned 64 bit integers.
The input values are assumed to be represented using 32 bit limbs, but this is not checked.
Stack transition looks as follows:
[b_lo, b_hi, a_lo, a_hi, ...] -> [c_lo, c_hi, ...], where c = a OR b.
This takes 5 cycles.
| | xor | Performs bitwise XOR of two unsigned 64 bit integers.
The input values are assumed to be represented using 32 bit limbs, but this is not checked.
Stack transition looks as follows:
[b_lo, b_hi, a_lo, a_hi, ...] -> [c_lo, c_hi, ...], where c = a XOR b.
This takes 5 cycles.
| | shl | Performs left shift of one unsigned 64-bit integer.
The input value to be shifted is assumed to be represented using 32 bit limbs, but this is not checked.
The shift value n should be in the range [0, 64), otherwise it will result in an error.
Stack transition looks as follows:
[n, a_lo, a_hi, ...] -> [c_lo, c_hi, ...], where c = (a << n) mod 2^64.
This takes 21 cycles.
| -| shr | Performs right shift of one unsigned 64-bit integer.
The input value to be shifted is assumed to be represented using 32 bit limbs, but this is not checked.
The shift value n should be in the range [0, 64), otherwise it will result in an error.
Stack transition looks as follows:
[n, a_lo, a_hi, ...] -> [c_lo, c_hi, ...], where c = a >> n.
This takes 49 cycles.
| -| rotl | Performs left rotation of one unsigned 64-bit integer.
The input value to be rotated is assumed to be represented using 32 bit limbs, but this is not checked.
The rotation amount n should be in the range [0, 64), otherwise it will result in an error.
Stack transition looks as follows:
[n, a_lo, a_hi, ...] -> [c_lo, c_hi, ...], where c = a <<< n (rotate left).
This takes 35 cycles.
| -| rotr | Performs right rotation of one unsigned 64-bit integer.
The input value to be rotated is assumed to be represented using 32 bit limbs, but this is not checked.
The rotation amount n should be in the range [0, 64), otherwise it will result in an error.
Stack transition looks as follows:
[n, a_lo, a_hi, ...] -> [c_lo, c_hi, ...], where c = a >>> n (rotate right).
This takes 44 cycles.
| +| shr | Performs right shift of one unsigned 64-bit integer.
The input value to be shifted is assumed to be represented using 32 bit limbs, but this is not checked.
The shift value n should be in the range [0, 64), otherwise it will result in an error.
Stack transition looks as follows:
[n, a_lo, a_hi, ...] -> [c_lo, c_hi, ...], where c = a >> n.
This takes 60 or 61 cycles, depending on n.
| +| rotl | Performs left rotation of one unsigned 64-bit integer.
The input value to be rotated is assumed to be represented using 32 bit limbs, but this is not checked.
The rotation amount n should be in the range [0, 64), otherwise it will result in an error.
Stack transition looks as follows:
[n, a_lo, a_hi, ...] -> [c_lo, c_hi, ...], where c = a <<< n (rotate left).
This takes 46 cycles.
| +| rotr | Performs right rotation of one unsigned 64-bit integer.
The input value to be rotated is assumed to be represented using 32 bit limbs, but this is not checked.
The rotation amount n should be in the range [0, 64), otherwise it will result in an error.
Stack transition looks as follows:
[n, a_lo, a_hi, ...] -> [c_lo, c_hi, ...], where c = a >>> n (rotate right).
This takes 60 cycles.
| | clz | Counts the number of leading zeros of one unsigned 64-bit integer.
The input value is assumed to be represented using 32 bit limbs, but this is not checked.
Stack transition looks as follows:
[n_lo, n_hi, ...] -> [clz, ...], where clz is the number of leading zeros of value n.
This takes 48 cycles.
| | ctz | Counts the number of trailing zeros of one unsigned 64-bit integer.
The input value is assumed to be represented using 32 bit limbs, but this is not checked.
Stack transition looks as follows:
[n_lo, n_hi, ...] -> [ctz, ...], where ctz is the number of trailing zeros of value n.
This takes 41 cycles.
| | clo | Counts the number of leading ones of one unsigned 64-bit integer.
The input value is assumed to be represented using 32 bit limbs, but this is not checked.
Stack transition looks as follows:
[n_lo, n_hi, ...] -> [clo, ...], where clo is the number of leading ones of value n.
This takes 47 cycles.
| diff --git a/crates/lib/core/docs/mem.md b/crates/lib/core/docs/mem.md index c5c8b08045..bfcfe3f581 100644 --- a/crates/lib/core/docs/mem.md +++ b/crates/lib/core/docs/mem.md @@ -2,9 +2,10 @@ ## miden::core::mem | Procedure | Description | | ----------- | ------------- | -| memcopy_words | Copies `n` words from `read_ptr` to `write_ptr`.

`read_ptr` and `write_ptr` pointers *must be* word-aligned.

Inputs: [n, read_ptr, write_ptr]
Outputs: []

Where:
- n is the number of words which should be copied.
- read_ptr is the memory pointer where the words to copy are stored.
- write_ptr is the memory pointer where the words will be copied.

Total cycles: 15 + 16 * num_words
| -| memcopy_elements | Copies `n` elements from `read_ptr` to `write_ptr`.

Inputs: [n, read_ptr, write_ptr]
Outputs: []

Where:
- n is the number of elements which should be copied.
- read_ptr is the memory pointer where the elements to copy are stored.
- write_ptr is the memory pointer where the elements will be copied.

Total cycles: 7 + 14 * num_elements
| -| pipe_double_words_to_memory | Copies an even number of words from the advice_stack to memory, computing their permutation.

Inputs: [R0, R1, C, write_ptr, end_ptr]
Outputs: [R0', R1', C', write_ptr]

Where:
- R0 is the first rate word (positions 0-3, on top of stack).
- R1 is the second rate word / digest (positions 4-7).
- C is the capacity word (positions 8-11).
- write_ptr is the memory pointer where the words will be copied.
- end_ptr is the memory pointer where the copying should end.

Notice that the `end_ptr - write_ptr` value must be positive and a multiple of 8.

Total cycles: 9 + 6 * num_word_pairs
| +| memcopy_words | Copies `n` words from `read_ptr` to `write_ptr`.

`read_ptr` and `write_ptr` pointers *must be* word-aligned.

Inputs: [n, read_ptr, write_ptr]
Outputs: []

Where:
- n is the number of words which should be copied.
- read_ptr is the memory pointer where the words to copy are stored.
- write_ptr is the memory pointer where the words will be copied.

# Panics

Panics if the source range `[read_ptr, read_ptr + 4*n)` and destination range
`[write_ptr, write_ptr + 4*n)` overlap.

Total cycles: 15 + 16 * num_words
| +| memcopy_elements | Copies `n` elements from `read_ptr` to `write_ptr`.

Inputs: [n, read_ptr, write_ptr]
Outputs: []

Where:
- n is the number of elements which should be copied.
- read_ptr is the memory pointer where the elements to copy are stored.
- write_ptr is the memory pointer where the elements will be copied.

# Panics

Panics if the source range `[read_ptr, read_ptr + n)` and destination range
`[write_ptr, write_ptr + n)` overlap.

Total cycles: 7 + 14 * num_elements
| +| pipe_double_words_to_memory | Copies an even number of words from the advice_stack to memory, computing their permutation.

Inputs: [R0, R1, C, write_ptr, end_ptr]
Outputs: [R0', R1', C', write_ptr]

Where:
- R0 is the first rate word / digest (positions 0-3, on top of stack).
- R1 is the second rate word (positions 4-7).
- C is the capacity word (positions 8-11).
- write_ptr is the memory pointer where the words will be copied.
- end_ptr is the memory pointer where the copying should end.

Notice that the `end_ptr - write_ptr` value must be positive and a multiple of 8.

Total cycles: 9 + 6 * num_word_pairs
| | pipe_words_to_memory | Copies an arbitrary number of words from the advice stack to memory, computing their permutation.

Inputs: [num_words, write_ptr]
Outputs: [R0, R1, C, write_ptr']

Where:
- num_words is the number of words which will be copied to the memory.
- write_ptr is the memory pointer where the words will be copied.
- write_ptr' is the memory pointer to the end of the copied words.
- R0, R1, C are the final Poseidon2 hasher state (R0 on top).

Total cycles:
- Even `num_words`: 43 + 9 * num_words / 2
- Odd `num_words`: 60 + 9 * round_down(num_words / 2)
| | pipe_preimage_to_memory | Moves an arbitrary number of words from the advice stack to memory and asserts it matches the
commitment.

Inputs: [num_words, write_ptr, COMMITMENT]
Outputs: [write_ptr']

Where:
- num_words is the number of words which will be copied to the memory.
- write_ptr is the memory pointer where the words will be copied.
- write_ptr' is the memory pointer to the end of the copied words.
- COMMITMENT is the commitment that the one calculated during this procedure will be compared
with.

Total cycles:
- Even `num_words`: 62 + 9 * num_words / 2
- Odd `num_words`: 79 + 9 * round_down(num_words / 2)
| -| pipe_double_words_preimage_to_memory | Moves an even number of words from the advice stack to memory and asserts that their sequential
hash matches a given commitment.

Inputs: [num_words, write_ptr, COMMITMENT]
Outputs: [write_ptr']

Where:
- num_words is the number of words which will be copied to the memory.
- write_ptr is the memory pointer where the words will be copied.
- write_ptr' is the memory pointer to the end of the copied words.
- COMMITMENT is the commitment that the one calculated during this procedure will be compared
with.

Total cycles: 56 + 3 * num_words / 2
| +| pipe_double_words_preimage_to_memory | Moves an even number of words from the advice stack to memory and asserts that their sequential
hash matches a given commitment.

Inputs: [num_words, write_ptr, COMMITMENT]
Outputs: [write_ptr']

Where:
- num_words is the number of words which will be copied to the memory.
- write_ptr is the memory pointer where the words will be copied.
- write_ptr' is the memory pointer to the end of the copied words.
- COMMITMENT is the commitment that the one calculated during this procedure will be compared
with.

Total cycles: 56 + 3 * num_words
| +| pipe_double_words_preimage_to_memory_with_domain | Moves an even number of words from the advice stack to memory and asserts that their
domain-tagged sequential hash matches a given commitment.

Like `pipe_double_words_preimage_to_memory`, but initializes the Poseidon2 capacity word to
`[0, domain, 0, 0]`.

Inputs: [domain, num_words, write_ptr, COMMITMENT]
Outputs: [write_ptr']

Where:
- domain is the domain identifier placed into the second element of the capacity word.
- num_words is the number of words which will be copied to the memory (must be even).
- write_ptr is the memory pointer where the words will be copied.
- write_ptr' is the memory pointer to the end of the copied words.
- COMMITMENT is the domain-tagged digest that the preimage must hash to.

Total cycles: 57 + 3 * num_words
| diff --git a/crates/lib/core/docs/pcs/fri/frie2f4.md b/crates/lib/core/docs/pcs/fri/frie2f4.md index c1756cba11..69b124f56c 100644 --- a/crates/lib/core/docs/pcs/fri/frie2f4.md +++ b/crates/lib/core/docs/pcs/fri/frie2f4.md @@ -2,8 +2,8 @@ ## miden::core::pcs::fri::frie2f4 | Procedure | Description | | ----------- | ------------- | -| preprocess | Stores the layer commitments C followed by [d_size, t_depth, a1, a0] and [poe, p, e1, e0] where:
1) d_size is the domain size divided by 4 of the domain corresponding to C.
2) t_depth is the tree depth of the Merkle tree with commitment C.
3) (a0, a1) is the folding challenge to create the next layer.
4) p is the query index and (e0, e1) is the evaluation at the first layer and poe is g^p with
g being the initial domain generator.
TODO: This pre-processing function should in fact compute d_size and t_depth for each C
starting from the original domain size.
| -| verify_query_layer | Checks that, for a query with index p at layer i, the folding procedure to create layer (i + 1)
was performed correctly. This also advances layer_ptr by 8 to point to the next query layer.

Input: [layer_ptr, layer_ptr, poe, p, e1, e0, layer_ptr, rem_ptr, x, x, x, x, x, x, x, x, ...]
Output: [is_not_last_layer, layer_ptr+8, layer_ptr+8, poe^4, f_pos, ne1, ne0, layer_ptr+8, rem_ptr, x, x, x, x, x, x, x, x, ...]

Cycles: 83
| -| verify_query_64 | Verifies one FRI query.

This procedure is specialized to the case when the remainder polynomial, used in the final check,
is expected to have degree at most 64.
This procedure is exactly the same as `verify_query_128` except for the remainder polynomial check,
thus any change to one procedure will imply an equivalent change to the other one.

Input: [poe, p, e1, e0, layer_ptr, rem_ptr, ...]
Output: [x, x, x, x, x, x, x, x, x, x, x, x, ...] (12 "garbage" elements)

- poe is g^p.
- p is a query index at the first layer.
- (e0, e1) is an extension field element corresponding to the value of the first layer at index p.
- layer_ptr is the memory address of the layer data (Merkle tree root, alpha etc.) for the next
layer.
- rem_ptr is the memory address of the remainder polynomial.

Cycles: 107 + num_layers * 83
| -| verify_query_128 | Verifies one FRI query.

This procedure is specialized to the case when the remainder polynomial, used in the final check,
is expected to have degree at most 128.
This procedure is exactly the same as `verify_query_64` except for the remainder polynomial check,
thus any change to one procedure will imply an equivalent change to the other one.

Input: [poe, p, e1, e0, layer_ptr, rem_ptr, ...]
Output: [x, x, x, x, x, x, x, x, x, x, x, x, ...] (12 "garbage" elements)

- poe is g^p.
- p is a query index at the first layer.
- (e0, e1) is an extension field element corresponding to the value of the first layer at index p.
- layer_ptr is the memory address of the layer data (Merkle tree root, alpha etc.) for the next
layer.
- rem_ptr is the memory address of the remainder polynomial.

Cycles: 140 + num_layers * 83
| -| verify | Verifies a FRI proof where the proof was generated over the quadratic extension of the base
field and layer folding was performed using folding factor 4.

Input: [...]
Output: [...]

Cycles:

Polynomial degree less than 64: 24 + num_queries * (107 + num_layers * 83)
Polynomial degree less than 128: 24 + num_queries * (140 + num_layers * 83)
| +| preprocess | Stores the layer commitments C followed by [d_size, t_depth, a0, a1] and [poe, p, e0, e1] where:
1) d_size is the domain size divided by 4 of the domain corresponding to C.
2) t_depth is the tree depth of the Merkle tree with commitment C.
3) (a0, a1) is the folding challenge to create the next layer.
4) p is the domain-order query index and (e0, e1) is the evaluation at the first layer and
poe is g^rev(p) with g being the initial domain generator and rev(.) the bit-reversal over
the LDE domain.
TODO: This pre-processing function should in fact compute d_size and t_depth for each C
starting from the original domain size.
| +| verify_query_layer | Checks that, for a query with index p at layer i, the folding procedure to create layer (i + 1)
was performed correctly. This also advances layer_ptr by 8 to point to the next query layer.

Input: [layer_ptr, layer_ptr, poe, p, e0, e1, layer_ptr, rem_ptr, x, x, x, x, x, x, x, x, ...]
Output: [is_not_last_layer, layer_ptr+8, layer_ptr+8, poe^4, f_pos, ne0, ne1, layer_ptr+8, rem_ptr, x, x, x, x, x, x, x, x, ...]

Cycles: 99
| +| verify_query_64 | Verifies one FRI query.

This procedure is specialized to the case when the remainder polynomial, used in the final check,
is expected to have degree at most 64.
This procedure is exactly the same as `verify_query_128` except for the remainder polynomial check,
thus any change to one procedure will imply an equivalent change to the other one.

Input: [poe, p, e0, e1, layer_ptr, rem_ptr, ...]
Output: [x, x, x, x, x, x, x, x, x, x, x, x, ...] (12 "garbage" elements)

- poe is g^rev(p).
- p is a query index at the first layer.
- (e0, e1) is an extension field element corresponding to the value of the first layer at index p.
- layer_ptr is the memory address of the layer data (Merkle tree root, alpha etc.) for the next
layer.
- rem_ptr is the memory address of the remainder polynomial.

Cycles: 107 + num_layers * 80
| +| verify_query_128 | Verifies one FRI query.

This procedure is specialized to the case when the remainder polynomial, used in the final check,
is expected to have degree at most 128.
This procedure is exactly the same as `verify_query_64` except for the remainder polynomial check,
thus any change to one procedure will imply an equivalent change to the other one.

Input: [poe, p, e0, e1, layer_ptr, rem_ptr, ...]
Output: [x, x, x, x, x, x, x, x, x, x, x, x, ...] (12 "garbage" elements)

- poe is g^rev(p).
- p is a query index at the first layer.
- (e0, e1) is an extension field element corresponding to the value of the first layer at index p.
- layer_ptr is the memory address of the layer data (Merkle tree root, alpha etc.) for the next
layer.
- rem_ptr is the memory address of the remainder polynomial.

Cycles: 140 + num_layers * 80
| +| verify | Verifies a FRI proof where the proof was generated over the quadratic extension of the base
field and layer folding was performed using folding factor 4.

Input: [...]
Output: [...]

Cycles:

Polynomial degree less than 64: 24 + num_queries * (107 + num_layers * 80)
Polynomial degree less than 128: 24 + num_queries * (140 + num_layers * 80)
| diff --git a/crates/lib/core/docs/pcs/fri/helper.md b/crates/lib/core/docs/pcs/fri/helper.md index 7c9e25043c..7edf554535 100644 --- a/crates/lib/core/docs/pcs/fri/helper.md +++ b/crates/lib/core/docs/pcs/fri/helper.md @@ -5,6 +5,6 @@ | evaluate_fri_remainder_poly_max_degree_plus_1_half | Evaluates FRI remainder polynomial of degree strictly less than `(max_degree + 1) / 2`.
| | evaluate_fri_remainder_poly_max_degree_plus_1 | Evaluates FRI remainder polynomial of degree strictly less than `max_degree + 1`.
| | generate_fri_parameters | Compute the number of FRI layers given log2 of the size of LDE domain. It also computes the
LDE domain generator and, from it, the trace generator and store these for later use.

Input: [...]
Output: [num_fri_layers, ...]
Cycles: 45
| -| load_fri_layer_commitments | Get FRI layer commitments and reseed with them in order to draw folding challenges i.e. alphas.

Input: [...]
Output: [...]
Cycles: 21 + 83 * num_fri_layers
| +| load_fri_layer_commitments | Get FRI layer commitments and reseed with them in order to draw folding challenges i.e. alphas.

Input: [...]
Output: [...]
Cycles: 21 + 225 * num_fri_layers
| | load_and_verify_remainder | Load and save the remainder polynomial from the advice provider and check that its hash
corresponds to its commitment and reseed with the latter.

Input: [...]
Output: [...]

Cycles:

1- Remainder polynomial of degree less
than 64: 157
2- Remainder polynomial of degree less
than 128: 191
| | compute_query_pointer | Compute the pointer to the first word storing the FRI queries.

Since the FRI queries are laid out just before the FRI commitments, we compute the address
to the first FRI query by subtracting from the pointer to the first FRI layer commitment
the total number of queries.

Input: [...]
Output: [...]

Cycles: 7
| diff --git a/crates/lib/core/docs/stark/constants.md b/crates/lib/core/docs/stark/constants.md index 802e674bbd..ca886ed480 100644 --- a/crates/lib/core/docs/stark/constants.md +++ b/crates/lib/core/docs/stark/constants.md @@ -4,6 +4,7 @@ | ----------- | ------------- | | set_lde_domain_info_word | Store details about the LDE domain.

The info stored is `[lde_size, log(lde_size), lde_g, 0]`.
| | get_lde_domain_info_word | Load details about the LDE domain.

The info stored is `[lde_size, log(lde_size), lde_g, 0]`.
| +| get_lde_domain_depth | Returns log(lde_size), i.e., the depth of the LDE domain Merkle tree.
| | z_ptr | Address for the point `z` and its exponentiation `z^N` where `N=trace_len`.

The word stored is `[z_0, z_1, z^n_0, z^n_1]`.
| | c_ptr | Returns the pointer to the capacity word of the Poseidon2-based random coin.
| | r1_ptr | Returns the pointer to the first rate word of the Poseidon2-based random coin.
| diff --git a/crates/lib/core/docs/stark/deep_queries.md b/crates/lib/core/docs/stark/deep_queries.md index c77cb46839..2c2a43b065 100644 --- a/crates/lib/core/docs/stark/deep_queries.md +++ b/crates/lib/core/docs/stark/deep_queries.md @@ -4,3 +4,4 @@ | ----------- | ------------- | | prepare_stack_deep_queries_computation | Prepares the stack for the computation of the DEEP composition polynomial FRI queries.

It also performs some pre-computations that are common to all queries as an optimization.

Input: [...]
Output: [Y, query_ptr, query_end_ptr, W, query_ptr, ...]

where:

1. `Y` is a garbage word,
2. `query_ptr` is a pointer to the memory region from where the query indices will be fetched
and to where the computed FRI queries will be stored in a word-aligned manner,
3. `query_end_ptr` is a memory pointer used to indicate the end of the memory region used in
storing the computed FRI queries,
4. `W` is the word `[q_z_0, q_z_1, q_gz_0, q_gz_1]` where `q_z = (q_z_0, q_z_1)` and
`q_gz = (q_gz_0, q_gz_1)` represent the constant terms across all FRI queries computations.
| | compute_deep_query | Compute the DEEP composition polynomial FRI query at `index`.

Input: [Y, X, index, query_ptr, query_end_ptr, W, query_ptr, ...]
Output: [?, Y, query_ptr+1, query_end_ptr, ...]

where:
1. `Y` is a garbage word,
2. `X` is `[q_x_at_alpha_0, q_x_at_alpha_1, q_x_at_alpha_0, q_x_at_alpha_1]` where
`q_x = (q_x_0, q_x_1)` is the variable part of the query,
3. `index` is the query index in the FRI domain,
4. `query_ptr` is a pointer to the memory region from where the query indices will be fetched
and to where the computed FRI queries will be stored in a word-aligned manner,
5. `query_end_ptr` is a memory pointer used to indicate the end of the memory region used in
storing the computed FRI queries,
6. `W` is the word `[q_z_0, q_z_1, q_gz_0, q_gz_1]` where `q_z = (q_z_0, q_z_1)` and
`q_gz = (q_gz_0, q_gz_1)` represent the constant terms across all FRI queries computations.
7. `?` is a binary flag indicating if there are further queries to process.
| +| compute_deep_composition_polynomial_queries | Computes the DEEP composition polynomial FRI queries.

Inputs: [...]
Outputs: [...]

Invocation: exec
| diff --git a/crates/lib/core/docs/stark/mod.md b/crates/lib/core/docs/stark/mod.md index d9b8f62a08..e47185e795 100644 --- a/crates/lib/core/docs/stark/mod.md +++ b/crates/lib/core/docs/stark/mod.md @@ -2,4 +2,4 @@ ## miden::core::stark::mod | Procedure | Description | | ----------- | ------------- | -| verify | Verifies a STARK proof.

The purpose of the following verifier is to serve as a generic core around which a specific
verifier can be built. It expects the following parameters on the stack from the caller:

1. `[D0, D1, D2, D3]` which are respectively the digests for dynamic execution of procedures
i. `compute_deep_composition_polynomial_queries`
ii. `execute_constraint_evaluation_check`
iii. `process_row_ood_evaluations`
iv. `process_public_inputs`
2. `num_constraints` which is the number of constraints in the AIR
3. `trace_info` which is a field element encoding the layout of the AIR
4. `num_fixed_len_pi` is the number of fixed length public inputs of the AIR

In addition to the above parameters, the verifier expects the following auxiliary proof parameters:

1. `log(trace_length)`, the logarithm base 2 of the trace length
2. `num_queries`, the number of FRI queries
3. `grinding`, the number of bits of grinding i.e., proof-of-work

The following simplifying assumptions are currently made and hardcoded:

- The blowup factor is set to 8.
- The maximal allowed degree of the remainder polynomial is 127.
- To boost soundness, the protocol is run on a quadratic extension field and this means that
the OOD evaluation frame is composed of elements in a quadratic extension field i.e. tuples.
Similarly, elements of the auxiliary trace are quadratic extension field elements. The random
values for computing random linear combinations are also in this extension field.

Inputs: [D3, D2, D1, D0, log(trace_length), num_queries, grinding, num_constraints, trace_info, num_fixed_len_pi]
Outputs: []
| +| verify | Verifies a STARK proof.

The purpose of the following verifier is to serve as a generic core around which a specific
verifier can be built. It expects the following parameters on the stack from the caller:

1. `[D0, D1, D2, D3, D4]` which are respectively the digests for dynamic execution of procedures
D0. `observe_aux_trace`
D1. `process_public_inputs`
D2. `process_row_ood_evaluations`
D3. `execute_constraint_evaluation_check`
D4. `compute_deep_composition_polynomial_queries`
2. Per-proof parameter: `log(trace_length)`
3. `[rd0, rd1, rd2, rd3]`: RELATION_DIGEST = hash(PROTOCOL_ID, CIRCUIT_COMMITMENT),
a compile-time constant that binds the Fiat-Shamir transcript to the AIR instance.

Precondition: security parameters (num_queries, query_pow_bits, deep_pow_bits,
folding_pow_bits) must already be stored in memory before calling this procedure.

The following simplifying assumptions are currently made and hardcoded:

- The blowup factor is set to 8.
- The maximal allowed degree of the remainder polynomial is 127.
- To boost soundness, the protocol is run on a quadratic extension field and this means that
the OOD evaluation frame is composed of elements in a quadratic extension field i.e. tuples.
Similarly, elements of the auxiliary trace are quadratic extension field elements. The random
values for computing random linear combinations are also in this extension field.

Inputs: [D0, D1, D2, D3, D4, log(trace_length), rd0, rd1, rd2, rd3]
Outputs: []
| diff --git a/crates/lib/core/docs/stark/ood_frames.md b/crates/lib/core/docs/stark/ood_frames.md index e3aea89dc0..3c3e58fd88 100644 --- a/crates/lib/core/docs/stark/ood_frames.md +++ b/crates/lib/core/docs/stark/ood_frames.md @@ -2,4 +2,4 @@ ## miden::core::stark::ood_frames | Procedure | Description | | ----------- | ------------- | -| load_and_horner_eval_ood_frames | Loads the execution trace and the quotient trace evaluation frames.

This also computes Q^z(alpha) and Q^gz(alpha) where:

Q^z(alpha) = (q_z_0, q_z_1) = \sum_{i=0}^{n+m+l} S_i * alpha^i

and

Q^gz(alpha) = (q_gz_0, q_gz_1) = \sum_{i=0}^{n+m+l} T_i * alpha^i

where:

1. n, m and l are the widths of the main segment, auxiliary segment and constraint composition
traces, respectively.
2. S_i are the evaluations of columns in the main segment, auxiliary segment and constraint
composition at the the out-of-domain point z.
3. T_i are the evaluations of columns in the main segment, auxiliary segment and constraint
composition at the the out-of-domain point gz.
4. alpha is the randomness used in order to build the DEEP polynomial.

Q^z(alpha) and Q^gz(alpha) is then stored, as a word, at OOD_FIXED_TERM_HORNER_EVALS_PTR

Inputs: []
Outputs: []
| +| load_and_horner_eval_ood_frames | Loads the execution trace and the quotient trace evaluation frames.

This also computes Q^z(alpha) and Q^gz(alpha) where:

Q^z(alpha) = (q_z_0, q_z_1) = \sum_{i=0}^{n+m+l} S_i * alpha^{n+m+l-i}

and

Q^gz(alpha) = (q_gz_0, q_gz_1) = \sum_{i=0}^{n+m+l} T_i * alpha^{n+m+l-i}

where:

1. n, m and l are the widths of the main segment, auxiliary segment and constraint composition
traces, respectively.
2. S_i are the evaluations of columns in the main segment, auxiliary segment and constraint
composition at the the out-of-domain point z.
3. T_i are the evaluations of columns in the main segment, auxiliary segment and constraint
composition at the the out-of-domain point gz.
4. alpha is the randomness used in order to build the DEEP polynomial.

Q^z(alpha) and Q^gz(alpha) is then stored, as a word, at OOD_FIXED_TERM_HORNER_EVALS_PTR

Inputs: []
Outputs: []
| diff --git a/crates/lib/core/docs/stark/public_inputs.md b/crates/lib/core/docs/stark/public_inputs.md index 2da4d00aca..6ad9b805d6 100644 --- a/crates/lib/core/docs/stark/public_inputs.md +++ b/crates/lib/core/docs/stark/public_inputs.md @@ -2,3 +2,6 @@ ## miden::core::stark::public_inputs | Procedure | Description | | ----------- | ------------- | +| process_public_inputs | Processes the public inputs.

This is a generic dispatch procedure that calls the instance-specific implementation
via `dynexec`. The instance-specific implementation loads fixed-length and variable-length
public inputs from the advice stack, reduces the variable-length inputs using auxiliary
randomness, and stores everything into the ACE READ section.

This involves:

1. Loading from the advice stack the fixed-length public inputs and storing them in memory
starting from the address pointed to by `public_inputs_address_ptr`.
2. Loading from the advice stack the variable-length public inputs, storing them temporarily
in memory, and then reducing them to an element in the challenge field using the auxiliary
randomness. This reduced value is then used to impose boundary conditions on the relevant
auxiliary columns.

Note that the fixed-length public inputs are stored as extension field elements while
the variable-length ones are stored as base field elements, because the ACE circuit operates
only on extension field elements and the latter inputs are not direct inputs to the circuit,
i.e., only their reduced values are.
Both fixed-length and variable-length public inputs are absorbed into the Fiat-Shamir
transcript via direct sponge absorption during loading.

It is worth noting that:

1. Only the fixed-length public inputs are stored for the lifetime of the verification
procedure. The variable-length public inputs are stored temporarily, as this simplifies
the task of reducing them using the auxiliary randomness. The resulting values from the
reductions are stored right after the fixed-length public inputs, in a word-aligned
manner and padded with zeros if needed.
2. The public inputs address is computed so that we end up with the following memory layout:

[..., a_0..a_{m-1}, b_0..b_{n-1}, beta0, beta1, alpha0, alpha1, OOD-start, ...]

where:

a) [a_0..a_{m-1}] are the fixed-length public inputs stored as extension field elements.
This section is double-word-aligned.
b) [b_0..b_{n-1}] are the results of reducing the variable-length public inputs using
auxiliary randomness. This section is word-aligned.
c) [beta0, beta1, alpha0, alpha1] is the auxiliary randomness.
d) OOD-start is the first field element of the section containing the OOD evaluations.
3. For each bus message in a group in the variable-length public inputs, each message is
expected to be padded to the next multiple of 8 and provided in reverse order. This has
the benefit of making the reduction using the auxiliary randomness more efficient using
`horner_eval_base`.

Inputs: [...]
Outputs: [...]

Invocation: exec
| +| compute_and_store_public_inputs_address | Computes the addresses where the public inputs are to be stored.

In order to call `eval_circuit`, we need to lay out the inputs to the constraint evaluation
circuit in a contiguous region of memory (called READ section in the ACE chiplet documentation)
right before the region storing the circuit description (called EVAL section).

As the number of public inputs is a per-instance parameter, while the sizes of the OOD
evaluation frames and the number of auxiliary random values are fixed, we lay out the public
inputs right before the auxiliary random values and OOD evaluations.
Hence the address where public inputs are stored is computed using a negative offset from the
address where the OOD evaluations are stored.

We compute two pointers:
var_len_ptr = OOD_EVALUATIONS_PTR - 4 - num_var_len_pi_groups * 4
pi_ptr = var_len_ptr - num_fixed_len_pi * 2

The `* 4` for VLPI groups provides word-alignment (each group uses 4 base felts = 2 EF
slots, even though the reduced value is only 1 EF). The `* 2` for FLPI converts the base
felt count to EF slots (each base felt is stored as [val, 0]).

The `-4` accounts for the auxiliary randomness word [beta0, beta1, alpha0, alpha1] at
AUX_RAND_ELEM_PTR (4 base felts between var_len_ptr and OOD_EVALUATIONS_PTR).

The var_len_ptr is the region that will temporarily store the variable-length public inputs
and permanently store the results of reducing them by the auxiliary randomness.

Inputs: [num_var_len_pi_groups, num_fixed_len_pi, ...]
Outputs: [...]

Invocation: exec
| +| load_base_store_extension_double_word | Loads 8 base field elements from the advice stack, stores them as extension field elements
in memory, and returns the original base element words in the rate positions for absorption
by the caller via `poseidon2::permute`.

The procedure does NOT absorb the elements into the transcript -- the caller is responsible
for calling `poseidon2::permute` after this procedure to complete the absorption.

Inputs: [Y, Y, C, ptr, ...]
Outputs: [A0, A1, C, ptr + 16, ..]

where A0 and A1 are the original base element words (from advice), positioned in the rate
slots so that a subsequent `poseidon2::permute` absorbs them into the sponge state.

Invocation: exec
| diff --git a/crates/lib/core/docs/stark/random_coin.md b/crates/lib/core/docs/stark/random_coin.md index 743d467950..b4690667be 100644 --- a/crates/lib/core/docs/stark/random_coin.md +++ b/crates/lib/core/docs/stark/random_coin.md @@ -1,22 +1,29 @@ -Disclaimer: most of the procedures in this file assume that the input pointers are word-aligned.
+Random coin for the STARK verifier, built on a Poseidon2 sponge.

The sponge state is stored in memory as three words: rate R1 (r1_ptr), rate R2 (r2_ptr),
and capacity C (c_ptr). R1 and R2 are contiguous (r2_ptr = r1_ptr + 4), so rate elements
0..7 can be addressed as r1_ptr + index.

Sampling uses an output_len counter that tracks how many rate elements remain. Each
permutation sets output_len=8; each sample_felt decrements it by 1 and reads
rate[output_len - 1]. Absorption (reseed_direct, reseed_with_felt, etc.) writes directly
to rate memory and permutes, bypassing any input buffer.
## miden::core::stark::random_coin | Procedure | Description | | ----------- | ------------- | -| get_rate_1 | Return the first half of the rate portion of the random coin state

The random coin uses Poseidon2 to generate data. The Poseidon2 state is composed of 3
words, 2 words for the rate, and 1 word for the capacity. This procedure
returns the first word of the Poseidon2 state.

Input: [...]
Output: [R1, ...]
Cycles: 6
| +| get_rate_1 | Return the first half of the rate portion of the random coin state.

Input: [...]
Output: [R1, ...]
Cycles: 6
| | set_rate_1 | Store the first half of the rate portion of the random coin state.

Input: [R1, ...]
Output: [...]
Cycles: 6
| -| get_rate_2 | Return the second half of the rate portion of the random coin state

The random coin uses Poseidon2 to generate data. The Poseidon2 state is composed of 3
words, 2 words for the rate, and 1 word for the capacity. This procedure
returns the first word of the Poseidon2 state.

Input: [...]
Output: [R2, ...]
Cycles: 6
| +| get_rate_2 | Return the second half of the rate portion of the random coin state.

Input: [...]
Output: [R2, ...]
Cycles: 6
| | set_rate_2 | Store the second half of the rate portion of the random coin state.

Input: [R2, ...]
Output: [...]
Cycles: 6
| -| get_capacity | Return the capacity portion of the random coin state

The random coin uses Poseidon2 to generate data. The Poseidon2 state is composed of 3
words, 2 words for the rate, and 1 word for the capacity. This procedure
returns the first word of the Poseidon2 state.

Input: [...]
Output: [C, ...]
Cycles: 6
| +| get_capacity | Return the capacity portion of the random coin state.

Input: [...]
Output: [C, ...]
Cycles: 6
| | set_capacity | Set the capacity portion of the random coin state.

Input: [C, ...]
Output: [...]
Cycles: 6
| -| load_random_coin_state | Load the random coin state on the stack.

Input: [...]
Output: [R2, R1, C, ...]
Cycles: 18
| -| store_random_coin_state | Store the random coin state to memory.

Input: [R2, R1, C, ...]
Output: [...]
Cycles: 18
| -| init_seed | Initializes the seed for randomness generation by computing the hash of the proof context using
the trace length, number of queries, the number of bits of grinding.
Currently, this part, as well as the rest of the STARK verifier assumes a blowup factor
equal to 8.
The ouput of this procedure is the capacity portion of the state after applying `poseidon2::permute`.

Input: [log(trace_length), num_queries, grinding, num_constraints, trace_info, num_fixed_len_pi, ...]
Output: [C, ...]
Cycles: 210
| -| reseed | Reseed the random coin with `DATA`

Input: [DATA, ...]
Ouput: [...]
Cycles: 54
| -| generate_aux_randomness | Draw a list of random extension field elements related to the auxiliary segment of the execution
trace and store them.

More specifically, we draw two challenges, alpha and beta. This means that our multi-set hash function
has the form `h(m) = alpha + \sum_{i=0}^{\|m\| - 1} m_i * beta^i` for a message `m`.

As these random challenges have already been used non-deterministically in prior computations, we
also check that the generated challenges matche the non-deterministically provided one.

Input: [...]
Output: [...]
Cycles: 20
| -| generate_constraint_composition_coefficients | Draw constraint composition random coefficient and save it at `compos_coef_ptr`.

Input: [...]
Output: [...]
Cycles: 13
| +| load_random_coin_state | Load the random coin state on the stack.

Input: [...]
Output: [R0, R1, C, ...]
Cycles: 18
| +| store_random_coin_state | Store the random coin state to memory.

Input: [R0, R1, C, ...]
Output: [...]
Cycles: 18
| +| sample_felt | Sample a single base field element from the transcript.

SAFETY: Requires output_len > 0. All call sites in the recursive verifier guarantee this
invariant because every sponge permutation sets output_len=8 and at most 8 elements are
consumed before the next permutation. An assertion guards against caller bugs.

Input: [...]
Output: [x, ...]
| +| sample_ext | Sample a quadratic extension field element from the transcript.

Input: [...]
Output: [x0, x1, ...]
| +| sample_bits | Sample a number of bits from the transcript.

Input: [bits, ...]
Output: [value, ...]
| +| init_seed | Initializes the random coin state with domain-separated Fiat-Shamir (DSFS) seeding,
then derives trace domain parameters.

Implements the transcript initialization:

Use the caller-supplied RELATION_DIGEST as initial sponge capacity,
absorb PCS parameters into the rate, and permute.
Rate layout: R1 = [nq, query_pow_bits, deep_pow_bits, folding_pow_bits]
R2 = [log_blowup, log_final_degree, fold_arity, 0]

RELATION_DIGEST = hash(PROTOCOL_ID, CIRCUIT_COMMITMENT) is a compile-time constant
computed once per AIR and pushed by the caller (the specific verifier).

Currently assumes a blowup factor equal to 8.

Precondition: num_queries, query_pow_bits, deep_pow_bits, and folding_pow_bits must
already be stored in memory before calling this procedure.

Input: [log(trace_length), rd0, rd1, rd2, rd3, ...]
Output: [...]
| +| observe_trace_height_and_discard_instance_challenge | Observe the single AIR instance shape and discard the instance challenge.

miden-lifted-stark 0.24 observes each log(trace_length) after public inputs and then samples
one extension-field instance challenge before absorbing the main trace commitment. The VM
recursive verifier only supports one AIR instance, so this helper observes the stored
log(trace_length), performs the partial-rate duplexing, and marks two base-field outputs as
consumed without materializing the unused extension element.

SAFETY:
1. input_len=0 (asserted).
2. The current random coin state has just absorbed the public inputs.
3. On exit: input_len=0, output_len=6.

Input: [...]
Output: [...]
| +| reseed_with_felt | Reseed with a commitment word and absorb an additional single felt, then permute.

Writes the commitment word to rate[0..3] and the felt to rate[4], leaving rate[5..7]
unchanged from the previous permutation, then permutes. Used in the FRI layer loop
where each round absorbs a layer commitment plus a PoW nonce felt.

SAFETY:
1. input_len=0 (asserted).
2. On exit: input_len=0, output_len=8 (fresh permutation output).

Input: [felt, w0, w1, w2, w3, ...]
Output: [...]
| +| reseed_direct | Reseed by writing a word directly to rate[0..3] and permuting.

Overwrites rate[0..3] with the given word, leaves rate[4..7] unchanged from the
previous permutation, then permutes. This is the standard overwrite-and-permute
absorption pattern for a single word.

SAFETY:
1. input_len=0 (asserted).
2. The word to absorb is on top of the stack.
3. On exit: input_len=0, output_len=8 (fresh permutation output).

Input: [w0, w1, w2, w3, ...]
Output: [...]
| +| sample_folding_pow_and_ext | Verify per-round FRI folding proof-of-work and sample one extension field element,
reading rate elements directly instead of going through `sample_felt`.

Reads rate[7] (grinding), rate[6] and rate[5] (ext element) from r2_ptr memory,
matching what `sample_felt` would return at output_len=8,7,6.

The folding PoW bit count is read from memory (set by load_security_params).
When folding_pow_bits=0 the check is trivially satisfied (mask=0).

Equivalent to: `get_folding_pow_bits sample_bits assertz; sample_ext`

SAFETY:
1. MUST be called immediately after `reseed_with_felt` with no intervening
random coin operations (output_len=8, input_len=0 guaranteed).
2. Sets output_len=5 on exit (3 elements consumed), input_len=0 unchanged.
3. folding_pow_bits must already be stored in memory.

Input: [...]
Output: [a0, a1, ...]
| +| generate_aux_randomness | Draw a list of random extension field elements related to the auxiliary segment of the execution
trace and store them.

More specifically, we draw two challenges, alpha and beta. This means that our multi-set hash function
has the form `h(m) = alpha + \sum_{i=0}^{\|m\| - 1} m_i * beta^i` for a message `m`.

As these random challenges have already been used non-deterministically in prior computations, we
also check that the generated challenges match the non-deterministically provided one.

Input: [...]
Output: [...]
Cycles: 20
| +| generate_constraint_composition_coefficients | Draw constraint composition random coefficient and save it at `compos_coef_ptr`.

Input: [...]
Output: [...]
Cycles: 13
| | generate_deep_composition_random_coefficients | Draw deep composition polynomial random coefficient and save it at `deep_rand_coef_ptr`.

As this random challenge has already been used non-deterministically in prior computations, we
also check that the generated challenge matches the non-deterministically provided one.

Input: [...]
Output: [...]
Cycles: 22
| -| generate_z_zN | Generate the OOD challenge point `z = (z0, z1)` and compute `z^N` where N is
the trace length. The resulting word `[(z_1, z_0)^N, z1, z0]` is stored in the
global memory address `exec.z_ptr` reserved for it.

Input: [X, ...]
Output: [...]
Note: The top word on the stack is consumed by this procedure.
Cycles: 21 + 10 * log(N)
| -| generate_list_indices | Generate a list of `num_queries` number of random indices in the range
[0, lde_size] and store it in memory starting from `query_ptr`.
The list is stored as `(r, depth, y, y)` where `depth` is `log(lde_domain_size)`.
`depth` is needed when computing the deep queries.

Input: [query_ptr, num_queries, ...]
Output: [...]

Cycles: 267 + q * 236 + r * 29 where q = num_queries / 8 and r = num_queries % 8

NOTE: This procedure is called first, and right after the PoW check, thus the first element
in the rate portion of the state is discarded.
NOTE: The cycles count can be estimated, using the fact that r < 8, via the more compact formula
470 + 236 * (num_queries / 8)
| -| check_pow | Check that the Proof-of-Work contained in the nonce is equal to the required number
of bits prescribed by grinding bits. The grinding factor is assumed to be less than 32.

Input: [...]
Output: [...]
Cycles: 73
| +| generate_z_zN | Generate the OOD challenge point `z = (z0, z1)` and compute `z^N` where N is
the trace length. The resulting word `[(z_0, z_1)^N, z0, z1]` is stored in the
global memory address `exec.z_ptr` reserved for it.

Input: [X, ...]
Output: [...]
Note: The top word on the stack is consumed by this procedure.
Cycles: 21 + 10 * log(N)
| +| generate_list_indices | Generate a list of `num_queries` number of random indices in the range
[0, lde_size) and store it in memory starting from `query_ptr`.
The list is stored as `(index, depth, index, 0)` where `index` is the sampled domain-order
index and `depth` is `log(lde_domain_size)`, which is needed when computing the DEEP queries.

Reads rate elements directly from memory (decrementing from output_len-1 down to 0),
permuting when the rate is exhausted, rather than calling sample_felt per query.

Input: [...]
Output: [...]

NOTE: This procedure is called right after the PoW check. The PoW check consumes one
rate element via sample_bits, leaving output_len = 7.
| +| check_deep_pow | Check the DEEP proof-of-work.

Called before sampling DEEP composition polynomial challenges.

SAFETY: Requires input_len=0.

Input: [...]
Output: [...]
| +| check_query_pow | Check the query proof-of-work.

Called after loading the FRI remainder, before sampling query indices.

SAFETY: Requires input_len=0 (guaranteed after load_and_verify_remainder).

Input: [...]
Output: [...]
| diff --git a/crates/lib/core/docs/stark/utils.md b/crates/lib/core/docs/stark/utils.md index 5591276fef..9d560d7d37 100644 --- a/crates/lib/core/docs/stark/utils.md +++ b/crates/lib/core/docs/stark/utils.md @@ -3,6 +3,9 @@ | Procedure | Description | | ----------- | ------------- | | compute_lde_generator | Compute the LDE domain generator from the log2 of its size.

Input: [log2(domain_size), ..]
Output: [domain_gen, ..]
Cycles: 63
| -| validate_inputs | Validates the inputs to the recursive verifier.

Input: [log(trace_length), num_queries, grinding, ...]
Output: [log(trace_length), num_queries, grinding, ...]

Cycles: 45
| -| set_up_auxiliary_inputs_ace | Sets up auxiliary inputs to the arithmetic circuit for the constraint evaluation check.

These inputs are:

1) OOD evaluation point z,
2) random challenge used in computing the DEEP composition polynomial,
3) z^N where N is the execution trace length
4) z^k where k = min_num_cycles = trace_len / max_cycle_len and max_cycle_len is the longest cycle
among all the cycles of periodic columns.
5) g^{-1} where g is the trace domain generator.

The only input to this procedure is the log2 of the max cycle length across all periodic columns.

Input: [max_cycle_len_log, ...]
Output: [...]
| -| store_dynamically_executed_procedures | Stores digests of dynamically executed procedures.

Input: [D3, D2, D1, D0, ...]
Output: [...]
| +| validate_inputs | Validates the inputs to the recursive verifier.

Checks log(trace_length) from the stack and security parameters from memory.
The security parameters must already be stored in memory before calling this
procedure (done by the specific verifier's load_security_params).

Input: [log(trace_length), ...]
Output: [log(trace_length), ...]
| +| bit_reverse_len_parallel | Reverse the lowest `bits` bits of `index` using parallel bit-swap.
`pow2_shift` must equal 2^(32 - bits); the caller pre-computes it once.

The algorithm has two parts:

1) Left-shift: multiply index by pow2_shift = 2^(32-bits) to place the `bits`
meaningful bits into the top of a 32-bit word. Since index < 2^bits, the
product is always < 2^32 so u32wrapping_mul is exact.

2) Full 32-bit reversal via 5 parallel swap steps. Each step k (for k=1,2,4,8,16)
swaps every adjacent group of k bits. A mask isolates the even-positioned
groups; the odd-positioned groups are the complement. Shifting each half by
k positions and combining swaps all groups simultaneously. After all 5 steps,
bit position i has moved to position 31-i, which (because of the initial
left-shift) is exactly position (bits-1-i) of the original -- i.e., the
reversed index. No final shift is needed.

The two halves never overlap, so XOR = OR = ADD; we use XOR (1 cycle vs 3 for
u32wrapping_add).

Input: [index, pow2_shift, ...]
Output: [rev_index, ...]
Cycles: 78
| +| set_up_auxiliary_inputs_ace | Sets up the stark-vars region of the ACE circuit input layout.

The stark-vars block is 10 EF slots (5 words) laid out as:

Word 0 (slots 0-1): alpha, z^N (EF: composition challenge, trace-length power)
Word 1 (slots 2-3): z_k, is_first (EF: periodic eval point, first-row selector)
Word 2 (slots 4-5): is_last, is_transition (EF: last-row selector, transition selector)
Word 3 (slots 6-7): gamma, weight0 (EF: batching challenge; base as EF: barycentric weight)
Word 4 (slots 8-9): f, s0 (base as EF: chunk shift ratio h^N, first shift)

Input: [max_cycle_len_log, ...]
Output: [...]
| +| execute_constraint_evaluation_check | Executes the constraints evaluation check.

Inputs: [...]
Outputs: [...]

Invocation: exec
| +| observe_aux_trace | Observes the auxiliary trace: draws aux randomness, reseeds with the aux trace commitment,
and absorbs aux trace boundary values into the transcript.

For AIRs without an auxiliary trace, the implementation should be a no-op.

Inputs: [...]
Outputs: [...]

Invocation: exec
| +| store_dynamically_executed_procedures | Stores digests of dynamically executed procedures.

Input: [D0, D1, D2, D3, D4, ...]
Output: [...]
| diff --git a/crates/lib/core/docs/stark/verifier.md b/crates/lib/core/docs/stark/verifier.md index fec43febf8..7fabf2229a 100644 --- a/crates/lib/core/docs/stark/verifier.md +++ b/crates/lib/core/docs/stark/verifier.md @@ -2,4 +2,4 @@ ## miden::core::stark::verifier | Procedure | Description | | ----------- | ------------- | -| verify | Verifies a STARK proof.

The purpose of the following verifier is to serve as a generic core around which a specific
verifier can be built. It expects the following parameters on the stack from the caller:

1. `[D0, D1, D2, D3]` which are respectively the digests for dynamic execution of procedures
i. `compute_deep_composition_polynomial_queries`
ii. `execute_constraint_evaluation_check`
iii. `process_row_ood_evaluations`
iv. `process_public_inputs`
2. `num_constraints` which is the number of constraints in the AIR
3. `trace_info` which is a field element encoding the layout of the AIR
4. `num_fixed_len_pi` is the number of fixed length public inputs of the AIR
5. `is_aux_trace` flag indicating the existence of an auxiliary segment in this AIR

In addition to the above parameters, the verifier expects the following auxiliary proof parameters:

1. `log(trace_length)`, the logarithm base 2 of the trace length
2. `num_queries`, the number of FRI queries
3. `grinding`, the number of bits of grinding i.e., proof-of-work

The following simplifying assumptions are currently made and hardcoded:

- The blowup factor is set to 8.
- The maximal allowed degree of the remainder polynomial is 127.
- To boost soundness, the protocol is run on a quadratic extension field and this means that
the OOD evaluation frame is composed of elements in a quadratic extension field i.e. tuples.
Similarly, elements of the auxiliary trace are quadratic extension field elements. The random
values for computing random linear combinations are also in this extension field.

Inputs: [D3, D2, D1, D0, log(trace_length), num_queries, grinding, num_constraints, trace_info, num_fixed_len_pi, is_aux_trace]
Outputs: []
| +| verify | Verifies a STARK proof.

The purpose of the following verifier is to serve as a generic core around which a specific
verifier can be built. It expects the following parameters on the stack from the caller:

1. `[D0, D1, D2, D3, D4]` which are the digests for dynamic execution of:
D0. `observe_aux_trace`
D1. `process_public_inputs`
D2. `process_row_ood_evaluations`
D3. `execute_constraint_evaluation_check`
D4. `compute_deep_composition_polynomial_queries`
2. Per-proof parameter: `log(trace_length)`
3. `[rd0, rd1, rd2, rd3]`: RELATION_DIGEST = hash(PROTOCOL_ID, CIRCUIT_COMMITMENT),
a compile-time constant that binds the Fiat-Shamir transcript to the AIR instance.

Precondition: security parameters (num_queries, query_pow_bits, deep_pow_bits,
folding_pow_bits) must already be stored in memory before calling this procedure.

The following simplifying assumptions are currently made and hardcoded:

- The blowup factor is set to 8.
- The maximal allowed degree of the remainder polynomial is 127.
- To boost soundness, the protocol is run on a quadratic extension field and this means that
the OOD evaluation frame is composed of elements in a quadratic extension field i.e. tuples.
Similarly, elements of the auxiliary trace are quadratic extension field elements. The random
values for computing random linear combinations are also in this extension field.

Inputs: [D0, D1, D2, D3, D4, log(trace_length), rd0, rd1, rd2, rd3]
Outputs: []
| diff --git a/crates/lib/core/docs/sys/mod.md b/crates/lib/core/docs/sys/mod.md index 3381ab2a20..36f8a803bb 100644 --- a/crates/lib/core/docs/sys/mod.md +++ b/crates/lib/core/docs/sys/mod.md @@ -4,4 +4,4 @@ | ----------- | ------------- | | truncate_stack | Removes elements deep in the stack until the depth of the stack is exactly 16. The elements
are removed in such a way that the top 16 elements of the stack remain unchanged. If the stack
would otherwise contain more than 16 elements at the end of execution, then adding a call to this
function at the end will reduce the size of the public inputs that are shared with the verifier.

Input: Stack with 16 or more elements.
Output: Stack with only the original top 16 elements.

Cycles: 17 + 11 * overflow_words, where `overflow_words` is the number of words needed to drop.
| | drop_stack_top | Drop 16 values from the stack.
| -| log_precompile_request | Logs a precompile commitment and removes the helper words produced by `log_precompile`.

Input: `[COMM, TAG, ...]`
Output: Stack without the three helper words `[R1, R0, CAP_NEXT]`.
Cycles: 1 (plus cost of the underlying `log_precompile` instruction).
| +| log_precompile_request | Logs a precompile commitment and removes the helper words produced by `log_precompile`.

Input: `[COMM, TAG, ...]`
Output: Stack without the three helper words `[R0, R1, CAP_NEXT]`.
Cycles: 1 (plus cost of the underlying `log_precompile` instruction).
| diff --git a/crates/lib/core/docs/sys/vm/aux_trace.md b/crates/lib/core/docs/sys/vm/aux_trace.md new file mode 100644 index 0000000000..88ac6da04f --- /dev/null +++ b/crates/lib/core/docs/sys/vm/aux_trace.md @@ -0,0 +1,5 @@ + +## miden::core::sys::vm::aux_trace +| Procedure | Description | +| ----------- | ------------- | +| observe_aux_trace | Observes the auxiliary trace for the Miden VM AIR.

Draws auxiliary randomness, reseeds the transcript with the auxiliary trace commitment,
and absorbs the boundary values (2 extension field elements = 4 base field elements = 1 word).
TODO(#3032): the second value is always zero (placeholder for trace splitting).

The advice provider must supply exactly 2 words in order:
[commitment, W0]

The commitment is stored at aux_trace_com_ptr and the boundary values at
aux_bus_boundary_ptr.

Precondition: input_len=0 (guaranteed by the preceding reseed_direct in the generic verifier).
Postcondition: input_len=0, output_len=8.

Input: [...]
Output: [...]
| diff --git a/crates/lib/core/docs/sys/vm/constraints_eval.md b/crates/lib/core/docs/sys/vm/constraints_eval.md index 47dc2005e6..d8cde2cb04 100644 --- a/crates/lib/core/docs/sys/vm/constraints_eval.md +++ b/crates/lib/core/docs/sys/vm/constraints_eval.md @@ -2,4 +2,4 @@ ## miden::core::sys::vm::constraints_eval | Procedure | Description | | ----------- | ------------- | -| execute_constraint_evaluation_check | Executes the constraints evaluation check by evaluating an arithmetic circuit using the ACE
chiplet.

The circuit description is hardcoded into the verifier using its commitment, which is computed as
the sequential hash of its description using Poseidon2 hasher. The circuit description, containing both
constants and evaluation gates description, is stored at the contiguous memory region starting
at `ACE_CIRCUIT_PTR`. The variable part of the circuit input is stored at the contiguous memory
region starting at `pi_ptr`. The (variable) inputs to the circuit are laid out such that the
aforementioned memory regions are together contiguous with the (variable) inputs section.

Inputs: []
Outputs: []
| +| execute_constraint_evaluation_check | Executes the constraints evaluation check by evaluating an arithmetic circuit using the ACE
chiplet.

The circuit description is hardcoded into the verifier using its commitment, which is computed as
the sequential hash of its description using Poseidon2 hasher. The circuit description,
containing both constants and evaluation gates description, is stored starting at
`ACE_CIRCUIT_STREAM_PTR` (right after the circuit inputs). The evaluation gates portion begins at
`ACE_CIRCUIT_PTR`. The variable part of the circuit input is stored at the contiguous memory
region starting at `pi_ptr`. The (variable) inputs to the circuit are laid out such that the
aforementioned memory regions are together contiguous with the (variable) inputs section.

Inputs: []
Outputs: []
| diff --git a/crates/lib/core/docs/sys/vm/mod.md b/crates/lib/core/docs/sys/vm/mod.md index c853bd2c91..315e97137a 100644 --- a/crates/lib/core/docs/sys/vm/mod.md +++ b/crates/lib/core/docs/sys/vm/mod.md @@ -2,4 +2,4 @@ ## miden::core::sys::vm::mod | Procedure | Description | | ----------- | ------------- | -| verify_proof | Verifies a STARK proof attesting to the correct execution of a program in the Miden VM.

- The public inputs are composed of the input and output stacks, of fixed size equal to 16, as
well as the program and the kernel procedures digests.
- There are two trace segments, main and auxiliary. It is assumed that the main trace segment
is 73 columns wide while the auxiliary trace segment is 8 columns wide. Note that we pad the main
trace to the next multiple of 8.
- The OOD evaluation frame is composed of two concatenated rows, current and next, each composed
of 73 elements representing the main trace portion and 8 elements for the auxiliary trace one.
Note that, due to the padding of the main trace columns, the number of OOD evaluations per row
is 80 for the main trace.

Inputs: [log(trace_length), num_queries, grinding]
Outputs: []

Cycles:
1- Remainder polynomial size 64:
2515 + num_queries * (512 + num_fri_layers * 83) + 108 * num_fri_layers + 10 * log(trace_length)
2- Remainder polynomial size 128:
2540 + num_queries * (541 + num_fri_layers * 83) + 108 * num_fri_layers + 10 * log(trace_length)

where num_fri_layers is computed as:

1- If log(trace_length) is even, then num_fri_layers = (log(trace_length) - 6) / 2, where 6 = log2(64),
2- If log(trace_length) is odd, then num_fri_layers = (log(trace_length) - 7) / 2, where 7 = log2(128).
| +| verify_proof | Verifies a STARK proof attesting to the correct execution of a program in the Miden VM.

Security parameters (num_queries, query_pow_bits, deep_pow_bits, folding_pow_bits) are
loaded from the advice stack, validated against the acceptable security policy, and
stored in memory for use by the generic verifier.

- The public inputs are composed of the input and output stacks, of fixed size equal to 16, as
well as the program and the kernel procedures digests.
- There are two trace segments, main and auxiliary. It is assumed that the main trace segment
is 73 columns wide while the auxiliary trace segment is 8 columns wide. Note that we pad the main
trace to the next multiple of 8.
- The OOD evaluation frame is composed of two concatenated rows, current and next, each composed
of 73 elements representing the main trace portion and 8 elements for the auxiliary trace one.
Note that, due to the padding of the main trace columns, the number of OOD evaluations per row
is 80 for the main trace.

Inputs: [log(trace_length)]
Outputs: []
| diff --git a/crates/lib/core/docs/sys/vm/ood_frames.md b/crates/lib/core/docs/sys/vm/ood_frames.md index debcc3a243..502ae08971 100644 --- a/crates/lib/core/docs/sys/vm/ood_frames.md +++ b/crates/lib/core/docs/sys/vm/ood_frames.md @@ -2,4 +2,4 @@ ## miden::core::sys::vm::ood_frames | Procedure | Description | | ----------- | ------------- | -| process_row_ood_evaluations | Processes the out-of-domain (OOD) evaluations of all committed polynomials.

Takes as input an Poseidon2 hasher state and a pointer, and loads from the advice provider the OOD
evaluations and stores at memory region using pointer `ptr` while absorbing the evaluations
into the hasher state and simultaneously computing a random linear combination using Horner
evaluation.


Inputs: [R2, R1, C, ptr, acc1, acc0]
Outputs: [R2, R1, C, ptr, acc1`, acc0`]

Cycles: 72
| +| process_row_ood_evaluations | Processes the out-of-domain (OOD) evaluations of all committed polynomials.

Takes as input an Poseidon2 hasher state and a pointer, and loads from the advice provider the OOD
evaluations and stores at memory region using pointer `ptr` while absorbing the evaluations
into the hasher state and simultaneously computing a random linear combination using Horner
evaluation.


Inputs: [R0, R1, C, ptr, acc0, acc1]
Outputs: [R0, R1, C, ptr, acc0`, acc1`]

Cycles: 78
| diff --git a/crates/lib/core/docs/sys/vm/public_inputs.md b/crates/lib/core/docs/sys/vm/public_inputs.md index 92560d3323..d5feaaad8e 100644 --- a/crates/lib/core/docs/sys/vm/public_inputs.md +++ b/crates/lib/core/docs/sys/vm/public_inputs.md @@ -2,4 +2,4 @@ ## miden::core::sys::vm::public_inputs | Procedure | Description | | ----------- | ------------- | -| process_public_inputs | Processes the public inputs.

This involves:

1. Loading from the advice stack the fixed-length public inputs and storing them in memory
starting from the address pointed to by `public_inputs_address_ptr`.
2. Loading from the advice stack the variable-length public inputs, storing them temporarily
in memory, and then reducing them to an element in the challenge field using the auxiliary
randomness. This reduced value is then used to impose a boundary condition on the relevant
auxiliary column.

Note that the fixed length public inputs are stored as extension field elements while
the variable length ones are stored as base field elements.

Note also that, while loading the above, we compute the hash of the public inputs. The hashing
starts with capacity registers of the hash function set to `C` that is the result of hashing
the proof context.

The output D, that is the digest of the above hashing, is then used in order to reseed
the random coin.

It is worth noting that:

1. Only the fixed-length public inputs are stored for the lifetime of the verification procedure.
The variable-length public inputs are stored temporarily, as this simplifies the task of
reducing them using the auxiliary randomness. On the other hand, the resulting values from
the aforementioned reductions are stored right after the fixed-length public inputs. These
are stored in a word-aligned manner and padded with zeros if needed.
2. The public inputs address is computed in such a way so as we end up with the following
memory layout:

[..., a_0...a_{m-1}, b_0...b_{n-1}, alpha0, alpha1, beta0, beta1, OOD-evaluations-start, ...]

where:

1. [a_0...a_{m-1}] are the fixed-length public inputs stored as extension field elements. This
section is double-word-aligned.
2. [b_0...b_{n-1}] are the results of reducing the variable length public inputs using
auxiliary randomness. This section is word-aligned.
3. [alpha0, alpha1, beta0, beta1] is the auxiliary randomness.
4. `OOD-evaluations-start` is the first field element of the section containing the OOD
evaluations.
3. Note that for each bus message in a group in the variable length public inputs, each
message is expected to be padded to the next multiple of 8 and provided in reverse order.
This has the benefit of making the reduction using the auxiliary randomness more efficient
using `horner_eval_base`.


Input: [C, ...]
Output: [...]
| +| process_public_inputs | Processes the public inputs.

This involves:

1. Loading from the advice stack the fixed-length public inputs and storing them in memory
starting from the address pointed to by `public_inputs_address_ptr`.
2. Loading kernel procedure digests from the advice stack, reducing them, and storing the
reduced result at `variable_length_public_inputs_address_ptr` (in the ACE READ section).
3. Loading the auxiliary randomness from the advice stack so it can be checked later.

Note that the fixed length public inputs are stored as extension field elements.
The kernel digests are temporarily stored in memory starting at
`variable_length_public_inputs_address_ptr` during reduction. The final reduced value
overwrites the start of this region and remains in the ACE READ section.

POSTCONDITION: random coin input_len=0 on return.

The generic verifier (stark/verifier.masm) calls reseed_direct immediately after this
procedure, which requires input_len=0. This postcondition holds because:
- FLPI (40 base felts) are absorbed in groups of 8 via direct sponge permutation
(5 iterations * 8 = 40), bypassing the buffer entirely.
- VLPI (kernel digests, each padded to 8 felts) are absorbed via adv_pipe + permute,
also bypassing the buffer.
- Both paths reset the buffer counters (input_len=0, output_len=8) after completion.

If FLPI size changes from a multiple of 8, or VLPI digest padding changes from 8,
this postcondition must be re-verified.

Input:
- Operand stack: [...]
- Advice stack: [fixed_len_PI..., num_kernel_proc_digests,
kernel_digest_elements..., beta0, beta1, alpha0, alpha1, ...]
Output: [...]
| diff --git a/crates/lib/core/docs/word.md b/crates/lib/core/docs/word.md index 60d983fea6..e85e80dc63 100644 --- a/crates/lib/core/docs/word.md +++ b/crates/lib/core/docs/word.md @@ -3,12 +3,12 @@ | Procedure | Description | | ----------- | ------------- | | reverse | Reverses order of the first four elements on the stack

Note: This functionality is also available as the `reversew` instruction

Inputs: [a, b, c, d, ...]
Outputs: [d, c, b, a, ...]

Cycles: 3
| -| store_word_u32s_le | Writes the components of a word to memory as eight u32 limbs in little-endian order.

Inputs: [w0, w1, w2, w3, out_ptr, ...]
Outputs: [...]

Where:
- `w*` are the felts of the input word. Each felt is split into a low and high 32-bit limb.
- `out_ptr` is an element address in memory.
- Memory layout after the call: `[w0_lo, w0_hi, w1_lo, w1_hi, w2_lo, w2_hi, w3_lo, w3_hi]`.

Cycles: 8 * (split + store pair) ~= 176
| +| store_word_u32s_le | Writes the components of a word to memory as eight u32 limbs in little-endian order.

Inputs: [w0, w1, w2, w3, out_ptr, ...]
Outputs: [...]

Where:
- `w*` are the felts of the input word. Each felt is split into a low and high 32-bit limb.
- `out_ptr` is an element address in memory.
- Memory layout after the call: `[w0_lo, w0_hi, w1_lo, w1_hi, w2_lo, w2_hi, w3_lo, w3_hi]`.

Cycles: 22
| | eqz | Returns a boolean indicating whether the input word is [0, 0, 0, 0].

Inputs: [INPUT_WORD]
Outputs: [is_empty_word]

Where:
- INPUT_WORD is the word to compare against [0, 0, 0, 0].
- is_empty_word is a boolean indicating whether INPUT_WORD is all zeros.

Cycles: 10
| | testz | Returns a boolean indicating whether the input word is [0, 0, 0, 0]. Unlike eqz, this does not
consume the inputs.

Inputs: [INPUT_WORD]
Outputs: [is_empty_word, INPUT_WORD]

Where:
- INPUT_WORD is the word to compare against [0, 0, 0, 0].
- is_empty_word is a boolean indicating whether INPUT_WORD is all zeros.

Cycles: 11
| -| gt | Returns true if LHS is strictly greater than RHS, false otherwise.

This compares words using the same ordering as Merkle tree key comparisons.

The implementation avoids branching for performance reasons.

For reference, this is equivalent to the following Rust function:

fn is_word_greater(word1: Word, word2: Word) -> bool {
let mut result = false;
let mut cont = true;

for i in (0..4).rev() {
let gt = word1[i].as_canonical_u64() > word2[i].as_canonical_u64();
let eq = word1[i].as_canonical_u64() == word2[i].as_canonical_u64();
result \|= gt & cont;
cont &= eq;
}

result
}

Inputs: [RHS, LHS]
Outputs: [is_lhs_greater]

Cycles: 117
| -| gte | Returns true if LHS is greater than or equal to RHS.

Inputs: [RHS, LHS]
Outputs: [is_lhs_greater_or_equal]

Cycles: 118
| -| lt | Returns true if LHS is strictly less than RHS, false otherwise.

The implementation avoids branching for performance reasons.

From an implementation standpoint this is exactly the same as `word::gt` except it uses
`lt` rather than `gt`. See its docs for details.

Inputs: [RHS, LHS]
Outputs: [is_lhs_lesser]

Cycles: 117
| -| lte | Returns true if LHS is less than or equal to RHS, false otherwise.

Inputs: [RHS, LHS]
Outputs: [is_lhs_less_or_equal]

Cycles: 118
| +| gt | Returns true if LHS is strictly greater than RHS, false otherwise.

This compares words using the same ordering as Merkle tree key comparisons.

The implementation avoids branching for performance reasons.

For reference, this is equivalent to the following Rust function:

fn is_word_greater(word1: Word, word2: Word) -> bool {
let mut result = false;
let mut cont = true;

for i in (0..4).rev() {
let gt = word1[i].as_canonical_u64() > word2[i].as_canonical_u64();
let eq = word1[i].as_canonical_u64() == word2[i].as_canonical_u64();
result \|= gt & cont;
cont &= eq;
}

result
}

Inputs: [RHS, LHS]
Outputs: [is_lhs_greater]

Cycles: 133
| +| gte | Returns true if LHS is greater than or equal to RHS.

Inputs: [RHS, LHS]
Outputs: [is_lhs_greater_or_equal]

Cycles: 130
| +| lt | Returns true if LHS is strictly less than RHS, false otherwise.

The implementation avoids branching for performance reasons.

From an implementation standpoint this is exactly the same as `word::gt` except it uses
`lt` rather than `gt`. See its docs for details.

Inputs: [RHS, LHS]
Outputs: [is_lhs_lesser]

Cycles: 129
| +| lte | Returns true if LHS is less than or equal to RHS, false otherwise.

Inputs: [RHS, LHS]
Outputs: [is_lhs_less_or_equal]

Cycles: 134
| | eq | Returns true if LHS is exactly equal to RHS, false otherwise.

The implementation does not branch, and always performs the same number of comparisons.

This is currently equivalent to the eqw instruction.

Inputs: [RHS, LHS]
Outputs: [lhs_eq_rhs]

Cycles: 13
| | test_eq | Returns true if LHS is exactly equal to RHS, false otherwise. Preserves stack inputs.

Like word::eq, the implementation does not branch, and always performs the same number
of comparisons.

Inputs: [RHS, LHS]
Outputs: [lhs_eq_rhs, RHS, LHS]

Cycles: 15
| diff --git a/crates/lib/core/src/bin/regenerate-constraints.rs b/crates/lib/core/src/bin/regenerate-constraints.rs new file mode 100644 index 0000000000..ba20d2cfa1 --- /dev/null +++ b/crates/lib/core/src/bin/regenerate-constraints.rs @@ -0,0 +1,52 @@ +use std::process::ExitCode; + +use miden_core_lib::constraints_regen::{self, Mode}; + +fn usage() { + println!("Usage:"); + println!(" regenerate-constraints [--check|--write]"); + println!(); + println!("Options:"); + println!(" --check Verify checked-in constraint artifacts (default)"); + println!(" --write Rebuild and write constraint artifacts"); + println!(" -h, --help Show this message"); +} + +fn parse_mode() -> Result { + let mut mode = Mode::Check; + + for arg in std::env::args().skip(1) { + match arg.as_str() { + "--check" => mode = Mode::Check, + "--write" => mode = Mode::Write, + "-h" | "--help" => { + usage(); + return Err(ExitCode::SUCCESS); + }, + other => { + eprintln!("Unknown argument: {other}"); + usage(); + return Err(ExitCode::FAILURE); + }, + } + } + + Ok(mode) +} + +fn main() -> ExitCode { + let mode = match parse_mode() { + Ok(mode) => mode, + Err(code) => return code, + }; + + if let Err(error) = constraints_regen::run(mode) { + eprintln!("failed: {error}"); + if mode == Mode::Check { + eprintln!("hint: rerun with `--write` to refresh checked-in artifacts"); + } + return ExitCode::FAILURE; + } + + ExitCode::SUCCESS +} diff --git a/crates/lib/core/src/constraints_regen.rs b/crates/lib/core/src/constraints_regen.rs new file mode 100644 index 0000000000..448ffec03a --- /dev/null +++ b/crates/lib/core/src/constraints_regen.rs @@ -0,0 +1,330 @@ +use alloc::{ + format, + string::{String, ToString}, + vec::Vec, +}; +use std::{fs, io, println}; + +use miden_ace_codegen::{AceCircuit, AceConfig, LayoutKind}; +use miden_air::ProcessorAir; +use miden_core::{Felt, crypto::hash::Poseidon2, field::QuadFelt}; + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum Mode { + Check, + Write, +} + +const MASM_CONFIG: AceConfig = AceConfig { + num_quotient_chunks: 8, + num_vlpi_groups: 1, + layout: LayoutKind::Masm, +}; +pub const RELATION_DIGEST_PATHS: (&str, &str) = + ("asm/sys/vm/mod.masm", "asm/sys/vm/constraints_eval.masm"); + +const PROTOCOL_ID: u64 = 0; +const AIR_CONFIG_PATH: &str = "../../../air/src/config.rs"; +const CONSTRAINTS_EVAL_PATH: &str = "asm/sys/vm/constraints_eval.masm"; +const RELATION_DIGEST_PATH: &str = RELATION_DIGEST_PATHS.0; + +/// Builds the batched ACE circuit used by the Miden VM recursive verifier. +pub fn build_batched_circuit(config: AceConfig) -> AceCircuit { + let air = ProcessorAir; + let batch_config = miden_air::ace::logup_boundary_config(); + miden_air::ace::build_batched_ace_circuit::<_, QuadFelt>(&air, config, &batch_config).unwrap() +} + +/// Computes the relation digest used by recursive verification. +pub fn compute_relation_digest(circuit_commitment: &[Felt; 4]) -> [Felt; 4] { + let input: Vec = core::iter::once(Felt::new_unchecked(PROTOCOL_ID)) + .chain(circuit_commitment.iter().copied()) + .collect(); + let digest = Poseidon2::hash_elements(&input); + let elems = digest.as_elements(); + [elems[0], elems[1], elems[2], elems[3]] +} + +/// Runs write (`--write`) or staleness-check (`--check`) mode. +pub fn run(mode: Mode) -> Result<(), String> { + match mode { + Mode::Check => check(), + Mode::Write => write().map_err(|e| format!("{e}")), + } +} + +/// Runs the full regeneration flow. +fn write() -> io::Result<()> { + let artifact = compute_artifacts()?; + write_artifacts(&artifact) +} + +/// Checks generated artifacts against current AIR-derived values. +fn check() -> Result<(), String> { + constraints_eval_masm_matches_air()?; + relation_digest_matches_air()?; + Ok(()) +} + +/// Generate a full computed snapshot from the current AIR. +fn compute_artifacts() -> io::Result { + let circuit = build_batched_circuit(MASM_CONFIG); + let encoded = circuit.to_ace().unwrap(); + + let num_inputs = encoded.num_vars(); + let num_eval_gates = encoded.num_eval_rows(); + let instructions = encoded.instructions(); + let size_in_felt = encoded.size_in_felt(); + if !size_in_felt.is_multiple_of(8) { + return Err(io::Error::new( + io::ErrorKind::InvalidData, + format!( + "circuit size_in_felt ({size_in_felt}) is not 8-aligned; adv_pipe requires 8-element chunks" + ), + )); + } + let adv_pipe_rows = size_in_felt / 8; + + let circuit_commitment: [Felt; 4] = encoded.circuit_hash().into(); + let relation_digest = compute_relation_digest(&circuit_commitment); + + let mut constraints_eval = read_file(CONSTRAINTS_EVAL_PATH); + { + replace_masm_const(&mut constraints_eval, "NUM_INPUTS_CIRCUIT", &num_inputs.to_string()); + replace_masm_const( + &mut constraints_eval, + "NUM_EVAL_GATES_CIRCUIT", + &num_eval_gates.to_string(), + ); + + let proc_start = + constraints_eval.find("proc load_ace_circuit_description").ok_or_else(|| { + io::Error::new( + io::ErrorKind::NotFound, + "proc load_ace_circuit_description not found", + ) + })?; + if let Some(repeat_offset) = constraints_eval[proc_start..].find("repeat.") { + let abs = proc_start + repeat_offset; + let end = constraints_eval[abs..] + .find('\n') + .map(|i| abs + i) + .unwrap_or(constraints_eval.len()); + constraints_eval.replace_range(abs..end, &format!("repeat.{adv_pipe_rows}")); + } + + let section_marker = "# CONSTRAINT EVALUATION CIRCUIT DESCRIPTION"; + let section_start = constraints_eval.find(section_marker).ok_or_else(|| { + io::Error::new(io::ErrorKind::NotFound, "constraints section marker not found") + })?; + constraints_eval.truncate(section_start); + let trimmed = constraints_eval.trim_end().len(); + constraints_eval.truncate(trimmed); + constraints_eval.push_str("\n\n# CONSTRAINT EVALUATION CIRCUIT DESCRIPTION\n"); + constraints_eval + .push_str("# =================================================================================================\n\n"); + constraints_eval.push_str("adv_map CIRCUIT_COMMITMENT = [\n"); + + for (i, chunk) in instructions.chunks(8).enumerate() { + let vals: Vec = + chunk.iter().map(|f| f.as_canonical_u64().to_string()).collect(); + let line = vals.join(","); + if i < adv_pipe_rows - 1 { + constraints_eval.push_str(&format!(" {line},\n")); + } else { + constraints_eval.push_str(&format!(" {line}\n")); + } + } + constraints_eval.push_str("]\n"); + } + + let mut relation_mod = read_file(RELATION_DIGEST_PATH); + for (i, elem) in relation_digest.iter().enumerate() { + replace_masm_const( + &mut relation_mod, + &format!("RELATION_DIGEST_{i}"), + &elem.as_canonical_u64().to_string(), + ); + } + + let mut air_config = read_file(AIR_CONFIG_PATH); + let marker = "pub const RELATION_DIGEST: [Felt; 4] = ["; + let start = air_config.find(marker).ok_or_else(|| { + io::Error::new(io::ErrorKind::NotFound, "RELATION_DIGEST not found in config.rs") + })?; + let block_start = start + marker.len(); + let block_end = + air_config[block_start..] + .find("];") + .map(|idx| idx + block_start) + .ok_or_else(|| { + io::Error::new(io::ErrorKind::NotFound, "RELATION_DIGEST terminator not found") + })?; + let mut new_block: String = relation_digest + .iter() + .map(|f| format!("\n Felt::new_unchecked({}),", f.as_canonical_u64())) + .collect(); + new_block.push('\n'); + air_config.replace_range(block_start..block_end, &new_block); + + Ok(ComputedArtifacts { + num_inputs, + num_eval_gates, + adv_pipe_rows, + circuit_commitment, + relation_digest, + constraints_eval, + relation_mod, + air_config, + }) +} + +fn write_artifacts(artifact: &ComputedArtifacts) -> io::Result<()> { + write_file(CONSTRAINTS_EVAL_PATH, &artifact.constraints_eval)?; + write_file(RELATION_DIGEST_PATH, &artifact.relation_mod)?; + write_file(AIR_CONFIG_PATH, &artifact.air_config)?; + println!( + "wrote asm/sys/vm/constraints_eval.masm ({} inputs, {} eval gates, repeat.{})", + artifact.num_inputs, artifact.num_eval_gates, artifact.adv_pipe_rows + ); + println!("wrote asm/sys/vm/mod.masm (RELATION_DIGEST)"); + println!("wrote air/src/config.rs (RELATION_DIGEST)"); + println!("done — run `cargo test -p miden-air --lib` to update the insta snapshot"); + Ok(()) +} + +/// Verify that the ACE circuit constants in `constraints_eval.masm` match the current AIR. +pub fn constraints_eval_masm_matches_air() -> Result<(), String> { + let artifact = compute_artifacts().map_err(|e| e.to_string())?; + let masm = read_file(RELATION_DIGEST_PATHS.1); + let actual_num_inputs: usize = + parse_masm_const(&masm, "NUM_INPUTS_CIRCUIT", "constraints_eval.masm")?; + let actual_num_eval: usize = + parse_masm_const(&masm, "NUM_EVAL_GATES_CIRCUIT", "constraints_eval.masm")?; + + let proc_start = masm + .find("proc load_ace_circuit_description") + .ok_or_else(|| "load_ace_circuit_description proc not found".to_string())?; + let actual_adv_pipe: usize = masm[proc_start..] + .lines() + .find_map(|line| line.trim().strip_prefix("repeat.").and_then(|v| v.parse::().ok())) + .ok_or_else(|| "repeat.N not found in load_ace_circuit_description".to_string())?; + + let adv_start = masm + .find("adv_map CIRCUIT_COMMITMENT = [") + .ok_or_else(|| "adv_map CIRCUIT_COMMITMENT not found".to_string())?; + let adv_end = masm[adv_start..] + .find(']') + .map(|idx| idx + adv_start) + .ok_or_else(|| "adv_map data block terminator not found".to_string())?; + let data_str = &masm[masm[..adv_start].len() + "adv_map CIRCUIT_COMMITMENT = [".len()..adv_end]; + let actual_data: Vec = data_str + .split(',') + .map(str::trim) + .filter(|s| !s.is_empty()) + .map(|s| { + s.parse::() + .map(Felt::new_unchecked) + .map_err(|_| "invalid u64 in adv_map".to_string()) + }) + .collect::>()?; + let actual_hash = Poseidon2::hash_elements(&actual_data); + + let actual_hash_u64: Vec = + actual_hash.as_elements().iter().map(Felt::as_canonical_u64).collect(); + let expected_hash_u64: Vec = + artifact.circuit_commitment.iter().map(Felt::as_canonical_u64).collect(); + + if actual_num_inputs != artifact.num_inputs { + return Err(format!( + "NUM_INPUTS_CIRCUIT is stale ({actual_num_inputs} != {})", + artifact.num_inputs, + )); + } + if actual_num_eval != artifact.num_eval_gates { + return Err(format!( + "NUM_EVAL_GATES_CIRCUIT is stale ({actual_num_eval} != {})", + artifact.num_eval_gates, + )); + } + if actual_adv_pipe != artifact.adv_pipe_rows { + return Err(format!( + "repeat.N in load_ace_circuit_description is stale ({actual_adv_pipe} != {})", + artifact.adv_pipe_rows, + )); + } + if actual_hash_u64 != expected_hash_u64 { + return Err("Circuit data in adv_map is stale (hash mismatch)".into()); + } + Ok(()) +} + +/// Verify that RELATION_DIGEST in `air/src/config.rs` and `sys/vm/mod.masm` matches current AIR. +pub fn relation_digest_matches_air() -> Result<(), String> { + let artifact = compute_artifacts().map_err(|e| e.to_string())?; + let expected = artifact.relation_digest; + + if miden_air::config::RELATION_DIGEST != expected { + return Err("RELATION_DIGEST in air/src/config.rs is stale".into()); + } + + let masm = read_file(RELATION_DIGEST_PATH); + let mut masm_digest: [Felt; 4] = [Felt::ZERO; 4]; + for (i, slot) in masm_digest.iter_mut().enumerate() { + let name = format!("RELATION_DIGEST_{i}"); + *slot = + parse_masm_const::(&masm, &name, "sys/vm/mod.masm").map(Felt::new_unchecked)?; + } + + if masm_digest != expected { + return Err("RELATION_DIGEST in sys/vm/mod.masm is stale".into()); + } + + Ok(()) +} + +fn parse_masm_const( + masm: &str, + name: &str, + file_label: &str, +) -> Result +where + T::Err: core::fmt::Debug, +{ + let prefix = format!("const {name} = "); + masm.lines() + .find_map(|line| line.trim().strip_prefix(&prefix).and_then(|v| v.parse::().ok())) + .ok_or_else(|| format!("constant {name} not found in {file_label}")) +} + +fn replace_masm_const(content: &mut String, name: &str, new_value: &str) { + let prefix = format!("const {name} = "); + let line_start = content.find(&prefix).unwrap_or_else(|| panic!("const {name} not found")); + let line_end = content[line_start..] + .find('\n') + .map(|i| line_start + i) + .unwrap_or(content.len()); + content.replace_range(line_start..line_end, &format!("{prefix}{new_value}")); +} + +fn read_file(rel_path: &str) -> String { + let path = format!("{}/{}", env!("CARGO_MANIFEST_DIR"), rel_path); + fs::read_to_string(&path).unwrap_or_else(|e| panic!("failed to read {path}: {e}")) +} + +fn write_file(rel_path: &str, contents: &str) -> io::Result<()> { + let path = format!("{}/{}", env!("CARGO_MANIFEST_DIR"), rel_path); + fs::write(&path, contents) + .map_err(|e| io::Error::new(e.kind(), format!("failed to write {path}: {e}"))) +} + +struct ComputedArtifacts { + num_inputs: usize, + num_eval_gates: usize, + adv_pipe_rows: usize, + circuit_commitment: [Felt; 4], + relation_digest: [Felt; 4], + constraints_eval: String, + relation_mod: String, + air_config: String, +} diff --git a/crates/lib/core/src/dsa.rs b/crates/lib/core/src/dsa.rs index e7fc7d0139..a37af2e590 100644 --- a/crates/lib/core/src/dsa.rs +++ b/crates/lib/core/src/dsa.rs @@ -21,14 +21,14 @@ pub mod ecdsa_k256_keccak { use alloc::vec::Vec; use miden_core::{Felt, Word, serde::Serializable, utils::bytes_to_packed_u32_elements}; - use miden_crypto::dsa::ecdsa_k256_keccak::{PublicKey, SecretKey, Signature}; + use miden_crypto::dsa::ecdsa_k256_keccak::{PublicKey, Signature, SigningKey}; /// Signs the provided message with the supplied secret key and encodes this signature and the /// associated public key into a vector of field elements in the format expected by /// `miden::core::crypto::dsa::ecdsa_k256_keccak::verify` procedure. /// /// See [`encode_signature()`] for more info. - pub fn sign(sk: &SecretKey, msg: Word) -> Vec { + pub fn sign(sk: &SigningKey, msg: Word) -> Vec { let pk = sk.public_key(); let sig = sk.sign(msg); encode_signature(&pk, &sig) @@ -65,14 +65,14 @@ pub mod eddsa_ed25519 { use alloc::vec::Vec; use miden_core::{Felt, Word, serde::Serializable, utils::bytes_to_packed_u32_elements}; - use miden_crypto::dsa::eddsa_25519_sha512::{PublicKey, SecretKey, Signature}; + use miden_crypto::dsa::eddsa_25519_sha512::{PublicKey, Signature, SigningKey}; /// Signs the provided message with the supplied secret key and encodes this signature and the /// associated public key into a vector of field elements in the format expected by /// `miden::core::crypto::dsa::eddsa_ed25519::verify` procedure. /// /// See [`encode_signature()`] for more info. - pub fn sign(sk: &SecretKey, msg: Word) -> Vec { + pub fn sign(sk: &SigningKey, msg: Word) -> Vec { let pk = sk.public_key(); let sig = sk.sign(msg); encode_signature(&pk, &sig) @@ -167,12 +167,13 @@ pub mod falcon512_poseidon2 { let mut polynomials = pk.to_elements(); polynomials.extend(s2.to_elements()); - polynomials.extend(pi.iter().map(|a| Felt::new(*a))); + polynomials.extend(pi.iter().map(|a| Felt::new_unchecked(*a))); let digest_polynomials = Poseidon2::hash_elements(&polynomials); let challenge = (digest_polynomials[0], digest_polynomials[1]); - // Push tau1 first, then tau0, so adv_push.2 produces _le format [tau0, tau1, ...] directly + // Push [tau1, tau0] so that after extend_stack reversal + two `adv_push` ops, + // operand stack is [tau0, tau1, ...] let mut result: Vec = vec![challenge.1, challenge.0]; result.extend_from_slice(&polynomials); result.extend_from_slice(&nonce.to_elements()); diff --git a/crates/lib/core/src/handlers/aead_decrypt.rs b/crates/lib/core/src/handlers/aead_decrypt.rs index b30e624764..242954845b 100644 --- a/crates/lib/core/src/handlers/aead_decrypt.rs +++ b/crates/lib/core/src/handlers/aead_decrypt.rs @@ -32,6 +32,9 @@ pub const AEAD_DECRYPT_EVENT_NAME: EventName = EventName::new("miden::core::cryp /// 4. Extracts only the data blocks (first num_blocks * 8 elements) from plaintext /// 5. Pushes the data blocks (WITHOUT padding) onto the advice stack in reverse order /// +/// Expected event payload order (excluding event id): +/// `(key: Word, nonce: Word, src_ptr, dst_ptr, num_blocks)`. +/// /// Memory layout at src_ptr: /// - [ciphertext_blocks(num_blocks * 8), encrypted_padding(8), tag(4)] /// - This handler reads ALL elements: data blocks + padding + tag @@ -48,7 +51,7 @@ pub const AEAD_DECRYPT_EVENT_NAME: EventName = EventName::new("miden::core::cryp /// 2. The deterministic encryption creates a bijection between plaintext and ciphertext /// 3. A malicious prover cannot provide incorrect plaintext without causing tag mismatch pub fn handle_aead_decrypt(process: &ProcessorState) -> Result, EventError> { - // Stack: [event_id, key(4), nonce(4), src_ptr, dst_ptr, num_blocks, ...] + // Stack: [event_id, key:Word(4), nonce:Word(4), src_ptr, dst_ptr, num_blocks, ...] // where: // src_ptr = ciphertext + encrypted_padding + tag location (input) // dst_ptr = plaintext destination (output) @@ -95,8 +98,7 @@ pub fn handle_aead_decrypt(process: &ProcessorState) -> Result Result // Assertion from the original code: r_hi should always be zero for Falcon modulus assert_eq!(r_hi, ZERO); - // `mod_12289` consumes the quotient via `adv_push.2` followed by the remainder via - // `adv_push.1`. Push the remainder first (so it stays below the quotient) and rely on - // `extend_stack_for_adv_push` to take care of the per-word little-endian layout. + // `mod_12289` consumes the quotient via `adv_push adv_push` and then the remainder via + // `adv_push`. `extend_stack([a, b, ...])` puts `a` on top of the advice stack (reverse + // iteration + push_front), and the mutations are applied in the order they appear in the + // returned vec. So applying remainder first then quotient leaves the advice stack, top first: + // [q_hi, q_lo, r_lo, ...] + // `adv_push adv_push` pops q_hi then q_lo → operand [q_lo, q_hi, ...] (LE); the subsequent + // `adv_push` pops r_lo. let remainder = AdviceMutation::extend_stack([r_lo]); let quotient = AdviceMutation::extend_stack([q_hi, q_lo]); Ok(vec![remainder, quotient]) diff --git a/crates/lib/core/src/handlers/keccak256.rs b/crates/lib/core/src/handlers/keccak256.rs index 189993610a..b85e0b6780 100644 --- a/crates/lib/core/src/handlers/keccak256.rs +++ b/crates/lib/core/src/handlers/keccak256.rs @@ -214,7 +214,7 @@ impl KeccakPreimage { fn precompile_tag(&self) -> Word { [ KECCAK_HASH_BYTES_EVENT_NAME.to_event_id().as_felt(), - Felt::new(self.as_ref().len() as u64), + Felt::new_unchecked(self.as_ref().len() as u64), ZERO, ZERO, ] diff --git a/crates/lib/core/src/handlers/mod.rs b/crates/lib/core/src/handlers/mod.rs index 703497b9cf..673ff69617 100644 --- a/crates/lib/core/src/handlers/mod.rs +++ b/crates/lib/core/src/handlers/mod.rs @@ -56,7 +56,7 @@ pub(crate) fn read_memory_region( process: &ProcessorState, start_ptr: u64, len: u64, -) -> Option> { +) -> Option> { // Validate inputs fit in u32 let start_addr: u32 = start_ptr.try_into().ok()?; let len_u32: u32 = len.try_into().ok()?; diff --git a/crates/lib/core/src/handlers/sha512.rs b/crates/lib/core/src/handlers/sha512.rs index 368a7fc29b..00d1c88261 100644 --- a/crates/lib/core/src/handlers/sha512.rs +++ b/crates/lib/core/src/handlers/sha512.rs @@ -141,7 +141,7 @@ impl Sha512Preimage { fn precompile_tag(&self) -> Word { [ SHA512_HASH_BYTES_EVENT_NAME.to_event_id().as_felt(), - Felt::new(self.as_ref().len() as u64), + Felt::new_unchecked(self.as_ref().len() as u64), ZERO, ZERO, ] diff --git a/crates/lib/core/src/handlers/smt_peek.rs b/crates/lib/core/src/handlers/smt_peek.rs index 2c4639dd01..6dc90c67dc 100644 --- a/crates/lib/core/src/handlers/smt_peek.rs +++ b/crates/lib/core/src/handlers/smt_peek.rs @@ -49,9 +49,9 @@ pub fn handle_smt_peek(process: &ProcessorState) -> Result, // K[3] is used as the leaf index (most significant in BE ordering) let node = process .advice_provider() - .get_tree_node(root, Felt::new(SMT_DEPTH as u64), key[3]) + .get_tree_node(root, Felt::new_unchecked(SMT_DEPTH as u64), key[3]) .map_err(|err| SmtPeekError::AdviceProviderError { - message: format!("Failed to get tree node: {}", err), + message: format!("Failed to get tree node: {err}"), })?; if node == *empty_leaf { diff --git a/crates/lib/core/src/handlers/sorted_array.rs b/crates/lib/core/src/handlers/sorted_array.rs index 3c967e180a..82e827c69d 100644 --- a/crates/lib/core/src/handlers/sorted_array.rs +++ b/crates/lib/core/src/handlers/sorted_array.rs @@ -1,8 +1,6 @@ use alloc::{vec, vec::Vec}; -use miden_core::{ - Felt, LexicographicWord, Word, events::EventName, field::PrimeCharacteristicRing, -}; +use miden_core::{Felt, Word, events::EventName, field::PrimeCharacteristicRing}; use miden_processor::{MemoryError, ProcessorState, advice::AdviceMutation, event::EventError}; /// Event name for the lowerbound_array operation. @@ -122,7 +120,7 @@ fn push_lowerbound_result( ])]); } - // Helper function to get a word from memory and convert it to a LexicographicWord + // Helper function to get a word from memory and normalize it to the requested key size. let get_word = { |addr: u32| { process @@ -147,8 +145,8 @@ fn push_lowerbound_result( if word < previous_word { return Err(SortedArrayError::NotAscendingOrder { index: addr, - value: word.into(), - predecessor: previous_word.into(), + value: word, + predecessor: previous_word, } .into()); } @@ -171,14 +169,14 @@ fn push_lowerbound_result( /// - If the `key_size` is [`KeySize::Half`], the word is returned with the two least significant /// elements (word[0] and word[1]) zeroized, keeping only the most significant half (word[2] and /// word[3]) for comparison. (In BE ordering, word[3] is most significant.) -fn word_to_search_key(mut word: Word, key_size: KeySize) -> LexicographicWord { +fn word_to_search_key(mut word: Word, key_size: KeySize) -> Word { match key_size { - KeySize::Full => LexicographicWord::new(word), + KeySize::Full => word, KeySize::Half => { word[0] = Felt::ZERO; word[1] = Felt::ZERO; - LexicographicWord::new(word) + word }, } } diff --git a/crates/lib/core/src/handlers/u64_div.rs b/crates/lib/core/src/handlers/u64_div.rs index 1f1233284d..21232a4df1 100644 --- a/crates/lib/core/src/handlers/u64_div.rs +++ b/crates/lib/core/src/handlers/u64_div.rs @@ -99,8 +99,8 @@ pub fn handle_u64_div(process: &ProcessorState) -> Result, E // Create mutations to extend the advice stack with the result. // extend_stack([a,b,c,d]) puts 'a' on top due to reverse iteration + push_front // So [q_hi, q_lo, r_hi, r_lo] puts q_hi on top - // After adv_push.2: pops q_hi then q_lo → operand stack [q_lo, q_hi, ...] (LE) - // After adv_push.2: pops r_hi then r_lo → operand stack [r_lo, r_hi, ...] (LE) + // After `adv_push adv_push`: pops q_hi then q_lo → operand stack [q_lo, q_hi, ...] (LE) + // After `adv_push adv_push`: pops r_hi then r_lo → operand stack [r_lo, r_hi, ...] (LE) let mutation = AdviceMutation::extend_stack([q_hi, q_lo, r_hi, r_lo]); Ok(vec![mutation]) } diff --git a/crates/lib/core/src/lib.rs b/crates/lib/core/src/lib.rs index 1ee5af8e3b..205475579c 100644 --- a/crates/lib/core/src/lib.rs +++ b/crates/lib/core/src/lib.rs @@ -1,5 +1,10 @@ #![no_std] +#[cfg(feature = "std")] +extern crate std; + +#[cfg(any(feature = "constraints-tools", all(test, feature = "std")))] +pub mod constraints_regen; pub mod dsa; pub mod handlers; diff --git a/crates/lib/core/tests/collections/mmr.rs b/crates/lib/core/tests/collections/mmr.rs index 9e64f3ad88..407959a8bd 100644 --- a/crates/lib/core/tests/collections/mmr.rs +++ b/crates/lib/core/tests/collections/mmr.rs @@ -70,7 +70,7 @@ fn test_mmr_get_single_peak() -> Result<(), MerkleError> { let merkle_root = merkle_tree.root(); let merkle_store = MerkleStore::from(&merkle_tree); let mut builder = AdviceStackBuilder::new(); - builder.push_for_adv_loadw(merkle_root); + builder.push_word(merkle_root); let advice_stack = builder.build_vec_u64(); for pos in 0..(leaves.len() as u64) { @@ -101,6 +101,20 @@ fn test_mmr_get_single_peak() -> Result<(), MerkleError> { Ok(()) } +#[test] +fn test_mmr_get_fails_for_absent_leaf() { + let source = " + use miden::core::collections::mmr + + begin + push.4 push.1000 mem_store + push.1000 push.4 exec.mmr::get + end"; + + let test = build_test!(source, &[]); + assert!(test.execute().is_err()); +} + #[test] fn test_mmr_get_two_peaks() -> Result<(), MerkleError> { // This test uses two merkle trees for the MMR, one with 8 elements, and one with 2 @@ -117,8 +131,8 @@ fn test_mmr_get_two_peaks() -> Result<(), MerkleError> { merkle_store.extend(merkle_tree2.inner_nodes()); let mut builder = AdviceStackBuilder::new(); - builder.push_for_adv_loadw(merkle_root1); - builder.push_for_adv_loadw(merkle_root2); + builder.push_word(merkle_root1); + builder.push_word(merkle_root2); let advice_stack = builder.build_vec_u64(); let examples = [ @@ -182,7 +196,7 @@ fn test_mmr_tree_with_one_element() -> Result<(), MerkleError> { // Test case for single element MMR let mut builder = AdviceStackBuilder::new(); - builder.push_for_adv_loadw(merkle_root3); + builder.push_word(merkle_root3); let advice_stack = builder.build_vec_u64(); let source = format!( " @@ -204,9 +218,9 @@ fn test_mmr_tree_with_one_element() -> Result<(), MerkleError> { // Test case for the single element tree in a MMR with multiple trees let mut builder = AdviceStackBuilder::new(); - builder.push_for_adv_loadw(merkle_root1); - builder.push_for_adv_loadw(merkle_root2); - builder.push_for_adv_loadw(merkle_root3); + builder.push_word(merkle_root1); + builder.push_word(merkle_root2); + builder.push_word(merkle_root3); let advice_stack = builder.build_vec_u64(); let num_leaves = leaves1.len() + leaves2.len() + leaves3.len(); let source = format!( @@ -241,8 +255,8 @@ fn test_mmr_unpack() { // 3 peaks. These hashes are invalid, we can't produce data for any of these peaks (only // for testing) [ZERO, ZERO, ZERO, ONE], - [ZERO, ZERO, ZERO, Felt::new(2)], - [ZERO, ZERO, ZERO, Felt::new(3)], + [ZERO, ZERO, ZERO, Felt::new_unchecked(2)], + [ZERO, ZERO, ZERO, Felt::new_unchecked(3)], // Padding, the MMR is padded to a minimum length of 16 EMPTY_WORD.into(), EMPTY_WORD.into(), @@ -270,7 +284,7 @@ fn test_mmr_unpack() { let store = MerkleStore::new(); let mut mmr_mem_repr: Vec = Vec::with_capacity(peaks.len() + 1); - mmr_mem_repr.extend_from_slice(&[Felt::new(number_of_leaves), ZERO, ZERO, ZERO]); + mmr_mem_repr.extend_from_slice(&[Felt::new_unchecked(number_of_leaves), ZERO, ZERO, ZERO]); mmr_mem_repr.extend_from_slice(&peaks.as_slice().concat()); // Advice map key is the hash word (positions 0-3 on stack) @@ -304,8 +318,8 @@ fn test_mmr_unpack_invalid_hash() { // 3 peaks. These hashes are invalid, we can't produce data for any of these peaks (only // for testing) [ZERO, ZERO, ZERO, ONE], - [ZERO, ZERO, ZERO, Felt::new(2)], - [ZERO, ZERO, ZERO, Felt::new(3)], + [ZERO, ZERO, ZERO, Felt::new_unchecked(2)], + [ZERO, ZERO, ZERO, Felt::new_unchecked(3)], // Padding, the MMR is padded to a minimum length o 16 EMPTY_WORD.into(), EMPTY_WORD.into(), @@ -337,7 +351,7 @@ fn test_mmr_unpack_invalid_hash() { hash_data[0][0] += ONE; let mut map_data: Vec = Vec::with_capacity(hash_data.len() + 1); - map_data.extend_from_slice(&[Felt::new(0b10101), ZERO, ZERO, ZERO]); // 3 peaks, 21 leaves + map_data.extend_from_slice(&[Felt::new_unchecked(0b10101), ZERO, ZERO, ZERO]); // 3 peaks, 21 leaves map_data.extend_from_slice(&hash_data.as_slice().concat()); let hash_key = hash; @@ -364,23 +378,23 @@ fn test_mmr_unpack_large_mmr() { // These hashes are invalid, we can't produce data for any of these peaks (only for // testing) [ZERO, ZERO, ZERO, ONE], - [ZERO, ZERO, ZERO, Felt::new(2)], - [ZERO, ZERO, ZERO, Felt::new(3)], - [ZERO, ZERO, ZERO, Felt::new(4)], - [ZERO, ZERO, ZERO, Felt::new(5)], - [ZERO, ZERO, ZERO, Felt::new(6)], - [ZERO, ZERO, ZERO, Felt::new(7)], - [ZERO, ZERO, ZERO, Felt::new(8)], - [ZERO, ZERO, ZERO, Felt::new(9)], - [ZERO, ZERO, ZERO, Felt::new(10)], - [ZERO, ZERO, ZERO, Felt::new(11)], - [ZERO, ZERO, ZERO, Felt::new(12)], - [ZERO, ZERO, ZERO, Felt::new(13)], - [ZERO, ZERO, ZERO, Felt::new(14)], - [ZERO, ZERO, ZERO, Felt::new(15)], - [ZERO, ZERO, ZERO, Felt::new(16)], + [ZERO, ZERO, ZERO, Felt::new_unchecked(2)], + [ZERO, ZERO, ZERO, Felt::new_unchecked(3)], + [ZERO, ZERO, ZERO, Felt::new_unchecked(4)], + [ZERO, ZERO, ZERO, Felt::new_unchecked(5)], + [ZERO, ZERO, ZERO, Felt::new_unchecked(6)], + [ZERO, ZERO, ZERO, Felt::new_unchecked(7)], + [ZERO, ZERO, ZERO, Felt::new_unchecked(8)], + [ZERO, ZERO, ZERO, Felt::new_unchecked(9)], + [ZERO, ZERO, ZERO, Felt::new_unchecked(10)], + [ZERO, ZERO, ZERO, Felt::new_unchecked(11)], + [ZERO, ZERO, ZERO, Felt::new_unchecked(12)], + [ZERO, ZERO, ZERO, Felt::new_unchecked(13)], + [ZERO, ZERO, ZERO, Felt::new_unchecked(14)], + [ZERO, ZERO, ZERO, Felt::new_unchecked(15)], + [ZERO, ZERO, ZERO, Felt::new_unchecked(16)], // Padding, peaks greater than 16 are padded to an even number - [ZERO, ZERO, ZERO, Felt::new(17)], + [ZERO, ZERO, ZERO, Felt::new_unchecked(17)], EMPTY_WORD.into(), ]; let peaks_hash = hash_elements(&peaks.concat()); @@ -396,7 +410,7 @@ fn test_mmr_unpack_large_mmr() { let store = MerkleStore::new(); let mut mmr_mem_repr: Vec = Vec::with_capacity(peaks.len() + 1); - mmr_mem_repr.extend_from_slice(&[Felt::new(number_of_leaves), ZERO, ZERO, ZERO]); + mmr_mem_repr.extend_from_slice(&[Felt::new_unchecked(number_of_leaves), ZERO, ZERO, ZERO]); mmr_mem_repr.extend_from_slice(&peaks.as_slice().concat()); // Advice map key is the hash word (positions 0-3 on stack) @@ -437,9 +451,9 @@ fn test_mmr_unpack_large_mmr() { #[test] fn test_mmr_pack_roundtrip() { let mut mmr = Mmr::new(); - mmr.add(init_merkle_leaf(1)); - mmr.add(init_merkle_leaf(2)); - mmr.add(init_merkle_leaf(3)); + mmr.add(init_merkle_leaf(1)).unwrap(); + mmr.add(init_merkle_leaf(2)).unwrap(); + mmr.add(init_merkle_leaf(3)).unwrap(); let accumulator = mmr.peaks(); let hash = accumulator.hash_peaks(); @@ -456,7 +470,12 @@ fn test_mmr_pack_roundtrip() { let mut hash_data = accumulator.peaks().to_vec(); hash_data.resize(16, Word::default()); let mut map_data: Vec = Vec::with_capacity(hash_data.len() + 1); - map_data.extend_from_slice(&[Felt::new(accumulator.num_leaves() as u64), ZERO, ZERO, ZERO]); + map_data.extend_from_slice(&[ + Felt::new_unchecked(accumulator.num_leaves() as u64), + ZERO, + ZERO, + ZERO, + ]); map_data.extend_from_slice(Word::words_as_elements(&hash_data).as_ref()); // Advice map key is the hash word @@ -475,7 +494,7 @@ fn test_mmr_pack_roundtrip() { "; let test = build_test!(source, &stack, advice_stack, store, advice_map.iter().cloned()); // Expected stack after pack: [HASH, ...], then swapw dropw leaves [h0, h1, h2, h3] - let expected_stack: Vec = hash.iter().map(|e| e.as_canonical_u64()).collect(); + let expected_stack: Vec = hash.iter().map(Felt::as_canonical_u64).collect(); let mut expect_memory: Vec = Vec::new(); @@ -511,7 +530,7 @@ fn test_mmr_pack() { #[rustfmt::skip] hash_data.extend_from_slice( &[ ONE, ZERO, ZERO, ZERO, // peak1 - Felt::new(2), ZERO, ZERO, ZERO, // peak2 + Felt::new_unchecked(2), ZERO, ZERO, ZERO, // peak2 ]); hash_data.resize(16 * 4, ZERO); // padding data @@ -521,7 +540,7 @@ fn test_mmr_pack() { let hash_key = hash; let mut expect_data: Vec = Vec::new(); - expect_data.extend_from_slice(&[Felt::new(3), ZERO, ZERO, ZERO]); // num_leaves + expect_data.extend_from_slice(&[Felt::new_unchecked(3), ZERO, ZERO, ZERO]); // num_leaves expect_data.extend_from_slice(&hash_data); let (execution_output, _) = build_test!(source).execute_for_output().unwrap(); @@ -575,8 +594,18 @@ fn test_mmr_two() { ); let mut mmr = Mmr::new(); - mmr.add([ONE, Felt::new(2), Felt::new(3), Felt::new(4)].into()); - mmr.add([Felt::new(5), Felt::new(6), Felt::new(7), Felt::new(8)].into()); + mmr.add([ONE, Felt::new_unchecked(2), Felt::new_unchecked(3), Felt::new_unchecked(4)].into()) + .unwrap(); + mmr.add( + [ + Felt::new_unchecked(5), + Felt::new_unchecked(6), + Felt::new_unchecked(7), + Felt::new_unchecked(8), + ] + .into(), + ) + .unwrap(); let accumulator = mmr.peaks(); let num_leaves = accumulator.num_leaves() as u64; @@ -673,7 +702,7 @@ fn test_add_mmr_large() { let mut mmr = Mmr::new(); for i in 1u64..=7 { - mmr.add(init_merkle_leaf(i)); + mmr.add(init_merkle_leaf(i)).unwrap(); } let accumulator = mmr.peaks(); @@ -715,7 +744,7 @@ fn debug_mmr_peaks_vs_vm_memory() { let mut mmr = Mmr::new(); for i in 1u64..=7 { // Use canonical leaf representation consistent with Merkle trees. - mmr.add(init_merkle_leaf(i)); + mmr.add(init_merkle_leaf(i)).unwrap(); } let accumulator = mmr.peaks(); let rust_peaks = accumulator.peaks(); @@ -733,7 +762,7 @@ fn debug_mmr_peaks_vs_vm_memory() { let addr = mmr_ptr + (word_idx as u32) * 4 + limb; let v = execution_output .memory - .read_element(ContextId::root(), Felt::new(addr as u64)) + .read_element(ContextId::root(), Felt::new_unchecked(addr as u64)) .unwrap() .as_canonical_u64(); vm_mem.push(v); @@ -752,7 +781,7 @@ fn test_mmr_large_add_roundtrip() { // Build the initial 7-leaf MMR using the canonical leaf encoding. let mut mmr = Mmr::new(); for i in 1u64..=7 { - mmr.add(init_merkle_leaf(i)); + mmr.add(init_merkle_leaf(i)).unwrap(); } let old_accumulator = mmr.peaks(); @@ -772,7 +801,7 @@ fn test_mmr_large_add_roundtrip() { let mut map_data: Vec = Vec::with_capacity(hash_data.len() + 1); let num_leaves = old_accumulator.num_leaves() as u64; - map_data.extend_from_slice(&[Felt::new(num_leaves), ZERO, ZERO, ZERO]); + map_data.extend_from_slice(&[Felt::new_unchecked(num_leaves), ZERO, ZERO, ZERO]); map_data.extend_from_slice(Word::words_as_elements(&hash_data)); // Advice map key is the hash word @@ -793,7 +822,7 @@ fn test_mmr_large_add_roundtrip() { " ); - mmr.add(init_merkle_leaf(8)); + mmr.add(init_merkle_leaf(8)).unwrap(); let new_accumulator = mmr.peaks(); let num_leaves = new_accumulator.num_leaves() as u64; @@ -823,5 +852,5 @@ fn digests_to_ints(digests: &[Word]) -> Vec { fn word_to_ints(word: &Word) -> Vec { let arr: [Felt; WORD_SIZE] = (*word).into(); - arr.iter().map(|v| v.as_canonical_u64()).collect() + arr.iter().map(Felt::as_canonical_u64).collect() } diff --git a/crates/lib/core/tests/collections/smt.rs b/crates/lib/core/tests/collections/smt.rs index c572587e82..f6946e2bb0 100644 --- a/crates/lib/core/tests/collections/smt.rs +++ b/crates/lib/core/tests/collections/smt.rs @@ -1,4 +1,5 @@ use miden_core_lib::handlers::smt_peek::SMT_PEEK_EVENT_NAME; +use miden_crypto::merkle::smt::LEAF_DOMAIN; use super::*; @@ -6,7 +7,12 @@ use super::*; // ================================================================================================ const fn word(e0: u64, e1: u64, e2: u64, e3: u64) -> Word { - Word::new([Felt::new(e0), Felt::new(e1), Felt::new(e2), Felt::new(e3)]) + Word::new([ + Felt::new_unchecked(e0), + Felt::new_unchecked(e1), + Felt::new_unchecked(e2), + Felt::new_unchecked(e3), + ]) } /// Note: We never insert at the same key twice. This is so that the `smt::get` test can loop over @@ -285,18 +291,33 @@ fn test_set_advice_map_single_key() { /// (i.e. removing a value that's already empty) #[test] fn test_set_empty_key_in_non_empty_leaf() { - let leaf_idx = Felt::new(42); + let leaf_idx = Felt::new_unchecked(42); let leaves: [(Word, Word); 1] = [( - Word::new([leaf_idx, Felt::new(102), Felt::new(103), Felt::new(104)]), - Word::new([Felt::new(1_u64), Felt::new(2_u64), Felt::new(3_u64), Felt::new(4_u64)]), + Word::new([ + leaf_idx, + Felt::new_unchecked(102), + Felt::new_unchecked(103), + Felt::new_unchecked(104), + ]), + Word::new([ + Felt::new_unchecked(1_u64), + Felt::new_unchecked(2_u64), + Felt::new_unchecked(3_u64), + Felt::new_unchecked(4_u64), + ]), )]; let mut smt = build_smt_from_pairs(&leaves); // This key has same K[0] (leaf index element) as key in the existing leaf, so will map to // the same leaf - let new_key = Word::new([leaf_idx, Felt::new(12), Felt::new(3), Felt::new(4)]); + let new_key = Word::new([ + leaf_idx, + Felt::new_unchecked(12), + Felt::new_unchecked(3), + Felt::new_unchecked(4), + ]); let source = " use miden::core::collections::smt @@ -353,6 +374,137 @@ fn test_smt_set_single_to_multi() { } } +/// Regression test: inserting into a single-leaf with a forged (attacker-controlled) advice +/// preimage must be rejected. Without preimage validation in `insert_single_to_multi_leaf`, +/// an attacker who controls the SMT `set` advice provider could replace the existing +/// single-leaf entry with arbitrary contents when the leaf is converted to a multi-leaf. +#[test] +fn test_smt_set_single_to_multi_rejects_forged_preimage() { + const SOURCE: &str = " + use miden::core::collections::smt + use miden::core::sys + + begin + # => [V, K, R] + exec.smt::set + # => [V_old, R_new] + exec.sys::truncate_stack + end + "; + + let k_real = word(101, 102, 103, 69420); + let v_real = word(1, 2, 3, 4); + let k_new = word(201, 202, 203, 69420); + let v_new = word(5, 6, 7, 8); + + // attacker-chosen preimage that shares the leaf index but is otherwise arbitrary + let k_fake = word(301, 302, 303, 69420); + let v_fake = EMPTY_WORD; + + let smt = build_smt_from_pairs(&[(k_real, v_real)]); + let root = smt.root(); + + // substitute a forged preimage for the real leaf hash in the advice map + let real_leaf_hash = smt.leaves().next().unwrap().1.hash(); + let forged_preimage = build_leaf_advice_value(&[(k_fake, v_fake)]); + let store = MerkleStore::from(&smt); + let advice_map = vec![(real_leaf_hash, forged_preimage)]; + + let mut initial_stack: Vec = Vec::new(); + push_word(&mut initial_stack, &root); + push_word(&mut initial_stack, &k_new); + push_word(&mut initial_stack, &v_new); + + let test = build_test!(SOURCE, &initial_stack, &[], store, advice_map); + crate::expect_assert_error_message!(test, contains "invalid single-leaf preimage"); +} + +/// Regression test for the multi-leaf no-op deletion bypass. +/// +/// Previously, `smt::set` loaded the leaf's node value (NV) via `adv.push_mtnode`, which +/// reads from the advice provider's Merkle store without verifying the path to the root. +/// A malicious prover could populate the store so traversal from root `R` lands on a +/// leaf value from a different tree — one whose preimage does not contain the target key. +/// When setting `V = ZERO` for that key, `set_multi_leaf` would then take the no-op branch +/// (key not found + empty V) and return an unchanged root, silently skipping the deletion. +/// +/// The fix replaces the unverified `adv.push_mtnode` at the top of `set` with `mtree_get`, +/// which fetches and verifies the Merkle path in a single step. The forged path no longer +/// hashes to `R`, so execution aborts with a `MerklePathVerificationFailed` error. +#[test] +fn test_smt_set_rejects_forged_merkle_path_on_noop_delete() { + use miden_utils_testing::crypto::InnerNodeInfo; + + // All keys share K[3] so they collide into the same leaf bucket, giving us a multi-leaf. + const K_TARGET: Word = word(777, 102, 103, 42); + const V_TARGET: Word = word(1, 2, 3, 4); + const K_SHARED: Word = word(778, 202, 203, 42); + const V_SHARED: Word = word(5, 6, 7, 8); + + // Real tree: contains K_TARGET. This is the tree the caller thinks they're updating. + let smt_real = build_smt_from_pairs(&[(K_TARGET, V_TARGET), (K_SHARED, V_SHARED)]); + let root_real = smt_real.root(); + + // Attacker's alternate tree: different multi-leaf at the same leaf index, NOT containing + // K_TARGET. Its preimage hashes to a different leaf value than smt_real's. + const K_FAKE_A: Word = word(888, 302, 303, 42); + const V_FAKE_A: Word = word(9, 10, 11, 12); + const K_FAKE_B: Word = word(889, 402, 403, 42); + const V_FAKE_B: Word = word(13, 14, 15, 16); + let smt_fake = build_smt_from_pairs(&[(K_FAKE_A, V_FAKE_A), (K_FAKE_B, V_FAKE_B)]); + let root_fake = smt_fake.root(); + assert_ne!(root_real, root_fake); + + // Merge both trees' inner nodes into a single store, then overwrite the entry for + // `root_real` to point at `root_fake`'s children. Traversal from `root_real` now + // follows `smt_fake`'s internal structure and terminates at `smt_fake`'s leaf value. + let mut store = MerkleStore::from(&smt_real); + store.extend(smt_fake.inner_nodes()); + let fake_root_entry = store + .inner_nodes() + .find(|n| n.value == root_fake) + .expect("root_fake should be present after extend"); + store.extend(core::iter::once(InnerNodeInfo { + value: root_real, + left: fake_root_entry.left, + right: fake_root_entry.right, + })); + + // Advice map serves smt_fake's leaf preimage under smt_fake's leaf hash, which is what + // the poisoned store's traversal will surface as NV. With this pairing, + // `pipe_double_words_preimage_to_memory`'s hash-vs-commitment check passes, so (without + // the fix) the code would proceed to find_key_value, miss K_TARGET, and no-op. + let advice_map: Vec<(Word, Vec)> = smt_fake + .leaves() + .map(|(_, leaf)| (leaf.hash(), build_leaf_advice_value(leaf.entries()))) + .collect(); + + const SOURCE: &str = " + use miden::core::collections::smt + use miden::core::sys + + begin + exec.smt::set + exec.sys::truncate_stack + end + "; + + let mut initial_stack: Vec = Vec::new(); + push_word(&mut initial_stack, &root_real); + push_word(&mut initial_stack, &K_TARGET); + push_word(&mut initial_stack, &EMPTY_WORD); + + let test = build_test!(SOURCE, &initial_stack, &[], store, advice_map); + + miden_utils_testing::expect_exec_error_matches!( + test, + miden_processor::ExecutionError::OperationError { + err: miden_processor::operation::OperationError::MerklePathVerificationFailed { .. }, + .. + } + ); +} + #[test] fn test_smt_set_in_multi() { const SOURCE: &str = " @@ -630,6 +782,64 @@ fn test_smt_leaf_hash_matches_merkle_store() { } } +/// Regression check: a single-entry leaf hash is domain-separated, so it must not equal the +/// plain `merge([K, V])` that would be produced with domain 0. +#[test] +fn test_smt_single_leaf_hash_differs_from_plain_merge() { + use miden_utils_testing::crypto::Poseidon2; + + let (key, value) = LEAVES[0]; + let smt = build_smt_from_pairs(&[(key, value)]); + + let leaf = smt.leaves().next().map(|(_, leaf)| leaf).unwrap(); + let leaf_hash = leaf.hash(); + + let plain_merge = Poseidon2::merge(&[key, value]); + let domain_merge = Poseidon2::merge_in_domain(&[key, value], LEAF_DOMAIN); + + assert_ne!( + leaf_hash, plain_merge, + "single-entry leaf hash must not equal plain merge([K, V])" + ); + assert_eq!( + leaf_hash, domain_merge, + "single-entry leaf hash must equal merge_in_domain([K, V], LEAF_DOMAIN)" + ); +} + +/// Regression check: a multi-entry leaf hash is domain-separated, so it must not equal the +/// plain `hash_elements` of its preimage. This would fail if the preimage check still used +/// domain 0 on either the Rust or MASM side. +#[test] +fn test_smt_multi_leaf_hash_differs_from_domain_zero() { + use miden_utils_testing::crypto::Poseidon2; + + let smt = build_smt_from_pairs(&LEAVES_MULTI); + + // Find the leaf that contains multiple entries (same K[0] bucket). + let multi_leaf = smt + .leaves() + .map(|(_, leaf)| leaf) + .find(|leaf| leaf.entries().len() > 1) + .expect("LEAVES_MULTI must produce at least one multi-entry leaf"); + assert!(multi_leaf.entries().len() >= 2); + + let leaf_hash = multi_leaf.hash(); + let elements: Vec = multi_leaf.to_elements().collect(); + + let plain_hash = Poseidon2::hash_elements(&elements); + let domain_hash = Poseidon2::hash_elements_in_domain(&elements, LEAF_DOMAIN); + + assert_ne!( + leaf_hash, plain_hash, + "multi-entry leaf hash must not equal plain hash_elements(preimage) (domain 0)" + ); + assert_eq!( + leaf_hash, domain_hash, + "multi-entry leaf hash must equal hash_elements_in_domain(preimage, LEAF_DOMAIN)" + ); +} + // HELPER FUNCTIONS // ================================================================================================ @@ -751,13 +961,13 @@ fn test_smt_randomized_round_trip() { /// multi-leaf functionality in the SMT. We constrain word[0] because it is the most /// significant element for lexicographic comparison. fn random_word(seed: &mut u64, buckets: usize) -> Word { - let mut word = [Felt::new(0); 4]; + let mut word = [Felt::new_unchecked(0); 4]; for element in word.iter_mut() { - *element = Felt::new(random_u64(seed)); + *element = Felt::new_unchecked(random_u64(seed)); } // Constrain word[0] to be one of buckets values (most significant in LE comparison) let bucket_value = random_u64(seed) % (buckets as u64); - word[0] = Felt::new(bucket_value); + word[0] = Felt::new_unchecked(bucket_value); Word::new(word) } @@ -794,8 +1004,8 @@ fn build_leaf_advice_value(entries: &[(Word, Word)]) -> Vec { let mut builder = AdviceStackBuilder::new(); for (key, value) in entries { - builder.push_for_adv_loadw(*key); - builder.push_for_adv_loadw(*value); + builder.push_word(*key); + builder.push_word(*value); } builder.into_elements() } diff --git a/crates/lib/core/tests/collections/sorted_array.rs b/crates/lib/core/tests/collections/sorted_array.rs index 58fc62a066..0cb3857846 100644 --- a/crates/lib/core/tests/collections/sorted_array.rs +++ b/crates/lib/core/tests/collections/sorted_array.rs @@ -1,3 +1,9 @@ +use miden_core_lib::{ + CoreLibrary, + handlers::sorted_array::{LOWERBOUND_ARRAY_EVENT_NAME, LOWERBOUND_KEY_VALUE_EVENT_NAME}, +}; +use miden_processor::{ProcessorState, advice::AdviceMutation, event::EventError}; + use super::*; #[test] @@ -290,7 +296,7 @@ fn test_malicious_advice_invalid_pointer() { # Pop the malicious values from advice stack (initialized at test start) # was_key_found, maybe_key_ptr - adv_push.2 + adv_push adv_push # => [maybe_key_ptr, was_key_found, KEY, start_ptr, end_ptr, ...] # Now validate the pointer is within bounds @@ -305,7 +311,8 @@ fn test_malicious_advice_invalid_pointer() { ); // Initialize advice stack with malicious values: [maybe_key_ptr=200, was_key_found=1] - // adv_push.2 pops values and pushes them, resulting in [maybe_key_ptr, was_key_found, ...] + // `adv_push adv_push` pops values and pushes them, resulting in [maybe_key_ptr, + // was_key_found, ...]. // The valid range is [100, 112], so 200 is clearly out of bounds let test = build_test!(source, &[], &[200, 1]); @@ -334,7 +341,7 @@ fn test_malicious_advice_misaligned_pointer() { push.104 push.100 push.[8456,415,4922,593] # Pop the malicious values from advice stack - adv_push.2 + adv_push adv_push # => [maybe_key_ptr, was_key_found, ...] # Validate alignment: pointer must be divisible by 4 @@ -350,8 +357,8 @@ fn test_malicious_advice_misaligned_pointer() { ); // Initialize advice stack with malicious values: [maybe_key_ptr=101, was_key_found=1] - // adv_push.2 pops values and pushes them, resulting in [maybe_key_ptr, was_key_found, ...] - // 101 is not divisible by 4, so it's misaligned + // adv_push adv_push pops values and pushes them, resulting in [maybe_key_ptr, + // was_key_found, ...] 101 is not divisible by 4, so it's misaligned let test = build_test!(source, &[], &[101, 1]); // Execution should fail due to alignment check @@ -380,7 +387,7 @@ fn test_malicious_advice_wrong_key_found_flag() { push.104 push.100 push.[9999,9999,9999,9999] # Pop the malicious values from advice stack - adv_push.2 + adv_push adv_push # => [maybe_key_ptr=100, was_key_found=1, KEY_search, start_ptr, end_ptr] # If was_key_found is true, verify the key at the pointer matches @@ -410,11 +417,167 @@ fn test_malicious_advice_wrong_key_found_flag() { ); // Initialize advice stack with malicious values: [maybe_key_ptr=100, was_key_found=1] - // adv_push.2 pops values and pushes them, resulting in [maybe_key_ptr, was_key_found, ...] - // Claiming the key was found at ptr=100, but we're searching for a different key + // adv_push adv_push pops values and pushes them, resulting in [maybe_key_ptr, + // was_key_found, ...] Claiming the key was found at ptr=100, but we're searching for a + // different key let test = build_test!(source, &[], &[100, 1]); // Should fail because the key at ptr=100 doesn't match the search key let result = test.execute(); assert!(result.is_err(), "Expected validation to fail for wrong key_found flag"); } + +#[test] +fn test_find_word_rejects_oob_pointer_above_end() { + let source = format!( + " + use miden::core::collections::sorted_array + {TRUNCATE_STACK_PROC} + begin + push.[9000,9000,9000,9000] mem_storew_le.204 dropw + + push.[8456,415,4922,593] mem_storew_le.100 dropw + push.[8675,5816,5458,2767] mem_storew_le.104 dropw + push.[3015,7211,2002,5143] mem_storew_le.108 dropw + + push.112 push.100 push.[8675,5816,5458,2767] + exec.sorted_array::find_word + + exec.truncate_stack + end + " + ); + let test = build_lib_test(&source, &[]) + .with_event_handler(LOWERBOUND_ARRAY_EVENT_NAME, malicious_lowerbound_oob_above); + + assert!( + test.execute().is_err(), + "find_word must reject maybe_value_ptr above end_ptr in the not-found branch", + ); +} + +#[test] +fn test_find_word_rejects_oob_pointer_below_start() { + let source = format!( + " + use miden::core::collections::sorted_array + {TRUNCATE_STACK_PROC} + begin + push.[9000,9000,9000,9000] mem_storew_le.40 dropw + + push.[8456,415,4922,593] mem_storew_le.100 dropw + push.[8675,5816,5458,2767] mem_storew_le.104 dropw + push.[3015,7211,2002,5143] mem_storew_le.108 dropw + + push.112 push.100 push.[8675,5816,5458,2767] + exec.sorted_array::find_word + + exec.truncate_stack + end + " + ); + let test = build_lib_test(&source, &[]) + .with_event_handler(LOWERBOUND_ARRAY_EVENT_NAME, malicious_lowerbound_oob_below); + + assert!( + test.execute().is_err(), + "find_word must reject maybe_value_ptr below start_ptr in the not-found branch", + ); +} + +#[test] +fn test_find_partial_key_value_rejects_oob_pointer_above_end() { + let source = format!( + " + use miden::core::collections::sorted_array + {TRUNCATE_STACK_PROC} + begin + push.[9000,9000,9000,9000] mem_storew_le.204 dropw + push.[9000,9000,9000,9000] mem_storew_le.208 dropw + + push.[8456,415,4922,593] mem_storew_le.100 dropw + push.[8595,8794,8303,7256] mem_storew_le.104 dropw + + push.[3348,6058,5470,2813] mem_storew_le.108 dropw + push.[3015,7211,2002,5143] mem_storew_le.112 dropw + + push.[7513,7106,9944,7176] mem_storew_le.116 dropw + push.[4942,5573,1077,1968] mem_storew_le.120 dropw + + push.124 push.100 push.[3348,6058,5470,2813] + exec.sorted_array::find_key_value + + exec.truncate_stack + end + " + ); + + let test = build_lib_test(&source, &[]) + .with_event_handler(LOWERBOUND_KEY_VALUE_EVENT_NAME, malicious_lowerbound_oob_above); + + assert!( + test.execute().is_err(), + "find_partial_key_value must reject maybe_key_ptr above end_ptr in the not-found branch", + ); +} + +#[test] +fn test_find_partial_key_value_rejects_oob_pointer_below_start() { + let source = format!( + " + use miden::core::collections::sorted_array + {TRUNCATE_STACK_PROC} + begin + push.[9000,9000,9000,9000] mem_storew_le.40 dropw + push.[9000,9000,9000,9000] mem_storew_le.44 dropw + + push.[8456,415,4922,593] mem_storew_le.100 dropw + push.[8595,8794,8303,7256] mem_storew_le.104 dropw + + push.[3348,6058,5470,2813] mem_storew_le.108 dropw + push.[3015,7211,2002,5143] mem_storew_le.112 dropw + + push.[7513,7106,9944,7176] mem_storew_le.116 dropw + push.[4942,5573,1077,1968] mem_storew_le.120 dropw + + push.124 push.100 push.[3348,6058,5470,2813] + exec.sorted_array::find_key_value + + exec.truncate_stack + end + " + ); + + let test = build_lib_test(&source, &[]) + .with_event_handler(LOWERBOUND_KEY_VALUE_EVENT_NAME, malicious_lowerbound_oob_below); + + assert!( + test.execute().is_err(), + "find_partial_key_value must reject maybe_key_ptr below start_ptr in the not-found branch", + ); +} + +// MALICIOUS ADVICE PROVIDERS +// ================================================================================================ + +/// Builds a test with the core library and no event handlers. +fn build_lib_test(source: &str, op_stack: &[u64]) -> miden_utils_testing::Test { + let core_lib = CoreLibrary::default(); + miden_utils_testing::build_test_by_mode!(false, source, op_stack) + .with_library(core_lib.library().clone()) +} + +/// Returns `(was_found = false, maybe_value_ptr = 204)` regardless of the actual array. 204 is +/// past the array's `end_ptr = 112`, so the bounds check must fire. +fn malicious_lowerbound_oob_above( + _process: &ProcessorState, +) -> Result, EventError> { + Ok(vec![AdviceMutation::extend_stack(vec![Felt::new_unchecked(204), Felt::ZERO])]) +} + +/// Returns `(was_found = false, maybe_value_ptr = 40)` which is below `start_ptr = 100`. +fn malicious_lowerbound_oob_below( + _process: &ProcessorState, +) -> Result, EventError> { + Ok(vec![AdviceMutation::extend_stack(vec![Felt::new_unchecked(40), Felt::ZERO])]) +} diff --git a/crates/lib/core/tests/crypto/aead.rs b/crates/lib/core/tests/crypto/aead.rs index cb2e8b5a0b..39edfa81a9 100644 --- a/crates/lib/core/tests/crypto/aead.rs +++ b/crates/lib/core/tests/crypto/aead.rs @@ -58,7 +58,7 @@ fn test_encrypt_documented_stack_contract() { let output = build_test!(source, &sentinels).execute().expect("encryption must succeed"); let stack = output.stack_outputs(); for (idx, sentinel) in sentinels.iter().enumerate() { - assert_eq!(stack.get_element(idx), Some(Felt::new(*sentinel))); + assert_eq!(stack.get_element(idx), Some(Felt::new_unchecked(*sentinel))); } } @@ -71,14 +71,14 @@ fn test_decrypt_documented_stack_contract() { let key = SecretKey::with_rng(&mut rng); let nonce = Nonce::with_rng(&mut rng); let plaintext = vec![ - Felt::new(10), - Felt::new(11), - Felt::new(12), - Felt::new(13), - Felt::new(14), - Felt::new(15), - Felt::new(16), - Felt::new(17), + Felt::new_unchecked(10), + Felt::new_unchecked(11), + Felt::new_unchecked(12), + Felt::new_unchecked(13), + Felt::new_unchecked(14), + Felt::new_unchecked(15), + Felt::new_unchecked(16), + Felt::new_unchecked(17), ]; let encrypted = key .encrypt_elements_with_nonce(&plaintext, &[], nonce) @@ -126,14 +126,14 @@ fn test_encrypt_with_known_values() { let nonce = Nonce::with_rng(&mut rng); let plaintext = vec![ - Felt::new(10), - Felt::new(11), - Felt::new(12), - Felt::new(13), - Felt::new(14), - Felt::new(15), - Felt::new(16), - Felt::new(17), + Felt::new_unchecked(10), + Felt::new_unchecked(11), + Felt::new_unchecked(12), + Felt::new_unchecked(13), + Felt::new_unchecked(14), + Felt::new_unchecked(15), + Felt::new_unchecked(16), + Felt::new_unchecked(17), ]; let encrypted = key @@ -210,14 +210,14 @@ fn test_decrypt_with_known_values() { let nonce = Nonce::with_rng(&mut rng); let plaintext = vec![ - Felt::new(10), - Felt::new(11), - Felt::new(12), - Felt::new(13), - Felt::new(14), - Felt::new(15), - Felt::new(16), - Felt::new(17), + Felt::new_unchecked(10), + Felt::new_unchecked(11), + Felt::new_unchecked(12), + Felt::new_unchecked(13), + Felt::new_unchecked(14), + Felt::new_unchecked(15), + Felt::new_unchecked(16), + Felt::new_unchecked(17), ]; // Encrypt to get ciphertext and tag @@ -246,6 +246,10 @@ fn test_decrypt_with_known_values() { # Store the tag at address 1016 push.{expected_tag:?} push.1016 mem_storew_le dropw + # Store unrelated data immediately after the plaintext output. + push.[91,92,93,94] push.2008 mem_storew_le dropw + push.[95,96,97,98] push.2012 mem_storew_le dropw + # Decrypt: [key(4), nonce(4), src_ptr, dst_ptr, num_blocks] push.1 # num_blocks = 1 (data blocks only, padding is automatic) push.2000 # dst_ptr (where plaintext will be written) @@ -263,12 +267,12 @@ fn test_decrypt_with_known_values() { padw push.2004 mem_loadw_le push.[14,15,16,17] eqw assert dropw dropw - # Verify padding block [1,0,0,0,0,0,0,0] + # Verify memory after the plaintext output is untouched. padw push.2008 mem_loadw_le - push.[1,0,0,0] eqw assert dropw dropw + push.[91,92,93,94] eqw assert dropw dropw padw push.2012 mem_loadw_le - padw eqw assert dropw dropw + push.[95,96,97,98] eqw assert dropw dropw end ", ciphertext_0 = &ciphertext[0..4], @@ -291,14 +295,14 @@ fn test_decrypt_with_wrong_key() { let nonce = Nonce::with_rng(&mut rng); let plaintext = vec![ - Felt::new(10), - Felt::new(11), - Felt::new(12), - Felt::new(13), - Felt::new(14), - Felt::new(15), - Felt::new(16), - Felt::new(17), + Felt::new_unchecked(10), + Felt::new_unchecked(11), + Felt::new_unchecked(12), + Felt::new_unchecked(13), + Felt::new_unchecked(14), + Felt::new_unchecked(15), + Felt::new_unchecked(16), + Felt::new_unchecked(17), ]; // Encrypt with correct key @@ -347,3 +351,104 @@ fn test_decrypt_with_wrong_key() { // Should fail with assertion error assert!(test.execute().is_err(), "Wrong key should cause assertion failure"); } + +#[test] +fn test_encrypt_fails_on_overlap() { + // With num_blocks=1, encrypt uses (1+1)*8 = 16 elements per range. + // Source [1000, 1016) and dest [1008, 1024) overlap at [1008, 1016). + let source = r#" + use miden::core::crypto::aead + + begin + push.[10,11,12,13] push.1000 mem_storew_le dropw + push.[14,15,16,17] push.1004 mem_storew_le dropw + + push.1 # num_blocks + push.1008 # dst_ptr (overlaps with source) + push.1000 # src_ptr + push.[1,2,3,4] # nonce + push.[5,6,7,8] # key + exec.aead::encrypt + end + "#; + + let test = build_test!(source, &[]); + expect_assert_error_message!(test, contains "overlap"); +} + +#[test] +fn test_encrypt_does_not_overwrite_source_adjacent_memory() { + let source = r#" + use miden::core::crypto::aead + + begin + # Store one plaintext block at address 1000. + push.[11,12,13,14] push.1000 mem_storew_le dropw + push.[15,16,17,18] push.1004 mem_storew_le dropw + + # Store unrelated data immediately after the plaintext buffer. + push.[91,92,93,94] push.1008 mem_storew_le dropw + push.[95,96,97,98] push.1012 mem_storew_le dropw + + push.1 + push.2000 + push.1000 + push.[1,2,3,4] + push.[5,6,7,8] + exec.aead::encrypt + dropw + end + "#; + + build_test!(source, &[]).expect_stack_and_memory(&[], 1008, &[91, 92, 93, 94, 95, 96, 97, 98]); +} + +#[test] +fn test_encrypt_zero_blocks_does_not_overwrite_source_memory() { + let source = r#" + use miden::core::crypto::aead + + begin + # Store unrelated data at src_ptr; encrypt with num_blocks = 0 should not touch it. + push.[41,42,43,44] push.1000 mem_storew_le dropw + push.[45,46,47,48] push.1004 mem_storew_le dropw + + push.0 + push.2000 + push.1000 + push.[1,2,3,4] + push.[5,6,7,8] + exec.aead::encrypt + dropw + end + "#; + + build_test!(source, &[]).expect_stack_and_memory(&[], 1000, &[41, 42, 43, 44, 45, 46, 47, 48]); +} + +#[test] +fn test_decrypt_fails_on_overlap() { + // With num_blocks=1, decrypt uses (1+1)*8 = 16 elements per range. + // Source [1000, 1016) and dest [1008, 1024) overlap at [1008, 1016). + let source = r#" + use miden::core::crypto::aead + + begin + push.[10,11,12,13] push.1000 mem_storew_le dropw + push.[14,15,16,17] push.1004 mem_storew_le dropw + push.[18,19,20,21] push.1008 mem_storew_le dropw + push.[22,23,24,25] push.1012 mem_storew_le dropw + push.[0,0,0,0] push.1016 mem_storew_le dropw + + push.1 # num_blocks + push.1008 # dst_ptr (overlaps with source) + push.1000 # src_ptr + push.[1,2,3,4] # nonce + push.[5,6,7,8] # key + exec.aead::decrypt + end + "#; + + let test = build_test!(source, &[]); + expect_assert_error_message!(test, contains "overlap"); +} diff --git a/crates/lib/core/tests/crypto/circuit_evaluation.rs b/crates/lib/core/tests/crypto/circuit_evaluation.rs index 9494f929b3..24b41a1054 100644 --- a/crates/lib/core/tests/crypto/circuit_evaluation.rs +++ b/crates/lib/core/tests/crypto/circuit_evaluation.rs @@ -1,5 +1,4 @@ -use miden_ace_codegen::{AceConfig, InputKey, LayoutKind, build_ace_circuit_for_air}; -use miden_air::ProcessorAir; +use miden_ace_codegen::{AceCircuit, AceConfig, InputKey, LayoutKind}; use miden_core::{ Felt, ONE, ZERO, advice::AdviceStackBuilder, @@ -7,6 +6,13 @@ use miden_core::{ }; use miden_utils_testing::rand::rand_quad_felt; +/// Build the batched ACE circuit for the Miden VM ProcessorAir. +fn build_batched_circuit(config: AceConfig) -> AceCircuit { + let air = miden_air::ProcessorAir; + let batch_config = miden_air::ace::logup_boundary_config(); + miden_air::ace::build_batched_ace_circuit::<_, QuadFelt>(&air, config, &batch_config).unwrap() +} + #[test] fn circuit_evaluation_prove_verify() { let num_repetitions = 20; @@ -64,13 +70,13 @@ fn circuit_evaluation_prove_verify() { // eval gates data.extend_from_slice(&[ // id = 3, v = rand + -1 - Felt::new(7 + (5 << 30) + (2 << 60)), // id_l = 7; id_r = 5; op = ADD + Felt::new_unchecked(7 + (5 << 30) + (2 << 60)), // id_l = 7; id_r = 5; op = ADD // id = 2, v = rand * (rand - 1) - Felt::new(7 + (3 << 30) + (1 << 60)), // id_l = 7; id_r = 3; op = MUL + Felt::new_unchecked(7 + (3 << 30) + (1 << 60)), // id_l = 7; id_r = 3; op = MUL // id = 1, v = rand * (rand - 1) - result = zero - Felt::new(2 + (6 << 30)), // id_l = 2; id_r = 6; op = SUB + Felt::new_unchecked(2 + (6 << 30)), // id_l = 2; id_r = 6; op = SUB // id = 0, v = zero * zero - Felt::new(1 + (1 << 30) + (1 << 60)), // id_l = 1; id_r = 1; op = MUL + Felt::new_unchecked(1 + (1 << 30) + (1 << 60)), // id_l = 1; id_r = 1; op = MUL ]); // padding related only to the use of "adv_pipe" in the MASM example @@ -78,7 +84,7 @@ fn circuit_evaluation_prove_verify() { // finalize the advice stack let adv_stack = data.repeat(num_repetitions); - let adv_stack: Vec = adv_stack.iter().map(|a| a.as_canonical_u64()).collect(); + let adv_stack: Vec = adv_stack.iter().map(Felt::as_canonical_u64).collect(); let test = miden_utils_testing::build_test!(source, &[], &adv_stack); test.expect_stack(&[]); @@ -87,13 +93,12 @@ fn circuit_evaluation_prove_verify() { #[test] fn processor_air_eval_circuit_masm() { - let air = ProcessorAir; let config = AceConfig { num_quotient_chunks: 8, - num_aux_inputs: 14, + num_vlpi_groups: 1, layout: LayoutKind::Masm, }; - let circuit = build_ace_circuit_for_air::<_, Felt, QuadFelt>(&air, config).unwrap(); + let circuit = build_batched_circuit(config); let layout = circuit.layout().clone(); let mut inputs = fill_inputs(&layout); @@ -156,16 +161,16 @@ fn fill_inputs(layout: &miden_ace_codegen::InputLayout) -> Vec { let mut state = 0x9e37_79b9_7f4a_7c15u64; for _ in 0..layout.total_inputs { state = state.wrapping_mul(6364136223846793005).wrapping_add(1); - let lo = Felt::new(state); + let lo = Felt::new_unchecked(state); state = state.wrapping_mul(6364136223846793005).wrapping_add(1); - let hi = Felt::new(state); + let hi = Felt::new_unchecked(state); values.push(QuadFelt::new([lo, hi])); } values } fn adjust_quotient_to_zero( - circuit: &miden_ace_codegen::AceCircuit, + circuit: &AceCircuit, layout: &miden_ace_codegen::InputLayout, inputs: &mut [QuadFelt], ) { @@ -182,7 +187,7 @@ fn adjust_quotient_to_zero( } fn find_nonzero_quotient_slope( - circuit: &miden_ace_codegen::AceCircuit, + circuit: &AceCircuit, layout: &miden_ace_codegen::InputLayout, inputs: &mut [QuadFelt], root: QuadFelt, diff --git a/crates/lib/core/tests/crypto/ecdsa_k256_keccak.rs b/crates/lib/core/tests/crypto/ecdsa_k256_keccak.rs index 1a85d2cbb2..6644b322be 100644 --- a/crates/lib/core/tests/crypto/ecdsa_k256_keccak.rs +++ b/crates/lib/core/tests/crypto/ecdsa_k256_keccak.rs @@ -2,7 +2,7 @@ //! //! Validates that: //! - Raw event handlers correctly perform ECDSA verification and populate advice provider -//! - MASM wrapper correctly returns commitment, tag, and result on stack +//! - Private implementation helper returns the expected commitment, tag, and result on stack //! - Both valid and invalid signatures are handled correctly use miden_core::{ @@ -17,7 +17,7 @@ use miden_core_lib::{ dsa::ecdsa_k256_keccak::sign as ecdsa_sign, handlers::ecdsa::{EcdsaPrecompile, EcdsaRequest}, }; -use miden_crypto::{dsa::ecdsa_k256_keccak::SecretKey, hash::poseidon2::Poseidon2}; +use miden_crypto::{dsa::ecdsa_k256_keccak::SigningKey as SecretKey, hash::poseidon2::Poseidon2}; use miden_processor::{ ProcessorState, advice::AdviceMutation, @@ -68,14 +68,14 @@ fn test_ecdsa_verify_cases() { ); let test = build_debug_test!(source, &[]); - let output = test.execute().unwrap(); + let (output, _) = test.execute_for_output().unwrap(); // Assert result - let result = output.stack_outputs().get_element(0).unwrap(); + let result = output.stack.get_element(0).unwrap(); assert_eq!(result, Felt::from_bool(expected_valid)); // Verify the precompile request was logged with the right event ID - let deferred = output.advice_provider().precompile_requests().to_vec(); + let deferred = output.advice.precompile_requests().to_vec(); assert_eq!(deferred.len(), 1); assert_eq!(deferred[0], request.as_precompile_request()); } @@ -92,28 +92,26 @@ fn test_ecdsa_verify_impl_commitment() { // Verify tag/commitment once on a valid request let memory_stores = generate_memory_store_masm(&request); - let source = format!( - " - use miden::core::crypto::dsa::ecdsa_k256_keccak - use miden::core::sys - - begin - # Store test data in memory - {memory_stores} + let source = private_proc_harness( + include_str!("../../asm/crypto/dsa/ecdsa_k256_keccak.masm"), + format!( + " + # Store test data in memory + {memory_stores} - # Call verify_impl: [ptr_pk, ptr_digest, ptr_sig] - push.{SIG_ADDR}.{DIGEST_ADDR}.{PK_ADDR} - exec.ecdsa_k256_keccak::verify_prehash_impl - # => [COMM, TAG, result, ...] + # Call verify_impl: [ptr_pk, ptr_digest, ptr_sig] + push.{SIG_ADDR}.{DIGEST_ADDR}.{PK_ADDR} + exec.verify_prehash_impl + # => [COMM, TAG, result, ...] - exec.sys::truncate_stack - end - ", + exec.sys::truncate_stack + ", + ), ); let test = build_debug_test!(source, &[]); - let output = test.execute().unwrap(); - let stack = output.stack_outputs(); + let (output, _) = test.execute_for_output().unwrap(); + let stack = output.stack; // Verify stack layout: [COMM (0-3), TAG (4-7), result (at position 8), ...] // TAG = [event_id, result, 0, 0] where TAG[1]=result is at position 5 @@ -137,11 +135,11 @@ fn test_ecdsa_verify_impl_commitment() { "result does not match expected validity" ); - let deferred = output.advice_provider().precompile_requests().to_vec(); + let deferred = output.advice.precompile_requests().to_vec(); assert_eq!(deferred.len(), 1, "expected a single deferred request"); assert_eq!(deferred[0], request.as_precompile_request()); - let advice_stack = output.advice_provider().stack(); + let advice_stack = output.advice.stack(); assert!(advice_stack.is_empty(), "advice stack should be empty after verify_impl"); } } @@ -175,8 +173,7 @@ impl EventHandler for EcdsaSignatureHandler { }; assert_eq!( provided_pk_commitment, pk_commitment, - "public key commitment mismatch: expected {:?}, got {:?}", - pk_commitment, provided_pk_commitment + "public key commitment mismatch: expected {pk_commitment:?}, got {provided_pk_commitment:?}" ); // Message starts at position 5 (after event_id + pk_commitment) @@ -193,7 +190,12 @@ fn test_ecdsa_verify_bis_wrapper() { let mut rng = StdRng::seed_from_u64(19260817); let secret_key = SecretKey::with_rng(&mut rng); let public_key = secret_key.public_key(); - let message = Word::from([Felt::new(11), Felt::new(22), Felt::new(33), Felt::new(44)]); + let message = Word::from([ + Felt::new_unchecked(11), + Felt::new_unchecked(22), + Felt::new_unchecked(33), + Felt::new_unchecked(44), + ]); let pk_commitment = { let pk_felts = bytes_to_packed_u32_elements(&public_key.to_bytes()); @@ -213,8 +215,8 @@ fn test_ecdsa_verify_bis_wrapper() { ", ); - let mut test = build_debug_test!(&source); - test.add_event_handler(EVENT_ECDSA_SIG_TO_STACK, EcdsaSignatureHandler::new(&secret_key)); + let test = build_debug_test!(&source) + .with_event_handler(EVENT_ECDSA_SIG_TO_STACK, EcdsaSignatureHandler::new(&secret_key)); test.expect_stack(&[]); } @@ -272,3 +274,7 @@ fn generate_memory_store_masm(request: &EcdsaRequest) -> String { ] .join(" ") } + +fn private_proc_harness(module_source: &str, body: impl AsRef) -> String { + format!("{}\n\nbegin\n{}\nend", module_source.replace("pub proc", "proc"), body.as_ref()) +} diff --git a/crates/lib/core/tests/crypto/eddsa_ed25519.rs b/crates/lib/core/tests/crypto/eddsa_ed25519.rs index 99eb2f57dd..af5b818f36 100644 --- a/crates/lib/core/tests/crypto/eddsa_ed25519.rs +++ b/crates/lib/core/tests/crypto/eddsa_ed25519.rs @@ -1,8 +1,8 @@ //! Tests for EdDSA (Ed25519) precompile. //! //! Validates that: -//! - Prehash flow (k-digest provided by the caller) works via `verify_prehash` and -//! `verify_prehash_impl` +//! - Prehash flow (k-digest provided by the caller) works via `verify_prehash` +//! - Private implementation helper returns the expected commitment, tag, and result on stack //! - Full message flow recomputes k-digest via SHA2-512 and verifies signatures //! - Deferred requests logged by the runtime match expected host-side requests @@ -21,7 +21,7 @@ use miden_core_lib::{ handlers::eddsa_ed25519::{EddsaPrecompile, EddsaRequest}, }; use miden_crypto::{ - dsa::eddsa_25519_sha512::{PublicKey, SecretKey, Signature}, + dsa::eddsa_25519_sha512::{PublicKey, Signature, SigningKey as SecretKey}, hash::{poseidon2::Poseidon2, sha2::Sha512}, }; use miden_processor::{ @@ -66,12 +66,12 @@ fn test_eddsa_verify_prehash_cases() { ); let test = build_debug_test!(source, &[]); - let output = test.execute().unwrap(); + let (output, _) = test.execute_for_output().unwrap(); - let result = output.stack_outputs().get_element(0).unwrap(); + let result = output.stack.get_element(0).unwrap(); assert_eq!(result, Felt::ONE, "verification result mismatch"); - let deferred = output.advice_provider().precompile_requests().to_vec(); + let deferred = output.advice.precompile_requests().to_vec(); assert_eq!(deferred.len(), 1, "expected one deferred request"); assert_eq!(deferred[0], valid_request.as_precompile_request()); @@ -94,12 +94,12 @@ fn test_eddsa_verify_prehash_cases() { ); let test = build_debug_test!(source, &[]); - let output = test.execute().unwrap(); + let (output, _) = test.execute_for_output().unwrap(); - let result = output.stack_outputs().get_element(0).unwrap(); + let result = output.stack.get_element(0).unwrap(); assert_eq!(result, Felt::ZERO, "verification result mismatch"); - let deferred = output.advice_provider().precompile_requests().to_vec(); + let deferred = output.advice.precompile_requests().to_vec(); assert_eq!(deferred.len(), 1, "expected one deferred request"); assert_eq!(deferred[0], invalid_request.as_precompile_request()); } @@ -116,25 +116,23 @@ fn test_eddsa_verify_prehash_impl_commitment() { for (request, message, expected_valid) in test_cases { let memory_stores = generate_memory_store_masm(&request, &message); - let source = format!( - " - use miden::core::crypto::dsa::eddsa_ed25519 - use miden::core::sys - - begin - {memory_stores} - - push.{SIG_ADDR}.{K_DIGEST_ADDR}.{PK_ADDR} - exec.eddsa_ed25519::verify_prehash_impl - - exec.sys::truncate_stack - end - ", + let source = private_proc_harness( + include_str!("../../asm/crypto/dsa/eddsa_ed25519.masm"), + format!( + " + {memory_stores} + + push.{SIG_ADDR}.{K_DIGEST_ADDR}.{PK_ADDR} + exec.verify_prehash_impl + + exec.sys::truncate_stack + ", + ), ); let test = build_debug_test!(source, &[]); - let output = test.execute().unwrap(); - let stack = output.stack_outputs(); + let (output, _) = test.execute_for_output().unwrap(); + let stack = output.stack; let commitment = stack.get_word(0).unwrap(); let tag = stack.get_word(4).unwrap(); @@ -148,12 +146,12 @@ fn test_eddsa_verify_prehash_impl_commitment() { let result = stack.get_element(5).unwrap(); assert_eq!(result, Felt::from_bool(expected_valid)); - let deferred = output.advice_provider().precompile_requests().to_vec(); + let deferred = output.advice.precompile_requests().to_vec(); assert_eq!(deferred.len(), 1, "expected a single deferred request"); assert_eq!(deferred[0], request.as_precompile_request()); assert!( - output.advice_provider().stack().is_empty(), + output.advice.stack().is_empty(), "advice stack should be empty after verify_prehash_impl" ); } @@ -161,7 +159,7 @@ fn test_eddsa_verify_prehash_impl_commitment() { #[test] fn test_eddsa_verify_with_message() { - let message = Word::new([1, 2, 3, 4].map(Felt::new)); + let message = Word::new([1, 2, 3, 4].map(Felt::new_unchecked)); let mut rng = StdRng::seed_from_u64(42); let secret_key = SecretKey::with_rng(&mut rng); @@ -225,8 +223,7 @@ impl EventHandler for EddsaSignatureHandler { }; assert_eq!( provided_pk_commitment, pk_commitment, - "public key commitment mismatch: expected {:?}, got {:?}", - pk_commitment, provided_pk_commitment + "public key commitment mismatch: expected {pk_commitment:?}, got {provided_pk_commitment:?}" ); // Message starts at position 5 (after event_id + pk_commitment) @@ -243,7 +240,12 @@ fn test_eddsa_verify_high_level_wrapper() { let mut rng = StdRng::seed_from_u64(19260817); let secret_key = SecretKey::with_rng(&mut rng); let public_key = secret_key.public_key(); - let message = Word::from([Felt::new(11), Felt::new(22), Felt::new(33), Felt::new(44)]); + let message = Word::from([ + Felt::new_unchecked(11), + Felt::new_unchecked(22), + Felt::new_unchecked(33), + Felt::new_unchecked(44), + ]); let pk_commitment = { let pk_felts = bytes_to_packed_u32_elements(&public_key.to_bytes()); @@ -262,8 +264,8 @@ fn test_eddsa_verify_high_level_wrapper() { ", ); - let mut test = build_debug_test!(&source); - test.add_event_handler(EVENT_EDDSA_SIG_TO_STACK, EddsaSignatureHandler::new(&secret_key)); + let test = build_debug_test!(&source) + .with_event_handler(EVENT_EDDSA_SIG_TO_STACK, EddsaSignatureHandler::new(&secret_key)); test.expect_stack(&[]); test.execute().unwrap(); @@ -293,7 +295,7 @@ fn generate_valid_data() -> EddsaTestData { let mut rng = StdRng::seed_from_u64(42); let secret_key = SecretKey::with_rng(&mut rng); let pk = secret_key.public_key(); - let message = Word::new([1, 2, 3, 4].map(Felt::new)); + let message = Word::new([1, 2, 3, 4].map(Felt::new_unchecked)); let sig = secret_key.sign(message); let message_bytes: Vec<_> = message .into_iter() @@ -345,3 +347,7 @@ fn generate_memory_store_masm(request: &EddsaRequest, message: &[u8; 32]) -> Str ] .join(" ") } + +fn private_proc_harness(module_source: &str, body: impl AsRef) -> String { + format!("{}\n\nbegin\n{}\nend", module_source.replace("pub proc", "proc"), body.as_ref()) +} diff --git a/crates/lib/core/tests/crypto/falcon.rs b/crates/lib/core/tests/crypto/falcon.rs index bac222be3e..1d4d1153dc 100644 --- a/crates/lib/core/tests/crypto/falcon.rs +++ b/crates/lib/core/tests/crypto/falcon.rs @@ -10,11 +10,10 @@ use miden_core::{ }; use miden_core_lib::{CoreLibrary, dsa::falcon512_poseidon2}; use miden_processor::{ - DefaultHost, ExecutionError, ProcessorState, Program, StackInputs, + DefaultHost, ExecutionError, FastProcessor, ProcessorState, Program, StackInputs, advice::{AdviceInputs, AdviceMutation}, crypto::random::RandomCoin, event::EventError, - execute_sync, operation::OperationError, }; use miden_utils_testing::{ @@ -83,7 +82,7 @@ pub fn push_falcon_signature(process: &ProcessorState) -> Result = pk_sk_felts.iter().map(|f| f.as_canonical_u64() as u8).collect(); // Reconstruct SecretKey from bytes - let sk = falcon512_poseidon2::SecretKey::read_from_bytes(&sk_bytes) + let sk = SecretKey::read_from_bytes(&sk_bytes) .map_err(|_| FalconError::MalformedSignatureKey { key_type: "Poseidon2 Falcon512" })?; let signature_result = falcon512_poseidon2::sign(&sk, msg) @@ -114,11 +113,11 @@ fn test_falcon512_norm_sq() { "; // normalize(e) = e^2 - phi * (2*M*e - M^2) where phi := (e > (M - 1)/2) - let upper = rand::rng().random_range(Q + 1..M); + let upper = rng().random_range(Q + 1..M); let test_upper = build_test!(source, &[upper]); test_upper.expect_stack(&[(M - upper) * (M - upper)]); - let lower = rand::rng().random_range(0..=Q); + let lower = rng().random_range(0..=Q); let test_lower = build_test!(source, &[lower]); test_lower.expect_stack(&[lower * lower]) } @@ -202,8 +201,8 @@ fn test_falcon512_probabilistic_product_deterministic() { let mut h_coeffs = Vec::new(); let mut s2_coeffs = Vec::new(); for _i in 0..N { - h_coeffs.push(Felt::new(rng.random_range(0..M))); - s2_coeffs.push(Felt::new(rng.random_range(0..M))); + h_coeffs.push(Felt::new_unchecked(rng.random_range(0..M))); + s2_coeffs.push(Felt::new_unchecked(rng.random_range(0..M))); } let h: Polynomial = Polynomial::new(h_coeffs); @@ -284,8 +283,8 @@ fn test_move_sig_to_adv_stack() { let adv_stack = vec![]; let store = MerkleStore::new(); - let mut test = build_debug_test!(source, &op_stack, &adv_stack, store, advice_map.into_iter()); - test.add_event_handler(EVENT_FALCON_SIG_TO_STACK, push_falcon_signature); + let test = build_debug_test!(source, &op_stack, &adv_stack, store, advice_map.into_iter()) + .with_event_handler(EVENT_FALCON_SIG_TO_STACK, push_falcon_signature); test.expect_stack(&[]) } @@ -297,8 +296,8 @@ fn falcon_execution() { let message = random_word(); let (source, op_stack, adv_stack, store, advice_map) = generate_test(sk, message); - let mut test = build_debug_test!(&source, &op_stack, &adv_stack, store, advice_map.into_iter()); - test.add_event_handler(EVENT_FALCON_SIG_TO_STACK, push_falcon_signature); + let test = build_debug_test!(&source, &op_stack, &adv_stack, store, advice_map.into_iter()) + .with_event_handler(EVENT_FALCON_SIG_TO_STACK, push_falcon_signature); test.expect_stack(&[]) } @@ -363,8 +362,8 @@ fn test_mod_12289_rejects_forged_remainder_zero(#[case] a_hi: u64, #[case] a_lo: let a = (a_hi << 32) | a_lo; let q = a.wrapping_mul(M_INV); - let q_hi = Felt::new(q >> 32); - let q_lo = Felt::new(q & 0xffff_ffff); + let q_hi = Felt::new_unchecked(q >> 32); + let q_lo = Felt::new_unchecked(q & 0xffff_ffff); let remainder = AdviceMutation::extend_stack([ZERO]); let quotient = AdviceMutation::extend_stack([q_hi, q_lo]); @@ -387,10 +386,10 @@ fn test_mod_12289_rejects_forged_remainder_zero(#[case] a_hi: u64, #[case] a_lo: // Use the upstream test builder directly so we do not auto-register the honest // falcon_div handler from CoreLibrary. - let core_lib = miden_core_lib::CoreLibrary::default(); - let mut test = miden_utils_testing::build_test_by_mode!(false, source, &op_stack, &adv_stack); - test.libraries.push(core_lib.library().clone()); - test.add_event_handler(FALCON_DIV, malicious_falcon_div); + let core_lib = CoreLibrary::default(); + let test = miden_utils_testing::build_test_by_mode!(false, source, &op_stack, &adv_stack) + .with_library(core_lib.library().clone()) + .with_event_handler(FALCON_DIV, malicious_falcon_div); // Hardened mod_12289 must reject forged advice. expect_exec_error_matches!( @@ -414,10 +413,10 @@ fn test_mod_12289_rejects_forged_addition_overflow() { // Malicious event handler that forges q/r to trigger the addition-overflow assertion. fn malicious_falcon_div(_process: &ProcessorState) -> Result, EventError> { - let q_hi = Felt::new(FORGED_Q >> 32); - let q_lo = Felt::new(FORGED_Q & 0xffff_ffff); + let q_hi = Felt::new_unchecked(FORGED_Q >> 32); + let q_lo = Felt::new_unchecked(FORGED_Q & 0xffff_ffff); - let remainder = AdviceMutation::extend_stack([Felt::new(FORGED_R)]); + let remainder = AdviceMutation::extend_stack([Felt::new_unchecked(FORGED_R)]); let quotient = AdviceMutation::extend_stack([q_hi, q_lo]); Ok(vec![remainder, quotient]) } @@ -434,7 +433,51 @@ fn test_mod_12289_rejects_forged_addition_overflow() { let op_stack = vec![a >> 32, a & 0xffff_ffff]; let adv_stack: Vec = vec![]; - let core_lib = miden_core_lib::CoreLibrary::default(); + let core_lib = CoreLibrary::default(); + let test = miden_utils_testing::build_test_by_mode!(false, source, &op_stack, &adv_stack) + .with_library(core_lib.library().clone()) + .with_event_handler(FALCON_DIV, malicious_falcon_div); + + expect_exec_error_matches!( + test, + ExecutionError::OperationError { + err: OperationError::FailedAssertion { err_msg, .. }, + .. + } if err_msg.as_deref() == Some("comparison failed: addition overflow") + ); +} + +#[test] +fn test_mod_12289_rejects_non_u32_remainder_advice() { + const FALCON_DIV: EventName = + EventName::new("miden::core::crypto::dsa::falcon512_poseidon2::falcon_div"); + + fn malicious_falcon_div(process: &ProcessorState) -> Result, EventError> { + let a_hi = process.get_stack_item(1).as_canonical_u64(); + let a_lo = process.get_stack_item(2).as_canonical_u64(); + let dividend = (a_hi << 32) | a_lo; + let quotient = dividend / M; + + let q_hi = Felt::new_unchecked(quotient >> 32); + let q_lo = Felt::new_unchecked(quotient & 0xffff_ffff); + let forged_remainder = Felt::new_unchecked(Felt::ORDER_U64 - 1); + + let remainder = AdviceMutation::extend_stack([forged_remainder]); + let quotient = AdviceMutation::extend_stack([q_hi, q_lo]); + Ok(vec![remainder, quotient]) + } + + let source = " + use miden::core::crypto::dsa::falcon512_poseidon2 + begin + exec.falcon512_poseidon2::mod_12289 + end + "; + + let op_stack = vec![0, 100_000]; + let adv_stack: Vec = vec![]; + + let core_lib = CoreLibrary::default(); let mut test = miden_utils_testing::build_test_by_mode!(false, source, &op_stack, &adv_stack); test.libraries.push(core_lib.library().clone()); test.add_event_handler(FALCON_DIV, malicious_falcon_div); @@ -442,9 +485,9 @@ fn test_mod_12289_rejects_forged_addition_overflow() { expect_exec_error_matches!( test, ExecutionError::OperationError { - err: OperationError::FailedAssertion { err_msg, .. }, + err: OperationError::NotU32Values { values }, .. - } if err_msg.as_deref() == Some("comparison failed: addition overflow") + } if values.iter().any(|value| value.as_canonical_u64() == Felt::ORDER_U64 - 1) ); } @@ -467,8 +510,12 @@ fn falcon_prove_verify() { host.register_handler(EVENT_FALCON_SIG_TO_STACK, Arc::new(push_falcon_signature)) .unwrap(); - let trace = execute_sync(&program, stack_inputs, advice_inputs, &mut host, Default::default()) - .expect("failed to execute"); + let trace_inputs = + FastProcessor::new_with_options(stack_inputs, advice_inputs, Default::default()) + .expect("processor advice inputs should fit advice map limits") + .execute_trace_inputs_sync(&program, &mut host) + .expect("failed to execute"); + let trace = miden_processor::trace::build_trace(trace_inputs).expect("failed to build trace"); trace.check_constraints(); } @@ -491,7 +538,7 @@ fn generate_test( let pk: Word = sk.public_key().to_commitment(); let sk_bytes = sk.to_bytes(); - let to_adv_map = sk_bytes.iter().map(|a| Felt::new(*a as u64)).collect::>(); + let to_adv_map = sk_bytes.iter().map(|a| Felt::new_unchecked(*a as u64)).collect::>(); let advice_map: Vec<(Word, Vec)> = vec![(pk, to_adv_map)]; @@ -506,10 +553,10 @@ fn generate_test( // ================================================================================================ /// Creates random coefficients of a polynomial in the range (0..M) using the given RNG. -fn random_coefficients_with_rng(rng: &mut R) -> Vec { +fn random_coefficients_with_rng(rng: &mut R) -> Vec { let mut res = Vec::new(); for _i in 0..N { - res.push(Felt::new(rng.random_range(0..M))) + res.push(Felt::new_unchecked(rng.random_range(0..M))) } res } @@ -551,21 +598,21 @@ fn generate_data_probabilistic_product_test( to_elements(h.clone()) }; - polynomials.extend(to_elements(s2.clone())); - polynomials.extend(pi.iter().map(|a| Felt::new(*a))); + polynomials.extend(to_elements(s2)); + polynomials.extend(pi.iter().map(|a| Felt::new_unchecked(*a))); // get the challenge point and push it to the advice stack - // Push tau1 first, then tau0, so adv_push.2 produces _le format [tau0, tau1, ...] directly + // Two sequential `adv_push` ops will place tau0 on top, tau1 at position 1. let digest_polynomials = Poseidon2::hash_elements(&polynomials[..]); - let challenge = (digest_polynomials[0], digest_polynomials[1]); + let tau0 = digest_polynomials[0]; + let tau1 = digest_polynomials[1]; let mut builder = AdviceStackBuilder::new(); - builder.push_element(challenge.1); - builder.push_element(challenge.0); + builder.push_for_adv_push(&[tau0, tau1]); builder.push_elements(polynomials.iter().copied()); let advice_stack = builder.build_vec_u64(); // compute hash of h and place it on the stack. - let h_hash = Poseidon2::hash_elements(&to_elements(h.clone())); + let h_hash = Poseidon2::hash_elements(&to_elements(h)); let operand_stack = stack_from_words(&[h_hash]); (operand_stack, advice_stack) @@ -576,5 +623,5 @@ fn generate_data_probabilistic_product_test( /// This matches `stack![]` semantics: `stack_from_words(&[A, B])` results in stack `[A, B, ...]` /// with A at position 0 (top). fn stack_from_words(words: &[Word]) -> Vec { - words.iter().flat_map(|w| w.iter().map(|f| f.as_canonical_u64())).collect() + words.iter().flat_map(|w| w.iter().map(Felt::as_canonical_u64)).collect() } diff --git a/crates/lib/core/tests/crypto/keccak256.rs b/crates/lib/core/tests/crypto/keccak256.rs index c8ae8734ae..8f896515a8 100644 --- a/crates/lib/core/tests/crypto/keccak256.rs +++ b/crates/lib/core/tests/crypto/keccak256.rs @@ -2,7 +2,8 @@ //! //! Verifies that: //! - Raw event handlers correctly compute Keccak256 and populate advice provider -//! - MASM wrappers correctly return commitment and digest on stack +//! - Public MASM wrappers correctly return the digest and log deferred requests +//! - Private implementation helpers return the expected commitment and tag //! - Both memory and digest merge operations work correctly //! - Various input sizes and edge cases are handled properly @@ -74,12 +75,12 @@ fn test_keccak_handler(input_u8: &[u8]) { let test = build_debug_test!(source, &[]); - let output = test.execute().unwrap(); + let (output, _) = test.execute_for_output().unwrap(); - let advice_stack = output.advice_provider().stack(); + let advice_stack = output.advice.stack(); assert_eq!(advice_stack, preimage.digest().as_ref()); - let deferred = output.advice_provider().precompile_requests().to_vec(); + let deferred = output.advice.precompile_requests().to_vec(); assert_eq!(deferred.len(), 1, "advice deferred must contain one entry"); let precompile_data = &deferred[0]; @@ -98,12 +99,10 @@ fn test_keccak_hash_bytes_impl(input_u8: &[u8]) { let input_felts = preimage.as_felts(); let memory_stores_source = masm_store_felts(&input_felts, INPUT_MEMORY_ADDR); - let source = format!( - r#" - use miden::core::sys - use miden::core::crypto::hashes::keccak256 - - begin + let source = private_proc_harness( + include_str!("../../asm/crypto/hashes/keccak256.masm"), + format!( + r#" # Store packed u32 values in memory {memory_stores_source} @@ -111,19 +110,19 @@ fn test_keccak_hash_bytes_impl(input_u8: &[u8]) { push.{len_bytes}.{INPUT_MEMORY_ADDR} # => [ptr, len_bytes] - exec.keccak256::hash_bytes_impl + exec.hash_bytes_impl # => [COMM, TAG, DIGEST_U32[8]] exec.sys::truncate_stack - end "#, + ), ); let test = build_debug_test!(source, &[]); - let output = test.execute().unwrap(); + let (output, _) = test.execute_for_output().unwrap(); - let stack = output.stack_outputs(); + let stack = output.stack; let commitment = stack.get_word(0).unwrap(); let tag = stack.get_word(4).unwrap(); let precompile_commitment = PrecompileCommitment::new(tag, commitment); @@ -134,13 +133,13 @@ fn test_keccak_hash_bytes_impl(input_u8: &[u8]) { let digest: [Felt; 8] = array::from_fn(|i| stack.get_element(8 + i).unwrap()); assert_eq!(&digest, preimage.digest().as_ref(), "output digest does not match"); - let deferred = output.advice_provider().precompile_requests().to_vec(); + let deferred = output.advice.precompile_requests().to_vec(); assert_eq!(deferred.len(), 1, "expected a single deferred request"); assert_eq!(deferred[0].event_id(), KECCAK_HASH_BYTES_EVENT_NAME.to_event_id()); assert_eq!(deferred[0].calldata(), preimage.as_ref()); assert_eq!(deferred[0], preimage.into()); - let advice_stack = output.advice_provider().stack(); + let advice_stack = output.advice.stack(); assert!(advice_stack.is_empty(), "advice stack should be empty after hash_bytes_impl"); } @@ -350,8 +349,13 @@ fn run_keccak_with_max_hash_len( let options = ExecutionOptions::default().with_max_hash_len_bytes(max_hash_len_bytes); let processor = - FastProcessor::new_with_options(StackInputs::default(), AdviceInputs::default(), options); + FastProcessor::new_with_options(StackInputs::default(), AdviceInputs::default(), options) + .map_err(ExecutionError::advice_error_no_context)?; processor.execute_sync(&program, &mut host)?; Ok(()) } + +fn private_proc_harness(module_source: &str, body: impl AsRef) -> String { + format!("{}\n\nbegin\n{}\nend", module_source.replace("pub proc", "proc"), body.as_ref()) +} diff --git a/crates/lib/core/tests/crypto/sha256.rs b/crates/lib/core/tests/crypto/sha256.rs index 0ac2cee9a3..b52052deb6 100644 --- a/crates/lib/core/tests/crypto/sha256.rs +++ b/crates/lib/core/tests/crypto/sha256.rs @@ -1,10 +1,26 @@ use miden_air::Serializable; use miden_crypto::hash::sha2::Sha256; +use miden_processor::{ExecutionError, operation::OperationError}; use miden_utils_testing::{ - Felt, IntoBytes, group_slice_elements, push_inputs, + Felt, IntoBytes, Test, group_slice_elements, push_inputs, rand::{rand_array, rand_value, rand_vector}, }; +const NON_U32_WORD: u64 = u32::MAX as u64 + 2; +const INVALID_SHA256_MESSAGE_WORD: &str = "invalid sha256 message word"; +const SHA256_HASH_SOURCE: &str = " + use miden::core::crypto::hashes::sha256 + + begin + exec.sha256::hash + end"; +const SHA256_MERGE_SOURCE: &str = " + use miden::core::crypto::hashes::sha256 + + begin + exec.sha256::merge + end"; + #[test] fn sha256_hash_bytes() { let length_in_bytes = rand_value::() & 1023; // length: 0-1023 @@ -73,13 +89,6 @@ fn sha256_hash_bytes() { #[test] fn sha256_2_to_1_hash() { - let source = " - use miden::core::crypto::hashes::sha256 - - begin - exec.sha256::merge - end"; - let input0 = rand_array::().into_bytes(); let input1 = rand_array::().into_bytes(); @@ -98,18 +107,11 @@ fn sha256_2_to_1_hash() { .map(|&bytes| u32::from_be_bytes(bytes) as u64) .collect(); - build_test!(source, &ifelts).expect_stack(&ofelts); + build_test!(SHA256_MERGE_SOURCE, &ifelts).expect_stack(&ofelts); } #[test] fn sha256_1_to_1_hash() { - let source = " - use miden::core::crypto::hashes::sha256 - - begin - exec.sha256::hash - end"; - let ibytes = rand_array::().into_bytes(); let ifelts: Vec = group_slice_elements::(&ibytes) .iter() @@ -122,5 +124,53 @@ fn sha256_1_to_1_hash() { .map(|&bytes| u32::from_be_bytes(bytes) as u64) .collect(); - build_test!(source, &ifelts).expect_stack(&ofelts); + build_test!(SHA256_HASH_SOURCE, &ifelts).expect_stack(&ofelts); +} + +#[test] +fn sha256_hash_rejects_non_u32_message_word() { + let mut input_words = vec![0; 8]; + input_words[1] = NON_U32_WORD; + + expect_non_u32_execution_error(build_test!(SHA256_HASH_SOURCE, &input_words)); +} + +#[test] +fn sha256_merge_rejects_non_u32_message_word() { + let mut input_words = vec![0; 16]; + input_words[1] = NON_U32_WORD; + + expect_non_u32_execution_error(build_test!(SHA256_MERGE_SOURCE, &input_words)); +} + +#[test] +fn sha256_hash_bytes_rejects_non_u32_memory_word() { + let source = format!( + " + use miden::core::crypto::hashes::sha256 + + begin + push.0.0.{NON_U32_WORD}.0 mem_storew_be.10000 dropw + + push.32.10000 + exec.sha256::hash_bytes + end" + ); + + expect_non_u32_execution_error(build_test!(source, &[])); +} + +fn expect_non_u32_execution_error(test: Test) { + let err = test.execute().expect_err("expected non-u32 SHA256 input to fail"); + match err { + ExecutionError::OperationError { + err: OperationError::U32AssertionFailed { err_msg, invalid_values, .. }, + .. + } => assert!( + err_msg.as_deref() == Some(INVALID_SHA256_MESSAGE_WORD) + && invalid_values.iter().any(|value| value.as_canonical_u64() == NON_U32_WORD), + "expected SHA256 message word assertion for {NON_U32_WORD}, got message {err_msg:?} and values {invalid_values:?}" + ), + err => panic!("expected SHA256 message word assertion, got {err:?}"), + } } diff --git a/crates/lib/core/tests/crypto/sha512.rs b/crates/lib/core/tests/crypto/sha512.rs index 498fb5f268..804db8631c 100644 --- a/crates/lib/core/tests/crypto/sha512.rs +++ b/crates/lib/core/tests/crypto/sha512.rs @@ -2,7 +2,8 @@ //! //! Validates that: //! - Raw event handlers correctly compute SHA512 and populate advice provider -//! - MASM wrapper returns commitment, tag, and digest on the stack +//! - Public MASM wrapper returns the digest and logs deferred requests +//! - Private implementation helper returns the expected commitment and tag //! - Various input lengths (including empty) are handled correctly use miden_core::{ @@ -56,12 +57,12 @@ fn test_sha512_handler(bytes: &[u8]) { ); let test = build_debug_test!(source, &[]); - let output = test.execute().unwrap(); + let (output, _) = test.execute_for_output().unwrap(); - let advice_stack: Vec<_> = output.advice_provider().stack().to_vec(); + let advice_stack: Vec<_> = output.advice.stack().to_vec(); assert_eq!(advice_stack, preimage.digest().as_ref()); - let deferred = output.advice_provider().precompile_requests().to_vec(); + let deferred = output.advice.precompile_requests().to_vec(); assert_eq!(deferred.len(), 1); let request = &deferred[0]; assert_eq!(request.calldata(), preimage.as_ref()); @@ -73,30 +74,28 @@ fn test_sha512_hash_memory_impl(bytes: &[u8]) { let input_felts = preimage.as_felts(); let memory_stores = masm_store_felts(&input_felts, INPUT_MEMORY_ADDR); - let source = format!( - r#" - use miden::core::sys - use miden::core::crypto::hashes::sha512 - - begin + let source = private_proc_harness( + include_str!("../../asm/crypto/hashes/sha512.masm"), + format!( + r#" {memory_stores} push.{len_bytes}.{INPUT_MEMORY_ADDR} - exec.sha512::hash_bytes_impl + exec.hash_bytes_impl exec.sys::truncate_stack - end - "# + "# + ), ); let test = build_debug_test!(source, &[]); - let output = test.execute().unwrap(); - let stack = output.stack_outputs(); + let (output, _) = test.execute_for_output().unwrap(); + let stack = &output.stack; // we cannot check the digest since it overflows the stack. // we check it in test_sha512_hash_memory - let deferred = output.advice_provider().precompile_requests().to_vec(); + let deferred = output.advice.precompile_requests().to_vec(); assert_eq!(deferred.len(), 1); let request = &deferred[0]; assert_eq!(request.event_id(), SHA512_HASH_BYTES_EVENT_NAME.to_event_id()); @@ -111,7 +110,7 @@ fn test_sha512_hash_memory_impl(bytes: &[u8]) { assert_eq!(precompile_commitment, verifier_commitment, "commitment mismatch"); assert!( - output.advice_provider().stack().is_empty(), + output.advice.stack().is_empty(), "advice stack must be empty after hash_memory_impl" ); } @@ -234,8 +233,13 @@ fn run_sha512_with_max_hash_len( let options = ExecutionOptions::default().with_max_hash_len_bytes(max_hash_len_bytes); let processor = - FastProcessor::new_with_options(StackInputs::default(), AdviceInputs::default(), options); + FastProcessor::new_with_options(StackInputs::default(), AdviceInputs::default(), options) + .map_err(ExecutionError::advice_error_no_context)?; processor.execute_sync(&program, &mut host)?; Ok(()) } + +fn private_proc_harness(module_source: &str, body: impl AsRef) -> String { + format!("{}\n\nbegin\n{}\nend", module_source.replace("pub proc", "proc"), body.as_ref()) +} diff --git a/crates/lib/core/tests/main.rs b/crates/lib/core/tests/main.rs index 4ff79520b9..5af051dfd1 100644 --- a/crates/lib/core/tests/main.rs +++ b/crates/lib/core/tests/main.rs @@ -5,11 +5,9 @@ extern crate alloc; macro_rules! build_test { ($($params:tt)+) => {{ let core_lib = miden_core_lib::CoreLibrary::default(); - let mut test = miden_utils_testing::build_test_by_mode!(false, $($params)+); - test.libraries.push(core_lib.library().clone()); - test.add_event_handlers(core_lib.handlers()); - - test + miden_utils_testing::build_test_by_mode!(false, $($params)+) + .with_library(core_lib.library().clone()) + .with_event_handlers(core_lib.handlers()) }} } @@ -18,11 +16,9 @@ macro_rules! build_test { macro_rules! build_debug_test { ($($params:tt)+) => {{ let core_lib = miden_core_lib::CoreLibrary::default(); - let mut test = miden_utils_testing::build_test_by_mode!(true, $($params)+); - test.libraries.push(core_lib.library().clone()); - test.add_event_handlers(core_lib.handlers()); - - test + miden_utils_testing::build_test_by_mode!(true, $($params)+) + .with_library(core_lib.library().clone()) + .with_event_handlers(core_lib.handlers()) }} } @@ -73,6 +69,41 @@ macro_rules! expect_assert_error_message { }; } +#[test] +fn core_library_does_not_export_precompile_impl_helpers() { + use miden_assembly::Path; + use miden_core_lib::CoreLibrary; + + let core_lib = CoreLibrary::default(); + let library = core_lib.library(); + + let public_paths = [ + "::miden::core::crypto::hashes::keccak256::hash_bytes", + "::miden::core::crypto::hashes::sha512::hash_bytes", + "::miden::core::crypto::dsa::ecdsa_k256_keccak::verify_prehash", + "::miden::core::crypto::dsa::eddsa_ed25519::verify_prehash", + ]; + for path in public_paths { + assert!( + library.get_procedure_root_by_path(Path::new(path)).is_some(), + "expected public wrapper to be exported: {path}", + ); + } + + let internal_paths = [ + "::miden::core::crypto::hashes::keccak256::hash_bytes_impl", + "::miden::core::crypto::hashes::sha512::hash_bytes_impl", + "::miden::core::crypto::dsa::ecdsa_k256_keccak::verify_prehash_impl", + "::miden::core::crypto::dsa::eddsa_ed25519::verify_prehash_impl", + ]; + for path in internal_paths { + assert!( + library.get_procedure_root_by_path(Path::new(path)).is_none(), + "internal precompile helper must not be exported: {path}", + ); + } +} + mod collections; mod crypto; mod helpers; @@ -83,6 +114,4 @@ mod stark_asserts; mod sys; mod word; -// These tests are disabled until the recursive verifier is updated to work with Plonky3 proofs -// mod pcs; -// mod stark; +mod stark; diff --git a/crates/lib/core/tests/mast_forest_merge.rs b/crates/lib/core/tests/mast_forest_merge.rs index d5c569ad7c..8fef5d25f3 100644 --- a/crates/lib/core/tests/mast_forest_merge.rs +++ b/crates/lib/core/tests/mast_forest_merge.rs @@ -75,7 +75,7 @@ fn test_core_lib_serialization_roundtrip() { for (idx, (orig_node, deser_node)) in original_forest.nodes().iter().zip(deserialized_forest.nodes()).enumerate() { - assert_eq!(orig_node.digest(), deser_node.digest(), "Node {} digest mismatch", idx); + assert_eq!(orig_node.digest(), deser_node.digest(), "Node {idx} digest mismatch"); // For basic blocks, verify OpBatch structure is preserved if let (MastNode::Block(orig_block), MastNode::Block(deser_block)) = (orig_node, deser_node) @@ -83,9 +83,20 @@ fn test_core_lib_serialization_roundtrip() { assert_eq!( orig_block.op_batches(), deser_block.op_batches(), - "Node {} OpBatch structure mismatch", - idx + "Node {idx} OpBatch structure mismatch" ); } } } + +/// Tests that stripped size hint matches the serialized length for the core library. +#[test] +fn test_core_lib_stripped_size_hint() { + let std_lib = miden_core_lib::CoreLibrary::default(); + let forest = std_lib.mast_forest().as_ref(); + + let mut stripped_bytes = Vec::new(); + forest.write_stripped(&mut stripped_bytes); + + assert_eq!(forest.stripped_size_hint(), stripped_bytes.len()); +} diff --git a/crates/lib/core/tests/math/u128_mod.rs b/crates/lib/core/tests/math/u128_mod.rs index bc027f841e..0b6993a2b8 100644 --- a/crates/lib/core/tests/math/u128_mod.rs +++ b/crates/lib/core/tests/math/u128_mod.rs @@ -45,7 +45,7 @@ fn test_u128_op_stack_preservation(op: &str, a: u128, b: u128, expected_len: usi let stack_value = output.stack_outputs().get_element(expected_len).unwrap(); assert_eq!( stack_value, - Felt::new(sentinel), + Felt::new_unchecked(sentinel), "Stack preservation failed for {op}: sentinel at position {expected_len} was corrupted" ); } @@ -782,10 +782,14 @@ fn shr_stack_padding_k1() { // Verify the result is correct and sentinels do not appear in the output let stack = result.stack_outputs(); - assert_eq!(stack.get_element(0).unwrap(), Felt::new(c0), "c0 mismatch"); - assert_eq!(stack.get_element(1).unwrap(), Felt::new(c1), "c1 mismatch"); - assert_eq!(stack.get_element(2).unwrap(), Felt::new(c2), "c2 mismatch"); - assert_eq!(stack.get_element(3).unwrap(), Felt::new(0), "c3 should be 0, not a sentinel"); + assert_eq!(stack.get_element(0).unwrap(), Felt::new_unchecked(c0), "c0 mismatch"); + assert_eq!(stack.get_element(1).unwrap(), Felt::new_unchecked(c1), "c1 mismatch"); + assert_eq!(stack.get_element(2).unwrap(), Felt::new_unchecked(c2), "c2 mismatch"); + assert_eq!( + stack.get_element(3).unwrap(), + Felt::new_unchecked(0), + "c3 should be 0, not a sentinel" + ); } #[test] @@ -811,10 +815,18 @@ fn shr_stack_padding_k2() { let result = test.execute().unwrap(); let stack = result.stack_outputs(); - assert_eq!(stack.get_element(0).unwrap(), Felt::new(c0), "c0 mismatch"); - assert_eq!(stack.get_element(1).unwrap(), Felt::new(c1), "c1 mismatch"); - assert_eq!(stack.get_element(2).unwrap(), Felt::new(0), "c2 should be 0, not a sentinel"); - assert_eq!(stack.get_element(3).unwrap(), Felt::new(0), "c3 should be 0, not a sentinel"); + assert_eq!(stack.get_element(0).unwrap(), Felt::new_unchecked(c0), "c0 mismatch"); + assert_eq!(stack.get_element(1).unwrap(), Felt::new_unchecked(c1), "c1 mismatch"); + assert_eq!( + stack.get_element(2).unwrap(), + Felt::new_unchecked(0), + "c2 should be 0, not a sentinel" + ); + assert_eq!( + stack.get_element(3).unwrap(), + Felt::new_unchecked(0), + "c3 should be 0, not a sentinel" + ); } #[test] @@ -840,10 +852,22 @@ fn shr_stack_padding_k3() { let result = test.execute().unwrap(); let stack = result.stack_outputs(); - assert_eq!(stack.get_element(0).unwrap(), Felt::new(c0), "c0 mismatch"); - assert_eq!(stack.get_element(1).unwrap(), Felt::new(0), "c1 should be 0, not a sentinel"); - assert_eq!(stack.get_element(2).unwrap(), Felt::new(0), "c2 should be 0, not a sentinel"); - assert_eq!(stack.get_element(3).unwrap(), Felt::new(0), "c3 should be 0, not a sentinel"); + assert_eq!(stack.get_element(0).unwrap(), Felt::new_unchecked(c0), "c0 mismatch"); + assert_eq!( + stack.get_element(1).unwrap(), + Felt::new_unchecked(0), + "c1 should be 0, not a sentinel" + ); + assert_eq!( + stack.get_element(2).unwrap(), + Felt::new_unchecked(0), + "c2 should be 0, not a sentinel" + ); + assert_eq!( + stack.get_element(3).unwrap(), + Felt::new_unchecked(0), + "c3 should be 0, not a sentinel" + ); } /// Test shr with non-zero m values and sentinels to verify cross-limb bit transfer @@ -870,10 +894,14 @@ fn shr_stack_padding_nonzero_m() { let result = test.execute().unwrap(); let stack = result.stack_outputs(); - assert_eq!(stack.get_element(0).unwrap(), Felt::new(c0), "c0 mismatch"); - assert_eq!(stack.get_element(1).unwrap(), Felt::new(c1), "c1 mismatch"); - assert_eq!(stack.get_element(2).unwrap(), Felt::new(c2), "c2 mismatch"); - assert_eq!(stack.get_element(3).unwrap(), Felt::new(0), "c3 should be 0, not a sentinel"); + assert_eq!(stack.get_element(0).unwrap(), Felt::new_unchecked(c0), "c0 mismatch"); + assert_eq!(stack.get_element(1).unwrap(), Felt::new_unchecked(c1), "c1 mismatch"); + assert_eq!(stack.get_element(2).unwrap(), Felt::new_unchecked(c2), "c2 mismatch"); + assert_eq!( + stack.get_element(3).unwrap(), + Felt::new_unchecked(0), + "c3 should be 0, not a sentinel" + ); } /// Test shr with boundary shift values. diff --git a/crates/lib/core/tests/math/u256_mod.rs b/crates/lib/core/tests/math/u256_mod.rs index 3bd3f5937e..42fa102ba5 100644 --- a/crates/lib/core/tests/math/u256_mod.rs +++ b/crates/lib/core/tests/math/u256_mod.rs @@ -1,44 +1,201 @@ -use miden_utils_testing::{proptest::prelude::*, rand::rand_vector}; -use num_bigint::BigUint; +use core::ops::{BitAnd, BitOr, BitXor}; + +use miden_utils_testing::proptest::prelude::*; // MULTIPLICATION // ================================================================================================ #[test] -fn mul_unsafe() { - let a = rand_u256(); - let b = rand_u256(); +fn wrapping_mul_regression_vectors() { + for (a, b) in regression_pairs() { + assert_wrapping_mul(a, b); + } +} + +#[test] +fn wrapping_mul_edge_cases() { + let zero = U256::ZERO; + let one = U256::from_le_u32_limbs([1, 0, 0, 0, 0, 0, 0, 0]); + let max = U256::from_le_u32_limbs([u32::MAX; 8]); + let lo_max = U256::from_le_u32_limbs([u32::MAX, u32::MAX, u32::MAX, u32::MAX, 0, 0, 0, 0]); + let hi_max = U256::from_le_u32_limbs([0, 0, 0, 0, u32::MAX, u32::MAX, u32::MAX, u32::MAX]); + let single_lo = U256::from_le_u32_limbs([u32::MAX, 0, 0, 0, 0, 0, 0, 0]); + let mixed = U256::from_le_u32_limbs([ + 0xdead_beef, + 0xcafe_f00d, + 0x1234_5678, + 0x0fed_cba9, + 0x8000_0000, + 0x7fff_ffff, + 0xaaaa_5555, + 0x5555_aaaa, + ]); + + // identity + assert_wrapping_mul(mixed, one); + assert_wrapping_mul(one, mixed); + // squaring (diagonal limb products) + assert_wrapping_mul(zero, zero); + assert_wrapping_mul(one, one); + assert_wrapping_mul(max, max); + assert_wrapping_mul(mixed, mixed); + assert_wrapping_mul(lo_max, lo_max); + assert_wrapping_mul(hi_max, hi_max); + + // halves crossed + assert_wrapping_mul(lo_max, hi_max); + + // single-limb operand stresses the row-0 special path under maximal carries + assert_wrapping_mul(single_lo, max); + assert_wrapping_mul(max, single_lo); +} + +#[test] +fn wrapping_mul_consumed_result_restores_min_stack_depth() { let source = " use miden::core::math::u256 begin exec.u256::wrapping_mul + dropw dropw + sdepth push.16 assert_eq end"; - // Stack layout: [b_lo..b_hi, a_lo..a_hi] with b's low limb on top (LE format) - let operands = [u256_to_le_limbs(&b), u256_to_le_limbs(&a)].concat(); + let a = U256::from_le_u32_limbs([11, 22, 33, 44, 55, 66, 77, 88]); + let b = U256::from_le_u32_limbs([101, 202, 303, 404, 505, 606, 707, 808]); + let operands = [b.to_le_limbs(), a.to_le_limbs()].concat(); - // Result in LE format (low limb on top) - let result = u256_to_le_limbs(&((a * b) & max_u256())); + build_test!(source, &operands).execute().unwrap(); +} - build_test!(source, &operands).expect_stack(&result); +#[test] +fn wrapping_mul_preserves_caller_stack() { + let a = [11, 22, 33, 44, 55, 66, 77, 88]; + let b = [101, 202, 303, 404, 505, 606, 707, 808]; + let sentinels = [ + 9001, 9002, 9003, 9004, 9005, 9006, 9007, 9008, 9009, 9010, 9011, 9012, 9013, 9014, 9015, + 9016, + ]; + + let source = format!( + " + use miden::core::math::u256 + begin + push.{sentinels} + push.{a} + push.{b} + exec.u256::wrapping_mul + dropw dropw + {assert_sentinels} + end", + sentinels = push_masm_values(&sentinels), + a = push_masm_values(&a), + b = push_masm_values(&b), + assert_sentinels = assert_stack_words(&sentinels), + ); + + build_test!(&source).execute().unwrap(); +} + +#[test] +fn arithmetic_regression_vectors() { + for (a, b) in regression_pairs() { + assert_binary_u256_op("wrapping_add", a, b, &a.wrapping_add(b).to_le_limbs()); + + let (overflow, sum) = a.overflowing_add(b); + let mut expected = vec![overflow]; + expected.extend(sum.to_le_limbs()); + assert_binary_u256_op("overflowing_add", a, b, &expected); + + let (sum, overflow) = a.widening_add(b); + let mut expected = sum.to_le_limbs(); + expected.push(overflow); + assert_binary_u256_op("widening_add", a, b, &expected); + + assert_binary_u256_op("wrapping_sub", a, b, &a.wrapping_sub(b).to_le_limbs()); + + let (underflow, diff) = a.overflowing_sub(b); + let mut expected = vec![underflow]; + expected.extend(diff.to_le_limbs()); + assert_binary_u256_op("overflowing_sub", a, b, &expected); + } +} + +#[test] +fn bitwise_and_comparison_regression_vectors() { + for (a, b) in regression_pairs() { + assert_binary_u256_op("and", a, b, &(a & b).to_le_limbs()); + assert_binary_u256_op("or", a, b, &(a | b).to_le_limbs()); + assert_binary_u256_op("xor", a, b, &(a ^ b).to_le_limbs()); + assert_binary_u256_op("eq", a, b, &[a.eq_u64(b)]); + } + + for value in regression_values() { + assert_unary_u256_op("eqz", value, &[value.eqz()]); + } } +// ADDITION +// ================================================================================================ + #[test] -fn wrapping_mul_documented_stack_contract() { +fn overflowing_add_edge_cases() { + // Carry-propagation cases that the regression-vector pairs do not cover, exercising single- + // limb carries, cross-word carries, and the 2^256 wrap point. let source = " use miden::core::math::u256 begin - exec.u256::wrapping_mul - sdepth push.16 assert_eq + exec.u256::overflowing_add end"; - let a = u256_from_limbs([11, 22, 33, 44, 55, 66, 77, 88]); - let b = u256_from_limbs([101, 202, 303, 404, 505, 606, 707, 808]); - let operands = [u256_to_le_limbs(&b), u256_to_le_limbs(&a)].concat(); - let expected = u256_to_le_limbs(&((a * b) & max_u256())); + let max = U256::from_le_u32_limbs([u32::MAX; 8]); + let one = U256::from_le_u32_limbs([1, 0, 0, 0, 0, 0, 0, 0]); + let one_in_limb1 = U256::from_le_u32_limbs([0, 1, 0, 0, 0, 0, 0, 0]); + let high_limb_max = U256::from_le_u32_limbs([u32::MAX, 0, 0, 0, 0, 0, 0, 0]); + let lo_word_max = U256::from_le_u32_limbs([u32::MAX, u32::MAX, u32::MAX, u32::MAX, 0, 0, 0, 0]); + + let cases = [ + // a + b with no overflow + (U256::ZERO, U256::ZERO), + (U256::ZERO, one), + // single-limb carry into limb 1 + (high_limb_max, one), + // carry propagating through several limbs + (U256::from_le_u32_limbs([u32::MAX, u32::MAX, u32::MAX, 0, 0, 0, 0, 0]), one), + // carry crossing the lo/hi 128-bit boundary + (lo_word_max, one), + // carry propagates through the bottom 7 limbs and is absorbed by the top limb (no + // overflow) + ( + U256::from_le_u32_limbs([ + u32::MAX, + u32::MAX, + u32::MAX, + u32::MAX, + u32::MAX, + u32::MAX, + u32::MAX, + 0, + ]), + one, + ), + // overflow at the top: max + 1 = 0 with overflow=1 + (max, one), + // overflow at the top via limb 1 increment + (max, one_in_limb1), + // saturated max + max = max-1 with overflow=1 + (max, max), + // commutativity sanity: pseudo-random pair both orderings + pseudo_random_pair(), + ]; - build_test!(source, &operands).expect_stack(&expected); + for (a, b) in cases { + let (overflow, sum) = a.overflowing_add(b); + let operands = [b.to_le_limbs(), a.to_le_limbs()].concat(); + let mut expected = vec![overflow]; + expected.extend(sum.to_le_limbs()); + build_test!(source, &operands).expect_stack(&expected); + } } // SUBTRACTION @@ -55,24 +212,24 @@ fn overflowing_sub_edge_cases() { let cases = [ // a = 0, b = 1 -> underflow, result = 2^256 - 1 ( - u256_from_limbs([0, 0, 0, 0, 0, 0, 0, 0]), - u256_from_limbs([1, 0, 0, 0, 0, 0, 0, 0]), + U256::from_le_u32_limbs([0, 0, 0, 0, 0, 0, 0, 0]), + U256::from_le_u32_limbs([1, 0, 0, 0, 0, 0, 0, 0]), ), // a = 1<<32, b = 1 -> borrow across one limb ( - u256_from_limbs([0, 1, 0, 0, 0, 0, 0, 0]), - u256_from_limbs([1, 0, 0, 0, 0, 0, 0, 0]), + U256::from_le_u32_limbs([0, 1, 0, 0, 0, 0, 0, 0]), + U256::from_le_u32_limbs([1, 0, 0, 0, 0, 0, 0, 0]), ), // a = 1<<224, b = 1 -> borrow across all limbs ( - u256_from_limbs([0, 0, 0, 0, 0, 0, 0, 1]), - u256_from_limbs([1, 0, 0, 0, 0, 0, 0, 0]), + U256::from_le_u32_limbs([0, 0, 0, 0, 0, 0, 0, 1]), + U256::from_le_u32_limbs([1, 0, 0, 0, 0, 0, 0, 0]), ), ]; for (a, b) in cases { let (underflow, result) = expected_sub(&a, &b); - let operands = [u256_to_le_limbs(&b), u256_to_le_limbs(&a)].concat(); + let operands = [b.to_le_limbs(), a.to_le_limbs()].concat(); let mut expected = vec![underflow]; expected.extend(result); build_test!(source, &operands).expect_stack(&expected); @@ -87,74 +244,448 @@ fn wrapping_sub_underflow() { exec.u256::wrapping_sub end"; - let a = u256_from_limbs([0, 0, 0, 0, 0, 0, 0, 0]); - let b = u256_from_limbs([1, 0, 0, 0, 0, 0, 0, 0]); + let a = U256::from_le_u32_limbs([0, 0, 0, 0, 0, 0, 0, 0]); + let b = U256::from_le_u32_limbs([1, 0, 0, 0, 0, 0, 0, 0]); let (_, result) = expected_sub(&a, &b); - let operands = [u256_to_le_limbs(&b), u256_to_le_limbs(&a)].concat(); + let operands = [b.to_le_limbs(), a.to_le_limbs()].concat(); build_test!(source, &operands).expect_stack(&result); } +// EQUALITY +// ================================================================================================ + +#[test] +fn eq_edge_cases() { + // Cases beyond the regression-pair coverage: equality at zero/max, and inequality isolated to + // a single limb at each position (lo word and hi word, plus the 32-bit boundary). + let source = " + use miden::core::math::u256 + begin + exec.u256::eq + end"; + + let max = U256::from_le_u32_limbs([u32::MAX; 8]); + + // (a, b, expected_eq) + let cases: [(U256, U256, u64); 11] = [ + (U256::ZERO, U256::ZERO, 1), + (max, max, 1), + (U256::from_bit(0), U256::from_bit(0), 1), + (U256::from_bit(255), U256::from_bit(255), 1), + // differ in exactly one limb, varying the position to exercise both eqw comparisons + (U256::ZERO, U256::from_le_u32_limbs([1, 0, 0, 0, 0, 0, 0, 0]), 0), + (U256::ZERO, U256::from_le_u32_limbs([0, 1, 0, 0, 0, 0, 0, 0]), 0), + (U256::ZERO, U256::from_le_u32_limbs([0, 0, 0, 1, 0, 0, 0, 0]), 0), + (U256::ZERO, U256::from_le_u32_limbs([0, 0, 0, 0, 1, 0, 0, 0]), 0), + (U256::ZERO, U256::from_le_u32_limbs([0, 0, 0, 0, 0, 0, 0, 1]), 0), + // full match in lo word, mismatch in hi word + ( + U256::from_le_u32_limbs([1, 2, 3, 4, 5, 6, 7, 8]), + U256::from_le_u32_limbs([1, 2, 3, 4, 5, 6, 7, 9]), + 0, + ), + // full match in hi word, mismatch in lo word + ( + U256::from_le_u32_limbs([1, 2, 3, 4, 5, 6, 7, 8]), + U256::from_le_u32_limbs([1, 2, 3, 5, 5, 6, 7, 8]), + 0, + ), + ]; + + for (a, b, expected_eq) in cases { + let operands = [b.to_le_limbs(), a.to_le_limbs()].concat(); + build_test!(source, &operands).expect_stack(&[expected_eq]); + } +} + proptest! { #[test] - fn overflowing_sub_proptest(a in prop::array::uniform8(any::()), b in prop::array::uniform8(any::())) { + fn wrapping_mul_proptest( + a in prop::array::uniform8(boundary_biased_u32()), + b in prop::array::uniform8(boundary_biased_u32()), + ) { + // assert_wrapping_mul embeds an assert_eqw against the expected product inside the + // MASM program; a mismatch surfaces as a MASM execution failure. + assert_wrapping_mul(U256::from_le_u32_limbs(a), U256::from_le_u32_limbs(b)); + } + + #[test] + fn overflowing_add_proptest( + a in prop::array::uniform8(boundary_biased_u32()), + b in prop::array::uniform8(boundary_biased_u32()), + ) { + let source = " + use miden::core::math::u256 + begin + exec.u256::overflowing_add + end"; + + let a = U256::from_le_u32_limbs(a); + let b = U256::from_le_u32_limbs(b); + let (overflow, sum) = a.overflowing_add(b); + let operands = [b.to_le_limbs(), a.to_le_limbs()].concat(); + let mut expected = vec![overflow]; + expected.extend(sum.to_le_limbs()); + build_test!(source, &operands).prop_expect_stack(&expected)?; + } + + #[test] + fn wrapping_add_proptest( + a in prop::array::uniform8(boundary_biased_u32()), + b in prop::array::uniform8(boundary_biased_u32()), + ) { + let source = " + use miden::core::math::u256 + begin + exec.u256::wrapping_add + end"; + + let a = U256::from_le_u32_limbs(a); + let b = U256::from_le_u32_limbs(b); + let result = a.wrapping_add(b); + let operands = [b.to_le_limbs(), a.to_le_limbs()].concat(); + build_test!(source, &operands).prop_expect_stack(&result.to_le_limbs())?; + } + + #[test] + fn widening_add_proptest( + a in prop::array::uniform8(boundary_biased_u32()), + b in prop::array::uniform8(boundary_biased_u32()), + ) { + let source = " + use miden::core::math::u256 + begin + exec.u256::widening_add + end"; + + let a = U256::from_le_u32_limbs(a); + let b = U256::from_le_u32_limbs(b); + let (sum, overflow) = a.widening_add(b); + let operands = [b.to_le_limbs(), a.to_le_limbs()].concat(); + let mut expected = sum.to_le_limbs(); + expected.push(overflow); + build_test!(source, &operands).prop_expect_stack(&expected)?; + } + + #[test] + fn overflowing_sub_proptest( + a in prop::array::uniform8(boundary_biased_u32()), + b in prop::array::uniform8(boundary_biased_u32()), + ) { let source = " use miden::core::math::u256 begin exec.u256::overflowing_sub end"; - let a = u256_from_limbs(a); - let b = u256_from_limbs(b); + let a = U256::from_le_u32_limbs(a); + let b = U256::from_le_u32_limbs(b); let (underflow, result) = expected_sub(&a, &b); - let operands = [u256_to_le_limbs(&b), u256_to_le_limbs(&a)].concat(); + let operands = [b.to_le_limbs(), a.to_le_limbs()].concat(); let mut expected = vec![underflow]; expected.extend(result); - build_test!(source, &operands).expect_stack(&expected); + build_test!(source, &operands).prop_expect_stack(&expected)?; } #[test] - fn wrapping_sub_proptest(a in prop::array::uniform8(any::()), b in prop::array::uniform8(any::())) { + fn wrapping_sub_proptest( + a in prop::array::uniform8(boundary_biased_u32()), + b in prop::array::uniform8(boundary_biased_u32()), + ) { let source = " use miden::core::math::u256 begin exec.u256::wrapping_sub end"; - let a = u256_from_limbs(a); - let b = u256_from_limbs(b); + let a = U256::from_le_u32_limbs(a); + let b = U256::from_le_u32_limbs(b); let (_, result) = expected_sub(&a, &b); - let operands = [u256_to_le_limbs(&b), u256_to_le_limbs(&a)].concat(); - build_test!(source, &operands).expect_stack(&result); + let operands = [b.to_le_limbs(), a.to_le_limbs()].concat(); + build_test!(source, &operands).prop_expect_stack(&result)?; + } + + #[test] + fn eq_proptest( + a in prop::array::uniform8(boundary_biased_u32()), + b in prop::array::uniform8(boundary_biased_u32()), + ) { + let source = " + use miden::core::math::u256 + begin + exec.u256::eq + end"; + + let a = U256::from_le_u32_limbs(a); + let b = U256::from_le_u32_limbs(b); + let operands = [b.to_le_limbs(), a.to_le_limbs()].concat(); + build_test!(source, &operands).prop_expect_stack(&[a.eq_u64(b)])?; + } + + #[test] + fn eq_proptest_self(a in prop::array::uniform8(boundary_biased_u32())) { + // Self-equality must always hold. + let source = " + use miden::core::math::u256 + begin + exec.u256::eq + end"; + + let a = U256::from_le_u32_limbs(a); + let operands = [a.to_le_limbs(), a.to_le_limbs()].concat(); + build_test!(source, &operands).prop_expect_stack(&[1])?; } } // HELPER FUNCTIONS // ================================================================================================ -fn rand_u256() -> BigUint { - let limbs = rand_vector::(8).iter().map(|&v| v as u32).collect::>(); - BigUint::new(limbs) +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +struct U256 { + lo: u128, + hi: u128, +} + +impl U256 { + const ZERO: Self = Self { lo: 0, hi: 0 }; + const MASK32: u128 = (1u128 << 32) - 1; + + const fn new(lo: u128, hi: u128) -> Self { + Self { lo, hi } + } + + fn from_bit(bit: u32) -> Self { + match bit { + 0..=127 => Self::new(1u128 << bit, 0), + 128..=255 => Self::new(0, 1u128 << (bit - 128)), + _ => panic!("bit index out of range"), + } + } + + fn from_le_u32_limbs(limbs: [u32; 8]) -> Self { + let lo = limbs[..4] + .iter() + .enumerate() + .fold(0u128, |acc, (i, &limb)| acc | ((limb as u128) << (i * 32))); + let hi = limbs[4..] + .iter() + .enumerate() + .fold(0u128, |acc, (i, &limb)| acc | ((limb as u128) << (i * 32))); + Self::new(lo, hi) + } + + fn to_le_u32_limbs(self) -> [u32; 8] { + [ + (self.lo & Self::MASK32) as u32, + ((self.lo >> 32) & Self::MASK32) as u32, + ((self.lo >> 64) & Self::MASK32) as u32, + ((self.lo >> 96) & Self::MASK32) as u32, + (self.hi & Self::MASK32) as u32, + ((self.hi >> 32) & Self::MASK32) as u32, + ((self.hi >> 64) & Self::MASK32) as u32, + ((self.hi >> 96) & Self::MASK32) as u32, + ] + } + + fn to_le_limbs(self) -> Vec { + self.to_le_u32_limbs().into_iter().map(u64::from).collect() + } + + fn overflowing_add(self, rhs: Self) -> (u64, Self) { + let (lo, carry_lo) = self.lo.overflowing_add(rhs.lo); + let (hi_partial, carry_hi0) = self.hi.overflowing_add(rhs.hi); + let (hi, carry_hi1) = hi_partial.overflowing_add(carry_lo as u128); + (u64::from(carry_hi0 || carry_hi1), Self::new(lo, hi)) + } + + fn wrapping_add(self, rhs: Self) -> Self { + self.overflowing_add(rhs).1 + } + + fn widening_add(self, rhs: Self) -> (Self, u64) { + let (overflow, sum) = self.overflowing_add(rhs); + (sum, overflow) + } + + fn overflowing_sub(self, rhs: Self) -> (u64, Self) { + let (lo, borrow_lo) = self.lo.overflowing_sub(rhs.lo); + let (hi_partial, borrow_hi0) = self.hi.overflowing_sub(rhs.hi); + let (hi, borrow_hi1) = hi_partial.overflowing_sub(borrow_lo as u128); + (u64::from(borrow_hi0 || borrow_hi1), Self::new(lo, hi)) + } + + fn wrapping_sub(self, rhs: Self) -> Self { + self.overflowing_sub(rhs).1 + } + + fn wrapping_mul(self, rhs: Self) -> Self { + let lhs = self.to_le_u32_limbs().map(|limb| limb as u128); + let rhs = rhs.to_le_u32_limbs().map(|limb| limb as u128); + let mut result = [0u128; 8]; + + for (i, &lhs_limb) in lhs.iter().enumerate() { + let mut carry = 0u128; + for (j, &rhs_limb) in rhs.iter().enumerate().take(8 - i) { + let idx = i + j; + let accum = result[idx] + lhs_limb * rhs_limb + carry; + result[idx] = accum & Self::MASK32; + carry = accum >> 32; + } + } + + Self::from_le_u32_limbs(result.map(|limb| limb as u32)) + } + + fn eq_u64(self, rhs: Self) -> u64 { + u64::from(self == rhs) + } + + fn eqz(self) -> u64 { + u64::from(self == Self::ZERO) + } +} + +impl BitAnd for U256 { + type Output = Self; + + fn bitand(self, rhs: Self) -> Self::Output { + Self::new(self.lo & rhs.lo, self.hi & rhs.hi) + } +} + +impl BitOr for U256 { + type Output = Self; + + fn bitor(self, rhs: Self) -> Self::Output { + Self::new(self.lo | rhs.lo, self.hi | rhs.hi) + } +} + +impl BitXor for U256 { + type Output = Self; + + fn bitxor(self, rhs: Self) -> Self::Output { + Self::new(self.lo ^ rhs.lo, self.hi ^ rhs.hi) + } +} + +fn regression_values() -> Vec { + vec![ + U256::ZERO, + U256::new(u64::MAX as u128, 0), + U256::new(0, u64::MAX as u128), + U256::new(u64::MAX as u128, u64::MAX as u128), + U256::from_bit(0), + U256::from_bit(31), + U256::from_bit(32), + U256::from_bit(63), + U256::from_bit(64), + U256::from_bit(127), + U256::from_bit(128), + U256::from_bit(191), + U256::from_bit(255), + pseudo_random_pair().0, + pseudo_random_pair().1, + ] } -fn u256_from_limbs(limbs: [u32; 8]) -> BigUint { - BigUint::new(limbs.to_vec()) +fn regression_pairs() -> Vec<(U256, U256)> { + let (rand_a, rand_b) = pseudo_random_pair(); + vec![ + (U256::ZERO, U256::ZERO), + (U256::new(u64::MAX as u128, 0), U256::ZERO), + (U256::ZERO, U256::new(u64::MAX as u128, 0)), + (U256::new(u64::MAX as u128, u64::MAX as u128), U256::new(u64::MAX as u128, 0)), + (U256::from_bit(0), U256::from_bit(255)), + (U256::from_bit(64), U256::from_bit(128)), + (U256::from_bit(127), U256::from_bit(127)), + (rand_a, rand_b), + ] } -fn u256_to_le_limbs(n: &BigUint) -> Vec { - let mut limbs: Vec = n.to_u32_digits().iter().map(|&v| v as u64).collect(); - limbs.resize(8, 0); - limbs +/// Strategy that mixes 32-bit boundary values with uniformly random ones. Each variant has equal +/// probability of being sampled; the boundary cases stress carry/borrow handling and the sign-bit +/// position within a limb. +fn boundary_biased_u32() -> impl Strategy { + prop_oneof![ + Just(0u32), + Just(1u32), + Just(u32::MAX), + Just(u32::MAX - 1), + Just(0x7fffffff), + Just(0x80000000), + any::(), + ] } -fn expected_sub(a: &BigUint, b: &BigUint) -> (u64, Vec) { - let underflow = if a < b { 1 } else { 0 }; - let modulus = max_u256() + 1u32; - let diff = if a >= b { a - b } else { a + &modulus - b }; - let result = diff & max_u256(); - (underflow, u256_to_le_limbs(&result)) +fn pseudo_random_pair() -> (U256, U256) { + ( + U256::new( + 0x1234_5678_9abc_def0_1357_9bdf_2468_ace0, + 0x0fed_cba9_8765_4321_0246_8ace_1357_9bdf, + ), + U256::new( + 0xdead_beef_cafe_f00d_3141_5926_5358_9793, + 0xa5a5_5a5a_0123_4567_f0e1_d2c3_b4a5_9687, + ), + ) +} + +fn assert_binary_u256_op(op: &str, a: U256, b: U256, expected: &[u64]) { + let source = format!( + " + use miden::core::math::u256 + begin + exec.u256::{op} + end" + ); + + let operands = [b.to_le_limbs(), a.to_le_limbs()].concat(); + build_test!(&source, &operands).expect_stack(expected); +} + +fn assert_wrapping_mul(a: U256, b: U256) { + let expected = a.wrapping_mul(b).to_le_limbs(); + let source = format!( + " + use miden::core::math::u256 + begin + exec.u256::wrapping_mul + {assert_expected} + end", + assert_expected = assert_stack_words(&expected), + ); + + let operands = [b.to_le_limbs(), a.to_le_limbs()].concat(); + build_test!(&source, &operands).execute().unwrap(); +} + +fn push_masm_values(values: &[u64]) -> String { + values.iter().rev().map(u64::to_string).collect::>().join(".") +} + +fn assert_stack_words(values: &[u64]) -> String { + values + .chunks(4) + .map(|word| format!("push.{} assert_eqw", push_masm_values(word))) + .collect::>() + .join("\n ") +} + +fn assert_unary_u256_op(op: &str, value: U256, expected: &[u64]) { + let source = format!( + " + use miden::core::math::u256 + begin + exec.u256::{op} + end" + ); + + build_test!(&source, &value.to_le_limbs()).expect_stack(expected); } -fn max_u256() -> BigUint { - (BigUint::from(1u32) << 256) - 1u32 +fn expected_sub(a: &U256, b: &U256) -> (u64, Vec) { + let (underflow, result) = a.overflowing_sub(*b); + (underflow, result.to_le_limbs()) } diff --git a/crates/lib/core/tests/math/u64_mod.rs b/crates/lib/core/tests/math/u64_mod.rs index ad9aba8413..926666d180 100644 --- a/crates/lib/core/tests/math/u64_mod.rs +++ b/crates/lib/core/tests/math/u64_mod.rs @@ -4,7 +4,8 @@ use miden_core::assert_matches; use miden_core_lib::handlers::u64_div::{U64_DIV_EVENT_NAME, U64DivError}; use miden_processor::{ExecutionError, operation::OperationError}; use miden_utils_testing::{ - Felt, U32_BOUND, expect_exec_error_matches, proptest::prelude::*, rand::rand_value, stack, + Felt, PrimeField64, U32_BOUND, expect_exec_error_matches, proptest::prelude::*, + rand::rand_value, stack, }; #[test] @@ -264,6 +265,57 @@ fn widening_mul() { test.expect_stack(&[c0, c1, c2, c3]); } +#[test] +fn widening_mul_edge_cases() { + // Hand-picked values that stress limb boundaries, identity, and zero handling. The deeper + // sentinel (`5`) verifies the procedure does not pollute the stack below its inputs. + let source = " + use miden::core::math::u64 + begin + exec.u64::widening_mul + end"; + + let cases: &[(u64, u64)] = &[ + // zero on either side + (0, 0), + (0, 1), + (1, 0), + (0, u64::MAX), + (u64::MAX, 0), + // identity + (1, 1), + (1, u64::MAX), + (u64::MAX, 1), + // u32::MAX squared: largest product fitting in 64 bits + (0xffffffff, 0xffffffff), + // 2^32 boundary: smallest values where the product needs the c_mid_hi limb + (1u64 << 32, 1u64 << 32), + (1u64 << 32, (1u64 << 32) - 1), + ((1u64 << 32) - 1, 1u64 << 32), + // single-limb operands + (0xffffffff, 0xffffffff_00000000), + (0xffffffff_00000000, 0xffffffff), + (0xffffffff_00000000, 0xffffffff_00000000), + // u64::MAX squared (already covered by widening_mul, kept for completeness) + (u64::MAX, u64::MAX), + // values where individual limbs are 0 and 0xFFFFFFFF, exercising mixed-limb carries + (0xffffffff_00000000, 0x00000000_ffffffff), + (0x00000000_ffffffff, 0xffffffff_00000000), + // arbitrary mid-range values to catch generic mixing bugs + (0xdeadbeef_cafebabe, 0x0123456789abcdef), + ]; + + for &(a, b) in cases { + let c = (a as u128) * (b as u128); + let (a1, a0) = split_u64(a); + let (b1, b0) = split_u64(b); + let (c3, c2, c1, c0) = split_u128(c); + let input_stack = stack![b0, b1, a0, a1, 777]; + let test = build_test!(source, &input_stack); + test.expect_stack(&[c0, c1, c2, c3, 777]); + } +} + // COMPARISONS // ------------------------------------------------------------------------------------------------ @@ -490,7 +542,7 @@ fn advice_push_u64div() { // push a/b onto the advice stack and then move these values onto the operand stack. // Uses [b_lo, b_hi, a_lo, a_hi] from top (divisor on top, then dividend) let source = format!( - "begin emit.event(\"{U64_DIV_EVENT_NAME}\") adv_push.2 adv_push.2 movupw.2 dropw end" + "begin emit.event(\"{U64_DIV_EVENT_NAME}\") adv_push adv_push adv_push adv_push movupw.2 dropw end" ); // get two random 64-bit integers and split them into 32-bit limbs @@ -517,21 +569,21 @@ fn advice_push_u64div() { let test = build_test!(source, &input_stack); // Handler uses extend_stack_for_adv_push which reverses for proper ordering. // Advice stack (top-to-bottom): [q_hi, q_lo, r_hi, r_lo] - // First adv_push.2: pops q_hi then q_lo → [q_lo, q_hi, ...] - // Second adv_push.2: pops r_hi then r_lo → [r_lo, r_hi, q_lo, q_hi, ...] + // First adv_push adv_push: pops q_hi then q_lo → [q_lo, q_hi, ...] + // Second adv_push adv_push: pops r_hi then r_lo → [r_lo, r_hi, q_lo, q_hi, ...] let expected = [r_lo, r_hi, q_lo, q_hi, b_lo, b_hi, a_lo, a_hi]; test.expect_stack(&expected); } #[test] fn advice_push_u64div_two_pushes() { - // Test that two separate adv_push.2 calls work correctly (like the div procedure uses) - // Uses [b_lo, b_hi, a_lo, a_hi] from top (divisor on top, then dividend) + // Test that two separate adv_push adv_push calls work correctly (like the div procedure + // uses) Uses [b_lo, b_hi, a_lo, a_hi] from top (divisor on top, then dividend) let source = format!( "begin emit.event(\"{U64_DIV_EVENT_NAME}\") - adv_push.2 # first push: quotient [q_lo, q_hi] - adv_push.2 # second push: remainder [r_lo, r_hi] + adv_push adv_push # first push: quotient [q_lo, q_hi] + adv_push adv_push # second push: remainder [r_lo, r_hi] # Stack: [r_lo, r_hi, q_lo, q_hi, b_lo, b_hi, a_lo, a_hi] # Drop input: positions 4-7 movup.7 drop # a_hi @@ -557,8 +609,8 @@ fn advice_push_u64div_local_procedure() { " proc foo emit.event(\"{U64_DIV_EVENT_NAME}\") - adv_push.2 # quotient - adv_push.2 # remainder + adv_push adv_push # quotient + adv_push adv_push # remainder end begin @@ -591,8 +643,8 @@ fn advice_push_u64div_local_procedure() { let test = build_test!(source, &input_stack); // Handler uses extend_stack_for_adv_push which reverses for proper ordering. // Advice stack (top-to-bottom): [q_hi, q_lo, r_hi, r_lo] - // First adv_push.2: pops q_hi then q_lo → [q_lo, q_hi, ...] - // Second adv_push.2: pops r_hi then r_lo → [r_lo, r_hi, q_lo, q_hi, ...] + // First adv_push adv_push: pops q_hi then q_lo → [q_lo, q_hi, ...] + // Second adv_push adv_push: pops r_hi then r_lo → [r_lo, r_hi, q_lo, q_hi, ...] let expected = [r_lo, r_hi, q_lo, q_hi, b_lo, b_hi, a_lo, a_hi]; test.expect_stack(&expected); } @@ -607,8 +659,8 @@ fn advice_push_u64div_conditional_execution() { eq if.true emit.event(\"{U64_DIV_EVENT_NAME}\") - adv_push.2 # quotient - adv_push.2 # remainder + adv_push adv_push # quotient + adv_push adv_push # remainder else padw end @@ -624,8 +676,8 @@ fn advice_push_u64div_conditional_execution() { let test = build_test!(&source, &[1, 1, 4, 0, 8, 0]); // Handler uses extend_stack_for_adv_push which reverses for proper ordering. // Advice stack (top-to-bottom): [q_hi, q_lo, r_hi, r_lo] - // First adv_push.2: pops q_hi then q_lo → [q_lo, q_hi, ...] - // Second adv_push.2: pops r_hi then r_lo → [r_lo, r_hi, q_lo, q_hi, ...] + // First adv_push adv_push: pops q_hi then q_lo → [q_lo, q_hi, ...] + // Second adv_push adv_push: pops r_hi then r_lo → [r_lo, r_hi, q_lo, q_hi, ...] // Result: [r_lo=0, r_hi=0, q_lo=2, q_hi=0, b_lo=4, b_hi=0, a_lo=8, a_hi=0] test.expect_stack(&[0, 0, 2, 0, 4, 0, 8, 0]); @@ -697,7 +749,7 @@ fn ensure_div_doesnt_crash() { } ); }, - Err(err) => panic!("Unexpected error type: {:?}", err), + Err(err) => panic!("Unexpected error type: {err:?}"), } // 2. dividend limbs not u32 @@ -719,7 +771,7 @@ fn ensure_div_doesnt_crash() { } ); }, - Err(err) => panic!("Unexpected error type: {:?}", err), + Err(err) => panic!("Unexpected error type: {err:?}"), } } @@ -829,8 +881,8 @@ fn checked_and_fail() { test, ExecutionError::OperationError{ err: OperationError::NotU32Values{ values }, .. } if values.len() == 2 && - values.contains(&Felt::new(a0)) && - values.contains(&Felt::new(b0)) + values.contains(&Felt::new_unchecked(a0)) && + values.contains(&Felt::new_unchecked(b0)) ); } @@ -877,8 +929,8 @@ fn checked_or_fail() { test, ExecutionError::OperationError{ err: OperationError::NotU32Values{ values }, .. } if values.len() == 2 && - values.contains(&Felt::new(a0)) && - values.contains(&Felt::new(b0)) + values.contains(&Felt::new_unchecked(a0)) && + values.contains(&Felt::new_unchecked(b0)) ); } @@ -925,8 +977,8 @@ fn checked_xor_fail() { test, ExecutionError::OperationError{ err: OperationError::NotU32Values{ values }, .. } if values.len() == 2 && - values.contains(&Felt::new(a0)) && - values.contains(&Felt::new(b0)) + values.contains(&Felt::new_unchecked(a0)) && + values.contains(&Felt::new_unchecked(b0)) ); } @@ -944,14 +996,14 @@ fn unchecked_shl() { let (a1, a0) = split_u64(a); let b: u32 = 0; - build_test!(source, &stack![b as u64, a0, a1, 5]).expect_stack(&[a0, a1, 5]); + build_test!(source, &stack![b as u64, a0, a1, 777]).expect_stack(&[a0, a1, 777]); // shift by 31 (max lower limb of b) let b: u32 = 31; let c = a.wrapping_shl(b); let (c1, c0) = split_u64(c); - build_test!(source, &stack![b as u64, a0, a1, 5]).expect_stack(&[c0, c1, 5]); + build_test!(source, &stack![b as u64, a0, a1, 777]).expect_stack(&[c0, c1, 777]); // shift by 32 (min for upper limb of b) let a = 1_u64; @@ -960,7 +1012,7 @@ fn unchecked_shl() { let c = a.wrapping_shl(b); let (c1, c0) = split_u64(c); - build_test!(source, &stack![b as u64, a0, a1, 5]).expect_stack(&[c0, c1, 5]); + build_test!(source, &stack![b as u64, a0, a1, 777]).expect_stack(&[c0, c1, 777]); // shift by 33 let a = 1_u64; @@ -969,7 +1021,7 @@ fn unchecked_shl() { let c = a.wrapping_shl(b); let (c1, c0) = split_u64(c); - build_test!(source, &stack![b as u64, a0, a1, 5]).expect_stack(&[c0, c1, 5]); + build_test!(source, &stack![b as u64, a0, a1, 777]).expect_stack(&[c0, c1, 777]); // shift 64 by 58 let a = 64_u64; @@ -978,7 +1030,7 @@ fn unchecked_shl() { let c = a.wrapping_shl(b); let (c1, c0) = split_u64(c); - build_test!(source, &stack![b as u64, a0, a1, 5]).expect_stack(&[c0, c1, 5]); + build_test!(source, &stack![b as u64, a0, a1, 777]).expect_stack(&[c0, c1, 777]); } #[test] @@ -995,22 +1047,22 @@ fn unchecked_shr() { let (a1, a0) = split_u64(a); let b: u32 = 0; - build_test!(source, &stack![b as u64, a0, a1, 5]).expect_stack(&[a0, a1, 5]); + build_test!(source, &stack![b as u64, a0, a1, 777]).expect_stack(&[a0, a1, 777]); // simple right shift: a=0x0000_0001_0000_0001 >> 1 = 0x0000_0000_8000_0000 // lo=1, hi=1 shifted right 1 gives lo=2^31, hi=0 - build_test!(source, &stack![1, 1, 1, 5]).expect_stack(&[2_u64.pow(31), 0, 5]); + build_test!(source, &stack![1, 1, 1, 777]).expect_stack(&[2_u64.pow(31), 0, 777]); // simple right shift: a=0x0000_0003_0000_0003 >> 1 = 0x0000_0001_8000_0001 // lo=3, hi=3 shifted right 1 gives lo=2^31+1, hi=1 - build_test!(source, &stack![1, 3, 3, 5]).expect_stack(&[2_u64.pow(31) + 1, 1, 5]); + build_test!(source, &stack![1, 3, 3, 777]).expect_stack(&[2_u64.pow(31) + 1, 1, 777]); // shift by 31 (max lower limb of b) let b: u32 = 31; let c = a.wrapping_shr(b); let (c1, c0) = split_u64(c); - build_test!(source, &stack![b as u64, a0, a1, 5]).expect_stack(&[c0, c1, 5]); + build_test!(source, &stack![b as u64, a0, a1, 777]).expect_stack(&[c0, c1, 777]); // shift by 32 (min for upper limb of b) let a = 1_u64; @@ -1019,7 +1071,7 @@ fn unchecked_shr() { let c = a.wrapping_shr(b); let (c1, c0) = split_u64(c); - build_test!(source, &stack![b as u64, a0, a1, 5]).expect_stack(&[c0, c1, 5]); + build_test!(source, &stack![b as u64, a0, a1, 777]).expect_stack(&[c0, c1, 777]); // shift by 33 let a = 1_u64; @@ -1028,7 +1080,7 @@ fn unchecked_shr() { let c = a.wrapping_shr(b); let (c1, c0) = split_u64(c); - build_test!(source, &stack![b as u64, a0, a1, 5]).expect_stack(&[c0, c1, 5]); + build_test!(source, &stack![b as u64, a0, a1, 777]).expect_stack(&[c0, c1, 777]); // shift 4294967296 by 2 let a = 4294967296; @@ -1037,7 +1089,7 @@ fn unchecked_shr() { let c = a.wrapping_shr(b); let (c1, c0) = split_u64(c); - build_test!(source, &stack![b as u64, a0, a1, 5]).expect_stack(&[c0, c1, 5]); + build_test!(source, &stack![b as u64, a0, a1, 777]).expect_stack(&[c0, c1, 777]); } /// POC: u64::shr produces wrong results when shift >= 32 and a_lo == 0xFFFF_FFFF. @@ -1115,14 +1167,14 @@ fn unchecked_rotl() { let (a1, a0) = split_u64(a); let b: u32 = 0; - build_test!(source, &stack![b as u64, a0, a1, 5]).expect_stack(&[a0, a1, 5]); + build_test!(source, &stack![b as u64, a0, a1, 777]).expect_stack(&[a0, a1, 777]); // shift by 31 (max lower limb of b) let b: u32 = 31; let c = a.rotate_left(b); let (c1, c0) = split_u64(c); - build_test!(source, &stack![b as u64, a0, a1, 5]).expect_stack(&[c0, c1, 5]); + build_test!(source, &stack![b as u64, a0, a1, 777]).expect_stack(&[c0, c1, 777]); // shift by 32 (min for upper limb of b) let a = 1_u64; @@ -1131,7 +1183,7 @@ fn unchecked_rotl() { let c = a.rotate_left(b); let (c1, c0) = split_u64(c); - build_test!(source, &stack![b as u64, a0, a1, 5]).expect_stack(&[c0, c1, 5]); + build_test!(source, &stack![b as u64, a0, a1, 777]).expect_stack(&[c0, c1, 777]); // shift by 33 let a = 1_u64; @@ -1140,7 +1192,7 @@ fn unchecked_rotl() { let c = a.rotate_left(b); let (c1, c0) = split_u64(c); - build_test!(source, &stack![b as u64, a0, a1, 5]).expect_stack(&[c0, c1, 5]); + build_test!(source, &stack![b as u64, a0, a1, 777]).expect_stack(&[c0, c1, 777]); // shift 64 by 58 let a = 64_u64; @@ -1149,7 +1201,7 @@ fn unchecked_rotl() { let c = a.rotate_left(b); let (c1, c0) = split_u64(c); - build_test!(source, &stack![b as u64, a0, a1, 5]).expect_stack(&[c0, c1, 5]); + build_test!(source, &stack![b as u64, a0, a1, 777]).expect_stack(&[c0, c1, 777]); } #[test] @@ -1166,14 +1218,14 @@ fn unchecked_rotr() { let (a1, a0) = split_u64(a); let b: u32 = 0; - build_test!(source, &stack![b as u64, a0, a1, 5]).expect_stack(&[a0, a1, 5]); + build_test!(source, &stack![b as u64, a0, a1, 777]).expect_stack(&[a0, a1, 777]); // shift by 31 (max lower limb of b) let b: u32 = 31; let c = a.rotate_right(b); let (c1, c0) = split_u64(c); - build_test!(source, &stack![b as u64, a0, a1, 5]).expect_stack(&[c0, c1, 5]); + build_test!(source, &stack![b as u64, a0, a1, 777]).expect_stack(&[c0, c1, 777]); // shift by 32 (min for upper limb of b) let a = 1_u64; @@ -1182,7 +1234,7 @@ fn unchecked_rotr() { let c = a.rotate_right(b); let (c1, c0) = split_u64(c); - build_test!(source, &stack![b as u64, a0, a1, 5]).expect_stack(&[c0, c1, 5]); + build_test!(source, &stack![b as u64, a0, a1, 777]).expect_stack(&[c0, c1, 777]); // shift by 33 let a = 1_u64; @@ -1191,7 +1243,7 @@ fn unchecked_rotr() { let c = a.rotate_right(b); let (c1, c0) = split_u64(c); - build_test!(source, &stack![b as u64, a0, a1, 5]).expect_stack(&[c0, c1, 5]); + build_test!(source, &stack![b as u64, a0, a1, 777]).expect_stack(&[c0, c1, 777]); // shift 64 by 58 let a = 64_u64; @@ -1200,7 +1252,67 @@ fn unchecked_rotr() { let c = a.rotate_right(b); let (c1, c0) = split_u64(c); - build_test!(source, &stack![b as u64, a0, a1, 5]).expect_stack(&[c0, c1, 5]); + build_test!(source, &stack![b as u64, a0, a1, 777]).expect_stack(&[c0, c1, 777]); +} + +#[test] +fn unchecked_rotr_large_value_by_0() { + let source = " + use miden::core::math::u64 + begin + exec.u64::rotr + end"; + + let a = Felt::ORDER_U64 + 1; + let (a1, a0) = split_u64(a); + + build_test!(source, &stack![0_u64, a0, a1, 777]).expect_stack(&[a0, a1, 777]); +} + +#[test] +fn unchecked_rotr_large_value_by_32() { + let source = " + use miden::core::math::u64 + begin + exec.u64::rotr + end"; + + let a = Felt::ORDER_U64 + 1; + let (a1, a0) = split_u64(a); + let c = a.rotate_right(32); + let (c1, c0) = split_u64(c); + + build_test!(source, &stack![32_u64, a0, a1, 777]).expect_stack(&[c0, c1, 777]); +} + +#[test] +fn unchecked_rotl_large_value_by_0() { + let source = " + use miden::core::math::u64 + begin + exec.u64::rotl + end"; + + let a = Felt::ORDER_U64 + 1; + let (a1, a0) = split_u64(a); + + build_test!(source, &stack![0_u64, a0, a1, 777]).expect_stack(&[a0, a1, 777]); +} + +#[test] +fn unchecked_rotl_large_value_by_32() { + let source = " + use miden::core::math::u64 + begin + exec.u64::rotl + end"; + + let a = Felt::ORDER_U64 + 1; + let (a1, a0) = split_u64(a); + let c = a.rotate_left(32); + let (c1, c0) = split_u64(c); + + build_test!(source, &stack![32_u64, a0, a1, 777]).expect_stack(&[c0, c1, 777]); } #[test] @@ -1442,6 +1554,25 @@ proptest! { build_test!(source, &stack![b0, b1, a0, a1]).prop_expect_stack(&[c0, c1])?; } + #[test] + fn widening_mul_proptest(a in boundary_biased_u64(), b in boundary_biased_u64()) { + + let c = (a as u128) * (b as u128); + + let (a1, a0) = split_u64(a); + let (b1, b0) = split_u64(b); + let (c3, c2, c1, c0) = split_u128(c); + + let source = " + use miden::core::math::u64 + begin + exec.u64::widening_mul + end"; + + // [b_lo, b_hi, a_lo, a_hi, sentinel] -> [c0, c1, c2, c3, sentinel] + build_test!(source, &stack![b0, b1, a0, a1, 777]).prop_expect_stack(&[c0, c1, c2, c3, 777])?; + } + #[test] fn shl_proptest(a in any::(), b in 0_u32..64) { @@ -1457,11 +1588,11 @@ proptest! { end"; // [n, a_lo, a_hi] -> [c_lo, c_hi] - build_test!(source, &stack![b as u64, a0, a1, 5]).prop_expect_stack(&[c0, c1, 5])?; + build_test!(source, &stack![b as u64, a0, a1, 777]).prop_expect_stack(&[c0, c1, 777])?; } #[test] - fn shr_proptest(a in any::(), b in 0_u32..64) { + fn shr_proptest(a in boundary_biased_u64(), b in boundary_biased_shift()) { let c = a.wrapping_shr(b); @@ -1475,11 +1606,11 @@ proptest! { end"; // [n, a_lo, a_hi] -> [c_lo, c_hi] - build_test!(source, &stack![b as u64, a0, a1, 5]).prop_expect_stack(&[c0, c1, 5])?; + build_test!(source, &stack![b as u64, a0, a1, 777]).prop_expect_stack(&[c0, c1, 777])?; } #[test] - fn rotl_proptest(a in any::(), b in 0_u32..64) { + fn rotl_proptest(a in boundary_biased_u64(), b in boundary_biased_shift()) { let c = a.rotate_left(b); @@ -1493,11 +1624,11 @@ proptest! { end"; // [n, a_lo, a_hi] -> [c_lo, c_hi] - build_test!(source, &stack![b as u64, a0, a1, 5]).prop_expect_stack(&[c0, c1, 5])?; + build_test!(source, &stack![b as u64, a0, a1, 777]).prop_expect_stack(&[c0, c1, 777])?; } #[test] - fn rotr_proptest(a in any::(), b in 0_u32..64) { + fn rotr_proptest(a in boundary_biased_u64(), b in boundary_biased_shift()) { let c = a.rotate_right(b); @@ -1511,7 +1642,7 @@ proptest! { end"; // [n, a_lo, a_hi] -> [c_lo, c_hi] - build_test!(source, &stack![b as u64, a0, a1, 5]).prop_expect_stack(&[c0, c1, 5])?; + build_test!(source, &stack![b as u64, a0, a1, 777]).prop_expect_stack(&[c0, c1, 777])?; } #[test] @@ -1582,6 +1713,39 @@ proptest! { // HELPER FUNCTIONS // ================================================================================================ +/// Strategy that mixes boundary u64 values with uniformly random ones. Each variant has equal +/// probability of being sampled; the boundary cases stress 32-bit limb edges where carry handling +/// is most likely to fail. +fn boundary_biased_u64() -> impl Strategy { + prop_oneof![ + Just(0u64), + Just(1u64), + Just(u32::MAX as u64), + Just(1u64 << 32), + Just((1u64 << 32) - 1), + Just((1u64 << 32) + 1), + Just(u64::MAX), + Just(u64::MAX - 1), + Just(u64::MAX << 32), + Just((u64::MAX << 32) | 1), + any::(), + ] +} + +/// Strategy for shift amounts in [0, 64) biased toward the values that exercise control-flow +/// boundaries in shr/rotl/rotr (32-bit limb edge, the no-op case, and the maximum). +fn boundary_biased_shift() -> impl Strategy { + prop_oneof![ + Just(0u32), + Just(1u32), + Just(31u32), + Just(32u32), + Just(33u32), + Just(63u32), + 0_u32..64, + ] +} + /// Split the provided u64 value into 32 high and low bits. fn split_u64(value: u64) -> (u64, u64) { (value >> 32, value as u32 as u64) diff --git a/crates/lib/core/tests/mem/mod.rs b/crates/lib/core/tests/mem/mod.rs index 6f9e1aa792..d2faaa0ed1 100644 --- a/crates/lib/core/tests/mem/mod.rs +++ b/crates/lib/core/tests/mem/mod.rs @@ -6,6 +6,48 @@ use miden_utils_testing::{ AdviceStackBuilder, build_expected_hash, build_expected_perm, felt_slice_to_ints, }; +#[test] +fn test_memcopy_words_fails_on_overlap() { + // Source [1000, 1000 + 4*3) = [1000, 1012) + // Dest [1008, 1008 + 4*3) = [1008, 1020) + // These overlap at [1008, 1012). + let source = " + use miden::core::mem + + begin + push.0.0.0.1.1000 mem_storew_be dropw + push.0.0.1.0.1004 mem_storew_be dropw + push.0.0.1.1.1008 mem_storew_be dropw + + push.1008.1000.3 exec.mem::memcopy_words + end + "; + + let test = build_test!(source, &[]); + expect_assert_error_message!(test, contains "overlap"); +} + +#[test] +fn test_memcopy_elements_fails_on_overlap() { + // Source [1000, 1000 + 10) = [1000, 1010) + // Dest [1005, 1005 + 10) = [1005, 1015) + // These overlap at [1005, 1010). + let source = " + use miden::core::mem + + begin + push.1.2.3.4.1000 mem_storew_be dropw + push.5.6.7.8.1004 mem_storew_be dropw + push.9.10.11.12.1008 mem_storew_be dropw + + push.1005.1000.10 exec.mem::memcopy_elements + end + "; + + let test = build_test!(source, &[]); + expect_assert_error_message!(test, contains "overlap"); +} + #[test] fn test_memcopy_words() { use miden_core_lib::CoreLibrary; @@ -160,8 +202,7 @@ fn test_memcopy_elements() { .read_element(ContextId::root(), Felt::from_u32(addr)) .unwrap(), Felt::from_u32(addr - 2000), - "Address {}", - addr + "Address {addr}" ); } } @@ -275,7 +316,7 @@ fn test_pipe_preimage_to_memory() { let operand_stack = &[]; let data: &[u64] = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; let mut builder = AdviceStackBuilder::new(); - builder.push_for_adv_loadw(build_expected_hash(data).into()); + builder.push_word(build_expected_hash(data).into()); builder.push_u64_slice(data); let advice_stack = builder.build_vec_u64(); build_test!(three_words, operand_stack, &advice_stack).expect_stack_and_memory( @@ -304,7 +345,7 @@ fn test_pipe_preimage_to_memory_invalid_preimage() { let mut corrupted_hash = build_expected_hash(data); corrupted_hash[0] += Felt::ONE; // corrupt the expected hash let mut builder = AdviceStackBuilder::new(); - builder.push_for_adv_loadw(corrupted_hash.into()); + builder.push_word(corrupted_hash.into()); builder.push_u64_slice(data); let advice_stack = builder.build_vec_u64(); let res = build_test!(three_words, operand_stack, &advice_stack).execute(); @@ -331,7 +372,7 @@ fn test_pipe_double_words_preimage_to_memory() { let operand_stack = &[]; let data: &[u64] = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; let mut builder = AdviceStackBuilder::new(); - builder.push_for_adv_loadw(build_expected_hash(data).into()); + builder.push_word(build_expected_hash(data).into()); builder.push_u64_slice(data); let advice_stack = builder.build_vec_u64(); build_test!(four_words, operand_stack, &advice_stack).expect_stack_and_memory( @@ -360,7 +401,7 @@ fn test_pipe_double_words_preimage_to_memory_invalid_preimage() { let mut corrupted_hash = build_expected_hash(data); corrupted_hash[0] += Felt::ONE; // corrupt the expected hash let mut builder = AdviceStackBuilder::new(); - builder.push_for_adv_loadw(corrupted_hash.into()); + builder.push_word(corrupted_hash.into()); builder.push_u64_slice(data); let advice_stack = builder.build_vec_u64(); let test = build_test!(four_words, operand_stack, &advice_stack); @@ -384,7 +425,7 @@ fn test_pipe_double_words_preimage_to_memory_invalid_count() { let operand_stack = &[]; let data: &[u64] = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; let mut builder = AdviceStackBuilder::new(); - builder.push_for_adv_loadw(build_expected_hash(data).into()); + builder.push_word(build_expected_hash(data).into()); builder.push_u64_slice(data); let advice_stack = builder.build_vec_u64(); let test = build_test!(three_words, operand_stack, &advice_stack); diff --git a/crates/lib/core/tests/stark/ace_circuit.rs b/crates/lib/core/tests/stark/ace_circuit.rs new file mode 100644 index 0000000000..180c7f6994 --- /dev/null +++ b/crates/lib/core/tests/stark/ace_circuit.rs @@ -0,0 +1,14 @@ +#![cfg(feature = "constraints-tools")] + +use miden_core_lib::constraints_regen; + +#[test] +fn constraints_eval_masm_matches_air() { + constraints_regen::constraints_eval_masm_matches_air() + .expect("constraints_eval.masm drift check failed"); +} + +#[test] +fn relation_digest_matches_air() { + constraints_regen::relation_digest_matches_air().expect("relation digest check failed"); +} diff --git a/crates/lib/core/tests/stark/ace_read_check.rs b/crates/lib/core/tests/stark/ace_read_check.rs new file mode 100644 index 0000000000..947dcc2f58 --- /dev/null +++ b/crates/lib/core/tests/stark/ace_read_check.rs @@ -0,0 +1,121 @@ +//! ACE READ section extraction and cross-validation. +//! +//! After the recursive verifier executes in MASM, this module: +//! 1. Extracts the ACE READ section from MASM memory into a flat `Vec`. +//! 2. Runs structural sanity checks on critical values (non-zero challenges, etc.). +//! 3. Evaluates the ACE circuit in Rust and asserts the result is zero. +//! +//! This catches bugs in the MASM verifier's input preparation (wrong values, wrong +//! memory slots, missing absorptions) that would silently break soundness. + +use miden_ace_codegen::{AceConfig, InputKey, InputLayout, LayoutKind}; +use miden_air::{ProcessorAir, ace::build_batched_ace_circuit}; +use miden_core::{ + Felt, + field::{PrimeCharacteristicRing, QuadFelt}, +}; +use miden_crypto::field::Field; +use miden_processor::{ContextId, ExecutionOutput}; + +// MASM CONSTANTS (must match crates/lib/core/asm/stark/constants.masm) +// ================================================================================================ + +const PUBLIC_INPUTS_ADDRESS_PTR: u32 = 3223322667; +const AUX_RAND_ELEM_PTR: u32 = 3225419776; + +// EXTRACTION +// ================================================================================================ + +/// Extract the ACE READ section from MASM memory into a flat input vector. +/// +/// Each pair of consecutive base felts forms one extension field element. +/// The returned vector has `layout.total_inputs` entries. +fn extract_ace_inputs(output: &ExecutionOutput, layout: &InputLayout) -> Vec { + let ctx = ContextId::root(); + + let pi_ptr = output + .memory + .read_element(ctx, Felt::from_u32(PUBLIC_INPUTS_ADDRESS_PTR)) + .expect("PUBLIC_INPUTS_ADDRESS_PTR not found in memory") + .as_canonical_u64() as u32; + + assert!( + pi_ptr < AUX_RAND_ELEM_PTR, + "pi_ptr ({pi_ptr}) >= AUX_RAND_ELEM_PTR ({AUX_RAND_ELEM_PTR})" + ); + + (0..layout.total_inputs) + .map(|i| { + let addr = pi_ptr + (i as u32) * 2; + let c0 = output.memory.read_element(ctx, Felt::from_u32(addr)).expect("read c0"); + let c1 = output.memory.read_element(ctx, Felt::from_u32(addr + 1)).expect("read c1"); + QuadFelt::new([c0, c1]) + }) + .collect() +} + +// SANITY CHECKS +// ================================================================================================ + +/// Assert critical Fiat-Shamir-derived values are non-zero. +fn sanity_check_ace_inputs(inputs: &[QuadFelt], layout: &InputLayout) { + let get = |key: InputKey| -> QuadFelt { inputs[layout.index(key).expect("missing key")] }; + + // Fiat-Shamir challenges + assert!(!get(InputKey::Alpha).is_zero(), "alpha is zero"); + assert!(!get(InputKey::AuxRandBeta).is_zero(), "beta is zero"); + assert!(!get(InputKey::Gamma).is_zero(), "gamma is zero"); + + // Vanishing polynomial + assert!( + !(get(InputKey::ZPowN) - QuadFelt::ONE).is_zero(), + "z^N - 1 = 0 -- OOD point is on the trace domain" + ); + + // Selector polynomials + assert!(!get(InputKey::IsFirst).is_zero(), "is_first is zero"); + assert!(!get(InputKey::IsLast).is_zero(), "is_last is zero"); + assert!(!get(InputKey::IsTransition).is_zero(), "is_transition is zero"); + + // Quotient recomposition + assert!(!get(InputKey::Weight0).is_zero(), "weight0 is zero"); + assert!(!get(InputKey::F).is_zero(), "f is zero"); + assert!(!get(InputKey::S0).is_zero(), "s0 is zero"); + + // OOD frame should have at least some non-zero values + assert!( + (0..layout.counts.width) + .any(|col| !get(InputKey::Main { offset: 0, index: col }).is_zero()), + "all main trace OOD values at current row are zero" + ); +} + +// CROSS-EVALUATION +// ================================================================================================ + +/// Build the ACE circuit, extract inputs from MASM memory, run sanity checks, +/// and verify the Rust evaluation matches (result is zero). +pub fn cross_check_ace_circuit(output: &ExecutionOutput) { + let config = AceConfig { + num_quotient_chunks: 8, + num_vlpi_groups: 1, + layout: LayoutKind::Masm, + }; + + let batch_config = miden_air::ace::logup_boundary_config(); + let circuit = build_batched_ace_circuit::<_, QuadFelt>(&ProcessorAir, config, &batch_config) + .expect("ace circuit"); + let layout = circuit.layout(); + + let inputs = extract_ace_inputs(output, layout); + assert_eq!(inputs.len(), layout.total_inputs, "extracted input count mismatch"); + + sanity_check_ace_inputs(&inputs, layout); + + let result = circuit.eval(&inputs).expect("ACE eval failed"); + assert!( + result.is_zero(), + "ACE cross-evaluation is non-zero: {result:?}\n\ + MASM verifier populated the READ section incorrectly." + ); +} diff --git a/crates/lib/core/tests/stark/batch_query_gen.rs b/crates/lib/core/tests/stark/batch_query_gen.rs new file mode 100644 index 0000000000..318d212626 --- /dev/null +++ b/crates/lib/core/tests/stark/batch_query_gen.rs @@ -0,0 +1,273 @@ +//! Unit tests for the batch `generate_list_indices` procedure. +//! +//! Verifies that the batch implementation produces identical query indices to a reference +//! implementation that calls `sample_bits` in a loop. Both programs start from the same +//! sponge state and parameters, and we compare the resulting query words stored in memory. + +use miden_core::Felt; +use miden_processor::ContextId; +use rand::{Rng, SeedableRng}; +use rand_chacha::ChaCha20Rng; +use rstest::rstest; + +// Memory layout constants (must match constants.masm). +const R1_PTR: u32 = 3223322672; +const R2_PTR: u32 = 3223322676; +const C_PTR: u32 = 3223322668; +const NUM_QUERIES_PTR: u32 = 3223322628; +const LDE_DOMAIN_LOG_SIZE_PTR: u32 = 3223322625; +const FRI_QUERIES_ADDRESS_PTR: u32 = 3223322633; +const RANDOM_COIN_INPUT_LEN_PTR: u32 = 3223322756; +const RANDOM_COIN_OUTPUT_LEN_PTR: u32 = 3223322757; + +// Fixed query storage address. +const QUERY_PTR: u32 = 100_000; + +// --------------------------------------------------------------------------- +// Helpers +// --------------------------------------------------------------------------- + +/// Build the MASM preamble that initializes the sponge state and verifier parameters. +/// +/// `sponge` is 12 field-element values `[r1_0..r1_3, r2_0..r2_3, c_0..c_3]`. +fn setup_masm(sponge: &[u64; 12], output_len: u32, num_queries: u32, depth: u32) -> String { + format!( + r#" + # Store R1 (rate word 1) + push.{r1_3}.{r1_2}.{r1_1}.{r1_0} + push.{R1_PTR} mem_storew_le dropw + + # Store R2 (rate word 2) + push.{r2_3}.{r2_2}.{r2_1}.{r2_0} + push.{R2_PTR} mem_storew_le dropw + + # Store C (capacity) + push.{c_3}.{c_2}.{c_1}.{c_0} + push.{C_PTR} mem_storew_le dropw + + # Random coin buffer state + push.0 push.{RANDOM_COIN_INPUT_LEN_PTR} mem_store + push.{output_len} push.{RANDOM_COIN_OUTPUT_LEN_PTR} mem_store + + # Verifier parameters + push.{num_queries} push.{NUM_QUERIES_PTR} mem_store + push.{depth} push.{LDE_DOMAIN_LOG_SIZE_PTR} mem_store + push.{QUERY_PTR} push.{FRI_QUERIES_ADDRESS_PTR} mem_store + "#, + r1_0 = sponge[0], + r1_1 = sponge[1], + r1_2 = sponge[2], + r1_3 = sponge[3], + r2_0 = sponge[4], + r2_1 = sponge[5], + r2_2 = sponge[6], + r2_3 = sponge[7], + c_0 = sponge[8], + c_1 = sponge[9], + c_2 = sponge[10], + c_3 = sponge[11], + ) +} + +/// MASM source that calls the batch `generate_list_indices`. +fn batch_source(setup: &str) -> String { + format!( + r#" + use miden::core::stark::random_coin + begin + {setup} + exec.random_coin::generate_list_indices + end + "#, + ) +} + +/// MASM source with a reference per-query loop. +fn reference_source(setup: &str) -> String { + format!( + r#" + use miden::core::stark::random_coin + use miden::core::stark::constants + use miden::core::crypto::hashes::poseidon2 + + #! Sample a felt, permuting first if the output buffer is empty. + proc sample_felt_safe + push.{RANDOM_COIN_OUTPUT_LEN_PTR} mem_load + push.0 eq + if.true + exec.random_coin::load_random_coin_state + exec.poseidon2::permute + exec.random_coin::store_random_coin_state + push.8 push.{RANDOM_COIN_OUTPUT_LEN_PTR} mem_store + end + exec.random_coin::sample_felt + end + + #! sample_bits using the safe wrapper. + proc sample_bits_safe + dup + pow2 + u32assert u32overflowing_sub.1 assertz + exec.sample_felt_safe + u32split + swap + drop + u32and + swap + drop + end + + begin + {setup} + + exec.constants::get_number_queries + exec.constants::get_fri_queries_address + exec.constants::get_lde_domain_depth + dup push.32 swap u32wrapping_sub pow2 + movdn.2 swap + dup.3 push.0 neq + while.true + dup.1 + exec.sample_bits_safe + dup.2 swap dup movdn.2 + push.0 movdn.3 + dup.4 + mem_storew_le + dropw + add.4 + movup.3 sub.1 movdn.3 + dup.3 push.0 neq + end + push.0 push.{RANDOM_COIN_INPUT_LEN_PTR} mem_store + drop drop drop drop + end + "#, + ) +} + +/// Run both batch and reference programs with identical initial state, then compare +/// all generated query words and the final `output_len`. +fn assert_batch_matches_reference( + sponge: &[u64; 12], + output_len: u32, + num_queries: u32, + depth: u32, +) { + let setup = setup_masm(sponge, output_len, num_queries, depth); + let batch_src = batch_source(&setup); + let ref_src = reference_source(&setup); + + let (batch_out, _) = build_test!(&batch_src, &[]).execute_for_output().unwrap_or_else(|e| { + panic!("batch failed (nq={num_queries}, d={depth}, ol={output_len}): {e}") + }); + let (ref_out, _) = build_test!(&ref_src, &[]).execute_for_output().unwrap_or_else(|e| { + panic!("reference failed (nq={num_queries}, d={depth}, ol={output_len}): {e}") + }); + + // Compare every stored query word. + for i in 0..num_queries { + let base = QUERY_PTR + i * 4; + for j in 0..4u32 { + let addr = base + j; + let bv = batch_out + .memory + .read_element(ContextId::root(), Felt::from_u32(addr)) + .map(|f| f.as_canonical_u64()) + .unwrap_or(0); + let rv = ref_out + .memory + .read_element(ContextId::root(), Felt::from_u32(addr)) + .map(|f| f.as_canonical_u64()) + .unwrap_or(0); + assert_eq!( + bv, rv, + "query {i} offset {j} (addr {addr}): batch={bv} vs ref={rv} \ + [nq={num_queries}, depth={depth}, output_len={output_len}]" + ); + } + } + + // Compare final output_len. + let b_ol = batch_out + .memory + .read_element(ContextId::root(), Felt::from_u32(RANDOM_COIN_OUTPUT_LEN_PTR)) + .map(|f| f.as_canonical_u64()) + .unwrap_or(u64::MAX); + let r_ol = ref_out + .memory + .read_element(ContextId::root(), Felt::from_u32(RANDOM_COIN_OUTPUT_LEN_PTR)) + .map(|f| f.as_canonical_u64()) + .unwrap_or(u64::MAX); + assert_eq!( + b_ol, r_ol, + "output_len mismatch: batch={b_ol} vs ref={r_ol} \ + [nq={num_queries}, depth={depth}, output_len={output_len}]" + ); +} + +/// Generate a deterministic sponge state from a seed. +fn random_sponge(seed: u64) -> [u64; 12] { + let mut rng = ChaCha20Rng::seed_from_u64(seed); + core::array::from_fn(|_| rng.random::()) +} + +// --------------------------------------------------------------------------- +// Parametric tests +// --------------------------------------------------------------------------- + +/// Test across a range of num_queries values with fixed sponge and depth. +/// Covers: 1 query, small batches, exact rate boundary (7), one past (8, 9), +/// typical (27), and a larger value (40 = 5 permutations). +#[rstest] +#[case::single_query(1)] +#[case::two_queries(2)] +#[case::three_queries(3)] +#[case::seven_queries_exact_first_batch(7)] +#[case::eight_queries_triggers_permute(8)] +#[case::nine_queries_one_past_permute(9)] +#[case::fifteen_queries_two_batches(15)] +#[case::twentyseven_queries_typical(27)] +#[case::forty_queries_five_permutes(40)] +fn batch_vs_reference_num_queries(#[case] num_queries: u32) { + let sponge = random_sponge(42); + assert_batch_matches_reference(&sponge, 7, num_queries, 17); +} + +/// Test across a range of LDE domain depths. +/// depth must be in 1..=31 (since pow2_shift = 2^(32-depth) must fit in u32, +/// and mask = 2^depth - 1 must be valid). +#[rstest] +#[case::depth_10(10)] +#[case::depth_13(13)] +#[case::depth_17(17)] +#[case::depth_20(20)] +#[case::depth_24(24)] +fn batch_vs_reference_depth(#[case] depth: u32) { + let sponge = random_sponge(99); + assert_batch_matches_reference(&sponge, 7, 27, depth); +} + +/// Test different initial output_len values. +/// After PoW the typical value is 7, but we test the range 1..=8 to ensure +/// the permute-on-exhaustion logic is correct at every boundary. +#[rstest] +#[case::output_len_1(1)] +#[case::output_len_2(2)] +#[case::output_len_4(4)] +#[case::output_len_7(7)] +#[case::output_len_8(8)] +fn batch_vs_reference_output_len(#[case] output_len: u32) { + let sponge = random_sponge(77); + assert_batch_matches_reference(&sponge, output_len, 27, 17); +} + +/// Test with several different random sponge states to exercise varied rate element values. +#[rstest] +#[case::seed_0(0)] +#[case::seed_1(1)] +#[case::seed_12345(12345)] +#[case::seed_999999(999999)] +fn batch_vs_reference_random_sponge(#[case] seed: u64) { + let sponge = random_sponge(seed); + assert_batch_matches_reference(&sponge, 7, 27, 17); +} diff --git a/crates/lib/core/tests/stark/mod.rs b/crates/lib/core/tests/stark/mod.rs index 67677fa5a0..5ebaea17d4 100644 --- a/crates/lib/core/tests/stark/mod.rs +++ b/crates/lib/core/tests/stark/mod.rs @@ -1,61 +1,76 @@ use std::array; -use miden_air::{FieldExtension, HashFunction, PublicInputs}; +use miden_air::PublicInputs; use miden_assembly::Assembler; use miden_core::{ - Felt, FieldElement, QuadFelt, WORD_SIZE, Word, ZERO, precompile::PrecompileTranscriptState, -}; -use miden_processor::{ - DefaultHost, Program, ProgramInfo, - crypto::RandomCoin, -}; -use miden_utils_testing::{ - AdviceInputs, ProvingOptions, StackInputs, VerifierError, proptest::proptest, prove, + Felt, WORD_SIZE, + field::{BasedVectorSpace, Field, PrimeCharacteristicRing, QuadFelt}, + precompile::PrecompileTranscriptState, + proof::HashFunction, }; +use miden_processor::{DefaultHost, ExecutionOptions, Program, ProgramInfo}; +use miden_utils_testing::{AdviceInputs, ProvingOptions, StackInputs, prove_sync}; use rand::{Rng, RngCore, SeedableRng}; use rand_chacha::ChaCha20Rng; use rstest::rstest; -use verifier_recursive::{VerifierData, generate_advice_inputs}; +use verifier_recursive::{VerifierData, VerifierError, generate_advice_inputs}; +mod ace_circuit; +mod ace_read_check; +mod batch_query_gen; mod verifier_recursive; -// Note: Changes to Miden VM may cause this test to fail when some of the assumptions documented -// in `crates/lib/core/asm/sys/vm/mod.masm` are violated. -#[rstest] -#[case(None)] -#[case(Some(KERNEL_EVEN_NUM_PROC))] -#[case(Some(KERNEL_ODD_NUM_PROC))] -#[ignore = "re-enable once we're done implementing all constraints in airscript"] -fn stark_verifier_e2f4(#[case] kernel: Option<&str>) { - // An example MASM program to be verified inside Miden VM. - let example_source = "begin - repeat.320 - swap dup.1 add - end - u32split drop - end"; - - let mut stack_inputs = vec![0_u64; 16]; - stack_inputs[15] = 0; - stack_inputs[14] = 1; - - let VerifierData { - initial_stack, - advice_stack: tape, - store, - advice_map, - } = generate_recursive_verifier_data(example_source, stack_inputs, kernel).unwrap(); - - // Verify inside Miden VM - let source = " - use miden::core::sys::vm - begin - exec.vm::verify_proof - end - "; +// RECURSIVE VERIFIER TESTS +// ================================================================================================ - let test = build_test!(source, &initial_stack, &tape, store, advice_map); - test.expect_stack(&[]); +#[test] +fn stark_verifier_e2f4_small() { + let inputs = fib_stack_inputs(); + let data = generate_recursive_verifier_data(EXAMPLE_FIB_SMALL, inputs, None).unwrap(); + run_recursive_verifier(&data); +} + +#[test] +fn stark_verifier_e2f4_large() { + let inputs = fib_stack_inputs(); + let data = generate_recursive_verifier_data(EXAMPLE_FIB_LARGE, inputs, None).unwrap(); + run_recursive_verifier(&data); +} + +#[test] +fn stark_verifier_e2f4_with_kernel_even() { + let inputs = fib_stack_inputs(); + let data = generate_recursive_verifier_data( + EXAMPLE_FIB_KERNEL_SMALL, + inputs, + Some(KERNEL_EVEN_NUM_PROC), + ) + .unwrap(); + run_recursive_verifier(&data); +} + +#[test] +fn stark_verifier_e2f4_with_kernel_odd() { + let inputs = fib_stack_inputs(); + let data = generate_recursive_verifier_data( + EXAMPLE_FIB_KERNEL_SMALL, + inputs, + Some(KERNEL_ODD_NUM_PROC), + ) + .unwrap(); + run_recursive_verifier(&data); +} + +#[test] +fn stark_verifier_e2f4_with_kernel_single() { + let inputs = fib_stack_inputs(); + let data = generate_recursive_verifier_data( + EXAMPLE_FIB_KERNEL_SMALL, + inputs, + Some(KERNEL_SINGLE_PROC), + ) + .unwrap(); + run_recursive_verifier(&data); } // Helper function for recursive verification @@ -64,31 +79,41 @@ pub fn generate_recursive_verifier_data( stack_inputs: Vec, kernel: Option<&str>, ) -> Result { - let program = { + let (program, kernel_lib) = { match kernel { Some(kernel) => { let context = miden_assembly::testing::TestContext::new(); let kernel_lib = Assembler::new(context.source_manager()).assemble_kernel(kernel).unwrap(); - let assembler = Assembler::with_kernel(context.source_manager(), kernel_lib); + let assembler = + Assembler::with_kernel(context.source_manager(), kernel_lib.clone()); let program: Program = assembler.assemble_program(source).unwrap(); - program + (program, Some(kernel_lib)) }, None => { let program: Program = Assembler::default().assemble_program(source).unwrap(); - program + (program, None) }, } }; let stack_inputs = StackInputs::try_from_ints(stack_inputs).unwrap(); let advice_inputs = AdviceInputs::default(); let mut host = DefaultHost::default(); + if let Some(ref kernel_lib) = kernel_lib { + host.load_library(kernel_lib.mast_forest()).unwrap(); + } - let options = - ProvingOptions::new(27, 8, 0, FieldExtension::Quadratic, 4, 127, HashFunction::Poseidon2); + let options = ProvingOptions::new(HashFunction::Poseidon2); - let (stack_outputs, proof) = - prove(&program, stack_inputs, advice_inputs, &mut host, options).unwrap(); + let (stack_outputs, proof) = prove_sync( + &program, + stack_inputs, + advice_inputs, + &mut host, + ExecutionOptions::default(), + options, + ) + .unwrap(); let program_info = ProgramInfo::from(program); @@ -99,10 +124,70 @@ pub fn generate_recursive_verifier_data( stack_outputs, PrecompileTranscriptState::default(), ); - let (_, proof, _precompile_requests) = proof.into_parts(); - Ok(generate_advice_inputs(proof, pub_inputs).unwrap()) + let (_, proof_bytes, _precompile_requests) = proof.into_parts(); + let data = generate_advice_inputs(&proof_bytes, pub_inputs).unwrap(); + Ok(data) +} + +/// Run the recursive verifier MASM program with the given VerifierData. +fn run_recursive_verifier(data: &VerifierData) { + let source = " + use miden::core::sys::vm + begin + exec.vm::verify_proof + end + "; + let test = build_test!( + source, + &data.initial_stack, + &data.advice_stack, + data.store.clone(), + data.advice_map.clone() + ); + let (output, _host) = test.execute_for_output().expect("recursive verifier execution failed"); + + // Cross-check: extract READ section, sanity-check values, evaluate circuit in Rust. + ace_read_check::cross_check_ace_circuit(&output); } +// EXAMPLE PROGRAMS +// ================================================================================================ + +/// repeat.320 -> log_trace_height=10 -> FRI remainder degree < 64 -> verify_64 path +const EXAMPLE_FIB_SMALL: &str = "begin + repeat.320 + swap dup.1 add + end + u32split drop + end"; + +/// repeat.400 -> log_trace_height=11 -> FRI remainder degree < 128 -> verify_128 path +const EXAMPLE_FIB_LARGE: &str = "begin + repeat.400 + swap dup.1 add + end + u32split drop + end"; + +/// Like EXAMPLE_FIB_SMALL but with a syscall, for kernel-aware tests. +const EXAMPLE_FIB_KERNEL_SMALL: &str = "begin + syscall.foo + repeat.320 + swap dup.1 add + end + u32split drop + end"; + +fn fib_stack_inputs() -> Vec { + let mut inputs = vec![0_u64; 16]; + inputs[15] = 0; + inputs[14] = 1; + inputs +} + +// VARIABLE LENGTH PUBLIC INPUTS TESTS +// ================================================================================================ + #[rstest] #[case(0)] #[case(1)] @@ -111,29 +196,16 @@ pub fn generate_recursive_verifier_data( #[case(8)] #[case(1000)] fn variable_length_public_inputs(#[case] num_kernel_proc_digests: usize) { - // STARK parameters - let num_queries = 27; - let log_trace_len = 10; - let grinding_bits = 16; - let num_constraints = 200; - let trace_info = 0x50010810; - let num_fixed_len_pi_padded = 40; - let mut initial_stack = vec![ - log_trace_len, - num_queries, - grinding_bits, - num_constraints, - trace_info, - num_fixed_len_pi_padded, - ]; - initial_stack.reverse(); - - // Seeded random number generator for reproducibility + // init_seed expects [log(trace_length), rd0, rd1, rd2, rd3, ...] + let log_trace_length = 10_u64; + // Relation digest values are arbitrary here; the test only validates VLPI reduction. + let rd = [1_u64, 2, 3, 4]; + let initial_stack = vec![log_trace_length, rd[0], rd[1], rd[2], rd[3]]; + let seed = [0_u8; 32]; let mut rng = ChaCha20Rng::from_seed(seed); - // 1) Generate fixed length public inputs - + // 1) Generate fixed-length public inputs let input_operand_stack: [u64; 16] = array::from_fn(|_| rng.next_u64()); let output_operand_stack: [u64; 16] = array::from_fn(|_| rng.next_u64()); let program_digest: [u64; 4] = array::from_fn(|_| rng.next_u64()); @@ -141,129 +213,72 @@ fn variable_length_public_inputs(#[case] num_kernel_proc_digests: usize) { let mut fixed_length_public_inputs = input_operand_stack.to_vec(); fixed_length_public_inputs.extend_from_slice(&output_operand_stack); fixed_length_public_inputs.extend_from_slice(&program_digest); - let fix_len_pi_with_padding = fixed_length_public_inputs.len().next_multiple_of(8); - fixed_length_public_inputs.resize(fix_len_pi_with_padding, 0); - - // 2) Generate the variable length public inputs, i.e., the kernel procedures digests + fixed_length_public_inputs.resize(fixed_length_public_inputs.len().next_multiple_of(8), 0); - let num_elements_kernel_proc_digests = num_kernel_proc_digests * WORD_SIZE.next_multiple_of(8); + // 2) Generate the variable-length public inputs (kernel procedure digests) let kernel_procedures_digests = generate_kernel_procedures_digests(&mut rng, num_kernel_proc_digests); // 3) Generate the auxiliary randomness - let auxiliary_rand_values: [u64; 4] = array::from_fn(|_| rng.next_u64()); // 4) Build the advice stack - - let mut advice_stack = vec![num_elements_kernel_proc_digests as u64]; - advice_stack.extend_from_slice(&fixed_length_public_inputs); + let mut advice_stack = fixed_length_public_inputs.clone(); + advice_stack.push(num_kernel_proc_digests as u64); advice_stack.extend_from_slice(&kernel_procedures_digests); advice_stack.extend_from_slice(&auxiliary_rand_values); - advice_stack.push(num_kernel_proc_digests as u64); - - // 5) Compute the expected randomness-reduced value of all the kernel procedures digests - let beta = - QuadFelt::new([Felt::new(auxiliary_rand_values[0]), Felt::new(auxiliary_rand_values[1])]); - let alpha = - QuadFelt::new([Felt::new(auxiliary_rand_values[2]), Felt::new(auxiliary_rand_values[3])]); - let reduced_value_inv = - reduce_kernel_procedures_digests(&kernel_procedures_digests, alpha, beta).inv(); - let [reduced_value_inv_0, reduced_value_inv_1] = reduced_value_inv.to_base_elements(); + // 5) Compute the expected reduced value + let beta = QuadFelt::new([ + Felt::new_unchecked(auxiliary_rand_values[0]), + Felt::new_unchecked(auxiliary_rand_values[1]), + ]); + let alpha = QuadFelt::new([ + Felt::new_unchecked(auxiliary_rand_values[2]), + Felt::new_unchecked(auxiliary_rand_values[3]), + ]); - // 6) Run the test + let reduced_value = reduce_kernel_procedures_digests(&kernel_procedures_digests, alpha, beta); + let coeffs: &[Felt] = reduced_value.as_basis_coefficients_slice(); - let source = format!( - " + // 6) Run process_public_inputs and verify the reduced value in memory + let source = " use miden::core::stark::random_coin use miden::core::stark::constants use miden::core::sys::vm::public_inputs begin - # 1) Initialize the FS transcript exec.random_coin::init_seed - # => [C, ...] - - # 2) Process the public inputs exec.public_inputs::process_public_inputs - # => [...] - - # 3) Load the reduced value of all kernel procedures digests - # Note that the memory layout is as follows: - # [..., a_0, ..., a_[m-1], b_0, b_1, 0, 0, alpha0, alpha1, beta0, beta1, OOD-evaluations-start, ...] - # - # where: - # - # i) [a_0, ..., a[m-1]] are the fixed length public inputs, - # ii) [b_0, b_1] is the reduced value of all kernel procedures digests, - # iii) [alpha0, alpha1, beta0, beta1] is the auxiliary randomness, - # iv) [OOD-evaluations-start, ...] the start of the section that will hold the OOD evaluations, - # - # Note that [b_0, b_1, 0, 0, alpha0, alpha1, beta0, beta1, OOD-evaluations-start, ...] will hold temporarily - # the kernel procedures digests, but there will be later on overwritten by the reduced value, the auxiliary - # randomness, and the OOD evaluations. - padw - exec.constants::ood_evaluations_ptr - sub.8 - mem_loadw_be - - # 4) Compare with the expected result, including the padding - push.{reduced_value_inv_0} - push.{reduced_value_inv_1} - push.0.0 - eqw assert - - # 5) Clean up the stack - dropw dropw end - " - ); + "; let test = build_test!(source, &initial_stack, &advice_stack); - test.expect_stack(&[]); -} - -#[test] -fn generate_query_indices() { - let source = TEST_RANDOM_INDICES_GENERATION; - - let num_queries = 27; - let lde_log_size = 18; - let lde_size = 1 << lde_log_size; - - let input_stack = vec![num_queries as u64, lde_log_size as u64, lde_size as u64]; - - let seed = Word::default(); - let mut coin = RandomCoin::new(seed); - let indices = coin - .draw_integers(num_queries, lde_size, 0) - .expect("should not fail to generate the indices"); - - let advice_stack: Vec = indices.iter().rev().map(|index| *index as u64).collect(); - - let test = build_test!(source, &input_stack, &advice_stack); - - test.expect_stack(&[]); -} - -proptest! { - #[test] - fn generate_query_indices_proptest(num_queries in 7..150_usize, lde_log_size in 9..32_usize) { - let source = TEST_RANDOM_INDICES_GENERATION; - let lde_size = 1 << lde_log_size; - - let seed = Word::default(); - let mut coin = RandomCoin::new(seed); - let indices = coin - .draw_integers(num_queries, lde_size, 0) - .expect("should not fail to generate the indices"); - let advice_stack: Vec = indices.iter().rev().map(|index| *index as u64).collect(); - - let input_stack = vec![num_queries as u64, lde_log_size as u64, lde_size as u64]; - let test = build_test!(source, &input_stack, &advice_stack); - test.prop_expect_stack(&[])?; - } + let (output, _host) = test.execute_for_output().expect("execution failed"); + + use miden_processor::ContextId; + let ctx = ContextId::root(); + + // Read reduced kernel value from var_len_ptr (in ACE READ section) + let var_len_addr_ptr = 3223322666_u32; // VARIABLE_LEN_PUBLIC_INPUTS_ADDRESS_PTR + let var_len_ptr = output + .memory + .read_element(ctx, Felt::from_u32(var_len_addr_ptr)) + .unwrap() + .as_canonical_u64() as u32; + let masm_0 = output.memory.read_element(ctx, Felt::from_u32(var_len_ptr)).unwrap(); + let masm_1 = output.memory.read_element(ctx, Felt::from_u32(var_len_ptr + 1)).unwrap(); + + assert_eq!( + masm_0.as_canonical_u64(), + coeffs[0].as_canonical_u64(), + "kernel_reduced coord 0 mismatch (nk={num_kernel_proc_digests})" + ); + assert_eq!( + masm_1.as_canonical_u64(), + coeffs[1].as_canonical_u64(), + "kernel_reduced coord 1 mismatch (nk={num_kernel_proc_digests})" + ); } // HELPERS @@ -297,34 +312,33 @@ fn reduce_kernel_procedures_digests( alpha: QuadFelt, beta: QuadFelt, ) -> QuadFelt { + // kernel_corr = Σ_i 1 / term_i (MASM: chiplet removes, boundary adds — no negation). kernel_procedures_digests .chunks(2 * WORD_SIZE) .map(|digest| reduce_digest(digest, alpha, beta)) - .fold(QuadFelt::ONE, |acc, term| acc * term) + .fold(QuadFelt::ZERO, |acc, term| { + acc + term.try_inverse().expect("zero kernel ROM denominator") + }) } fn reduce_digest(digest: &[u64], alpha: QuadFelt, beta: QuadFelt) -> QuadFelt { - const KERNEL_OP_LABEL: Felt = Felt::new(48); - alpha - + KERNEL_OP_LABEL.into() - + beta - * digest - .iter() - .fold(QuadFelt::ZERO, |acc, coef| acc * beta + QuadFelt::from(*coef)) + // gamma = beta^MAX_MESSAGE_WIDTH = beta^16 + let gamma = (0..16).fold(QuadFelt::ONE, |acc, _| acc * beta); + // KERNEL_ROM_INIT = 0, so bus_prefix = alpha + (0+1) * gamma = alpha + gamma + let bus_prefix = alpha + gamma; + // Horner evaluation matches MASM `horner_eval_base` over the 8-element reversed digest. + bus_prefix + + digest.iter().fold(QuadFelt::ZERO, |acc, coef| { + acc * beta + QuadFelt::from(Felt::new_unchecked(*coef)) + }) } // CONSTANTS // =============================================================================================== -const KERNEL_ODD_NUM_PROC: &str = r#" +const KERNEL_SINGLE_PROC: &str = r#" pub proc foo add - end - pub proc bar - div - end - pub proc baz - mul end"#; const KERNEL_EVEN_NUM_PROC: &str = r#" @@ -335,60 +349,13 @@ const KERNEL_EVEN_NUM_PROC: &str = r#" div end"#; -const TEST_RANDOM_INDICES_GENERATION: &str = r#" - const QUERY_ADDRESS = 1024 - - use miden::core::stark::random_coin - use miden::core::stark::constants - - begin - exec.constants::set_lde_domain_size - exec.constants::set_lde_domain_log_size - exec.constants::set_number_queries - push.QUERY_ADDRESS exec.constants::set_fri_queries_address - - exec.random_coin::load_random_coin_state - hperm - hperm - exec.random_coin::store_random_coin_state - - exec.random_coin::generate_list_indices - - exec.constants::get_lde_domain_log_size - exec.constants::get_number_queries neg - push.QUERY_ADDRESS - # => [query_ptr, loop_counter, lde_size_log, ...] - - push.1 - while.true - dup add.3 mem_load - movdn.3 - # => [query_ptr, loop_counter, lde_size_log, query_index, ...] - dup - add.2 mem_load - dup.3 assert_eq - - add.4 - # => [query_ptr + 4, loop_counter, lde_size_log, query_index, ...] - - swap add.1 swap - # => [query_ptr + 4, loop_counter, lde_size_log, query_index, ...] - - dup.1 neq.0 - # => [?, query_ptr + 4, loop_counter + 1, lde_size_log, query_index, ...] - end - drop drop drop - - exec.constants::get_number_queries neg - push.1 - while.true - swap - adv_push.1 - assert_eq - add.1 - dup - neq.0 - end - drop +const KERNEL_ODD_NUM_PROC: &str = r#" + pub proc foo + add end - "#; + pub proc bar + div + end + pub proc baz + mul + end"#; diff --git a/crates/lib/core/tests/stark/verifier_recursive/channel.rs b/crates/lib/core/tests/stark/verifier_recursive/channel.rs deleted file mode 100644 index 3d504a0b18..0000000000 --- a/crates/lib/core/tests/stark/verifier_recursive/channel.rs +++ /dev/null @@ -1,433 +0,0 @@ -use alloc::vec::Vec; - -use miden_air::ProcessorAir; -use miden_core::{Felt, FieldElement, PrimeField64, QuadFelt, Word}; -use miden_utils_testing::{ - MerkleTreeVC, VerifierError, - crypto::{BatchMerkleProof, PartialMerkleTree, Poseidon2}, - group_slice_elements, -}; -use winter_air::{ - Air, - proof::{Proof, Queries, QuotientOodFrame, Table, TraceOodFrame}, -}; -use winter_fri::{VerifierChannel as FriVerifierChannel, folding::fold_positions}; - -type AdvMap = Vec<(Word, Vec)>; - -/// A view into a [Proof] for a computation structured to simulate an "interactive" channel. -/// -/// A channel is instantiated for a specific proof, which is parsed into structs over the -/// appropriate field (specified by type parameter `E`). This also validates that the proof is -/// well-formed in the context of the computation for the specified [Air]. -pub struct VerifierChannel { - // trace queries - trace_roots: Vec, - trace_queries: Option, - // constraint queries - constraint_root: Word, - constraint_queries: Option, - // FRI proof - fri_roots: Option>, - fri_layer_proofs: Vec>, - fri_layer_queries: Vec>, - fri_remainder: Option>, - fri_num_partitions: usize, - // out-of-domain frame - ood_trace_frame: Option>, - ood_constraint_evaluations: Option>, - // query proof-of-work - pow_nonce: u64, -} - -impl VerifierChannel { - // CONSTRUCTOR - // -------------------------------------------------------------------------------------------- - /// Creates and returns a new [VerifierChannel] initialized from the specified `proof`. - pub fn new(air: &ProcessorAir, proof: Proof) -> Result { - let Proof { - context, - commitments, - trace_queries, - constraint_queries, - ood_frame, - fri_proof, - pow_nonce, - num_unique_queries, - } = proof; - - // make AIR and proof base fields are the same - if Felt::get_modulus_le_bytes() != context.field_modulus_bytes() { - return Err(VerifierError::InconsistentBaseField); - } - - let num_trace_segments = air.trace_info().num_segments(); - let main_trace_width = air.trace_info().main_trace_width(); - let aux_trace_width = air.trace_info().aux_segment_width(); - let lde_domain_size = air.lde_domain_size(); - let fri_options = air.options().to_fri_options(); - let constraint_frame_width = air.context().num_constraint_composition_columns(); - - // --- parse commitments ------------------------------------------------------------------ - let (trace_roots, constraint_root, fri_roots) = commitments - .parse::(num_trace_segments, fri_options.num_fri_layers(lde_domain_size)) - .map_err(|err| VerifierError::ProofDeserializationError(err.to_string()))?; - // --- parse trace and constraint queries ------------------------------------------------- - let trace_queries = TraceQueries::new(trace_queries, air, num_unique_queries as usize)?; - let constraint_queries = - ConstraintQueries::new(constraint_queries, air, num_unique_queries as usize)?; - - // --- parse FRI proofs ------------------------------------------------------------------- - let fri_num_partitions = fri_proof.num_partitions(); - let fri_remainder = fri_proof - .parse_remainder() - .map_err(|err| VerifierError::ProofDeserializationError(err.to_string()))?; - let (fri_layer_queries, fri_layer_proofs) = fri_proof - .parse_layers::>( - lde_domain_size, - fri_options.folding_factor(), - ) - .map_err(|err| VerifierError::ProofDeserializationError(err.to_string()))?; - - // --- parse out-of-domain evaluation frame ----------------------------------------------- - let (ood_trace_evaluations, ood_constraint_evaluations) = ood_frame - .parse(main_trace_width, aux_trace_width, constraint_frame_width) - .map_err(|err| VerifierError::ProofDeserializationError(err.to_string()))?; - - Ok(VerifierChannel { - // trace queries - trace_roots, - trace_queries: Some(trace_queries), - // constraint queries - constraint_root, - constraint_queries: Some(constraint_queries), - // FRI proof - fri_roots: Some(fri_roots), - fri_layer_proofs, - fri_layer_queries, - fri_remainder: Some(fri_remainder), - fri_num_partitions, - // out-of-domain evaluation - ood_trace_frame: Some(ood_trace_evaluations), - ood_constraint_evaluations: Some(ood_constraint_evaluations), - // query seed - pow_nonce, - }) - } - - // DATA READERS - // -------------------------------------------------------------------------------------------- - - /// Returns execution trace commitments sent by the prover. - /// - /// For computations requiring multiple trace segment, the returned slice will contain a - /// commitment for each trace segment. - pub fn read_trace_commitments(&self) -> &[Word] { - &self.trace_roots - } - - /// Returns constraint evaluation commitment sent by the prover. - pub fn read_constraint_commitment(&self) -> Word { - self.constraint_root - } - - /// Returns trace polynomial evaluations at out-of-domain points z and z * g, where g is the - /// generator of the LDE domain. - /// - /// For computations requiring multiple trace segments, evaluations of auxiliary trace - /// polynomials are also included as the second value of the returned tuple. Otherwise, the - /// second value is None. - pub fn read_ood_trace_frame(&mut self) -> TraceOodFrame { - self.ood_trace_frame.take().expect("already read") - } - - /// Returns evaluations of composition polynomial columns at z, where z is the out-of-domain - /// point. - pub fn read_ood_constraint_evaluations(&mut self) -> QuotientOodFrame { - self.ood_constraint_evaluations.take().expect("already read") - } - - /// Returns query proof-of-work nonce sent by the prover. - pub fn read_pow_nonce(&self) -> u64 { - self.pow_nonce - } - - /// Returns trace states at the specified positions of the LDE domain. This also checks if - /// the trace states are valid against the trace commitment sent by the prover. - /// - /// For computations requiring multiple trace segments, trace states for auxiliary segments - /// are also included as the second value of the returned tuple (trace states for all auxiliary - /// segments are merged into a single table). Otherwise, the second value is None. - pub fn read_queried_trace_states( - &mut self, - positions: &[usize], - ) -> Result<(AdvMap, Vec), VerifierError> { - let queries = self.trace_queries.take().expect("already read"); - let proofs = queries.query_proofs; - let main_queries = queries.main_states; - let aux_queries = queries.aux_states; - let main_queries_vec: Vec> = main_queries.rows().map(|a| a.to_owned()).collect(); - - let aux_queries_vec: Vec> = aux_queries - .as_ref() - .unwrap() - .rows() - .map(|a| QuadFelt::slice_as_base_elements(a).to_vec()) - .collect(); - - let (main_trace_pmt, mut main_trace_adv_map) = - unbatch_to_partial_mt(positions.to_vec(), main_queries_vec, proofs[0].clone()); - let (aux_trace_pmt, mut aux_trace_adv_map) = - unbatch_to_partial_mt(positions.to_vec(), aux_queries_vec, proofs[1].clone()); - - let mut trees = vec![main_trace_pmt]; - trees.push(aux_trace_pmt); - - main_trace_adv_map.append(&mut aux_trace_adv_map); - Ok((main_trace_adv_map, trees)) - } - - /// Returns constraint evaluations at the specified positions of the LDE domain. This also - /// checks if the constraint evaluations are valid against the constraint commitment sent by - /// the prover. - pub fn read_constraint_evaluations( - &mut self, - positions: &[usize], - ) -> Result<(AdvMap, PartialMerkleTree), VerifierError> { - let queries = self.constraint_queries.take().expect("already read"); - let proof = queries.query_proofs; - - let queries = queries - .evaluations - .rows() - .map(|a| QuadFelt::slice_as_base_elements(a).into()) - .collect(); - let (constraint_pmt, constraint_adv_map) = - unbatch_to_partial_mt(positions.to_vec(), queries, proof); - - Ok((constraint_adv_map, constraint_pmt)) - } - - /// Returns the FRI layers Merkle batch proofs. - pub fn fri_layer_proofs(&self) -> Vec> { - self.fri_layer_proofs.clone() - } - - /// Returns the unbatched Merkle proofs as well as a global key-value map for all the FRI layer - /// proofs. - pub fn unbatch_fri_layer_proofs( - &mut self, - positions_: &[usize], - domain_size: usize, - layer_commitments: Vec, - ) -> (Vec, Vec<(Word, Vec)>) { - let all_layers_queries = self.fri_layer_queries.clone(); - let mut current_domain_size = domain_size; - let mut positions = positions_.to_vec(); - let number_of_folds = layer_commitments.len() - 1; - - let mut global_adv_key_map = Vec::new(); - let mut global_partial_merkle_trees = Vec::new(); - let mut layer_proofs = self.fri_layer_proofs(); - for current_layer_queries in all_layers_queries.iter().take(number_of_folds) { - let mut folded_positions = fold_positions(&positions, current_domain_size, N); - - let layer_proof = layer_proofs.remove(0); - let queries: Vec<_> = group_slice_elements::(current_layer_queries) - .iter() - .map(|query| QuadFelt::slice_as_base_elements(query).to_vec()) - .collect(); - - let (current_partial_merkle_tree, mut cur_adv_key_map) = - unbatch_to_partial_mt(folded_positions.clone(), queries, layer_proof); - - global_partial_merkle_trees.push(current_partial_merkle_tree); - global_adv_key_map.append(&mut cur_adv_key_map); - - core::mem::swap(&mut positions, &mut folded_positions); - current_domain_size /= N; - } - - (global_partial_merkle_trees, global_adv_key_map) - } -} - -// FRI VERIFIER CHANNEL IMPLEMENTATION -// ================================================================================================ - -impl FriVerifierChannel for VerifierChannel { - type Hasher = Poseidon2; - type VectorCommitment = MerkleTreeVC; - - fn read_fri_num_partitions(&self) -> usize { - self.fri_num_partitions - } - - fn read_fri_layer_commitments(&mut self) -> Vec { - self.fri_roots.take().expect("already read") - } - - fn take_next_fri_layer_proof(&mut self) -> BatchMerkleProof { - self.fri_layer_proofs.remove(0) - } - - fn take_next_fri_layer_queries(&mut self) -> Vec { - self.fri_layer_queries.remove(0) - } - - fn take_fri_remainder(&mut self) -> Vec { - self.fri_remainder.take().expect("already read") - } -} - -// TRACE QUERIES -// ================================================================================================ - -/// Container of trace query data, including: -/// * Queried states for all trace segments. -/// * Merkle authentication paths for all queries. -/// -/// Trace states for all auxiliary segments are stored in a single table. -struct TraceQueries { - query_proofs: Vec>, - main_states: Table, - aux_states: Option>, -} - -impl TraceQueries { - /// Parses the provided trace queries into trace states in the specified field and - /// corresponding Merkle authentication paths. - pub fn new( - mut queries: Vec, - air: &ProcessorAir, - num_queries: usize, - ) -> Result { - // parse main trace segment queries; parsing also validates that hashes of each table row - // form the leaves of Merkle authentication paths in the proofs - let main_segment_width = air.trace_info().main_trace_width(); - let main_segment_queries = queries.remove(0); - let (main_segment_query_proofs, main_segment_states) = main_segment_queries - .parse::>( - air.lde_domain_size(), - num_queries, - main_segment_width, - ) - .map_err(|err| { - VerifierError::ProofDeserializationError(format!( - "main trace segment query deserialization failed: {err}" - )) - })?; - - // all query proofs will be aggregated into a single vector - let mut query_proofs = vec![main_segment_query_proofs]; - - // parse auxiliary trace segment queries (if any); parsing also validates that hashes of - // each table row form the leaves of Merkle authentication paths in the proofs - let aux_trace_states = if air.trace_info().is_multi_segment() { - assert_eq!(queries.len(), 1); - let segment_width = air.trace_info().aux_segment_width(); - let aux_segment_queries = queries.remove(0); - - let (segment_query_proof, segment_trace_states) = aux_segment_queries - .parse::>( - air.lde_domain_size(), - num_queries, - segment_width, - ) - .map_err(|err| { - VerifierError::ProofDeserializationError(format!( - "auxiliary trace segment query deserialization failed: {err}" - )) - })?; - - query_proofs.push(segment_query_proof); - - Some(segment_trace_states) - } else { - None - }; - - Ok(Self { - query_proofs, - main_states: main_segment_states, - aux_states: aux_trace_states, - }) - } -} - -// CONSTRAINT QUERIES -// ================================================================================================ - -/// Container of constraint evaluation query data, including: -/// * Queried constraint evaluation values. -/// * Merkle authentication paths for all queries. -struct ConstraintQueries { - query_proofs: BatchMerkleProof, - evaluations: Table, -} - -impl ConstraintQueries { - /// Parses the provided constraint queries into evaluations in the specified field and - /// corresponding Merkle authentication paths. - pub fn new( - queries: Queries, - air: &ProcessorAir, - num_queries: usize, - ) -> Result { - let (query_proofs, evaluations) = queries - .parse::>( - air.lde_domain_size(), - num_queries, - air.ce_blowup_factor(), - ) - .map_err(|err| { - VerifierError::ProofDeserializationError(format!( - "constraint evaluation query deserialization failed: {err}" - )) - })?; - - Ok(Self { query_proofs, evaluations }) - } -} - -// HELPER FUNCTIONS -// ================================================================================================ - -/// Takes a set of positions, query values of a trace at these positions and a Merkle batch proof -/// against a commitment to this trace, and outputs a partial Merkle tree with individual Merkle -/// paths for each position as well as a key-value map mapping the digests of the query values -/// (i.e. Merkle tree leaves) to their corresponding query values. -pub fn unbatch_to_partial_mt( - positions: Vec, - queries: Vec>, - proof: BatchMerkleProof, -) -> (PartialMerkleTree, Vec<(Word, Vec)>) { - // hash the query values in order to get the leaf - let leaves: Vec = queries.iter().map(|row| Poseidon2::hash_elements(row)).collect(); - - // use the computed leaves with the indices in order to unbatch the Merkle proof batch proof - let unbatched_proof = proof - .into_openings(&leaves, &positions) - .expect("failed to unbatch the batched Merkle proof"); - - // construct the partial Merkle tree data - let mut paths_with_leaves = vec![]; - for (position, merkle_proof) in positions.iter().zip(unbatched_proof.iter()) { - paths_with_leaves.push(( - *position as u64, - merkle_proof.0.to_owned(), - merkle_proof.1.to_owned().into(), - )) - } - - // construct the advice key map linking leaves to query values - let mut adv_key_map = Vec::new(); - leaves.into_iter().zip(queries.iter()).for_each(|(leaf, query_data)| { - adv_key_map.push((leaf, query_data.to_owned())); - }); - - ( - PartialMerkleTree::with_paths(paths_with_leaves).expect("should not fail from paths"), - adv_key_map, - ) -} diff --git a/crates/lib/core/tests/stark/verifier_recursive/mod.rs b/crates/lib/core/tests/stark/verifier_recursive/mod.rs index ea254f2389..20f2182c07 100644 --- a/crates/lib/core/tests/stark/verifier_recursive/mod.rs +++ b/crates/lib/core/tests/stark/verifier_recursive/mod.rs @@ -1,19 +1,45 @@ +//! Advice provision for the recursive STARK verifier. +//! +//! This module mirrors the Fiat-Shamir protocol implemented in MASM +//! (`crates/lib/core/asm/stark/`) on the Rust side. It deserializes a STARK proof, +//! replays the verifier transcript to extract commitments, challenges, and openings, +//! then packs them into the advice inputs (initial stack, advice stack, Merkle store, +//! and advice map) that the MASM recursive verifier consumes. +//! +//! The advice stack ordering must match the MASM consumption order exactly: +//! +//! security params (nq, query_pow, deep_pow, folding_pow) -> +//! fixed-length PI -> num_kernel_proc_digests -> kernel_digests -> +//! aux randomness -> main commit -> aux commit -> +//! aux finals -> quotient commit -> deep alpha ND -> OOD evals -> +//! DEEP PoW witness -> FRI rounds -> FRI remainder -> query PoW witness +//! +//! See `build_advice` for the authoritative layout. + use alloc::vec::Vec; -use miden_air::ProcessorAir; -use miden_core::{Felt, FieldElement, QuadFelt, ToElements, WORD_SIZE, Word}; -use miden_utils_testing::{ - MIN_STACK_DEPTH, VerifierError, - crypto::{MerkleStore, Poseidon2, RandomCoin}, -}; -use winter_air::{ - Air, - proof::{Proof, merge_ood_evaluations}, +use miden_air::{ProcessorAir, PublicInputs, config}; +use miden_core::{Felt, WORD_SIZE, Word, field::QuadFelt}; +use miden_crypto::{ + field::BasedVectorSpace, + stark::{ + StarkConfig, + challenger::CanObserve, + fri::PcsTranscript, + lmcs::{Lmcs, proof::BatchProofView}, + proof::StarkTranscript, + verifier::VerifierError as CryptoVerifierError, + }, }; -use winter_fri::VerifierChannel as FriVerifierChannel; +use miden_lifted_stark::AirInstance; +use miden_utils_testing::crypto::{MerklePath, MerkleStore, PartialMerkleTree}; + +// TYPES +// ================================================================================================ -mod channel; -use channel::VerifierChannel; +type Challenge = QuadFelt; +type P2Config = config::Poseidon2Config; +type P2Lmcs = >::Lmcs; #[derive(Debug, Clone, Eq, PartialEq)] pub struct VerifierData { @@ -23,211 +49,342 @@ pub struct VerifierData { pub advice_map: Vec<(Word, Vec)>, } +#[derive(Debug, thiserror::Error)] +pub enum VerifierError { + #[error("proof deserialization error: {0}")] + ProofDeserializationError(String), + #[error("invalid proof shape: {0}")] + InvalidProofShape(&'static str), + #[error("transcript error: {0}")] + Transcript(#[from] CryptoVerifierError), +} + +/// Merkle store + advice map pair returned by Merkle data construction. +type MerkleAdvice = (MerkleStore, Vec<(Word, Vec)>); + +/// Partial trees + advice map entries returned by single batch proof conversion. +type BatchMerkleResult = (Vec, Vec<(Word, Vec)>); + +// PUBLIC API +// ================================================================================================ + +/// Deserialize a STARK proof and build the advice inputs for the MASM recursive verifier. pub fn generate_advice_inputs( - proof: Proof, - pub_inputs: ::PublicInputs, + proof_bytes: &[u8], + pub_inputs: PublicInputs, ) -> Result { - // we compute the number of procedures in the kernel - // the public inputs contain, in addition to the kernel procedure roots: - // - // 1. The input operand stack (16 field elements), - // 2. The output operand stack (16 field elements), - // 3. The program hash (4 field elements). - let pub_inputs_elements = pub_inputs.to_elements(); - let num_elements_pi = pub_inputs_elements.len(); - // note that since we are padding the fixed length inputs, in our case the program digest, to - // be double-word aligned, we have to subtract `2 * WORD_SIZE` instead of `WORD_SIZE` for - // the program digest - let digests_elements = num_elements_pi - MIN_STACK_DEPTH * 2 - 2 * WORD_SIZE; - assert_eq!(digests_elements % WORD_SIZE, 0); - let num_kernel_procedures_digests = digests_elements / (2 * WORD_SIZE); - - // we need to provide the following instance specific data through the operand stack - let initial_stack = vec![ - proof.context.options().grinding_factor() as u64, - proof.context.options().num_queries() as u64, - proof.context.trace_info().length().ilog2() as u64, - ]; - - // build a seed for the public coin; the initial seed is the hash of public inputs and proof - // context, but as the protocol progresses, the coin will be reseeded with the info received - // from the prover - let mut advice_stack = vec![digests_elements as u64]; - let mut public_coin_seed = proof.context.to_elements(); - public_coin_seed.extend_from_slice(&pub_inputs_elements); - - // add the public inputs, which is nothing but the input and output stacks to the VM as well as - // the digests of the procedures making up the kernel against which the program was compiled, - // to the advice tape - let pub_inputs_int: Vec = - pub_inputs_elements.iter().map(|a| a.as_canonical_u64()).collect(); - advice_stack.extend_from_slice(&pub_inputs_int); - - // add a placeholder for the auxiliary randomness - let aux_rand_insertion_index = advice_stack.len(); - advice_stack.extend_from_slice(&[0, 0, 0, 0]); - advice_stack.push(num_kernel_procedures_digests as u64); - - // create AIR instance for the computation specified in the proof - let air = ProcessorAir::new(proof.trace_info().to_owned(), pub_inputs, proof.options().clone()); - let seed_digest = Poseidon2::hash_elements(&public_coin_seed); - let mut public_coin: RandomCoin = RandomCoin::new(seed_digest); - let mut channel = VerifierChannel::new(&air, proof)?; - - // 1 ----- main segment trace ----------------------------------------------------------------- - let trace_commitments = channel.read_trace_commitments(); - - // reseed the coin with the commitment to the main segment trace - public_coin.reseed(trace_commitments[0]); - advice_stack.extend_from_slice(&digest_to_int_vec(trace_commitments)); - - // 2 ----- auxiliary segment trace ------------------------------------------------------------ - - // generate the auxiliary random elements - let mut aux_trace_rand_elements = vec![]; - for commitment in trace_commitments.iter().skip(1) { - let rand_elements: Vec = air - .get_aux_rand_elements(&mut public_coin) - .map_err(|_| VerifierError::RandomCoinError)? - .rand_elements() - .to_vec(); - aux_trace_rand_elements.push(rand_elements); - public_coin.reseed(*commitment); - } + let params = config::pcs_params(); + let config = config::poseidon2_config(params); + + // 1. Deserialize STARK proof bytes. + let transcript_data = bincode::deserialize(proof_bytes) + .map_err(|e| VerifierError::ProofDeserializationError(e.to_string()))?; + + // 2. Build domain-separated challenger, then observe public values. + let (public_values, kernel_felts) = pub_inputs.to_air_inputs(); + let mut challenger = config.challenger(); + config::observe_protocol_params(&mut challenger); + challenger.observe_slice(&public_values); + let var_len_public_inputs: &[&[Felt]] = &[&kernel_felts]; + config::observe_var_len_public_inputs(&mut challenger, var_len_public_inputs, &[WORD_SIZE]); + + // 3. Build AIR instance. + let air = ProcessorAir; + let instance = AirInstance { + public_values: &public_values, + var_len_public_inputs, + }; + + // 4. Parse STARK transcript (mirrors Fiat-Shamir protocol). + let (stark, _digest) = + StarkTranscript::from_proof(&config, &[(&air, instance)], &transcript_data, challenger)?; + let log_trace_height = stark.instance_shapes.log_trace_heights()[0] as usize; + + // 5. Reconstruct kernel digests as Words for advice building. + let kernel_digests: Vec = kernel_felts + .chunks_exact(4) + .map(|c| Word::new([c[0], c[1], c[2], c[3]])) + .collect(); + + // 6. Build advice from parsed transcript. + build_advice(&config, &stark, log_trace_height, pub_inputs, &kernel_digests) +} - let alpha = aux_trace_rand_elements[0][0].to_owned(); - let beta = aux_trace_rand_elements[0][2].to_owned(); - advice_stack[aux_rand_insertion_index] = QuadFelt::base_element(&beta, 0).as_canonical_u64(); - advice_stack[aux_rand_insertion_index + 1] = - QuadFelt::base_element(&beta, 1).as_canonical_u64(); - advice_stack[aux_rand_insertion_index + 2] = - QuadFelt::base_element(&alpha, 0).as_canonical_u64(); - advice_stack[aux_rand_insertion_index + 3] = - QuadFelt::base_element(&alpha, 1).as_canonical_u64(); - - // 3 ----- constraint composition trace ------------------------------------------------------- - - // build random coefficients for the composition polynomial. we don't need them but we have to - // generate them in order to update the random coin - let _constraint_coeffs: winter_air::ConstraintCompositionCoefficients = air - .get_constraint_composition_coefficients(&mut public_coin) - .map_err(|_| VerifierError::RandomCoinError)?; - - let constraint_commitment = channel.read_constraint_commitment(); - advice_stack.extend_from_slice(&digest_to_int_vec(&[constraint_commitment])); - public_coin.reseed(constraint_commitment); - - // 4 ----- OOD frames -------------------------------------------------------------- - - // generate the the OOD point - let _z: QuadFelt = public_coin.draw().unwrap(); - - // read the main and auxiliary segments' OOD frames and add them to advice tape - let ood_trace_frame = channel.read_ood_trace_frame(); - let ood_constraint_evaluations = channel.read_ood_constraint_evaluations(); - let ood_evals = merge_ood_evaluations(&ood_trace_frame, &ood_constraint_evaluations); - - // placeholder for the alpha_deep - let alpha_deep_index = advice_stack.len(); - advice_stack.extend_from_slice(&[0, 0]); - - // add OOD evaluations to advice stack - advice_stack.extend_from_slice(&to_int_vec(&ood_evals)); - - // reseed with the digest of the OOD evaluations - let ood_digest = Poseidon2::hash_elements(&ood_evals); - public_coin.reseed(ood_digest); - - // 5 ----- FRI ------------------------------------------------------------------------------- - - // read the FRI layer commitments as well as remainder polynomial - let fri_commitments_digests = channel.read_fri_layer_commitments(); - let poly = channel.read_remainder().unwrap(); - - // add the above to the advice tape - let fri_commitments: Vec = digest_to_int_vec(&fri_commitments_digests); - advice_stack.extend_from_slice(&fri_commitments); - advice_stack.extend_from_slice(&to_int_vec(&poly)); - - // reseed with FRI layer commitments - let deep_coefficients = air - .get_deep_composition_coefficients::(&mut public_coin) - .map_err(|_| VerifierError::RandomCoinError)?; - - // since we are using Horner batching, the randomness will be located in the penultimate - // position, the last position holds the constant `1` - assert_eq!( - deep_coefficients.constraints[deep_coefficients.constraints.len() - 1], - QuadFelt::ONE +// ADVICE CONSTRUCTION +// ================================================================================================ + +/// Packs the parsed STARK transcript into the advice inputs consumed by the MASM verifier. +/// +/// The initial operand stack receives `[log_trace_height]`. +/// The advice stack receives security parameters first, then all remaining data +/// in the order listed in the module doc. +fn build_advice( + config: &P2Config, + stark: &StarkTranscript, + log_trace_height: usize, + pub_inputs: PublicInputs, + kernel_digests: &[Word], +) -> Result { + let pcs = &stark.pcs_transcript; + + // --- initial stack --- + // Only log(trace_length) is on the operand stack. Security parameters are on the advice stack. + let initial_stack = vec![log_trace_height as u64]; + + // --- advice stack --- + let mut advice_stack = Vec::new(); + + // 0. Security parameters: [num_queries, query_pow_bits, deep_pow_bits, folding_pow_bits]. + // Consumed first by load_security_params in the specific verifier. num_queries is the + // configured protocol parameter, not the potentially deduplicated count (e.g. + // tree_indices.len()) + let params = config::pcs_params(); + let num_queries = params.num_queries(); + advice_stack.push(num_queries as u64); + advice_stack.push(params.query_pow_bits() as u64); + // DEEP and folding PoW bits are not publicly exposed on PcsParams; + // use the constants from air/src/config.rs directly. + advice_stack.push(config::DEEP_POW_BITS as u64); + advice_stack.push(config::FOLDING_POW_BITS as u64); + + // 1. Fixed-length public inputs. + let fixed_len_inputs = build_fixed_len_inputs(&pub_inputs); + advice_stack.extend_from_slice(&fixed_len_inputs); + + // 2. Number of kernel procedure digests. + let num_kernel_proc_digests = kernel_digests.len(); + advice_stack.push(num_kernel_proc_digests as u64); + + // 3. Kernel procedure digest elements (each digest padded to 8 elements, reversed). + let kernel_advice = build_kernel_digest_advice(kernel_digests); + advice_stack.extend_from_slice(&kernel_advice); + + // 4. Auxiliary randomness [beta0, beta1, alpha0, alpha1]. + assert!( + stark.randomness.len() >= 2, + "expected at least 2 randomness challenges (alpha, beta), got {}", + stark.randomness.len() ); - let alpha_deep = deep_coefficients.constraints[deep_coefficients.constraints.len() - 2]; - advice_stack[alpha_deep_index] = alpha_deep.base_element(0).as_canonical_u64(); - advice_stack[alpha_deep_index + 1] = alpha_deep.base_element(1).as_canonical_u64(); - - let layer_commitments = fri_commitments_digests.clone(); - for commitment in layer_commitments.iter() { - public_coin.reseed(*commitment); - let _alpha: QuadFelt = public_coin.draw().expect("failed to draw random indices"); + let alpha = stark.randomness[0]; + let beta = stark.randomness[1]; + let beta_coeffs: &[Felt] = beta.as_basis_coefficients_slice(); + let alpha_coeffs: &[Felt] = alpha.as_basis_coefficients_slice(); + advice_stack.extend_from_slice(&[ + beta_coeffs[0].as_canonical_u64(), + beta_coeffs[1].as_canonical_u64(), + alpha_coeffs[0].as_canonical_u64(), + alpha_coeffs[1].as_canonical_u64(), + ]); + + // 5. Main trace commitment (4 felts). + advice_stack.extend_from_slice(&commitment_to_u64s(stark.main_commit)); + + // 6. Aux trace commitment. + advice_stack.extend_from_slice(&commitment_to_u64s(stark.aux_commit)); + + // 7. Aux finals (bus boundary values). + if !stark.all_aux_values.is_empty() { + let aux_values = &stark.all_aux_values[0]; + advice_stack.extend_from_slice(&challenges_to_u64s(aux_values)); } - // 6 ----- trace and constraint queries ------------------------------------------------------- - - // read proof-of-work nonce sent by the prover and draw pseudo-random query positions for - // the LDE domain from the public coin - let pow_nonce = channel.read_pow_nonce(); - let mut query_positions = public_coin - .draw_integers(air.options().num_queries(), air.lde_domain_size(), pow_nonce) - .map_err(|_| VerifierError::RandomCoinError)?; - advice_stack.extend_from_slice(&[pow_nonce]); - query_positions.sort(); - query_positions.dedup(); - - // read advice maps and Merkle paths of the queries to main/aux and constraint composition - // traces - let (mut main_aux_adv_map, mut partial_trees_traces) = - channel.read_queried_trace_states(&query_positions)?; - let (mut constraint_adv_map, partial_tree_constraint) = - channel.read_constraint_evaluations(&query_positions)?; - - let (mut partial_trees_fri, mut fri_adv_map) = channel.unbatch_fri_layer_proofs::<4>( - &query_positions, - air.lde_domain_size(), - fri_commitments_digests, - ); + // 8. Quotient commitment. + advice_stack.extend_from_slice(&commitment_to_u64s(stark.quotient_commit)); - // consolidate advice maps - main_aux_adv_map.append(&mut constraint_adv_map); - main_aux_adv_map.append(&mut fri_adv_map); + // 9. Deep alpha (2 felts) -- the DEEP column-batching challenge. + let deep_alpha = pcs.deep_transcript.challenge_columns; + let deep_coeffs: &[Felt] = deep_alpha.as_basis_coefficients_slice(); + advice_stack + .extend_from_slice(&[deep_coeffs[1].as_canonical_u64(), deep_coeffs[0].as_canonical_u64()]); - // build the full MerkleStore - partial_trees_fri.append(&mut partial_trees_traces); - partial_trees_fri.push(partial_tree_constraint); - let mut store = MerkleStore::new(); - for partial_tree in &partial_trees_fri { - store.extend(partial_tree.inner_nodes()); + // 10. OOD evaluations. + append_ood_evaluations(&mut advice_stack, pcs); + + // 11. DEEP PoW witness. + advice_stack.push(pcs.deep_transcript.pow_witness.as_canonical_u64()); + + // 12. FRI layer commitments + per-round PoW witnesses. + for round in &pcs.fri_transcript.rounds { + advice_stack.extend_from_slice(&commitment_to_u64s(round.commitment)); + advice_stack.push(round.pow_witness.as_canonical_u64()); } + // 13. FRI remainder polynomial (already in descending degree order from the prover, matching + // the order observed into the Fiat-Shamir transcript). + let final_poly = &pcs.fri_transcript.final_poly; + let remainder_base: Vec = QuadFelt::flatten_to_base(final_poly.to_vec()); + let remainder_u64s: Vec = remainder_base.iter().map(Felt::as_canonical_u64).collect(); + advice_stack.extend_from_slice(&remainder_u64s); + + // 14. Query PoW witness. + advice_stack.push(pcs.query_pow_witness.as_canonical_u64()); + + // --- Merkle data --- + let (store, advice_map) = build_merkle_data(config, stark)?; + Ok(VerifierData { initial_stack, advice_stack, store, - advice_map: main_aux_adv_map, + advice_map, }) } -// HELPER FUNCTIONS +// OOD EVALUATIONS // ================================================================================================ -pub fn digest_to_int_vec(digest: &[Word]) -> Vec { - digest - .iter() - .flat_map(|digest| digest.as_elements().iter().map(|e| e.as_canonical_u64())) - .collect() +/// Flatten OOD evaluations into the advice stack. +/// +/// The DEEP transcript contains evaluations at two points (z and z*g) for each committed +/// matrix (main, aux, quotient). We split them into local (at z) and next (at z*g) rows, +/// then append local followed by next. +fn append_ood_evaluations(advice_stack: &mut Vec, pcs: &PcsTranscript) +where + L: Lmcs, +{ + let evals = &pcs.deep_transcript.evals; + let mut local_values = Vec::new(); + let mut next_values = Vec::new(); + + for group in evals { + for matrix in group { + let width = matrix.width; + let values = matrix.values.as_slice(); + let local_row = &values[..width]; + let next_row = if values.len() > width { + &values[width..2 * width] + } else { + &[] + }; + local_values.extend_from_slice(local_row); + next_values.extend_from_slice(next_row); + } + } + + advice_stack.extend_from_slice(&challenges_to_u64s(&local_values)); + advice_stack.extend_from_slice(&challenges_to_u64s(&next_values)); +} + +// MERKLE DATA +// ================================================================================================ + +/// Build Merkle store and advice map from the DEEP and FRI opening proofs. +/// +/// Each opening proof is converted into a `PartialMerkleTree` (for the Merkle store) +/// and leaf-hash -> leaf-data entries (for the advice map). The MASM verifier uses +/// `mtree_get` to fetch authentication paths and `adv_keyval` to retrieve leaf data. +fn build_merkle_data( + config: &P2Config, + stark: &StarkTranscript, +) -> Result { + let pcs = &stark.pcs_transcript; + let lmcs = config.lmcs(); + + let mut partial_trees = Vec::new(); + let mut advice_map = Vec::new(); + + // DEEP openings -- one BatchProof per commitment (main, aux, quotient). + for batch_proof in pcs.deep_witnesses.iter() { + let (trees, advs) = batch_proof_to_merkle(lmcs, batch_proof)?; + partial_trees.extend(trees); + advice_map.extend(advs); + } + + // FRI openings -- one BatchProof per FRI round. + for batch_proof in pcs.fri_witnesses.iter() { + let (trees, advs) = batch_proof_to_merkle(lmcs, batch_proof)?; + partial_trees.extend(trees); + advice_map.extend(advs); + } + + let mut store = MerkleStore::new(); + for tree in &partial_trees { + store.extend(tree.inner_nodes()); + } + + Ok((store, advice_map)) +} + +/// Convert a `BatchProof` into `PartialMerkleTree` entries and advice map entries. +/// +/// For each query index, reconstructs the Merkle authentication path from the batch proof, +/// computes the leaf hash, and produces: +/// - A `(index, leaf_hash, path)` triple for the partial Merkle tree +/// - A `(leaf_hash, leaf_data)` pair for the advice map +fn batch_proof_to_merkle( + lmcs: &L, + batch_proof: &L::BatchProof, +) -> Result +where + L: Lmcs, + L::Commitment: Copy + Into<[Felt; 4]>, + L::BatchProof: BatchProofView, + L::Commitment: PartialEq, +{ + let mut paths = Vec::new(); + let mut advice_entries = Vec::new(); + + for index in batch_proof.indices() { + let rows = batch_proof + .opening(index) + .ok_or(VerifierError::InvalidProofShape("missing opening for query index"))?; + let siblings = batch_proof + .path(index) + .ok_or(VerifierError::InvalidProofShape("missing Merkle path for query index"))?; + + let leaf_data: Vec = rows.as_slice().to_vec(); + let leaf_hash = lmcs.hash(rows.iter_rows()); + let leaf_word: Word = Word::new(leaf_hash.into()); + let merkle_path = + MerklePath::new(siblings.into_iter().map(|c| Word::new(c.into())).collect()); + + paths.push((index as u64, leaf_word, merkle_path)); + advice_entries.push((leaf_word, leaf_data)); + } + + let tree = PartialMerkleTree::with_paths(paths) + .map_err(|_| VerifierError::InvalidProofShape("invalid merkle paths"))?; + + Ok((vec![tree], advice_entries)) +} + +/// Build kernel digest advice data. +/// +/// Each digest (4 elements) is padded to 8 elements with zeros, then reversed. This matches +/// the format used by the MASM `reduce_kernel_digests` procedure which uses `mem_stream` + +/// `horner_eval_base` to process digests in 8-element chunks. +fn build_kernel_digest_advice(kernel_digests: &[Word]) -> Vec { + let mut result = Vec::with_capacity(kernel_digests.len() * 8); + for digest in kernel_digests { + let mut padded: Vec = + digest.as_elements().iter().map(Felt::as_canonical_u64).collect(); + padded.resize(8, 0); + padded.reverse(); + result.extend_from_slice(&padded); + } + result +} + +/// Build the fixed-length public inputs in the order the MASM random coin observes them. +/// +/// Must stay in sync with `PublicInputs::to_air_inputs()`. +fn build_fixed_len_inputs(pub_inputs: &PublicInputs) -> Vec { + let mut felts = Vec::::new(); + felts.extend_from_slice(pub_inputs.program_info().program_hash().as_elements()); + felts.extend_from_slice(pub_inputs.stack_inputs().as_ref()); + felts.extend_from_slice(pub_inputs.stack_outputs().as_ref()); + felts.extend_from_slice(pub_inputs.pc_transcript_state().as_ref()); + let mut fixed_len: Vec = felts.iter().map(Felt::as_canonical_u64).collect(); + fixed_len.resize(fixed_len.len().next_multiple_of(8), 0); + fixed_len +} + +fn commitment_to_u64s>(commitment: C) -> Vec { + let felts: [Felt; 4] = commitment.into(); + felts.iter().map(Felt::as_canonical_u64).collect() } -pub fn to_int_vec(ext_felts: &[QuadFelt]) -> Vec { - QuadFelt::slice_as_base_elements(ext_felts) - .iter() - .map(|e| e.as_canonical_u64()) - .collect() +fn challenges_to_u64s(challenges: &[Challenge]) -> Vec { + let base: Vec = QuadFelt::flatten_to_base(challenges.to_vec()); + base.iter().map(Felt::as_canonical_u64).collect() } diff --git a/crates/lib/core/tests/stark_asserts/mod.rs b/crates/lib/core/tests/stark_asserts/mod.rs index 8470390e9f..74294befe2 100644 --- a/crates/lib/core/tests/stark_asserts/mod.rs +++ b/crates/lib/core/tests/stark_asserts/mod.rs @@ -1,39 +1,83 @@ +// ---- validate_inputs tests ---- +// +// validate_inputs reads log(trace_length) from the stack and security parameters +// (num_queries, query_pow_bits, deep_pow_bits, folding_pow_bits) from memory. +// Tests must store the parameters in memory before calling validate_inputs. + +fn validate_inputs_source( + log_tl: u32, + num_queries: u32, + query_pow_bits: u32, + deep_pow_bits: u32, + folding_pow_bits: u32, +) -> String { + format!( + "use miden::core::stark::utils + use miden::core::stark::constants + begin + push.{num_queries} exec.constants::set_number_queries + push.{query_pow_bits} exec.constants::set_query_pow_bits + push.{deep_pow_bits} exec.constants::set_deep_pow_bits + push.{folding_pow_bits} exec.constants::set_folding_pow_bits + push.{log_tl} + exec.utils::validate_inputs + end" + ) +} + #[test] fn validate_inputs_trace_length_upper_bound() { - let test = build_test!(validate_inputs_source(), &[30, 7, 0]); + // log(trace_length) = 30 must be rejected (must be < 30) + let source = validate_inputs_source(30, 27, 0, 0, 16); + let test = build_test!(&source, &[]); expect_assert_error_message!(test); } #[test] fn validate_inputs_trace_length_lower_bound() { - let test = build_test!(validate_inputs_source(), &[5, 7, 0]); + // log(trace_length) = 5 must be rejected (must be > 5) + let source = validate_inputs_source(5, 27, 0, 0, 16); + let test = build_test!(&source, &[]); expect_assert_error_message!(test); } #[test] fn validate_inputs_num_queries_upper_bound() { - let test = build_test!(validate_inputs_source(), &[10, 151, 0]); + // num_queries = 151 must be rejected (must be < 151) + let source = validate_inputs_source(10, 151, 0, 0, 16); + let test = build_test!(&source, &[]); expect_assert_error_message!(test); } #[test] fn validate_inputs_num_queries_lower_bound() { - let test = build_test!(validate_inputs_source(), &[10, 6, 0]); + // num_queries = 6 must be rejected (must be > 6) + let source = validate_inputs_source(10, 6, 0, 0, 16); + let test = build_test!(&source, &[]); expect_assert_error_message!(test); } #[test] fn validate_inputs_grinding_upper_bound() { - let test = build_test!(validate_inputs_source(), &[10, 7, 32]); + // folding_pow_bits = 32 must be rejected (must be < 32) + let source = validate_inputs_source(10, 27, 0, 0, 32); + let test = build_test!(&source, &[]); expect_assert_error_message!(test); } +// ---- init_seed tests ---- +// +// init_seed expects: +// Stack: [log(trace_length), rd0, rd1, rd2, rd3, ...] +// Memory: num_queries, query_pow_bits, deep_pow_bits, folding_pow_bits + #[test] fn init_seed_trace_length_too_large_has_message() { + // log(trace_length) = 32 overflows u32 at pow2, triggering an assertion. let source = " use miden::core::stark::random_coin begin - push.0 push.0 push.0 push.0 push.7 push.32 + push.0.0.0.0 push.32 exec.random_coin::init_seed end "; @@ -58,24 +102,23 @@ fn generate_aux_randomness_mismatch_has_message() { #[test] fn check_pow_invalid_has_message() { + // Store query_pow_bits = 16 so check_pow actually exercises the PoW path. + // Use a valid log(trace_length) = 10 so init_seed succeeds. + // The advice nonce (0) will fail the PoW check. let source = " use miden::core::stark::random_coin + use miden::core::stark::constants begin - push.0 push.0 push.0 push.1 push.7 push.32 + push.27 exec.constants::set_number_queries + push.16 exec.constants::set_query_pow_bits + push.0 exec.constants::set_deep_pow_bits + push.16 exec.constants::set_folding_pow_bits + push.0.0.0.0 push.10 exec.random_coin::init_seed - exec.random_coin::check_pow + exec.random_coin::check_query_pow end "; let advice_stack = &[0_u64]; let test = build_test!(source, &[], advice_stack); expect_assert_error_message!(test); } - -fn validate_inputs_source() -> &'static str { - " - use miden::core::stark::utils - begin - exec.utils::validate_inputs - end - " -} diff --git a/crates/lib/core/tests/sys/mod.rs b/crates/lib/core/tests/sys/mod.rs index b039104d4a..45c443ba3a 100644 --- a/crates/lib/core/tests/sys/mod.rs +++ b/crates/lib/core/tests/sys/mod.rs @@ -13,7 +13,7 @@ use miden_core::{ }; use miden_core_lib::CoreLibrary; use miden_processor::{ - DefaultHost, ProcessorState, Program, StackInputs, + DefaultHost, ExecutionOptions, ProcessorState, Program, StackInputs, advice::{AdviceInputs, AdviceMutation}, event::{EventError, EventHandler}, }; @@ -30,11 +30,28 @@ fn truncate_stack() { } #[test] -fn reduce_kernel_digests_too_many_procs_has_message() { +fn reduce_kernel_digests_upper_bound() { + // init_seed contract: + // Stack: [log(trace_length), rd0, rd1, rd2, rd3, ...] + // Memory: num_queries, query_pow_bits, deep_pow_bits, folding_pow_bits + // + // process_public_inputs advice stack (consumed in order): + // 1. load_public_inputs: 40 fixed-length PI felts (5 iterations of 8) + // 2. reduce_variable_length_public_inputs: + // - 1 felt (num_kernel_proc_digests) + // - num_kernel_proc_digests * 8 felts (digests via adv_pipe) + // - 4 felts (aux randomness via adv_loadw) + // 3. reduce_kernel_digests asserts num_kernel_proc_digests < 1024 let source = " use miden::core::stark::random_coin + use miden::core::stark::constants use miden::core::sys::vm::public_inputs begin + push.27 exec.constants::set_number_queries + push.0 exec.constants::set_query_pow_bits + push.0 exec.constants::set_deep_pow_bits + push.16 exec.constants::set_folding_pow_bits + push.0.0.0.0 push.10 exec.random_coin::init_seed exec.public_inputs::process_public_inputs end @@ -46,40 +63,15 @@ fn reduce_kernel_digests_too_many_procs_has_message() { let kernel_procedures_digests = vec![0_u64; num_elements_kernel_proc_digests]; let auxiliary_rand_values = [0_u64; 4]; - let mut advice_stack = vec![num_elements_kernel_proc_digests as u64]; + // Advice layout (consumed top-to-bottom): + // 40 fixed-len PI, 1 num_kernel_proc_digests, 8192 digest felts, 4 aux rand + let mut advice_stack = Vec::new(); advice_stack.extend_from_slice(&fixed_length_public_inputs); + advice_stack.push(num_kernel_proc_digests as u64); advice_stack.extend_from_slice(&kernel_procedures_digests); advice_stack.extend_from_slice(&auxiliary_rand_values); - advice_stack.push(num_kernel_proc_digests as u64); - - let mut initial_stack = vec![10, 27, 16, 200, 0x50010810, 40]; - initial_stack.reverse(); - - let test = build_test!(source, &initial_stack, &advice_stack); - expect_assert_error_message!(test); -} - -#[test] -fn process_public_inputs_misaligned_var_len_has_message() { - let source = " - use miden::core::stark::random_coin - use miden::core::sys::vm::public_inputs - begin - exec.random_coin::init_seed - exec.public_inputs::process_public_inputs - end - "; - // Not divisible by 8, so the alignment assert in load_public_inputs should fire. - let num_var_len_pi = 1_u64; - let fixed_length_public_inputs = vec![0_u64; 40]; - let mut advice_stack = vec![num_var_len_pi]; - advice_stack.extend_from_slice(&fixed_length_public_inputs); - - let mut initial_stack = vec![10, 27, 16, 200, 0x50010810, 40]; - initial_stack.reverse(); - - let test = build_test!(source, &initial_stack, &advice_stack); + let test = build_test!(source, &[], &advice_stack); expect_assert_error_message!(test); } @@ -111,8 +103,18 @@ fn log_precompile_request_procedure() { let event_id = EventId::from_name(EVENT_NAME); let calldata = vec![1u8, 2, 3, 4]; - let tag = Word::from([event_id.as_felt(), Felt::new(1), Felt::new(0), Felt::new(7)]); - let comm = Word::from([Felt::new(43), Felt::new(62), Felt::new(24), Felt::new(1)]); + let tag = Word::from([ + event_id.as_felt(), + Felt::new_unchecked(1), + Felt::new_unchecked(0), + Felt::new_unchecked(7), + ]); + let comm = Word::from([ + Felt::new_unchecked(43), + Felt::new_unchecked(62), + Felt::new_unchecked(24), + Felt::new_unchecked(1), + ]); let commitment = PrecompileCommitment::new(tag, comm); let source = format!( @@ -130,8 +132,7 @@ fn log_precompile_request_procedure() { let handler = DummyLogPrecompileHandler { event_id, calldata: calldata.clone() }; - let mut test = build_debug_test!(&source, &[]); - test.add_event_handler(EVENT_NAME, handler.clone()); + let test = build_debug_test!(&source, &[]).with_event_handler(EVENT_NAME, handler.clone()); let trace = test.execute().expect("failed to execute log_precompile test"); @@ -162,13 +163,19 @@ fn log_precompile_request_procedure() { let mut host = DefaultHost::default(); let core_lib = CoreLibrary::default(); host.load_library(&core_lib).expect("failed to load core library into host"); - host.register_handler(EVENT_NAME, Arc::new(handler.clone())) + host.register_handler(EVENT_NAME, Arc::new(handler)) .expect("failed to register dummy handler"); let options = ProvingOptions::with_96_bit_security(HashFunction::Blake3_256); - let (stack_outputs, proof) = - miden_utils_testing::prove_sync(&program, stack_inputs, advice_inputs, &mut host, options) - .expect("failed to generate proof for log_precompile helper"); + let (stack_outputs, proof) = miden_utils_testing::prove_sync( + &program, + stack_inputs, + advice_inputs, + &mut host, + ExecutionOptions::default(), + options, + ) + .expect("failed to generate proof for log_precompile helper"); // Proof should include the single deferred request that we expect. assert_eq!(proof.precompile_requests().len(), 1); @@ -193,7 +200,7 @@ fn log_precompile_request_procedure() { ); let program_info = ProgramInfo::from(program); - let (_, transcript_digest) = miden_verifier::verify_with_precompiles( + let (_, pc_transcript_digest) = miden_verifier::verify_with_precompiles( program_info, stack_inputs, stack_outputs, @@ -201,7 +208,7 @@ fn log_precompile_request_procedure() { &verifier_registry, ) .expect("proof verification with precompiles failed"); - assert_eq!(transcript.finalize(), transcript_digest); + assert_eq!(transcript.finalize(), pc_transcript_digest); } #[derive(Clone)] diff --git a/crates/lib/core/tests/word/mod.rs b/crates/lib/core/tests/word/mod.rs index eefec45738..e25a487f05 100644 --- a/crates/lib/core/tests/word/mod.rs +++ b/crates/lib/core/tests/word/mod.rs @@ -1,6 +1,6 @@ use core::cmp::Ordering; -use miden_core::{Felt, LexicographicWord, Word}; +use miden_core::{Felt, Word}; use miden_utils_testing::rand; use num::Integer; use rstest::rstest; @@ -12,7 +12,7 @@ use rstest::rstest; #[case::lt("lt", &[Ordering::Less])] #[case::lte("lte", &[Ordering::Less, Ordering::Equal])] fn test_word_comparison(#[case] proc_name: &str, #[case] valid_ords: &[Ordering]) { - let source = &format!( + let source = format!( " use miden::core::word @@ -22,13 +22,14 @@ fn test_word_comparison(#[case] proc_name: &str, #[case] valid_ords: &[Ordering] " ); + let test = build_test!(&source); let mut seed = 0xfacade; for i in 0..1000 { let lhs = rand::seeded_word(&mut seed); let rhs = if i.is_even() { rand::seeded_word(&mut seed) } else { lhs }; - let expected_cmp = LexicographicWord::cmp(&lhs.into(), &rhs.into()); + let expected_cmp = lhs.cmp(&rhs); let mut operand_stack: Vec = Default::default(); prepend_word(&mut operand_stack, lhs); @@ -37,7 +38,7 @@ fn test_word_comparison(#[case] proc_name: &str, #[case] valid_ords: &[Ordering] let expected = u64::from(valid_ords.contains(&expected_cmp)); - build_test!(source, &operand_stack).expect_stack(&[expected]); + test.expect_stack_with_inputs(&operand_stack, &[expected]); } } @@ -49,6 +50,7 @@ fn test_reverse() { end "; + let test = build_test!(SOURCE); let mut seed = 0xfacade; for _ in 0..1000 { let word = rand::seeded_word(&mut seed); @@ -56,8 +58,8 @@ fn test_reverse() { prepend_word(&mut operand_stack, word); // reversew reverses [w0, w1, w2, w3] → [w3, w2, w1, w0] - let expected: Vec = word.iter().rev().map(|f| f.as_canonical_u64()).collect(); - build_test!(SOURCE, &operand_stack).expect_stack(&expected); + let expected: Vec = word.iter().rev().map(Felt::as_canonical_u64).collect(); + test.expect_stack_with_inputs(&operand_stack, &expected); } } @@ -103,6 +105,7 @@ fn test_preserving_eq() { end "; + let test = build_test!(SOURCE); let mut seed = 0xfacade; for i in 0..1000 { let lhs = rand::seeded_word(&mut seed); @@ -116,7 +119,7 @@ fn test_preserving_eq() { let mut expected: Vec = vec![is_equal.into()]; expected.extend(operand_stack.iter()); - build_test!(SOURCE, &operand_stack).expect_stack(&expected); + test.expect_stack_with_inputs(&operand_stack, &expected); } } @@ -142,19 +145,14 @@ fn store_word_u32s_le_stores_limbs() { use miden::core::word begin - push.{ptr} - push.{w3} - push.{w2} - push.{w1} - push.{w0} + push.{PTR} + push.{W3} + push.{W2} + push.{W1} + push.{W0} exec.word::store_word_u32s_le end ", - ptr = PTR, - w0 = W0, - w1 = W1, - w2 = W2, - w3 = W3, ); let expected_mem = [w0_lo, w0_hi, w1_lo, w1_hi, w2_lo, w2_hi, w3_lo, w3_hi]; diff --git a/crates/mast-package/Cargo.toml b/crates/mast-package/Cargo.toml index fef21ed858..2032e36ca3 100644 --- a/crates/mast-package/Cargo.toml +++ b/crates/mast-package/Cargo.toml @@ -18,9 +18,9 @@ bench = false doctest = false [features] -default = ["std", "serde"] +default = ["std"] arbitrary = ["std", "dep:proptest-derive", "dep:proptest", "miden-assembly-syntax/arbitrary"] -std = ["miden-assembly-syntax/std", "miden-core/std", "serde/std", "thiserror/std"] +std = ["miden-assembly-syntax/std", "miden-core/std", "serde?/std", "thiserror/std"] serde = ["dep:serde", "miden-assembly-syntax/serde", "miden-core/serde"] [dependencies] @@ -30,7 +30,6 @@ miden-core.workspace = true miden-debug-types.workspace = true # External dependencies -derive_more.workspace = true proptest = { workspace = true, optional = true } proptest-derive = { workspace = true, optional = true } serde = { workspace = true, optional = true } diff --git a/crates/mast-package/src/debug_info/types.rs b/crates/mast-package/src/debug_info/types.rs index 7b1183fb83..86e3a86616 100644 --- a/crates/mast-package/src/debug_info/types.rs +++ b/crates/mast-package/src/debug_info/types.rs @@ -33,8 +33,13 @@ use serde::{Deserialize, Serialize}; /// This prevents accidental misuse of raw `u32` indices (e.g., using a string index /// where a type index is expected). #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "arbitrary", derive(proptest_derive::Arbitrary))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", serde(transparent))] +#[cfg_attr( + all(feature = "arbitrary", test), + miden_test_serde_macros::serde_test(binary_serde(true)) +)] pub struct DebugTypeIdx(u32); impl DebugTypeIdx { diff --git a/crates/mast-package/src/package/id.rs b/crates/mast-package/src/package/id.rs index 0d9142aa74..de45a22b69 100644 --- a/crates/mast-package/src/package/id.rs +++ b/crates/mast-package/src/package/id.rs @@ -1,6 +1,8 @@ use alloc::{string::ToString, sync::Arc}; use core::{borrow::Borrow, fmt, ops::Deref}; +#[cfg(all(feature = "arbitrary", test))] +use miden_core::serde::{Deserializable, Serializable}; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; @@ -12,6 +14,10 @@ use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", serde(transparent))] +#[cfg_attr( + all(feature = "arbitrary", test), + miden_test_serde_macros::serde_test(binary_serde(true)) +)] #[repr(transparent)] pub struct PackageId(Arc); diff --git a/crates/mast-package/src/package/manifest.rs b/crates/mast-package/src/package/manifest.rs index ce4d9187fc..c74dc360df 100644 --- a/crates/mast-package/src/package/manifest.rs +++ b/crates/mast-package/src/package/manifest.rs @@ -8,6 +8,8 @@ use miden_assembly_syntax::{ }, library::Library, }; +#[cfg(all(feature = "arbitrary", test))] +use miden_core::serde::{Deserializable, Serializable}; use miden_core::{Word, utils::DisplayHex}; #[cfg(feature = "arbitrary")] use proptest::prelude::{Strategy, any}; @@ -24,6 +26,10 @@ use crate::{Dependency, PackageId}; /// and exported items (procedures, constants, types), if known. #[derive(Debug, Default, Clone, PartialEq, Eq)] #[cfg_attr(feature = "arbitrary", derive(proptest_derive::Arbitrary))] +#[cfg_attr( + all(feature = "arbitrary", test), + miden_test_serde_macros::serde_test(binary_serde(true), serde_test(false)) +)] pub struct PackageManifest { /// The set of exports in this package. #[cfg_attr( @@ -168,7 +174,10 @@ impl PackageManifest { #[derive(Debug, Clone, PartialEq, Eq)] #[repr(u8)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[cfg_attr(all(feature = "arbitrary", test), miden_test_serde_macros::serde_test)] +#[cfg_attr( + all(feature = "arbitrary", test), + miden_test_serde_macros::serde_test(binary_serde(true)) +)] pub enum PackageExport { /// A procedure definition or alias with 'pub' visibility Procedure(ProcedureExport) = 1, @@ -261,7 +270,10 @@ impl proptest::arbitrary::Arbitrary for PackageExport { #[derive(Clone, PartialEq, Eq)] #[cfg_attr(feature = "arbitrary", derive(proptest_derive::Arbitrary))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[cfg_attr(all(feature = "arbitrary", test), miden_test_serde_macros::serde_test)] +#[cfg_attr( + all(feature = "arbitrary", test), + miden_test_serde_macros::serde_test(binary_serde(true)) +)] pub struct ProcedureExport { /// The fully-qualified path of the procedure exported by this package. #[cfg_attr(feature = "serde", serde(with = "miden_assembly_syntax::ast::path"))] @@ -299,7 +311,10 @@ impl fmt::Debug for ProcedureExport { #[derive(Clone, PartialEq, Eq)] #[cfg_attr(feature = "arbitrary", derive(proptest_derive::Arbitrary))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[cfg_attr(all(feature = "arbitrary", test), miden_test_serde_macros::serde_test)] +#[cfg_attr( + all(feature = "arbitrary", test), + miden_test_serde_macros::serde_test(binary_serde(true)) +)] pub struct ConstantExport { /// The fully-qualified path of the constant exported by this package. #[cfg_attr(feature = "serde", serde(with = "miden_assembly_syntax::ast::path"))] @@ -333,7 +348,10 @@ impl fmt::Debug for ConstantExport { #[derive(Clone, PartialEq, Eq)] #[cfg_attr(feature = "arbitrary", derive(proptest_derive::Arbitrary))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[cfg_attr(all(feature = "arbitrary", test), miden_test_serde_macros::serde_test)] +#[cfg_attr( + all(feature = "arbitrary", test), + miden_test_serde_macros::serde_test(binary_serde(true)) +)] pub struct TypeExport { /// The fully-qualified path of the type exported by this package. #[cfg_attr(feature = "serde", serde(with = "miden_assembly_syntax::ast::path"))] diff --git a/crates/mast-package/src/package/mod.rs b/crates/mast-package/src/package/mod.rs index 76112502ef..78b3a5d125 100644 --- a/crates/mast-package/src/package/mod.rs +++ b/crates/mast-package/src/package/mod.rs @@ -17,7 +17,12 @@ use alloc::{ use miden_assembly_syntax::{ KernelLibrary, Library, Report, ast::QualifiedProcedureName, library::ModuleInfo, }; -use miden_core::{Word, program::Kernel, serde::Deserializable}; +use miden_core::{ + Word, + crypto::hash::Poseidon2, + program::Kernel, + serde::{ByteWriter, Deserializable, Serializable}, +}; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; @@ -107,6 +112,49 @@ impl Package { *self.mast.digest() } + /// Returns a digest of the package content relevant to assembly and dependency resolution. + /// + /// This is distinct from [`Self::digest`], which is only the digest of the underlying MAST + /// artifact. The content digest currently binds the MAST digest, package name, semantic + /// version, package kind, manifest, and any semantic package sections. Package descriptions + /// and opaque custom sections are intentionally excluded for now; kernel-section binding is + /// added separately. + pub fn content_digest(&self) -> Word { + let mut bytes = Vec::new(); + self.write_content_digest_preimage(&mut bytes, None); + Poseidon2::hash(&bytes) + } + + fn write_content_digest_preimage( + &self, + target: &mut W, + kernel_digest: Option<&Word>, + ) { + target.write_bytes(b"miden.package.content.v2"); + self.digest().write_into(target); + self.name.write_into(target); + self.version.to_string().write_into(target); + target.write_u8(self.kind.into()); + self.manifest.write_into(target); + self.write_content_digest_sections(target); + target.write_bool(kernel_digest.is_some()); + if let Some(kernel_digest) = kernel_digest { + kernel_digest.write_into(target); + } + } + + fn write_content_digest_sections(&self, target: &mut W) { + let semantic_sections = self + .sections + .iter() + .filter(|section| section.id == SectionId::ACCOUNT_COMPONENT_METADATA) + .collect::>(); + target.write_usize(semantic_sections.len()); + for section in semantic_sections { + section.write_into(target); + } + } + /// Returns true if this package was produced for an executable target pub fn is_program(&self) -> bool { self.kind.is_executable() @@ -145,6 +193,11 @@ impl Package { } }) .collect::>(); + if exports.is_empty() { + return Err(Report::msg( + "invalid kernel package: does not export any kernel procedures", + )); + } Kernel::new(&exports).map_err(|err| Report::msg(format!("invalid kernel package: {err}"))) } @@ -175,17 +228,23 @@ impl Package { ))); } let main_path = MasmPath::exec_path().join(ast::ProcedureName::MAIN_PROC_NAME); - if let Some(digest) = self.mast.get_procedure_root_by_path(&main_path) - && let Some(entrypoint) = self.mast.mast_forest().find_procedure_root(digest) - { + if let Some(entrypoint) = self.mast.get_procedure_node_by_path(&main_path) { let mast_forest = self.mast.mast_forest().clone(); - match self.try_embedded_kernel_library()? { - Some(kernel_library) => Ok(Program::with_kernel( + let kernel_dependency = self.kernel_runtime_dependency()?.cloned(); + match (self.try_embedded_kernel_library()?, kernel_dependency) { + (Some(kernel_library), _) => Ok(Program::with_kernel( mast_forest, entrypoint, kernel_library.kernel().clone(), )), - None => Ok(Program::new(mast_forest, entrypoint)), + (None, Some(kernel_dependency)) => Err(Report::msg(format!( + "package '{}' declares kernel runtime dependency '{}@{}#{}', but does not embed the kernel package required to reconstruct a program", + self.name, + kernel_dependency.name, + kernel_dependency.version, + kernel_dependency.digest + ))), + (None, None) => Ok(Program::new(mast_forest, entrypoint)), } } else { Err(Report::msg(format!( @@ -331,24 +390,29 @@ impl Package { return Err(Report::msg("expected library but got an executable")); } + let entrypoint_namespace = entrypoint.namespace().to_absolute(); let module = self .mast .module_infos() - .find(|info| info.path() == entrypoint.namespace()) + .find(|info| info.path() == entrypoint_namespace.as_ref()) .ok_or_else(|| { Report::msg(format!( "invalid entrypoint: library does not contain a module named '{}'", entrypoint.namespace() )) })?; - if let Some(digest) = module.get_procedure_digest_by_name(entrypoint.name()) { + if let Some(procedure) = module.get_procedure_by_name(entrypoint.name()) { let mast_forest = self.mast.mast_forest().clone(); - let node_id = mast_forest.find_procedure_root(digest).ok_or_else(|| { - Report::msg( - "invalid entrypoint: malformed library - procedure exported, but digest has \ - no node in the forest", - ) - })?; + let digest = procedure.digest; + let node_id = procedure + .source_root_id() + .or_else(|| mast_forest.find_procedure_root(digest)) + .ok_or_else(|| { + Report::msg( + "invalid entrypoint: malformed library - procedure exported, but digest \ + has no node in the forest", + ) + })?; let exec_path: Arc = MasmPath::exec_path().join(masm::ProcedureName::MAIN_PROC_NAME).into(); @@ -454,15 +518,16 @@ fn arbitrary_library() -> Arc { #[cfg(test)] mod tests { use alloc::{collections::BTreeMap, sync::Arc, vec, vec::Vec}; + use core::str::FromStr; use miden_assembly_syntax::{ Library, - ast::{Path as AstPath, PathBuf}, + ast::{Path as AstPath, PathBuf, ProcedureName, QualifiedProcedureName}, library::{LibraryExport, ProcedureExport as LibraryProcedureExport}, }; use miden_core::{ mast::{BasicBlockNodeBuilder, MastForest, MastForestContributor, MastNodeId}, - operations::Operation, + operations::{AssemblyOp, Operation}, serde::Serializable, }; @@ -495,6 +560,35 @@ mod tests { Arc::new(Library::new(Arc::new(forest), exports).expect("failed to build library")) } + fn build_same_digest_library(exports: &[(&str, &str)]) -> Arc { + let mut forest = MastForest::new(); + let mut library_exports = BTreeMap::new(); + + for (path_str, context_name) in exports { + let asm_op_id = forest + .debug_info_mut() + .add_asm_op(AssemblyOp::new(None, (*context_name).into(), 1, "add".into())) + .expect("failed to add asm op"); + let node_id = BasicBlockNodeBuilder::new(vec![Operation::Add], Vec::new()) + .add_to_forest(&mut forest) + .expect("failed to build basic block"); + let num_ops = forest[node_id].get_basic_block().unwrap().num_operations() as usize; + forest + .debug_info_mut() + .register_asm_ops(node_id, num_ops, vec![(0, asm_op_id)]) + .expect("failed to register asm ops"); + forest.make_root(node_id); + + let path = absolute_path(path_str); + library_exports.insert( + Arc::clone(&path), + LibraryExport::Procedure(LibraryProcedureExport::new(node_id, path)), + ); + } + + Arc::new(Library::new(Arc::new(forest), library_exports).expect("failed to build library")) + } + fn build_package( name: &str, kind: TargetType, @@ -517,6 +611,23 @@ mod tests { build_package(name, TargetType::Kernel, &format!("{name}::boot"), [], Vec::new()) } + #[test] + fn to_kernel_rejects_empty_kernel_exports() { + let mut package = build_package("kernel", TargetType::Kernel, "$kernel::boot", [], vec![]); + package.manifest = + PackageManifest::new([]).expect("empty package manifest should be valid"); + + let error = package + .to_kernel() + .expect_err("kernel packages without exported procedures should be rejected"); + + assert!( + error + .to_string() + .contains("invalid kernel package: does not export any kernel procedures") + ); + } + fn kernel_dependency(package: &Package) -> Dependency { Dependency { name: package.name.clone(), @@ -566,4 +677,45 @@ mod tests { assert!(error.to_string().contains("declares multiple kernel runtime dependencies")); } + + #[test] + fn make_executable_preserves_selected_same_digest_root_metadata() { + let library = + build_same_digest_library(&[("app::alias_a", "alias_a"), ("app::alias_b", "alias_b")]); + let package = *Package::from_library( + PackageId::from("app"), + Version::new(1, 0, 0), + TargetType::Library, + library, + [], + ); + + let entrypoint = QualifiedProcedureName::from_str("app::alias_b").unwrap(); + let executable = package.make_executable(&entrypoint).unwrap(); + + let main_path = + miden_assembly_syntax::Path::exec_path().join(ProcedureName::MAIN_PROC_NAME); + let entrypoint_node = executable.mast.get_procedure_node_by_path(&main_path).unwrap(); + assert_eq!( + executable + .mast + .mast_forest() + .debug_info() + .first_asm_op_for_node(entrypoint_node) + .unwrap() + .context_name(), + "alias_b" + ); + + let program = executable.try_into_program().unwrap(); + assert_eq!( + program + .mast_forest() + .debug_info() + .first_asm_op_for_node(program.entrypoint()) + .unwrap() + .context_name(), + "alias_b" + ); + } } diff --git a/crates/mast-package/src/package/section.rs b/crates/mast-package/src/package/section.rs index 74c7094082..1211e78643 100644 --- a/crates/mast-package/src/package/section.rs +++ b/crates/mast-package/src/package/section.rs @@ -1,3 +1,5 @@ +#[cfg(feature = "arbitrary")] +use alloc::vec; use alloc::{ borrow::{Cow, ToOwned}, format, @@ -9,6 +11,8 @@ use miden_assembly_syntax::DisplayHex; use miden_core::serde::{ ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable, }; +#[cfg(feature = "arbitrary")] +use proptest::prelude::*; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; @@ -16,6 +20,7 @@ use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", serde(transparent))] +#[cfg_attr(all(feature = "arbitrary", test), miden_test_serde_macros::serde_test)] #[repr(transparent)] pub struct SectionId(Cow<'static, str>); @@ -157,3 +162,49 @@ impl Deserializable for Section { Ok(Section { id, data: Cow::Owned(bytes.to_owned()) }) } } + +#[cfg(feature = "arbitrary")] +impl Arbitrary for SectionId { + type Parameters = (); + type Strategy = BoxedStrategy; + + fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { + use alloc::string::String; + + let builtins = proptest::sample::select(vec![ + Self::DEBUG_TYPES, + Self::DEBUG_SOURCES, + Self::DEBUG_FUNCTIONS, + Self::ACCOUNT_COMPONENT_METADATA, + Self::PROJECT_SOURCE_PROVENANCE, + Self::KERNEL, + ]); + + let custom = ( + proptest::prop_oneof![ + proptest::char::range('a', 'z'), + proptest::char::range('A', 'Z'), + Just('_'), + ], + proptest::collection::vec( + proptest::prop_oneof![ + proptest::char::range('a', 'z'), + proptest::char::range('A', 'Z'), + proptest::char::range('0', '9'), + Just('.'), + Just('_'), + Just('-'), + ], + 0..31, + ), + ) + .prop_map(|(first, rest)| { + let mut name = String::with_capacity(rest.len() + 1); + name.push(first); + name.extend(rest); + Self::custom(name).expect("generated custom section ids are valid") + }); + + proptest::prop_oneof![builtins, custom].boxed() + } +} diff --git a/crates/mast-package/src/package/seed_gen.rs b/crates/mast-package/src/package/seed_gen.rs index 379878c5bd..fbf7b8fd90 100644 --- a/crates/mast-package/src/package/seed_gen.rs +++ b/crates/mast-package/src/package/seed_gen.rs @@ -48,7 +48,7 @@ fn build_library(signature: Option) -> Arc { Arc::new(Library::new(Arc::new(forest), exports).expect("failed to build library")) } -fn build_package(library: Arc, signature: FunctionType) -> Package { +fn build_package(library: Arc, signature: Option) -> Package { let path = absolute_path("test::proc"); let node_id = library.get_export_node_id(path.as_ref()); let digest = library.mast_forest()[node_id].digest(); @@ -56,7 +56,7 @@ fn build_package(library: Arc, signature: FunctionType) -> Package { let export = PackageExport::Procedure(PackageProcedureExport { path: Arc::clone(&path), digest, - signature: Some(signature), + signature, attributes: AttributeSet::default(), }); @@ -96,8 +96,16 @@ fn generate_fuzz_seeds() { &library_with_signature.to_bytes(), ); - let package = build_package(library_with_signature, signature); + let package = build_package(Arc::clone(&library), None); write_seed("package_deserialize", "minimal_package.bin", &package.to_bytes()); + write_seed("package_semantic_deserialize", "minimal_package.bin", &package.to_bytes()); + + let package_with_signature = build_package(library_with_signature, Some(signature)); + write_seed( + "package_deserialize", + "package_with_signature.bin", + &package_with_signature.to_bytes(), + ); println!("\nSeed corpus generated in ../../miden-core-fuzz/corpus"); } diff --git a/crates/mast-package/src/package/serialization.rs b/crates/mast-package/src/package/serialization.rs index e53f85ab66..3c6efe683d 100644 --- a/crates/mast-package/src/package/serialization.rs +++ b/crates/mast-package/src/package/serialization.rs @@ -32,7 +32,10 @@ use miden_assembly_syntax::{ }; use miden_core::{ Word, - serde::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable}, + serde::{ + BudgetedReader, ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable, + SliceReader, + }, }; use super::{ConstantExport, PackageId, ProcedureExport, TargetType, TypeExport}; @@ -49,6 +52,12 @@ const MAGIC_PACKAGE: &[u8; 5] = b"MASP\0"; /// If future modifications are made to this format, the version should be incremented by 1. const VERSION: [u8; 3] = [4, 0, 0]; +/// Byte-read budget multiplier for package deserialization from a byte slice. +/// +/// The budget is intentionally finite to reject malicious length prefixes, but larger than the +/// source length because collection deserialization uses conservative per-element size estimates. +const PACKAGE_BYTE_READ_BUDGET_MULTIPLIER: usize = 64; + // PACKAGE SERIALIZATION/DESERIALIZATION // ================================================================================================ @@ -136,6 +145,12 @@ impl Deserializable for Package { sections, }) } + + fn read_from_bytes(bytes: &[u8]) -> Result { + let budget = bytes.len().saturating_mul(PACKAGE_BYTE_READ_BUDGET_MULTIPLIER); + let mut reader = BudgetedReader::new(SliceReader::new(bytes), budget); + Self::read_from(&mut reader) + } } // PACKAGE MANIFEST SERIALIZATION/DESERIALIZATION @@ -272,10 +287,7 @@ impl Deserializable for PackageManifest { fn read_from(source: &mut R) -> Result { // Read exports let exports_len = source.read_usize()?; - let mut exports = Vec::with_capacity(exports_len); - for _ in 0..exports_len { - exports.push(PackageExport::read_from(source)?); - } + let exports = source.read_many_iter(exports_len)?.collect::, _>>()?; // Read dependencies let dependencies = Vec::::read_from(source)?; @@ -377,7 +389,13 @@ impl Deserializable for TypeExport { #[cfg(test)] mod tests { - use alloc::{collections::BTreeMap, string::ToString, sync::Arc, vec, vec::Vec}; + use alloc::{ + collections::BTreeMap, + string::{String, ToString}, + sync::Arc, + vec, + vec::Vec, + }; use miden_assembly_syntax::{ Library, @@ -385,6 +403,7 @@ mod tests { library::{LibraryExport, ProcedureExport as LibraryProcedureExport}, }; use miden_core::{ + Word, mast::{BasicBlockNodeBuilder, MastForest, MastForestContributor, MastNodeExt, MastNodeId}, operations::Operation, serde::{ @@ -395,9 +414,12 @@ mod tests { #[cfg(feature = "serde")] use serde_json::{json, to_value}; - use super::{MAGIC_PACKAGE, Package, PackageExport, PackageManifest, VERSION}; + use super::{ + MAGIC_PACKAGE, PACKAGE_BYTE_READ_BUDGET_MULTIPLIER, Package, PackageExport, + PackageManifest, Section, VERSION, + }; use crate::{ - Dependency, ManifestValidationError, PackageId, TargetType, + Dependency, ManifestValidationError, PackageId, SectionId, TargetType, package::manifest::ProcedureExport as PackageProcedureExport, }; @@ -480,6 +502,84 @@ mod tests { bytes } + #[test] + fn package_content_digest_changes_when_identity_fields_change() { + let package = build_package(); + let digest = package.content_digest(); + + let renamed = Package { + name: PackageId::from("renamed_pkg"), + ..package.clone() + }; + assert_ne!(digest, renamed.content_digest()); + + let versioned = Package { + version: crate::Version::new(1, 2, 3), + ..package.clone() + }; + assert_ne!(digest, versioned.content_digest()); + + let executable = Package { kind: TargetType::Executable, ..package }; + assert_ne!(digest, executable.content_digest()); + } + + #[test] + fn package_content_digest_changes_when_manifest_changes() { + let package = build_package(); + let digest = package.content_digest(); + + let mut with_dependency = package; + with_dependency + .manifest + .add_dependency(Dependency { + name: PackageId::from("dep_pkg"), + kind: TargetType::Library, + version: crate::Version::new(1, 0, 0), + digest: Word::from([1_u32, 2, 3, 4]), + }) + .expect("test dependency should be unique"); + assert_ne!(digest, with_dependency.content_digest()); + } + + #[test] + fn package_content_digest_changes_when_account_component_metadata_changes() { + let package = build_package(); + let digest = package.content_digest(); + + let with_metadata = Package { + sections: vec![Section::new(SectionId::ACCOUNT_COMPONENT_METADATA, vec![1, 2, 3, 4])], + ..package.clone() + }; + assert_ne!(digest, with_metadata.content_digest()); + + let with_different_metadata = Package { + sections: vec![Section::new(SectionId::ACCOUNT_COMPONENT_METADATA, vec![4, 3, 2, 1])], + ..package + }; + assert_ne!(with_metadata.content_digest(), with_different_metadata.content_digest()); + } + + #[test] + fn package_content_digest_ignores_description_and_opaque_custom_sections_for_now() { + let package = build_package(); + let digest = package.content_digest(); + + let described = Package { + description: Some(String::from("human-facing package description")), + ..package.clone() + }; + assert_eq!(digest, described.content_digest()); + + let with_section = Package { + sections: vec![Section::new( + SectionId::custom("opaque").expect("valid custom section id"), + vec![1, 2, 3, 4], + )], + ..package + }; + assert_eq!(digest, with_section.content_digest()); + } + #[test] fn package_manifest_rejects_over_budget_dependencies() { let mut bytes = Vec::new(); @@ -499,6 +599,44 @@ mod tests { assert!(matches!(err, DeserializationError::InvalidValue(_))); } + #[test] + fn package_read_from_bytes_rejects_fuzzed_oom_payload() { + // This fuzz payload encodes counts large enough to cause excessive allocation or read work. + // If this starts succeeding, package byte-slice deserialization is no longer budgeted. + let payload = [ + 0x4d, 0x41, 0x53, 0x50, 0x00, 0x04, 0x00, 0x00, 0x11, 0x74, 0x65, 0x73, 0x74, 0x5f, + 0x70, 0x6b, 0x67, 0x0b, 0x30, 0x2e, 0x30, 0x2e, 0x30, 0x00, 0x00, 0x4d, 0x41, 0x53, + 0x54, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x17, 0x03, 0x22, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x30, 0x2f, 0x08, 0x0a, 0x21, 0xa9, 0xb6, 0xf6, 0x1a, 0x52, 0x30, 0xc5, + 0x64, 0xc7, 0xdb, 0x4d, 0x83, 0x0b, 0x32, 0x58, 0x89, 0x88, 0xb2, 0x78, 0x69, 0xbb, + 0x23, 0xa6, 0x18, 0x9c, 0xc9, 0x35, 0x2d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x03, 0x00, 0x0c, 0x00, 0x3a, 0x3a, 0x74, 0x65, 0x73, + 0x74, 0x3a, 0x3a, 0x70, 0x72, 0x6f, 0x63, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03, + 0x0f, 0x03, 0x0f, 0x01, 0x00, 0x00, 0x17, 0x03, 0x22, 0x01, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0xc9, 0x35, 0x2d, 0x01, 0x00, 0x03, 0x0f, 0x03, + 0x0f, 0x01, 0x01, 0x01, + ]; + + let result = Package::read_from_bytes(&payload); + assert!(result.is_err()); + + // Wrapped fuzz inputs must use the generic budgeted entry point; otherwise the outer + // collection length can drive unbounded work before the inner package fails. + let mut vec_payload = vec![0]; + vec_payload.extend_from_slice(&1000u64.to_le_bytes()); + let budget = vec_payload.len().saturating_mul(PACKAGE_BYTE_READ_BUDGET_MULTIPLIER); + let result = Vec::::read_from_bytes_with_budget(&vec_payload, budget); + assert!(result.is_err()); + + let mut option_payload = vec![1]; + option_payload.extend_from_slice(&payload); + let budget = option_payload.len().saturating_mul(PACKAGE_BYTE_READ_BUDGET_MULTIPLIER); + let result = Option::::read_from_bytes_with_budget(&option_payload, budget); + assert!(result.is_err()); + } + #[test] fn package_manifest_new_rejects_duplicate_export_paths() { let library = build_library(); diff --git a/crates/mast-package/src/package/target_type.rs b/crates/mast-package/src/package/target_type.rs index e470e391bd..6a76f4d447 100644 --- a/crates/mast-package/src/package/target_type.rs +++ b/crates/mast-package/src/package/target_type.rs @@ -3,6 +3,8 @@ use alloc::string::String; use alloc::{boxed::Box, string::ToString}; use core::fmt; +#[cfg(all(feature = "arbitrary", test))] +use miden_core::serde::{Deserializable, Serializable}; #[cfg(feature = "serde")] use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error as DeError}; @@ -15,7 +17,10 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error as DeErr /// component, a note script, etc.). #[derive(Default, Debug, Clone, Copy, PartialEq, Eq)] #[cfg_attr(feature = "arbitrary", derive(proptest_derive::Arbitrary))] -#[cfg_attr(all(feature = "arbitrary", test), miden_test_serde_macros::serde_test)] +#[cfg_attr( + all(feature = "arbitrary", test), + miden_test_serde_macros::serde_test(binary_serde(true)) +)] #[non_exhaustive] #[repr(u8)] pub enum TargetType { diff --git a/crates/package-registry-local/Cargo.toml b/crates/package-registry-local/Cargo.toml new file mode 100644 index 0000000000..bbf46c22da --- /dev/null +++ b/crates/package-registry-local/Cargo.toml @@ -0,0 +1,33 @@ +[package] +name = "miden-package-registry-local" +version.workspace = true +description = "Filesystem-backed local package registry for Miden packages" +documentation = "https://docs.rs/miden-package-registry-local" +readme = "README.md" +categories = ["compilers", "command-line-utilities"] +keywords = ["miden", "package", "registry"] +license.workspace = true +authors.workspace = true +homepage.workspace = true +repository.workspace = true +rust-version.workspace = true +edition.workspace = true + +[[bin]] +name = "miden-registry" +path = "src/main.rs" + +[dependencies] +clap.workspace = true +miden-assembly-syntax.workspace = true +miden-core.workspace = true +miden-mast-package.workspace = true +miden-package-registry = { workspace = true, features = ["resolver", "serde"] } +serde.workspace = true +serde_json = { workspace = true, features = ["std"] } +thiserror.workspace = true +toml = { workspace = true, features = ["display", "parse", "serde", "std"] } + +[dev-dependencies] +miden-mast-package = { workspace = true, features = ["arbitrary"] } +tempfile = { workspace = true, features = ["getrandom"] } diff --git a/crates/package-registry-local/README.md b/crates/package-registry-local/README.md new file mode 100644 index 0000000000..1b00230cdc --- /dev/null +++ b/crates/package-registry-local/README.md @@ -0,0 +1,69 @@ +# miden-package-registry-local + +Local filesystem-backed registry and CLI for publishing and inspecting Miden packages. + +The data managed by this registry using the local filesystem is as follows: + +- The registry index, stored at `$MIDEN_SYSROOT/etc/registry/index.toml` +- The artifacts of registered packages, as `$MIDEN_SYSROOT/lib/{pkdid}-{version}-.masp` + +The `MIDEN_SYSROOT` directory is managed by [`midenup`](https://github.com/0xMiden/midenup), and automatically made available to `miden-registry` when invoked as `miden registry`. If running `miden-registry` directly, you must ensure that the `MIDEN_SYSROOT` environment variable is set in your shell. + +## Usage + +When installed via `midenup`, this tool can be invoked with `miden registry`, otherwise it can be built and used directly as `miden-registry`. In the docs here, we will use `miden registry`. + +The `miden registry` command has the following subcommands: + +- `list`, for listing registered packages and their available versions +- `show`, for showing details of a specific package version +- `publish`, for publishing packages to the registry + +See below for more details. + +### Listing packages + +To show a list of available packages, use the `list` subcommand: + +``` +miden registry list [--json] +``` + +The `--json` flag will cause the output to be in JSON format, which makes it easier to consume by other tools if needed. + +### Showing package details + +To show details of a specific package version, use the `show` subcommand: + +``` +# Show details for the latest version of `` +miden registry show [--json] [--quiet] + +# Show details for version `` of `` +miden registry show --version [--json] [--quiet] +``` + +The `--json` flag will cause the output to be in JSON format, which makes it easier to consume by other tools if needed. + +The `--quiet` flag causes error output to be suppressed if a given package or version doesn't exist in the registry. This can be convenient when used in scripts to test for the existence of a package in the registry. By default, the specific reason for an error is emitted to stderr. + +### Publishing a package + +To make a newly-assembled package available via the registry, it must be published, like so: + +``` +miden registry publish path/to/.masp +``` + +This will output an error if the package is invalid, that version of the package has already been registered, or if there is an issue persisting the updated index. + +In addition to ensuring the package artifact is valid, additional rules are enforced as part of the publishing process: + +- The package must embed semantic version metadata +- Each package semantic version maps to at most one canonical published artifact in the local registry, i.e. a given version of a package may only be published once. +- Every dependency in the package manifest must already exist in the registry by exact digest +- Dependency requirements are persisted as exact resolved digests, not the original declared version requirements + +## License + +This project is dual-licensed under the [MIT](http://opensource.org/licenses/MIT) and [Apache 2.0](https://opensource.org/license/apache-2-0) licenses. diff --git a/crates/package-registry-local/src/lib.rs b/crates/package-registry-local/src/lib.rs new file mode 100644 index 0000000000..d5d807df21 --- /dev/null +++ b/crates/package-registry-local/src/lib.rs @@ -0,0 +1,1216 @@ +use std::{ + collections::BTreeMap, + env, fs, + io::{Read, Seek, Write}, + path::{Path, PathBuf}, + sync::Arc, +}; + +use miden_assembly_syntax::Report; +use miden_core::{ + serde::{Deserializable, Serializable}, + utils::DisplayHex, +}; +use miden_mast_package::Package as MastPackage; +use miden_package_registry::{ + InMemoryPackageRegistry, PackageCache, PackageId, PackageIndex, PackageProvider, PackageRecord, + PackageRegistry, PackageStore, PackageVersions, Version, VersionRequirement, +}; +use serde::{Deserialize, Serialize}; + +/// The error raised when operations on a [LocalPackageRegistry] fail +#[derive(Debug, thiserror::Error)] +pub enum LocalRegistryError { + #[error("missing required environment variable '{var}'")] + MissingEnv { var: &'static str }, + #[error("failed to read registry index: {0}")] + IndexRead(#[source] std::io::Error), + #[error("failed to seek in registry index stream: {0}")] + IndexSeek(#[source] std::io::Error), + #[error("failed to lock registry index for reading: {0}")] + IndexReadLock(#[source] fs::TryLockError), + #[error("failed to write registry index: {0}")] + IndexWrite(#[source] std::io::Error), + #[error("failed to lock registry index for writing: {0}")] + IndexWriteLock(#[source] fs::TryLockError), + #[error( + "failed to write registry index: the index was modified by another process, please try again" + )] + WriteToStaleIndex, + #[error("failed to parse registry index: {0}")] + IndexParse(#[from] toml::de::Error), + #[error("failed to serialize registry index: {0}")] + IndexSerialize(#[from] toml::ser::Error), + #[error("failed to decode package artifact '{path}': {error}")] + PackageDecode { path: PathBuf, error: String }, + #[error("package artifact '{path}' is missing semantic version metadata")] + MissingPackageVersion { path: PathBuf }, + #[error("package '{package}' version '{version}' is already registered")] + DuplicateSemanticVersion { + package: PackageId, + version: miden_package_registry::SemVer, + }, + #[error("package '{package}' with version '{version}' is not present in the registry")] + MissingPackage { package: PackageId, version: Version }, + #[error("package '{package}' version '{version}' has no artifact digest")] + MissingArtifactDigest { package: PackageId, version: Version }, + #[error("package artifact for '{package}' version '{version}' was not found at '{path}'")] + MissingArtifact { + package: PackageId, + version: Version, + path: PathBuf, + }, + #[error( + "package artifact at '{path}' does not match requested package '{expected_package}' version '{expected_version}' (found '{actual_package}' version '{actual_version}')" + )] + ArtifactMismatch { + path: PathBuf, + expected_package: PackageId, + expected_version: Box, + actual_package: PackageId, + actual_version: Box, + }, + #[error( + "package '{package}' depends on unpublished package '{dependency}' with version '{version}'" + )] + MissingDependency { + package: PackageId, + dependency: PackageId, + version: Version, + }, +} + +/// A [PackageRegistry] implementation that uses the local filesystem for storage of: +/// +/// * The package index, as a TOML manifest, written to `$MIDEN_SYSROOT/etc/registry/index.toml` +/// * The package artifacts (i.e. `.masp` files) of registered packages, stored under +/// `$MIDEN_SYSROOT/lib`. +/// +/// The index is associated with a specific toolchain for now, as it makes integration into +/// `midenup` easier, and we're still at a stage where having a clean slate when switching +/// to a new toolchain prevents confusing errors. +/// +/// TODO(pauls): In the future, we should move the registry to a toolchain-agnostic location, and +/// make registry operations global. +pub struct LocalPackageRegistry { + index_path: PathBuf, + artifact_dir: PathBuf, + index: InMemoryPackageRegistry, + index_checksum: [u8; 32], +} + +/// The metadata about a package produced when listing or describing a package in the index +#[derive(Debug, Clone, PartialEq, Eq, Serialize)] +pub struct PackageSummary { + /// The package identifier/name + pub name: PackageId, + /// The package semantic version and digest + pub version: Version, + /// The package description + pub description: Option>, + /// The version requirements for dependencies of this package + pub dependencies: BTreeMap, + /// The location of the assembled artifact on disk. + /// + /// If `None`, the package has been registered virtually, and so has no location on disk. + pub artifact_path: Option, +} + +/// A succinct summary of a package, produced when it is published to the registry. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct PublishedPackage { + pub name: PackageId, + pub version: Version, + pub artifact_path: PathBuf, +} + +/// The representation of the on-disk package index +#[derive(Default, Serialize, Deserialize)] +struct PersistedIndex { + #[serde(default)] + packages: BTreeMap, +} + +impl Default for LocalPackageRegistry { + fn default() -> Self { + Self::load_from_env().expect("could not create a default instance of the package registry") + } +} + +impl LocalPackageRegistry { + /// Create a new [LocalPackageRegistry], by deriving the index and artifact storage locations + /// from the `$MIDEN_SYSROOT` environment variable. + /// + /// This produces an error if the environment variable is unset, or the index fails to load. + pub fn load_from_env() -> Result { + let sysroot = PathBuf::from( + env::var_os("MIDEN_SYSROOT") + .ok_or(LocalRegistryError::MissingEnv { var: "MIDEN_SYSROOT" })?, + ); + + let index_path = sysroot.join("etc").join("registry").join("index.toml"); + let artifact_dir = sysroot.join("lib"); + Self::load(index_path, artifact_dir) + } + + /// Create a new [LocalPackageRegistry], specifying the locations of the registry index, and + /// artifact storage. + /// + /// Requirements: + /// + /// * The `index_path` must be a file path to the index manifest, which is a TOML file. + /// * The `artifact_dir` must be a directory path. + /// + /// This produces an error if the paths are invalid, or the index fails to load. + pub fn load(index_path: PathBuf, artifact_dir: PathBuf) -> Result { + if let Some(parent) = index_path.parent() { + fs::create_dir_all(parent).map_err(LocalRegistryError::IndexWrite)?; + } + fs::create_dir_all(&artifact_dir).map_err(LocalRegistryError::IndexWrite)?; + + let index_checksum: [u8; 32]; + let index = if index_path.exists() { + let mut contents = String::with_capacity(4 * 1024); + #[allow(clippy::verbose_file_reads)] + { + let mut file = + fs::File::open(&index_path).map_err(LocalRegistryError::IndexRead)?; + // Acquire a non-exclusive lock on the file for reading, but return an error if + // there is an outstanding exclusive lock on the file already. + // + // This will fail if a handle to the index file has an exclusive lock on it for + // writing, see `save` for details. + // + // Multiple readers can hold this type of lock simultaneously, but a shared lock + // cannot be acquired in the presence of an exclusive lock, and vice versa. + file.try_lock_shared().map_err(LocalRegistryError::IndexReadLock)?; + file.read_to_string(&mut contents).map_err(LocalRegistryError::IndexRead)?; + } + let contents = contents.trim(); + index_checksum = + *miden_core::crypto::hash::Sha256::hash(contents.as_bytes()).as_bytes(); + if contents.is_empty() { + InMemoryPackageRegistry::default() + } else { + let persisted = toml::from_str::(contents)?; + InMemoryPackageRegistry::from_packages(persisted.packages) + } + } else { + index_checksum = *miden_core::crypto::hash::Sha256::hash(&[]).as_bytes(); + InMemoryPackageRegistry::default() + }; + + Ok(Self { + index_path, + artifact_dir, + index, + index_checksum, + }) + } + + /// Publish the Miden package found at `package_path`. + /// + /// The provided path must be a path to a `.masp` file (or at least a file containing a valid + /// Miden package). + /// + /// Returns an error if the package cannot be found, is invalid, or cannot be written to the + /// artifact store of the registry. + pub fn publish( + &mut self, + package_path: impl AsRef, + ) -> Result { + let package_path = package_path.as_ref(); + let bytes = fs::read(package_path).map_err(LocalRegistryError::IndexRead)?; + let package = MastPackage::read_from_bytes(&bytes).map_err(|error| { + LocalRegistryError::PackageDecode { + path: package_path.to_path_buf(), + error: error.to_string(), + } + })?; + + self.publish_package_with_bytes(Arc::new(package), bytes) + } + + /// List all of the packages indexed by this registry + pub fn list(&self) -> Vec { + self.index + .packages() + .iter() + .flat_map(|(name, versions)| { + versions.values().map(|record| { + self.package_summary(name.clone(), record.version().clone(), record) + }) + }) + .collect() + } + + /// Get the package summary for the given package and version. + /// + /// If no version is specified, the latest version will be returned. + /// + /// If the package is not indexed, or the specified version cannot be found, this returns `None` + pub fn show(&self, package: &PackageId, version: Option<&Version>) -> Option { + let (version, record) = match version { + Some(version) => self + .index + .get_by_version(package, version) + .map(|record| (record.version().clone(), record))?, + None => self + .index + .available_versions(package)? + .values() + .next_back() + .map(|record| (record.version().clone(), record))?, + }; + + Some(self.package_summary(package.clone(), version, record)) + } + + /// Get the path in the artifact store for `package` at `version` + pub fn artifact_path(&self, package: &PackageId, version: &Version) -> Option { + self.artifact_path_for_summary(package, version) + } + + fn artifact_path_for_summary(&self, package: &PackageId, version: &Version) -> Option { + let digest = *version.digest.as_ref()?; + let artifact_path = self.artifact_path_for_package(package, &version.version, digest); + if artifact_path.exists() { + return Some(artifact_path); + } + + let legacy_path = self.legacy_artifact_path_for_digest(digest); + if self.legacy_artifact_matches(package, version, &legacy_path) { + Some(legacy_path) + } else { + Some(artifact_path) + } + } + + fn legacy_artifact_matches(&self, package: &PackageId, version: &Version, path: &Path) -> bool { + let Ok(bytes) = fs::read(path) else { + return false; + }; + let Ok(loaded) = MastPackage::read_from_bytes(&bytes) else { + return false; + }; + let actual_version = Version::new(loaded.version.clone(), loaded.digest()); + loaded.name == *package && actual_version == *version + } + + /// Loads the given version of `package` from the artifact store. + /// + /// Returns an error if the artifact cannot be loaded, or is unknown to the registry. + pub fn load_package( + &self, + package: &PackageId, + version: &Version, + ) -> Result, LocalRegistryError> { + self.index.get_by_version(package, version).ok_or_else(|| { + LocalRegistryError::MissingPackage { + package: package.clone(), + version: version.clone(), + } + })?; + + let digest = version.digest.ok_or_else(|| LocalRegistryError::MissingArtifactDigest { + package: package.clone(), + version: version.clone(), + })?; + let path = self.artifact_path_for_package(package, &version.version, digest); + let path = if path.exists() { + path + } else { + let legacy_path = self.legacy_artifact_path_for_digest(digest); + if legacy_path.exists() { + legacy_path + } else { + return Err(LocalRegistryError::MissingArtifact { + package: package.clone(), + version: version.clone(), + path, + }); + } + }; + + let bytes = fs::read(&path).map_err(LocalRegistryError::IndexRead)?; + let loaded = MastPackage::read_from_bytes(&bytes).map_err(|error| { + LocalRegistryError::PackageDecode { + path: path.clone(), + error: error.to_string(), + } + })?; + + let actual_version = Version::new(loaded.version.clone(), loaded.digest()); + if loaded.name != *package || actual_version != *version { + return Err(LocalRegistryError::ArtifactMismatch { + path, + expected_package: package.clone(), + expected_version: Box::new(version.clone()), + actual_package: loaded.name, + actual_version: Box::new(actual_version), + }); + } + + Ok(Arc::new(loaded)) + } + + fn save_with_locked_operation( + &mut self, + operation: impl FnOnce() -> Result<(), LocalRegistryError>, + ) -> Result<(), LocalRegistryError> { + let persisted = PersistedIndex { packages: self.index.packages().clone() }; + let contents = toml::to_string_pretty(&persisted)?; + let mut file = fs::File::options() + .read(true) + .write(true) + .truncate(false) + .create(true) + .open(&self.index_path) + .map_err(LocalRegistryError::IndexWrite)?; + // Acquire an exclusive lock for writing the index file, and return an error if we cannot + // obtain one due to any other outstanding lock on the file. + // + // This will fail if another write is being performed on the same file, or if the index is + // currently being loaded by another process. + // + // See `load` for the non-exclusive lock obtained for reads + file.try_lock().map_err(LocalRegistryError::IndexWriteLock)?; + + // Validate that the contents of the persisted index have not changed under us, by + // recomputing the checksum of its contents and comparing to when we last loaded the index. + #[allow(clippy::verbose_file_reads)] + { + let mut prev_contents = Vec::with_capacity(1024); + file.read_to_end(&mut prev_contents).map_err(LocalRegistryError::IndexRead)?; + let checksum = miden_core::crypto::hash::Sha256::hash(prev_contents.trim_ascii()); + if &self.index_checksum != checksum.as_bytes() { + return Err(LocalRegistryError::WriteToStaleIndex); + } + } + + operation()?; + + // Compute the new checksum of the updated index contents before we write, but do not + // update the in-memory state until we've successfully persisted the index + let new_checksum = miden_core::crypto::hash::Sha256::hash(contents.as_bytes().trim_ascii()); + + // Truncate the file to ensure that if the new index is smaller than the old one, that + // we don't end up with a corrupted index. + file.rewind().map_err(LocalRegistryError::IndexSeek)?; + file.set_len(0).map_err(LocalRegistryError::IndexWrite)?; + file.write_all(contents.as_bytes()).map_err(LocalRegistryError::IndexWrite)?; + + // Update the index checksum for the next write + self.index_checksum = *new_checksum.as_bytes(); + + Ok(()) + } + + fn register_and_save_with_locked_operation( + &mut self, + name: PackageId, + record: PackageRecord, + operation: impl FnOnce() -> Result<(), LocalRegistryError>, + ) -> Result<(), LocalRegistryError> { + let previous_packages = self.index.packages().clone(); + self.register(name, record)?; + match self.save_with_locked_operation(operation) { + Ok(()) => Ok(()), + Err(error) => { + self.index = InMemoryPackageRegistry::from_packages(previous_packages); + Err(error) + }, + } + } + + fn write_cache_artifact_from_legacy_or_bytes( + artifact_path: &Path, + legacy_path: &Path, + package: &MastPackage, + version: &Version, + bytes: &[u8], + ) -> Result<(), LocalRegistryError> { + match fs::read(legacy_path) { + Ok(existing_bytes) => match MastPackage::read_from_bytes(&existing_bytes) { + Ok(existing_package) => { + let existing_version = + Version::new(existing_package.version.clone(), existing_package.digest()); + if existing_package.name == package.name && existing_version == *version { + if &existing_package == package { + fs::write(artifact_path, existing_bytes) + .map_err(LocalRegistryError::IndexWrite) + } else { + Err(LocalRegistryError::DuplicateSemanticVersion { + package: package.name.clone(), + version: package.version.clone(), + }) + } + } else { + fs::write(artifact_path, bytes).map_err(LocalRegistryError::IndexWrite) + } + }, + Err(_) => fs::write(artifact_path, bytes).map_err(LocalRegistryError::IndexWrite), + }, + Err(_) => fs::write(artifact_path, bytes).map_err(LocalRegistryError::IndexWrite), + } + } + + fn repair_cache_artifact( + artifact_path: &Path, + legacy_path: &Path, + package: &MastPackage, + version: &Version, + bytes: &[u8], + ) -> Result<(), LocalRegistryError> { + match fs::read(artifact_path) { + Ok(existing_bytes) => match MastPackage::read_from_bytes(&existing_bytes) { + Ok(existing_package) if &existing_package == package => Ok(()), + Ok(_) => Err(LocalRegistryError::DuplicateSemanticVersion { + package: package.name.clone(), + version: package.version.clone(), + }), + Err(_) => Self::write_cache_artifact_from_legacy_or_bytes( + artifact_path, + legacy_path, + package, + version, + bytes, + ), + }, + Err(_) => Self::write_cache_artifact_from_legacy_or_bytes( + artifact_path, + legacy_path, + package, + version, + bytes, + ), + } + } + + /// Derive the path in the artifact store for a package with `digest` + /// + /// The file name includes the package name and semantic version to avoid collisions between + /// package identities that share the same underlying MAST digest. + fn artifact_path_for_package( + &self, + package: &PackageId, + version: &miden_package_registry::SemVer, + digest: miden_core::Word, + ) -> PathBuf { + let package_id = DisplayHex(package.as_bytes()); + let semantic_version = version.to_string(); + let semantic_version = DisplayHex(semantic_version.as_bytes()); + let digest_bytes = digest.as_bytes(); + let digest = DisplayHex::new(&digest_bytes); + let filename = format!("{package_id}-{semantic_version}-{digest:#}.masp"); + self.artifact_dir.join(filename) + } + + /// Derive the artifact path used before filenames included package identity. + fn legacy_artifact_path_for_digest(&self, digest: miden_core::Word) -> PathBuf { + let filename = format!("{:#}.masp", DisplayHex::new(&digest.as_bytes())); + self.artifact_dir.join(filename) + } + + /// Construct the [PackageSummary] for the given package version + fn package_summary( + &self, + name: PackageId, + version: Version, + record: &PackageRecord, + ) -> PackageSummary { + PackageSummary { + artifact_path: self.artifact_path_for_summary(&name, &version), + dependencies: record + .dependencies() + .iter() + .map(|(dependency, requirement)| (dependency.clone(), requirement.clone())) + .collect(), + description: record.description().cloned(), + name, + version, + } + } + + fn record_for_package( + package: &MastPackage, + version: Version, + ) -> (PackageRecord, Vec<(PackageId, Version, VersionRequirement)>) { + let dependencies = package + .manifest + .dependencies() + .map(|dependency| { + let dependency_name = dependency.id().clone(); + let dependency_version = + Version::new(dependency.version.clone(), dependency.digest); + ( + dependency_name, + dependency_version.clone(), + VersionRequirement::Exact(dependency_version), + ) + }) + .collect::>(); + + let record = match package.description.clone() { + Some(description) => PackageRecord::new( + version, + dependencies + .iter() + .map(|(name, _version, requirement)| (name.clone(), requirement.clone())), + ) + .with_description(description), + None => PackageRecord::new( + version, + dependencies + .iter() + .map(|(name, _version, requirement)| (name.clone(), requirement.clone())), + ), + }; + + (record, dependencies) + } + + fn cache_package_with_bytes( + &mut self, + package: Arc, + bytes: Vec, + ) -> Result { + let digest = package.digest(); + let version = Version::new(package.version.clone(), digest); + let (record, _dependencies) = Self::record_for_package(&package, version.clone()); + let artifact_path = self.artifact_path_for_package(&package.name, &package.version, digest); + + if let Some(existing) = self.index.get_by_semver(&package.name, &package.version) { + if existing.version() != &version || existing != &record { + return Err(LocalRegistryError::DuplicateSemanticVersion { + package: package.name.clone(), + version: package.version.clone(), + }); + } + + let legacy_path = self.legacy_artifact_path_for_digest(digest); + self.save_with_locked_operation(|| { + Self::repair_cache_artifact( + &artifact_path, + &legacy_path, + package.as_ref(), + &version, + &bytes, + ) + })?; + return Ok(PublishedPackage { + name: package.name.clone(), + version, + artifact_path, + }); + } + + self.register_and_save_with_locked_operation(package.name.clone(), record, || { + fs::write(&artifact_path, bytes).map_err(LocalRegistryError::IndexWrite) + })?; + + Ok(PublishedPackage { + name: package.name.clone(), + version, + artifact_path, + }) + } + + /// Publish `package`, with `bytes` representing the serialized form of `package` which + /// determines its provenance, i.e. if we deserialized `package` from `bytes`, then `bytes` + /// is those exact bytes, not the bytes we would get by serializing `package`, which might + /// differ from the original bytes. + fn publish_package_with_bytes( + &mut self, + package: Arc, + bytes: Vec, + ) -> Result { + let digest = package.digest(); + let version = Version::new(package.version.clone(), digest); + let (record, dependencies) = Self::record_for_package(&package, version.clone()); + + for (dependency_name, dependency_version, _requirement) in dependencies.iter() { + if self.index.get_exact_version(dependency_name, dependency_version).is_none() { + return Err(LocalRegistryError::MissingDependency { + package: package.name.clone(), + dependency: dependency_name.clone(), + version: dependency_version.clone(), + }); + } + } + + // Write the package artifact to the registry + let artifact_path = self.artifact_path_for_package(&package.name, &package.version, digest); + if self.index.get_by_semver(&package.name, &package.version).is_some() { + return Err(LocalRegistryError::DuplicateSemanticVersion { + package: package.name.clone(), + version: package.version.clone(), + }); + } + + // Persist the updated registry index and artifact under the index write lock. + self.register_and_save_with_locked_operation(package.name.clone(), record, || { + fs::write(&artifact_path, bytes).map_err(LocalRegistryError::IndexWrite) + })?; + + Ok(PublishedPackage { + name: package.name.clone(), + version, + artifact_path, + }) + } +} + +impl PackageRegistry for LocalPackageRegistry { + fn available_versions(&self, package: &PackageId) -> Option<&PackageVersions> { + self.index.available_versions(package) + } +} + +impl PackageIndex for LocalPackageRegistry { + type Error = LocalRegistryError; + + fn register(&mut self, name: PackageId, record: PackageRecord) -> Result<(), Self::Error> { + let semver = record.semantic_version().clone(); + self.index.insert_record(name.clone(), record).map_err(|_error| { + LocalRegistryError::DuplicateSemanticVersion { package: name, version: semver } + }) + } +} + +impl PackageProvider for LocalPackageRegistry { + fn load_package( + &self, + package: &PackageId, + version: &Version, + ) -> Result, Report> { + Self::load_package(self, package, version).map_err(|error| Report::msg(error.to_string())) + } +} + +impl PackageCache for LocalPackageRegistry { + type Error = LocalRegistryError; + + fn cache_package(&mut self, package: Arc) -> Result { + let bytes = package.to_bytes(); + self.cache_package_with_bytes(package, bytes).map(|published| published.version) + } +} + +impl PackageStore for LocalPackageRegistry { + fn publish_package(&mut self, package: Arc) -> Result { + let bytes = package.to_bytes(); + self.publish_package_with_bytes(package, bytes) + .map(|published| published.version) + } +} + +#[cfg(test)] +mod tests { + use miden_mast_package::{Dependency, Package, Section, SectionId, TargetType}; + use tempfile::TempDir; + + use super::*; + + fn build_package<'a>( + name: &str, + version: &str, + dependencies: impl IntoIterator, + ) -> Box { + Package::generate( + name.into(), + version.parse().unwrap(), + TargetType::Library, + dependencies.into_iter().map(|(name, version, kind, digest)| Dependency { + name: name.into(), + version: version.parse().unwrap(), + kind, + digest, + }), + ) + } + + fn load_registry(tempdir: &TempDir) -> LocalPackageRegistry { + let index_path = tempdir.path().join("midenup").join("registry").join("index.toml"); + let artifact_dir = tempdir.path().join("sysroot").join("lib"); + LocalPackageRegistry::load(index_path, artifact_dir).expect("failed to load registry") + } + + #[test] + fn publish_persists_artifact_and_index() { + let tempdir = TempDir::new().unwrap(); + let mut registry = load_registry(&tempdir); + + let dep_path = tempdir.path().join("dep.masp"); + let dep = build_package("dep", "1.0.0", []); + dep.write_to_file(&dep_path).unwrap(); + registry.publish(&dep_path).expect("failed to publish dependency"); + + let package_path = tempdir.path().join("pkg.masp"); + let package = + build_package("pkg", "2.0.0", [("dep", "1.0.0", TargetType::Library, dep.digest())]); + package.write_to_file(&package_path).unwrap(); + + let published = registry.publish(&package_path).expect("failed to publish package"); + let artifact = &published.artifact_path; + assert!(artifact.exists()); + + let reloaded = load_registry(&tempdir); + let listed = reloaded.list(); + assert_eq!(listed.len(), 2); + + let shown = reloaded.show(&PackageId::from("pkg"), None).expect("missing package"); + assert_eq!(shown.version.version, "2.0.0".parse().unwrap()); + assert_eq!(shown.dependencies.len(), 1); + assert_eq!(shown.dependencies.keys().next().unwrap(), &PackageId::from("dep")); + assert_eq!( + shown.dependencies.values().next().unwrap().to_string(), + format!("1.0.0#{}", dep.digest()) + ); + } + + #[test] + fn publish_rejects_missing_dependencies() { + let tempdir = TempDir::new().unwrap(); + let mut registry = load_registry(&tempdir); + + let package_path = tempdir.path().join("pkg.masp"); + let package = build_package( + "pkg", + "1.0.0", + [( + "dep", + "1.0.0", + TargetType::Library, + miden_core::utils::hash_string_to_word("dep"), + )], + ); + package.write_to_file(&package_path).unwrap(); + + let error = registry.publish(&package_path).expect_err("publish should fail"); + assert!(matches!(error, LocalRegistryError::MissingDependency { .. })); + } + + #[test] + fn cache_persists_packages_with_missing_dependencies() { + let tempdir = TempDir::new().unwrap(); + let mut registry = load_registry(&tempdir); + + let dependency_digest = miden_core::utils::hash_string_to_word("dep"); + let package = build_package( + "pkg", + "1.0.0", + [("dep", "1.0.0", TargetType::Library, dependency_digest)], + ); + let version = registry + .cache_package(Arc::from(package)) + .expect("cache should accept unresolved dependencies"); + + let reloaded = load_registry(&tempdir); + let shown = reloaded + .show(&PackageId::from("pkg"), Some(&version)) + .expect("cached package should be indexed"); + assert_eq!(shown.dependencies.len(), 1); + assert!(reloaded.load_package(&PackageId::from("pkg"), &version).is_ok()); + } + + #[test] + fn cache_rejects_different_artifact_for_existing_exact_version() { + let tempdir = TempDir::new().unwrap(); + let mut registry = load_registry(&tempdir); + + let package_path = tempdir.path().join("pkg.masp"); + build_package("pkg", "1.0.0", []).write_to_file(&package_path).unwrap(); + let published = registry.publish(&package_path).unwrap(); + + let mut conflicting_package = build_package("pkg", "1.0.0", []); + conflicting_package + .sections + .push(Section::new(SectionId::custom("cache-test").unwrap(), Vec::from([1, 2, 3]))); + assert_eq!(Some(conflicting_package.digest()), published.version.digest); + + let error = registry + .cache_package(Arc::from(conflicting_package)) + .expect_err("cache should reject conflicting package artifacts"); + assert!(matches!(error, LocalRegistryError::DuplicateSemanticVersion { .. })); + + let loaded = registry.load_package(&PackageId::from("pkg"), &published.version).unwrap(); + assert_eq!(loaded.manifest.dependencies().count(), 0); + assert!(loaded.sections.is_empty()); + } + + #[test] + fn stale_cache_does_not_overwrite_artifact() { + let tempdir = TempDir::new().unwrap(); + let mut stale_registry = load_registry(&tempdir); + let mut current_registry = load_registry(&tempdir); + + let package_path = tempdir.path().join("pkg.masp"); + build_package("pkg", "1.0.0", []).write_to_file(&package_path).unwrap(); + let published = current_registry.publish(&package_path).unwrap(); + let original_bytes = fs::read(&published.artifact_path).unwrap(); + + let mut conflicting_package = build_package("pkg", "1.0.0", []); + conflicting_package.sections.push(Section::new( + SectionId::custom("stale-cache-test").unwrap(), + Vec::from([1, 2, 3]), + )); + assert_eq!(Some(conflicting_package.digest()), published.version.digest); + + let error = stale_registry + .cache_package(conflicting_package.into()) + .expect_err("stale cache should fail before writing artifact bytes"); + assert!(matches!(error, LocalRegistryError::WriteToStaleIndex)); + assert_eq!(fs::read(&published.artifact_path).unwrap(), original_bytes); + } + + #[test] + fn concurrent_cache_repair_does_not_overwrite_existing_artifact() { + let tempdir = TempDir::new().unwrap(); + let mut registry = load_registry(&tempdir); + + let package_path = tempdir.path().join("pkg.masp"); + build_package("pkg", "1.0.0", []).write_to_file(&package_path).unwrap(); + let published = registry.publish(&package_path).unwrap(); + fs::remove_file(&published.artifact_path).unwrap(); + + let mut first_registry = load_registry(&tempdir); + let mut second_registry = load_registry(&tempdir); + let repaired_package = build_package("pkg", "1.0.0", []); + let repaired_bytes = repaired_package.to_bytes(); + first_registry.cache_package(repaired_package.into()).unwrap(); + + let mut conflicting_package = build_package("pkg", "1.0.0", []); + conflicting_package.sections.push(Section::new( + SectionId::custom("cache-repair-race-test").unwrap(), + Vec::from([1, 2, 3]), + )); + assert_eq!(Some(conflicting_package.digest()), published.version.digest); + let error = second_registry + .cache_package(conflicting_package.into()) + .expect_err("cache repair should revalidate the artifact under the index lock"); + assert!(matches!(error, LocalRegistryError::DuplicateSemanticVersion { .. })); + assert_eq!(fs::read(&published.artifact_path).unwrap(), repaired_bytes); + } + + #[test] + fn cache_repair_checks_legacy_artifact_before_writing_qualified_artifact() { + let tempdir = TempDir::new().unwrap(); + let mut registry = load_registry(&tempdir); + + let package_path = tempdir.path().join("pkg.masp"); + build_package("pkg", "1.0.0", []).write_to_file(&package_path).unwrap(); + let published = registry.publish(&package_path).unwrap(); + let original_bytes = fs::read(&published.artifact_path).unwrap(); + let legacy_path = + registry.legacy_artifact_path_for_digest(published.version.digest.unwrap()); + fs::rename(&published.artifact_path, &legacy_path).unwrap(); + + let mut conflicting_package = build_package("pkg", "1.0.0", []); + conflicting_package.sections.push(Section::new( + SectionId::custom("legacy-cache-repair-test").unwrap(), + Vec::from([1, 2, 3]), + )); + assert_eq!(Some(conflicting_package.digest()), published.version.digest); + + let error = registry + .cache_package(conflicting_package.into()) + .expect_err("cache repair should reject conflicts with the legacy artifact"); + assert!(matches!(error, LocalRegistryError::DuplicateSemanticVersion { .. })); + assert!(!published.artifact_path.exists()); + assert_eq!(fs::read(&legacy_path).unwrap(), original_bytes); + + let loaded = registry.load_package(&PackageId::from("pkg"), &published.version).unwrap(); + assert!(loaded.sections.is_empty()); + } + + #[test] + fn cache_repair_checks_legacy_artifact_before_replacing_corrupt_qualified_artifact() { + let tempdir = TempDir::new().unwrap(); + let mut registry = load_registry(&tempdir); + + let package_path = tempdir.path().join("pkg.masp"); + build_package("pkg", "1.0.0", []).write_to_file(&package_path).unwrap(); + let published = registry.publish(&package_path).unwrap(); + let original_bytes = fs::read(&published.artifact_path).unwrap(); + let legacy_path = + registry.legacy_artifact_path_for_digest(published.version.digest.unwrap()); + fs::write(&legacy_path, &original_bytes).unwrap(); + fs::write(&published.artifact_path, b"not a package").unwrap(); + + let mut conflicting_package = build_package("pkg", "1.0.0", []); + conflicting_package.sections.push(Section::new( + SectionId::custom("legacy-cache-corrupt-qualified-test").unwrap(), + Vec::from([1, 2, 3]), + )); + assert_eq!(Some(conflicting_package.digest()), published.version.digest); + + let error = registry + .cache_package(conflicting_package.into()) + .expect_err("cache repair should reject conflicts with the legacy artifact"); + assert!(matches!(error, LocalRegistryError::DuplicateSemanticVersion { .. })); + assert_eq!(fs::read(&legacy_path).unwrap(), original_bytes); + assert_eq!(fs::read(&published.artifact_path).unwrap(), b"not a package"); + } + + #[test] + fn list_and_show_include_multiple_versions() { + let tempdir = TempDir::new().unwrap(); + let mut registry = load_registry(&tempdir); + + let first_path = tempdir.path().join("pkg-1.masp"); + let second_path = tempdir.path().join("pkg-2.masp"); + build_package("pkg", "1.0.0", []).write_to_file(&first_path).unwrap(); + build_package("pkg", "2.0.0", []).write_to_file(&second_path).unwrap(); + + registry.publish(&first_path).unwrap(); + registry.publish(&second_path).unwrap(); + + let listed = registry.list(); + assert_eq!(listed.len(), 2); + + let latest = registry.show(&PackageId::from("pkg"), None).unwrap(); + assert_eq!(latest.version.version, "2.0.0".parse().unwrap()); + + let exact = + registry.show(&PackageId::from("pkg"), Some(&"1.0.0".parse().unwrap())).unwrap(); + assert_eq!(exact.version.version, "1.0.0".parse().unwrap()); + } + + #[test] + fn publish_rejects_duplicate_semantic_versions() { + let tempdir = TempDir::new().unwrap(); + let mut registry = load_registry(&tempdir); + + let first_path = tempdir.path().join("pkg-1.masp"); + let second_path = tempdir.path().join("pkg-2.masp"); + build_package("pkg", "1.0.0", []).write_to_file(&first_path).unwrap(); + build_package("pkg", "1.0.0", []).write_to_file(&second_path).unwrap(); + + registry.publish(&first_path).unwrap(); + let error = registry.publish(&second_path).expect_err("duplicate semver should fail"); + assert!(matches!(error, LocalRegistryError::DuplicateSemanticVersion { .. })); + } + + #[test] + fn publish_rejects_duplicate_semantic_versions_for_identical_bytes() { + let tempdir = TempDir::new().unwrap(); + let mut registry = load_registry(&tempdir); + + let package_path = tempdir.path().join("pkg.masp"); + build_package("pkg", "1.0.0", []).write_to_file(&package_path).unwrap(); + + registry.publish(&package_path).unwrap(); + let error = registry + .publish(&package_path) + .expect_err("duplicate semver should fail even for identical bytes"); + assert!(matches!(error, LocalRegistryError::DuplicateSemanticVersion { .. })); + } + + #[test] + fn publish_duplicate_semver_does_not_overwrite_artifact() { + let tempdir = TempDir::new().unwrap(); + let mut registry = load_registry(&tempdir); + + let package_path = tempdir.path().join("pkg.masp"); + build_package("pkg", "1.0.0", []).write_to_file(&package_path).unwrap(); + let published = registry.publish(&package_path).unwrap(); + let original_bytes = fs::read(&published.artifact_path).unwrap(); + + let mut conflicting_package = build_package("pkg", "1.0.0", []); + conflicting_package + .sections + .push(Section::new(SectionId::custom("publish-test").unwrap(), Vec::from([1, 2, 3]))); + assert_eq!(Some(conflicting_package.digest()), published.version.digest); + let conflicting_path = tempdir.path().join("pkg-conflicting.masp"); + conflicting_package.write_to_file(&conflicting_path).unwrap(); + + let error = registry + .publish(&conflicting_path) + .expect_err("duplicate semver should fail before writing artifact bytes"); + assert!(matches!(error, LocalRegistryError::DuplicateSemanticVersion { .. })); + assert_eq!(fs::read(&published.artifact_path).unwrap(), original_bytes); + + let loaded = registry.load_package(&PackageId::from("pkg"), &published.version).unwrap(); + assert!(loaded.sections.is_empty()); + } + + #[test] + fn stale_publish_duplicate_semver_does_not_overwrite_artifact() { + let tempdir = TempDir::new().unwrap(); + let mut stale_registry = load_registry(&tempdir); + let mut current_registry = load_registry(&tempdir); + + let package_path = tempdir.path().join("pkg.masp"); + build_package("pkg", "1.0.0", []).write_to_file(&package_path).unwrap(); + let published = current_registry.publish(&package_path).unwrap(); + let original_bytes = fs::read(&published.artifact_path).unwrap(); + + let mut conflicting_package = build_package("pkg", "1.0.0", []); + conflicting_package.sections.push(Section::new( + SectionId::custom("stale-publish-test").unwrap(), + Vec::from([1, 2, 3]), + )); + assert_eq!(Some(conflicting_package.digest()), published.version.digest); + let conflicting_path = tempdir.path().join("pkg-conflicting.masp"); + conflicting_package.write_to_file(&conflicting_path).unwrap(); + + let error = stale_registry + .publish(&conflicting_path) + .expect_err("stale publish should fail before writing artifact bytes"); + assert!(matches!(error, LocalRegistryError::WriteToStaleIndex)); + assert_eq!(fs::read(&published.artifact_path).unwrap(), original_bytes); + } + + #[test] + fn failed_publish_artifact_write_does_not_persist_index_on_later_save() { + let tempdir = TempDir::new().unwrap(); + let mut registry = load_registry(&tempdir); + + let package = build_package("pkg", "1.0.0", []); + let package_path = tempdir.path().join("pkg.masp"); + package.write_to_file(&package_path).unwrap(); + let artifact_path = + registry.artifact_path_for_package(&package.name, &package.version, package.digest()); + fs::create_dir(&artifact_path).unwrap(); + + let error = registry + .publish(&package_path) + .expect_err("artifact write should fail while the artifact path is a directory"); + assert!(matches!(error, LocalRegistryError::IndexWrite(_))); + fs::remove_dir(&artifact_path).unwrap(); + + let other_path = tempdir.path().join("other.masp"); + build_package("other", "1.0.0", []).write_to_file(&other_path).unwrap(); + registry.publish(&other_path).expect("later publish should succeed"); + + let reloaded = load_registry(&tempdir); + assert!(reloaded.show(&PackageId::from("pkg"), None).is_none()); + assert!(reloaded.show(&PackageId::from("other"), None).is_some()); + } + + #[test] + #[should_panic = "stale registry write failed"] + fn publish_rejects_writes_to_a_stale_index() { + let tempdir = TempDir::new().unwrap(); + let mut first_registry = load_registry(&tempdir); + let mut stale_registry = load_registry(&tempdir); + + let first_path = tempdir.path().join("a.masp"); + let second_path = tempdir.path().join("longer-package-name.masp"); + build_package("a", "1.0.0", []).write_to_file(&first_path).unwrap(); + build_package("longer-package-name", "1.0.0", []) + .write_to_file(&second_path) + .unwrap(); + + // This write succeeds because the index is not yet stale, but this write will make it + // stale + first_registry.publish(&first_path).unwrap(); + // This write will fail because it's view of the index is now stale + stale_registry.publish(&second_path).expect("stale registry write failed"); + + let reloaded = load_registry(&tempdir); + assert!(reloaded.show(&PackageId::from("a"), None).is_some()); + assert!(reloaded.show(&PackageId::from("longer-package-name"), None).is_some()); + } + + #[test] + fn load_package_rejects_artifact_that_does_not_match_requested_identity() { + let tempdir = TempDir::new().unwrap(); + let mut registry = load_registry(&tempdir); + + let package_path = tempdir.path().join("pkg.masp"); + build_package("pkg", "1.0.0", []).write_to_file(&package_path).unwrap(); + let published = registry.publish(&package_path).unwrap(); + + build_package("other", "1.0.0", []) + .write_to_file(&published.artifact_path) + .unwrap(); + + let error = registry + .load_package(&PackageId::from("pkg"), &published.version) + .expect_err("artifact mismatch should be rejected"); + assert!(matches!(error, LocalRegistryError::ArtifactMismatch { .. })); + } + + #[test] + fn load_package_accepts_legacy_digest_only_artifact_path() { + let tempdir = TempDir::new().unwrap(); + let mut registry = load_registry(&tempdir); + + let package = build_package("pkg", "1.0.0", []); + let package_path = tempdir.path().join("pkg.masp"); + package.write_to_file(&package_path).unwrap(); + let published = registry.publish(&package_path).unwrap(); + let legacy_path = + registry.legacy_artifact_path_for_digest(published.version.digest.unwrap()); + assert_ne!(published.artifact_path, legacy_path); + fs::rename(&published.artifact_path, &legacy_path).unwrap(); + + let shown = registry.show(&PackageId::from("pkg"), Some(&published.version)).unwrap(); + assert_eq!(shown.artifact_path.as_ref(), Some(&legacy_path)); + assert_eq!( + registry.artifact_path(&PackageId::from("pkg"), &published.version), + Some(legacy_path.clone()) + ); + let listed = registry.list(); + assert_eq!(listed.len(), 1); + assert_eq!(listed[0].artifact_path.as_ref(), Some(&legacy_path)); + + let loaded = registry.load_package(&PackageId::from("pkg"), &published.version).unwrap(); + assert_eq!(loaded.as_ref(), package.as_ref()); + } + + #[test] + fn summaries_do_not_report_legacy_artifact_for_different_package_identity() { + let tempdir = TempDir::new().unwrap(); + let mut registry = load_registry(&tempdir); + + let first = build_package("first", "1.0.0", []); + let second = build_package("second", "1.0.0", []); + assert_eq!(first.digest(), second.digest()); + + let first_path = tempdir.path().join("first.masp"); + let second_path = tempdir.path().join("second.masp"); + first.write_to_file(&first_path).unwrap(); + second.write_to_file(&second_path).unwrap(); + + let first = registry.publish(&first_path).unwrap(); + let second = registry.publish(&second_path).unwrap(); + let legacy_path = registry.legacy_artifact_path_for_digest(first.version.digest.unwrap()); + fs::rename(&first.artifact_path, &legacy_path).unwrap(); + fs::remove_file(&second.artifact_path).unwrap(); + + let first_summary = registry.show(&PackageId::from("first"), Some(&first.version)).unwrap(); + assert_eq!(first_summary.artifact_path.as_ref(), Some(&legacy_path)); + let second_summary = + registry.show(&PackageId::from("second"), Some(&second.version)).unwrap(); + assert_eq!(second_summary.artifact_path.as_ref(), Some(&second.artifact_path)); + } + + #[test] + fn artifact_paths_distinguish_packages_with_same_mast_digest() { + let tempdir = TempDir::new().unwrap(); + let mut registry = load_registry(&tempdir); + + let first = build_package("first", "1.0.0", []); + let second = build_package("second", "1.0.0", []); + assert_eq!(first.digest(), second.digest()); + + let first_path = tempdir.path().join("first.masp"); + let second_path = tempdir.path().join("second.masp"); + first.write_to_file(&first_path).unwrap(); + second.write_to_file(&second_path).unwrap(); + + let first = registry.publish(&first_path).unwrap(); + let second = registry.publish(&second_path).unwrap(); + assert_ne!(first.artifact_path, second.artifact_path); + + let first_loaded = + registry.load_package(&PackageId::from("first"), &first.version).unwrap(); + let second_loaded = + registry.load_package(&PackageId::from("second"), &second.version).unwrap(); + assert_eq!(first_loaded.name, PackageId::from("first")); + assert_eq!(second_loaded.name, PackageId::from("second")); + } +} diff --git a/crates/package-registry-local/src/main.rs b/crates/package-registry-local/src/main.rs new file mode 100644 index 0000000000..155a04558b --- /dev/null +++ b/crates/package-registry-local/src/main.rs @@ -0,0 +1,120 @@ +use std::{io::Write, path::PathBuf, process::ExitCode}; + +use clap::{Parser, Subcommand}; +use miden_package_registry::{PackageId, PackageRegistry, Version}; +use miden_package_registry_local::LocalPackageRegistry; + +#[derive(Debug, Parser)] +#[command( + name = "miden-registry", + version, + about, + rename_all = "kebab-case", + arg_required_else_help(true) +)] +struct Cli { + #[command(subcommand)] + command: Command, +} + +#[derive(Debug, Subcommand)] +enum Command { + /// Publish `package` to the local package registry + Publish { package: PathBuf }, + /// List all available packages known to the local registry + List { + /// Emit package list in JSON format, rather than the default human-readable format + #[arg(long)] + json: bool, + }, + /// Query for information about a package in the registry + Show { + /// The package identifier/name + package: String, + /// The version of the package to show information for. + /// + /// If not specified, the latest version of the package is shown. + #[arg(long)] + version: Option, + /// If an error occurs, do not emit any output, just exit with a non-zero code + #[arg(long)] + quiet: bool, + /// Emit package information in JSON format, rather than the default human-readable format + #[arg(long)] + json: bool, + }, +} + +fn main() -> Result> { + let cli = Cli::parse(); + let mut registry = LocalPackageRegistry::load_from_env()?; + + match cli.command { + Command::Publish { package } => { + let published = registry.publish(package)?; + println!( + "published {}@{} -> {}", + published.name, + published.version, + published.artifact_path.display() + ); + }, + Command::List { json } => { + let summaries = registry.list(); + if json { + let mut stdout = std::io::stdout(); + serde_json::to_writer_pretty(&mut stdout, &summaries)?; + writeln!(&mut stdout)?; + } else { + for package in registry.list() { + println!("{} {}", package.name, package.version); + } + } + }, + Command::Show { package, version, quiet, json } => { + let package_id = PackageId::from(package); + let version = version.map(|version| version.parse::()).transpose()?; + if let Some(summary) = registry.show(&package_id, version.as_ref()) { + if json { + let mut stdout = std::io::stdout(); + serde_json::to_writer_pretty(&mut stdout, &summary)?; + writeln!(&mut stdout)?; + } else { + println!("package: {}", summary.name); + println!("version: {}", summary.version); + if let Some(description) = summary.description { + println!("description: {description}"); + } + if let Some(path) = summary.artifact_path { + println!("artifact: {}", path.display()); + } + if summary.dependencies.is_empty() { + println!("dependencies: none"); + } else { + println!("dependencies:"); + for (dependency, requirement) in summary.dependencies { + println!(" {dependency} {requirement}"); + } + } + } + } else { + if !quiet { + if registry.is_available(&package_id) { + if let Some(version) = version { + eprintln!( + "Version '{version}' does not exist for package '{package_id}'" + ); + } else { + eprintln!("No available versions for package '{package_id}'"); + } + } else { + eprintln!("'{package_id}' is not a registered package"); + } + } + return Ok(ExitCode::from(2)); + } + }, + } + + Ok(ExitCode::SUCCESS) +} diff --git a/crates/package-registry/Cargo.toml b/crates/package-registry/Cargo.toml index e4bea41f5e..0807af2f75 100644 --- a/crates/package-registry/Cargo.toml +++ b/crates/package-registry/Cargo.toml @@ -13,16 +13,21 @@ repository.workspace = true rust-version.workspace = true edition.workspace = true +[package.metadata.cargo-shear] +ignored = ["serde_json"] + [features] -default = ["std", "serde"] +default = ["std"] +arbitrary = ["std", "dep:proptest", "miden-mast-package/arbitrary"] resolver = ["std", "dep:pubgrub", "dep:smallvec"] -std = ["miden-assembly-syntax/std", "miden-core/std", "serde/std"] +std = ["miden-assembly-syntax/std", "miden-core/std", "proptest?/std", "serde?/std"] serde = ["dep:serde", "miden-assembly-syntax/serde", "miden-core/serde", "miden-mast-package/serde"] [dependencies] miden-assembly-syntax.workspace = true miden-core.workspace = true miden-mast-package.workspace = true +proptest = { workspace = true, optional = true } pubgrub = { version = "0.3", optional = true } serde = { workspace = true, optional = true } smallvec = { workspace = true, optional = true } @@ -30,6 +35,8 @@ thiserror.workspace = true [dev-dependencies] miden-core.workspace = true +miden-test-serde-macros.workspace = true +proptest.workspace = true serde_json.workspace = true [lints.rust] diff --git a/crates/package-registry/src/lib.rs b/crates/package-registry/src/lib.rs index f41b5c3c2f..830c5693a4 100644 --- a/crates/package-registry/src/lib.rs +++ b/crates/package-registry/src/lib.rs @@ -20,9 +20,11 @@ pub use miden_assembly_syntax::{ semver, semver::{Version as SemVer, VersionReq}, }; -pub use miden_core::{LexicographicWord, Word}; +pub use miden_core::Word; use miden_mast_package::Package as MastPackage; pub use miden_mast_package::PackageId; +#[cfg(feature = "arbitrary")] +use proptest::prelude::*; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; @@ -42,6 +44,7 @@ pub type PackageRequirements = BTreeMap; /// Metadata tracked for a specific canonical package version. #[derive(Debug, Clone, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(all(feature = "arbitrary", test), miden_test_serde_macros::serde_test)] pub struct PackageRecord { /// The exact published version associated with this package version: Version, @@ -82,7 +85,7 @@ impl PackageRecord { /// The digest of the MAST forest contained in this package pub fn digest(&self) -> Option<&Word> { - self.version.digest.as_ref().map(|word| word.inner()) + self.version.digest.as_ref() } /// Returns the package description, if known. @@ -96,6 +99,32 @@ impl PackageRecord { } } +#[cfg(feature = "arbitrary")] +impl Arbitrary for PackageRecord { + type Parameters = (); + type Strategy = BoxedStrategy; + + fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { + let description = proptest::option::of( + proptest::collection::vec(proptest::char::range('a', 'z'), 1..32) + .prop_map(|chars| Arc::::from(chars.into_iter().collect::())), + ); + let dependencies = + proptest::collection::vec((any::(), any::()), 0..4) + .prop_map(|entries| entries.into_iter().collect::>()); + + (any::(), description, dependencies) + .prop_map(|(version, description, dependencies)| { + let mut record = Self::new(version, dependencies); + if let Some(description) = description { + record = record.with_description(description); + } + record + }) + .boxed() + } +} + /// A type alias for all known canonical semantic versions of a specific package. /// /// Each semantic version maps to at most one canonical published artifact. The exact artifact @@ -147,12 +176,11 @@ pub trait PackageRegistry { /// Return the metadata for `package` with `digest`, if present. fn get_by_digest(&self, package: &PackageId, digest: &Word) -> Option<&PackageRecord> { - let digest = LexicographicWord::new(*digest); self.available_versions(package).and_then(|versions| { versions .values() .rev() - .find(|record| record.version().digest.is_some_and(|d| d == digest)) + .find(|record| record.version().digest.as_ref() == Some(digest)) }) } @@ -193,10 +221,16 @@ pub trait PackageIndex: PackageRegistry { fn register(&mut self, name: PackageId, record: PackageRecord) -> Result<(), Self::Error>; } -/// A writable package store used to publish assembled package artifacts and index metadata. -pub trait PackageStore: PackageRegistry + PackageProvider { +/// A writable package cache used to store assembled package artifacts resolved during assembly. +pub trait PackageCache: PackageRegistry + PackageProvider { type Error: fmt::Display; + /// Cache `package`, returning the fully-qualified stored version. + fn cache_package(&mut self, package: Arc) -> Result; +} + +/// A writable package store used to publish assembled package artifacts and index metadata. +pub trait PackageStore: PackageCache { /// Publish `package` to the store, returning the fully-qualified stored version. fn publish_package(&mut self, package: Arc) -> Result; } @@ -206,7 +240,10 @@ pub trait PackageStore: PackageRegistry + PackageProvider { #[error("{0}")] pub struct NoPackageStoreError(String); -/// A package store implementation which always refuses publication. +/// A package store implementation which refuses publication and loading. +/// +/// Cache writes are accepted as a no-op so callers which do not need a persistent package store can +/// still assemble source dependencies. #[derive(Default)] pub struct NoPackageStore; @@ -226,9 +263,15 @@ impl PackageProvider for NoPackageStore { } } -impl PackageStore for NoPackageStore { +impl PackageCache for NoPackageStore { type Error = NoPackageStoreError; + fn cache_package(&mut self, package: Arc) -> Result { + Ok(Version::new(package.version.clone(), package.digest())) + } +} + +impl PackageStore for NoPackageStore { fn publish_package(&mut self, package: Arc) -> Result { Err(NoPackageStoreError(format!( "cannot publish package {}@{}", @@ -236,3 +279,74 @@ impl PackageStore for NoPackageStore { ))) } } + +#[cfg(test)] +mod tests { + use alloc::{collections::BTreeMap, vec, vec::Vec}; + + use miden_assembly_syntax::{ + Library, + ast::{Path as AstPath, PathBuf}, + library::{LibraryExport, ProcedureExport as LibraryProcedureExport}, + }; + use miden_core::{ + mast::{BasicBlockNodeBuilder, MastForest, MastForestContributor, MastNodeId}, + operations::Operation, + }; + use miden_mast_package::{Package, TargetType}; + + use super::*; + + fn build_forest() -> (MastForest, MastNodeId) { + let mut forest = MastForest::new(); + let node_id = BasicBlockNodeBuilder::new(vec![Operation::Add], Vec::new()) + .add_to_forest(&mut forest) + .expect("failed to build basic block"); + forest.make_root(node_id); + (forest, node_id) + } + + fn absolute_path(name: &str) -> Arc { + let path = PathBuf::new(name).expect("invalid path"); + let path = path.as_path().to_absolute().into_owned(); + Arc::from(path.into_boxed_path()) + } + + fn build_library(export: &str) -> Arc { + let (forest, node_id) = build_forest(); + let path = absolute_path(export); + let export = LibraryProcedureExport::new(node_id, Arc::clone(&path)); + + let mut exports = BTreeMap::new(); + exports.insert(path, LibraryExport::Procedure(export)); + + Arc::new(Library::new(Arc::new(forest), exports).expect("failed to build library")) + } + + #[test] + fn no_package_store_cache_package_is_noop() { + let package: Arc = Package::from_library( + PackageId::from("pkg"), + "1.0.0".parse().unwrap(), + TargetType::Library, + build_library("test::pkg::entry"), + [], + ) + .into(); + let expected = Version::new(package.version.clone(), package.digest()); + + let mut store = NoPackageStore; + let cached = store + .cache_package(Arc::clone(&package)) + .expect("no package store should accept cache writes as no-op"); + + assert_eq!(cached, expected); + assert!(store.available_versions(&package.name).is_none()); + store + .load_package(&package.name, &cached) + .expect_err("no package store should not persist cache writes"); + store + .publish_package(package) + .expect_err("no package store should still reject publication"); + } +} diff --git a/crates/package-registry/src/resolver/index.rs b/crates/package-registry/src/resolver/index.rs index d95c45f5cf..39806d0de1 100644 --- a/crates/package-registry/src/resolver/index.rs +++ b/crates/package-registry/src/resolver/index.rs @@ -4,8 +4,8 @@ use miden_assembly_syntax::Report; use miden_mast_package::Package as MastPackage; use crate::{ - PackageId, PackageIndex, PackageProvider, PackageRecord, PackageRegistry, PackageStore, - PackageVersions, SemVer, Version, VersionRequirement, + PackageCache, PackageId, PackageIndex, PackageProvider, PackageRecord, PackageRegistry, + PackageStore, PackageVersions, SemVer, Version, VersionRequirement, }; #[derive(Debug, thiserror::Error)] @@ -44,7 +44,7 @@ impl InMemoryPackageRegistry { P: Into, V: Into, { - let record_version = version.clone(); + let record_version = version; let record = PackageRecord::new( record_version, dependencies @@ -127,9 +127,51 @@ impl PackageProvider for InMemoryPackageRegistry { } } -impl PackageStore for InMemoryPackageRegistry { +impl PackageCache for InMemoryPackageRegistry { type Error = InMemoryPackageStoreError; + fn cache_package(&mut self, package: Arc) -> Result { + let version = Version::new(package.version.clone(), package.digest()); + let dependencies = package.manifest.dependencies().map(|dependency| { + let dependency_version = Version::new(dependency.version.clone(), dependency.digest); + (dependency.name.clone(), VersionRequirement::Exact(dependency_version)) + }); + + let record = match package.description.clone() { + Some(description) => { + PackageRecord::new(version.clone(), dependencies).with_description(description) + }, + None => PackageRecord::new(version.clone(), dependencies), + }; + + if let Some(existing) = self.get_by_semver(&package.name, &package.version) { + if existing.version() != &version || existing != &record { + return Err(InMemoryPackageStoreError::DuplicateSemanticVersion { + package: package.name.clone(), + version: package.version.clone(), + }); + } + let artifact_key = (package.name.clone(), version.clone()); + if let Some(existing_package) = self.artifacts.get(&artifact_key) { + if existing_package.as_ref() != package.as_ref() { + return Err(InMemoryPackageStoreError::DuplicateSemanticVersion { + package: package.name.clone(), + version: package.version.clone(), + }); + } + } else { + self.artifacts.insert(artifact_key, package); + } + return Ok(version); + } + + self.insert_record(package.name.clone(), record)?; + self.artifacts.insert((package.name.clone(), version.clone()), package); + Ok(version) + } +} + +impl PackageStore for InMemoryPackageRegistry { fn publish_package(&mut self, package: Arc) -> Result { let version = Version::new(package.version.clone(), package.digest()); if self.is_semver_available(&package.name, &package.version) { @@ -191,3 +233,88 @@ where index } } + +#[cfg(test)] +mod tests { + use alloc::{collections::BTreeMap, vec, vec::Vec}; + + use miden_assembly_syntax::{ + Library, + ast::{Path as AstPath, PathBuf}, + library::{LibraryExport, ProcedureExport as LibraryProcedureExport}, + }; + use miden_core::{ + mast::{BasicBlockNodeBuilder, MastForest, MastForestContributor, MastNodeId}, + operations::Operation, + }; + use miden_mast_package::{Dependency, Package, Section, SectionId, TargetType}; + + use super::*; + + fn build_forest() -> (MastForest, MastNodeId) { + let mut forest = MastForest::new(); + let node_id = BasicBlockNodeBuilder::new(vec![Operation::Add], Vec::new()) + .add_to_forest(&mut forest) + .expect("failed to build basic block"); + forest.make_root(node_id); + (forest, node_id) + } + + fn absolute_path(name: &str) -> Arc { + let path = PathBuf::new(name).expect("invalid path"); + let path = path.as_path().to_absolute().into_owned(); + Arc::from(path.into_boxed_path()) + } + + fn build_library(export: &str) -> Arc { + let (forest, node_id) = build_forest(); + let path = absolute_path(export); + let export = LibraryProcedureExport::new(node_id, Arc::clone(&path)); + + let mut exports = BTreeMap::new(); + exports.insert(path, LibraryExport::Procedure(export)); + + Arc::new(Library::new(Arc::new(forest), exports).expect("failed to build library")) + } + + fn build_package<'a>( + name: &str, + version: &str, + dependencies: impl IntoIterator, + ) -> Arc { + Package::from_library( + name.into(), + version.parse().unwrap(), + TargetType::Library, + build_library("test::pkg::entry"), + dependencies.into_iter().map(|(name, version, kind, digest)| Dependency { + name: name.into(), + version: version.parse().unwrap(), + kind, + digest, + }), + ) + .into() + } + + #[test] + fn cache_rejects_different_artifact_for_existing_exact_version() { + let mut registry = InMemoryPackageRegistry::default(); + let package = build_package("pkg", "1.0.0", []); + let version = registry.cache_package(package.clone()).unwrap(); + + let mut conflicting_package = build_package("pkg", "1.0.0", []); + Arc::make_mut(&mut conflicting_package) + .sections + .push(Section::new(SectionId::custom("cache-test").unwrap(), Vec::from([1, 2, 3]))); + assert_eq!(Some(conflicting_package.digest()), version.digest); + + let error = registry + .cache_package(conflicting_package) + .expect_err("cache should reject conflicting package artifacts"); + assert!(matches!(error, InMemoryPackageStoreError::DuplicateSemanticVersion { .. })); + + let loaded = registry.load_package(&PackageId::from("pkg"), &version).unwrap(); + assert_eq!(loaded.as_ref(), package.as_ref()); + } +} diff --git a/crates/package-registry/src/resolver/provider.rs b/crates/package-registry/src/resolver/provider.rs index 9aaec1e14f..d23ed239b2 100644 --- a/crates/package-registry/src/resolver/provider.rs +++ b/crates/package-registry/src/resolver/provider.rs @@ -44,7 +44,7 @@ impl<'a, R: PackageRegistry + ?Sized> PackageResolver<'a, R> { Self { index, context: ResolverContext::Workspace { - members: SmallVec::from_iter(members.into_iter().map(|member| member.into())), + members: SmallVec::from_iter(members.into_iter().map(Into::into)), root: root.into(), root_version: version, }, @@ -302,7 +302,7 @@ mod tests { use crate::{VersionReq, VersionRequirement}; fn any() -> VersionRequirement { - VersionRequirement::from(VersionReq::STAR.clone()) + VersionRequirement::from(VersionReq::STAR) } fn req(value: &str) -> VersionRequirement { @@ -329,7 +329,7 @@ mod tests { Some((version, hex)) => { let version = version.parse::().unwrap(); let word = Word::parse(hex).unwrap(); - Version { version, digest: Some(word.into()) } + Version { version, digest: Some(word) } }, None => Version { version: version.parse::().unwrap(), @@ -673,7 +673,7 @@ mod tests { assert!(matches!( error, - crate::resolver::index::InMemoryPackageStoreError::DuplicateSemanticVersion { + index::InMemoryPackageStoreError::DuplicateSemanticVersion { package, version, } if package == dep_id && version == "1.0.0".parse().unwrap() diff --git a/crates/package-registry/src/resolver/pubgrub_compat.rs b/crates/package-registry/src/resolver/pubgrub_compat.rs index 8feb9ae9be..305768900b 100644 --- a/crates/package-registry/src/resolver/pubgrub_compat.rs +++ b/crates/package-registry/src/resolver/pubgrub_compat.rs @@ -797,8 +797,6 @@ mod test { use std::{collections::HashSet, eprintln, format, ops::RangeBounds}; use super::*; - use crate::semver; - const OPS: &[&str] = &["^", "~", "=", "<", ">", "<=", ">="]; #[test] @@ -819,15 +817,15 @@ mod test { "18446744073709551615.18446744073709551615.18446744073709551615", ] { let raw_req = format!("{op}{psot}"); - let req = semver::VersionReq::parse(&raw_req).unwrap(); + let req = VersionReq::parse(&raw_req).unwrap(); let pver: SemverPubgrub = (&req).into(); let bounding_range = pver.bounding_range(); let raw_ver = "18446744073709551615.1.0"; - let ver = semver::Version::parse(raw_ver).unwrap(); + let ver = Version::parse(raw_ver).unwrap(); let mat = req.matches(&ver); if mat != pver.contains(&ver) { - eprintln!("{}", ver); - eprintln!("{}", req); + eprintln!("{ver}"); + eprintln!("{req}"); assert_eq!(mat, pver.contains(&ver)); } @@ -859,15 +857,15 @@ mod test { "0.0.2-r, ^0.0.1", ] { let raw_req = format!("{op}{psot}"); - let req = semver::VersionReq::parse(&raw_req).unwrap(); + let req = VersionReq::parse(&raw_req).unwrap(); let pver: SemverPubgrub = (&req).into(); let bounding_range = pver.bounding_range(); for raw_ver in ["0.0.0-0", "0.0.1-z0", "0.0.2-z0", "0.9.8-z", "1.0.1-z0"] { - let ver = semver::Version::parse(raw_ver).unwrap(); + let ver = Version::parse(raw_ver).unwrap(); let mat = req.matches(&ver); if mat != pver.contains(&ver) { - eprintln!("{}", ver); - eprintln!("{}", req); + eprintln!("{ver}"); + eprintln!("{req}"); assert_eq!(mat, pver.contains(&ver)); } @@ -886,7 +884,7 @@ mod test { "0.0.2", "0.1.0-0", "0.1.0-r", "0.1.0", "0.1.1", "0.2.0-0", "0.2.0-r", "0.2.0", "1.0.0-0", "1.0.0-r", "1.0.0", "1.1.0", "2.0.0-0", "2.0.0-r", "2.0.0", "3.0.0", ]; - let vers = raw_vers.map(|raw_ver| semver::Version::parse(raw_ver).unwrap()); + let vers = raw_vers.map(|raw_ver| Version::parse(raw_ver).unwrap()); assert!(vers.is_sorted()); assert!(vers.is_sorted_by_key(SemverCompatibility::from)); for op in OPS { @@ -909,7 +907,7 @@ mod test { "1.0.0-r, <=2.0.0-0", ] { let raw_req = format!("{op}{psot}"); - let req = semver::VersionReq::parse(&raw_req).unwrap(); + let req = VersionReq::parse(&raw_req).unwrap(); let pver: SemverPubgrub = (&req).into(); let set: HashSet<_> = vers @@ -917,8 +915,8 @@ mod test { .filter_map(|ver| { let mat = req.matches(ver); if mat != pver.contains(ver) { - eprintln!("{}", ver); - eprintln!("{}", req); + eprintln!("{ver}"); + eprintln!("{req}"); assert_eq!(mat, pver.contains(ver)); } let cap: SemverCompatibility = ver.into(); @@ -939,10 +937,10 @@ mod test { "0.0.2", "0.1.0-0", "0.1.0-r", "0.1.0", "0.1.1", "0.2.0-0", "0.2.0-r", "0.2.0", "1.0.0-0", "1.0.0-r", "1.0.0", "1.1.0", "2.0.0-0", "2.0.0-r", "2.0.0", "3.0.0", ]; - let vers = raw_vers.map(|raw_ver| semver::Version::parse(raw_ver).unwrap()); + let vers = raw_vers.map(|raw_ver| Version::parse(raw_ver).unwrap()); assert!(vers.is_sorted()); assert!(vers.is_sorted_by_key(SemverCompatibility::from)); - let reqs = vers.clone().map(|v| SemverPubgrub::singleton(v.clone())); + let reqs = vers.clone().map(SemverPubgrub::singleton); for pver in &reqs { pver.as_singleton().unwrap(); // Singletons can only match one thing so they definitely only match one compatibility @@ -956,7 +954,7 @@ mod test { for preq in req_unions { let set: HashSet = - vers.iter().filter(|ver| preq.contains(ver)).map(|ver| ver.into()).collect(); + vers.iter().filter(|ver| preq.contains(ver)).map(Into::into).collect(); let only_one_comp = preq.only_one_compatibility_range(); assert_eq!(set.len() <= 1, only_one_comp.is_some()); if only_one_comp.is_none() { diff --git a/crates/package-registry/src/resolver/version_set.rs b/crates/package-registry/src/resolver/version_set.rs index 2c25aa435a..4a3746e2b6 100644 --- a/crates/package-registry/src/resolver/version_set.rs +++ b/crates/package-registry/src/resolver/version_set.rs @@ -1,6 +1,6 @@ use core::fmt; -use miden_core::{LexicographicWord, Word}; +use miden_core::Word; use pubgrub::VersionSet as _; use smallvec::{SmallVec, smallvec}; @@ -36,7 +36,7 @@ pub struct VersionSet { /// The content digest filter, represented as the set of content digests that are considered /// to be members of this set. When non-empty, the set _only_ includes versions that are /// considered contained in `range` _and_ have a content digest in `digests`. - digests: SmallVec<[LexicographicWord; 1]>, + digests: SmallVec<[Word; 1]>, } /// Represents an additional filter on the versions considered a member of a [VersionSet]. @@ -45,7 +45,7 @@ pub enum VersionSetFilter<'a> { /// Matches any version, regardless of content digest Any, /// Matches only versions which have a content digest in the given set of digests - Digest(&'a [LexicographicWord]), + Digest(&'a [Word]), } impl VersionSetFilter<'_> { @@ -86,7 +86,6 @@ impl VersionSet { digest: Word, versions: impl IntoIterator, ) -> Self { - let digest = LexicographicWord::new(digest); let mut range = SemverPubgrub::empty(); let mut matched = false; @@ -116,7 +115,7 @@ impl From for VersionSet { fn from(value: Word) -> Self { Self { range: SemverPubgrub::full(), - digests: smallvec![LexicographicWord::new(value)], + digests: smallvec![value], } } } @@ -178,14 +177,14 @@ impl fmt::Display for VersionSet { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.digests.as_slice() { [] => write!(f, "{}", &self.range), - [digest] => write!(f, "{} in {}", digest.inner(), &self.range), + [digest] => write!(f, "{digest} in {}", &self.range), digests => { f.write_str("any of ")?; for (i, digest) in digests.iter().enumerate() { if i > 0 { f.write_str(", ")?; } - write!(f, "{}", &digest.inner())?; + write!(f, "{digest}")?; } write!(f, " in {}", &self.range) }, diff --git a/crates/package-registry/src/version.rs b/crates/package-registry/src/version.rs index 9f419b0b34..c656b12381 100644 --- a/crates/package-registry/src/version.rs +++ b/crates/package-registry/src/version.rs @@ -1,7 +1,11 @@ use core::{borrow::Borrow, fmt, str::FromStr}; pub use miden_assembly_syntax::semver::{Error as SemVerError, Version as SemVer}; -use miden_core::{LexicographicWord, Word}; +use miden_core::Word; +#[cfg(feature = "arbitrary")] +use miden_core::utils::hash_string_to_word; +#[cfg(feature = "arbitrary")] +use proptest::prelude::*; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; @@ -16,6 +20,24 @@ pub enum InvalidVersionError { Version(SemVerError), } +#[cfg(feature = "arbitrary")] +impl Arbitrary for InvalidVersionError { + type Parameters = (); + type Strategy = BoxedStrategy; + + fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { + any::() + .prop_map(|use_digest| { + if use_digest { + Self::Digest("invalid digest") + } else { + Self::Version("not-a-version".parse::().unwrap_err()) + } + }) + .boxed() + } +} + /// The representation of versioning information associated with packages in the package index. /// /// This type provides the means by which dependency resolution can satisfy versioning constraints @@ -32,6 +54,7 @@ pub enum InvalidVersionError { /// * Record the exact published identity of a canonical package artifact as `semver#digest` /// * Provide a total ordering for package versions that may or may not include a specific digest #[derive(Debug, Clone, Eq, PartialEq)] +#[cfg_attr(all(feature = "arbitrary", test), miden_test_serde_macros::serde_test)] pub struct Version { /// The semantic version information /// @@ -41,7 +64,7 @@ pub struct Version { /// /// This is the most precise version for a package, and uniquely identifies the canonical /// published artifact associated with a semantic version. - pub digest: Option, + pub digest: Option, } #[cfg(feature = "serde")] @@ -70,7 +93,7 @@ impl<'de> Deserialize<'de> for Version { impl Version { /// Construct a [Version] from its component parts. pub fn new(version: SemVer, digest: Word) -> Self { - Self { version, digest: Some(digest.into()) } + Self { version, digest: Some(digest) } } /// Get a [Version] without an attached digest for comparison purposes @@ -103,10 +126,9 @@ impl Version { pub fn satisfies(&self, requirement: &VersionRequirement) -> bool { match requirement { VersionRequirement::Semantic(req) => req.matches(&self.version), - VersionRequirement::Digest(req) => self - .digest - .as_ref() - .is_some_and(|digest| &LexicographicWord::new(req.into_inner()) == digest), + VersionRequirement::Digest(req) => { + self.digest.as_ref().is_some_and(|digest| req.into_inner() == *digest) + }, VersionRequirement::Exact(req) => self == req, } } @@ -138,7 +160,7 @@ impl From for Version { impl From<(SemVer, Word)> for Version { fn from(version: (SemVer, Word)) -> Self { let (version, word) = version; - Self { version, digest: Some(word.into()) } + Self { version, digest: Some(word) } } } @@ -152,7 +174,7 @@ impl Borrow for Version { impl fmt::Display for Version { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if let Some(digest) = self.digest.as_ref() { - write!(f, "{}#{}", &self.version, digest.inner()) + write!(f, "{}#{digest}", &self.version) } else { fmt::Display::fmt(&self.version, f) } @@ -178,3 +200,25 @@ impl Ord for Version { }) } } + +#[cfg(feature = "arbitrary")] +impl Arbitrary for Version { + type Parameters = (); + type Strategy = BoxedStrategy; + + fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { + let semver = (0u64..=5, 0u64..=15, 0u64..=31).prop_map(|(major, minor, patch)| { + format!("{major}.{minor}.{patch}") + .parse::() + .expect("generated semantic versions are valid") + }); + let digest = proptest::option::of( + proptest::collection::vec(proptest::char::range('a', 'z'), 1..16).prop_map(|chars| { + let material = chars.into_iter().collect::(); + hash_string_to_word(material.as_str()) + }), + ); + + (semver, digest).prop_map(|(version, digest)| Self { version, digest }).boxed() + } +} diff --git a/crates/package-registry/src/version_requirement.rs b/crates/package-registry/src/version_requirement.rs index 0bca9b0085..96752b86bf 100644 --- a/crates/package-registry/src/version_requirement.rs +++ b/crates/package-registry/src/version_requirement.rs @@ -1,14 +1,19 @@ use core::fmt; use miden_assembly_syntax::debuginfo::Span; +#[cfg(feature = "arbitrary")] +use miden_core::utils::hash_string_to_word; +#[cfg(feature = "arbitrary")] +use proptest::prelude::*; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; use super::*; -use crate::{LexicographicWord, Word}; +use crate::Word; /// Represents a requirement on a specific version (or versions) of a dependency. #[derive(Debug, Clone)] +#[cfg_attr(all(feature = "arbitrary", test), miden_test_serde_macros::serde_test)] pub enum VersionRequirement { /// A semantic versioning constraint, e.g. `~> 0.1` /// @@ -54,9 +59,7 @@ impl PartialEq for VersionRequirement { fn eq(&self, other: &Self) -> bool { match (self, other) { (Self::Exact(l), Self::Exact(r)) => l == r, - (Self::Digest(l), Self::Digest(r)) => { - LexicographicWord::new(l.into_inner()) == LexicographicWord::new(r.into_inner()) - }, + (Self::Digest(l), Self::Digest(r)) => l.into_inner() == r.into_inner(), (Self::Semantic(l), Self::Semantic(r)) => l == r, (Self::Semantic(_) | Self::Exact(_), Self::Digest(_)) | (Self::Semantic(_), Self::Exact(_)) @@ -123,10 +126,10 @@ impl<'de> Deserialize<'de> for VersionRequirement { { use core::str::FromStr; - let value = ::deserialize(deserializer)?; + let value = ::deserialize(deserializer)?; if value == "*" { - return Ok(Self::from(VersionReq::STAR.clone())); + return Ok(Self::from(VersionReq::STAR)); } if let Some((version, digest)) = value.split_once('#') { @@ -143,3 +146,39 @@ impl<'de> Deserialize<'de> for VersionRequirement { Ok(Self::from(requirement)) } } + +#[cfg(feature = "arbitrary")] +impl Arbitrary for VersionRequirement { + type Parameters = (); + type Strategy = BoxedStrategy; + + fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { + let semantic = + (0u64..=4, 0u64..=8, 0u64..=16, 0u8..=2).prop_map(|(major, minor, patch, kind)| { + let req = match kind { + 0 => format!("^{major}.{minor}.{patch}"), + 1 => format!("~{major}.{minor}.{patch}"), + _ => format!("={major}.{minor}.{patch}"), + } + .parse::() + .expect("generated version requirements are valid"); + + Self::Semantic(Span::unknown(req)) + }); + + let digest = + proptest::collection::vec(proptest::char::range('a', 'z'), 1..16).prop_map(|chars| { + let material = chars.into_iter().collect::(); + let digest = hash_string_to_word(material.as_str()); + Self::Digest(Span::unknown(digest)) + }); + + let exact = any::() + .prop_filter("exact requirements must include a digest", |version| { + version.digest.is_some() + }) + .prop_map(Self::Exact); + + proptest::prop_oneof![Just(Self::from(VersionReq::STAR)), semantic, digest, exact,].boxed() + } +} diff --git a/crates/project/Cargo.toml b/crates/project/Cargo.toml index cfbcb1a7b6..b85f45a55a 100644 --- a/crates/project/Cargo.toml +++ b/crates/project/Cargo.toml @@ -13,11 +13,14 @@ repository.workspace = true rust-version.workspace = true edition.workspace = true +[package.metadata.cargo-shear] +ignored = ["serde_json"] + [features] -default = ["std", "serde"] -arbitrary = ["std", "dep:proptest-derive", "dep:proptest", "miden-assembly-syntax/arbitrary"] +default = ["std"] +arbitrary = ["std", "dep:proptest", "dep:proptest-derive", "miden-assembly-syntax/arbitrary"] resolver = ["std", "miden-package-registry/resolver"] -std = ["miden-assembly-syntax/std", "serde/std", "thiserror/std", "toml/std", "miden-package-registry/std", "miden-package-registry/resolver", "tempfile/getrandom"] +std = ["miden-assembly-syntax/std", "miden-package-registry/std", "miden-package-registry/resolver", "proptest?/std", "serde?/std", "tempfile/getrandom", "thiserror/std", "toml/std"] serde = ["dep:serde", "dep:serde-untagged", "miden-assembly-syntax/serde", "miden-core/serde", "miden-package-registry/serde", "toml/serde", "toml/parse", "toml/display"] [dependencies] @@ -30,15 +33,16 @@ proptest-derive = { workspace = true, optional = true } serde = { workspace = true, optional = true } serde-untagged = { workspace = true, optional = true } thiserror.workspace = true -toml = { version = "1.0", default-features = false } +toml = { workspace = true, features = ["serde"] } [dev-dependencies] miden-core.workspace = true miden-mast-package = { workspace = true, features = ["arbitrary"] } miden-test-serde-macros.workspace = true +proptest.workspace = true serde_json.workspace = true tempfile.workspace = true -toml = { version = "1.0", default-features = false, features = ["std", "serde", "parse"] } +toml = { workspace = true, features = ["std", "serde", "parse"] } [lints.rust] # This is needed until this warning appears in stable when this is commented out. Currently, it diff --git a/crates/project/examples/protocol/kernel/bin/main-alt.masm b/crates/project/examples/protocol/kernel/bin/main-alt.masm index 8b3b356195..462ab6f950 100644 --- a/crates/project/examples/protocol/kernel/bin/main-alt.masm +++ b/crates/project/examples/protocol/kernel/bin/main-alt.masm @@ -2,15 +2,12 @@ # program to be executed, so we store that into procedure local memory, and then dyncall it @locals(4) proc invoke_user_script - loc_storew.0 + loc_storew_be.0 locaddr.0 dyncall end begin - # At program start, initialize the kernel environment - exec.$kernel::init - # Execute the user script whose entrypoint digest is on top of the stack exec.invoke_user_script end diff --git a/crates/project/examples/protocol/kernel/bin/main.masm b/crates/project/examples/protocol/kernel/bin/main.masm index 8b3b356195..462ab6f950 100644 --- a/crates/project/examples/protocol/kernel/bin/main.masm +++ b/crates/project/examples/protocol/kernel/bin/main.masm @@ -2,15 +2,12 @@ # program to be executed, so we store that into procedure local memory, and then dyncall it @locals(4) proc invoke_user_script - loc_storew.0 + loc_storew_be.0 locaddr.0 dyncall end begin - # At program start, initialize the kernel environment - exec.$kernel::init - # Execute the user script whose entrypoint digest is on top of the stack exec.invoke_user_script end diff --git a/crates/project/examples/protocol/kernel/kernel/io.masm b/crates/project/examples/protocol/kernel/kernel/io.masm index 851adb296f..8b2458c0cd 100644 --- a/crates/project/examples/protocol/kernel/kernel/io.masm +++ b/crates/project/examples/protocol/kernel/kernel/io.masm @@ -1,4 +1,4 @@ -const PRINTLN = event("sys.println") +const PRINTLN = 0 #! Prints the given null-terminated byte string to stdout, if debug tracing is enabled pub proc println(message: ptr) diff --git a/crates/project/examples/protocol/kernel/kernel/mod.masm b/crates/project/examples/protocol/kernel/kernel/mod.masm index 5000ce1c60..cf048a3964 100644 --- a/crates/project/examples/protocol/kernel/kernel/mod.masm +++ b/crates/project/examples/protocol/kernel/kernel/mod.masm @@ -7,11 +7,11 @@ const PRINTLN_ADDR = SYSCALL_TABLE_ADDR + 2 #! Initializes the kernel environment pub proc init procref.is_valid_syscall - mem_storew.SYSCALL_TABLE_ADDR + mem_storew_be.SYSCALL_TABLE_ADDR procref.$kernel::sys::panic - mem_storew.PANIC_ADDR + mem_storew_be.PANIC_ADDR procref.$kernel::io::println - mem_storew.PRINTLN_ADDR + mem_storew_be.PRINTLN_ADDR end #! Execute one of this kernel's syscalls @@ -24,7 +24,7 @@ pub proc system_call # validate syscall id dup.0 mem_load.SYSCALL_TABLE_ADDR dynexec # invoke the syscall - add.SYSCALL_TABLE_ADDR mem_loadw dynexec + add.SYSCALL_TABLE_ADDR mem_loadw_be dynexec end proc is_valid_syscall diff --git a/crates/project/src/ast/package.rs b/crates/project/src/ast/package.rs index 2d436b2835..613b25ecda 100644 --- a/crates/project/src/ast/package.rs +++ b/crates/project/src/ast/package.rs @@ -450,7 +450,7 @@ impl Validate for ProjectFile { entry.insert(None); }, Entry::Occupied(mut entry) => { - let path_span = target.path.as_ref().map(|p| p.span()).unwrap_or(span); + let path_span = target.path.as_ref().map(Span::span).unwrap_or(span); let conflict_label = Label::new(path_span, "conflict occurs here"); let path = entry.key().clone(); match entry.get_mut() { @@ -482,7 +482,7 @@ impl Validate for ProjectFile { entry.insert(None); }, Entry::Occupied(mut entry) => { - let ns_span = target.name.as_ref().map(|ns| ns.span()).unwrap_or(span); + let ns_span = target.name.as_ref().map(Span::span).unwrap_or(span); let conflict_label = Label::new(ns_span, "conflict occurs here"); let ns = entry.key().clone(); match entry.get_mut() { @@ -509,7 +509,7 @@ impl Validate for ProjectFile { if !invalid_config.is_empty() { return Err(ProjectFileError::InvalidBuildTargets { - source_file: source.clone(), + source_file: source, related: invalid_config, } .into()); diff --git a/crates/project/src/ast/parsing.rs b/crates/project/src/ast/parsing.rs index b9449a2675..745738743d 100644 --- a/crates/project/src/ast/parsing.rs +++ b/crates/project/src/ast/parsing.rs @@ -36,9 +36,9 @@ mod maybe_inherit { use super::MaybeInherit; - impl<'de, T> serde::Deserialize<'de> for MaybeInherit + impl<'de, T> Deserialize<'de> for MaybeInherit where - T: serde::Deserialize<'de>, + T: Deserialize<'de>, { fn deserialize(deserializer: D) -> Result where diff --git a/crates/project/src/ast/workspace.rs b/crates/project/src/ast/workspace.rs index 0fea591431..49bd26de64 100644 --- a/crates/project/src/ast/workspace.rs +++ b/crates/project/src/ast/workspace.rs @@ -135,7 +135,7 @@ impl Validate for WorkspaceFile { "cannot use the 'workspace' option in a workspace-level dependency spec" }; return Err(Report::from(ProjectFileError::InvalidWorkspaceDependency { - source_file: source.clone(), + source_file: source, label: Label::new(dependency.span(), label), })); } diff --git a/crates/project/src/dependencies.rs b/crates/project/src/dependencies.rs index 1c0b8fd504..69935e462e 100644 --- a/crates/project/src/dependencies.rs +++ b/crates/project/src/dependencies.rs @@ -58,7 +58,7 @@ impl Dependency { version.as_ref().map(|spanned| VersionRequirement::Semantic(spanned.clone())) }, }; - req.unwrap_or_else(|| VersionRequirement::from(VersionReq::STAR.clone())) + req.unwrap_or_else(|| VersionRequirement::from(VersionReq::STAR)) } } diff --git a/crates/project/src/dependencies/graph.rs b/crates/project/src/dependencies/graph.rs index b47f3980f6..e063b2daa0 100644 --- a/crates/project/src/dependencies/graph.rs +++ b/crates/project/src/dependencies/graph.rs @@ -125,9 +125,20 @@ pub enum ProjectDependencyNodeProvenance { path: PathBuf, /// The version of the preassembled package selected: Version, + /// The target kind of the preassembled package + kind: crate::TargetType, + /// The dependency requirements declared by the preassembled package manifest + requirements: BTreeMap, }, } +/// The manifest dependency metadata pinned for a preassembled package. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct PreassembledDependencyMetadata { + pub version: Version, + pub kind: crate::TargetType, +} + /// Represents information about a package whose provenance is a Miden project in source form. #[derive(Debug, Clone, PartialEq, Eq)] pub enum ProjectSource { @@ -328,7 +339,7 @@ impl<'a, R: PackageRegistry + ?Sized> ProjectDependencyGraphBuilder<'a, R> { ) -> Result { let root = loaded.package.name().into_inner(); let mut graph = CollectedDependencyGraph { - root: root.clone(), + root, nodes: BTreeMap::new(), registry_requirements: BTreeMap::new(), }; @@ -473,16 +484,9 @@ impl<'a, R: PackageRegistry + ?Sized> ProjectDependencyGraphBuilder<'a, R> { continue; } - let Some(versions) = self.registry.available_versions(&package) else { - continue; - }; - - for record in versions.values() { - registry - .insert_record(package.clone(), record.clone()) - .map_err(|error| Report::msg(error.to_string()))?; - - for dependency in record.dependencies().keys() { + if let Some(versions) = registry.available_versions(&package) { + for dependency in versions.values().flat_map(|record| record.dependencies().keys()) + { if local_packages.contains(dependency) { return Err(Report::msg(format!( "dependency conflict for '{dependency}': local source or preassembled dependency conflicts with a registry dependency" @@ -492,6 +496,26 @@ impl<'a, R: PackageRegistry + ?Sized> ProjectDependencyGraphBuilder<'a, R> { pending.insert(dependency.clone()); } } + continue; + } + + if let Some(versions) = self.registry.available_versions(&package) { + for record in versions.values() { + registry + .insert_record(package.clone(), record.clone()) + .map_err(|error| Report::msg(error.to_string()))?; + + for dependency in record.dependencies().keys() { + if local_packages.contains(dependency) { + return Err(Report::msg(format!( + "dependency conflict for '{dependency}': local source or preassembled dependency conflicts with a registry dependency" + ))); + } + if !copied.contains(dependency) { + pending.insert(dependency.clone()); + } + } + } } } @@ -505,10 +529,7 @@ impl<'a, R: PackageRegistry + ?Sized> ProjectDependencyGraphBuilder<'a, R> { ) -> Result { let CollectedDependencyGraph { root, nodes, registry_requirements } = collected; let local_packages = nodes.keys().cloned().collect::>(); - let mut graph = ProjectDependencyGraph { - root: root.clone(), - nodes: BTreeMap::new(), - }; + let mut graph = ProjectDependencyGraph { root, nodes: BTreeMap::new() }; let direct_registry_dependencies = nodes .values() @@ -696,7 +717,7 @@ impl<'a, R: PackageRegistry + ?Sized> ProjectDependencyGraphBuilder<'a, R> { match project { crate::Project::Package(package) => self.loaded_package_from_arc(package, None), crate::Project::WorkspacePackage { package, workspace } => { - let workspace_root = workspace.workspace_root().map(|path| path.to_path_buf()); + let workspace_root = workspace.workspace_root().map(Path::to_path_buf); self.loaded_package_from_arc(package, workspace_root) }, } @@ -711,7 +732,7 @@ impl<'a, R: PackageRegistry + ?Sized> ProjectDependencyGraphBuilder<'a, R> { match project { crate::Project::Package(package) => self.loaded_package_from_arc(package, None), crate::Project::WorkspacePackage { package, workspace } => { - let workspace_root = workspace.workspace_root().map(|path| path.to_path_buf()); + let workspace_root = workspace.workspace_root().map(Path::to_path_buf); self.loaded_package_from_arc(package, workspace_root) }, } @@ -722,7 +743,7 @@ impl<'a, R: PackageRegistry + ?Sized> ProjectDependencyGraphBuilder<'a, R> { package: Arc, workspace_root: Option, ) -> Result { - let manifest_path = package.manifest_path().map(|path| path.to_path_buf()); + let manifest_path = package.manifest_path().map(Path::to_path_buf); let project_root = match manifest_path.as_ref() { Some(manifest_path) => Some( manifest_path @@ -765,17 +786,37 @@ impl<'a, R: PackageRegistry + ?Sized> ProjectDependencyGraphBuilder<'a, R> { self.ensure_version_satisfies(expected_name, requirement, selected.clone())?; } + let mut dependencies = Vec::with_capacity(package.manifest.num_dependencies()); + let requirements = package_requirements(&package); + let mut solver_dependencies = BTreeMap::new(); + for dependency in package.manifest.dependencies() { + solver_dependencies.insert( + dependency.name.clone(), + VersionRequirement::Exact(Version::new( + dependency.version.clone(), + dependency.digest, + )), + ); + + dependencies.push(ProjectDependencyEdge { + dependency: dependency.name.clone(), + linkage: Linkage::Dynamic, + }); + } + Ok(CollectedDependencyNode { graph_node: ProjectDependencyNode { - dependencies: Vec::new(), + dependencies, name: PackageId::from(expected_name), provenance: ProjectDependencyNodeProvenance::Preassembled { path, selected: selected.clone(), + kind: package.kind, + requirements, }, - version: selected.version.clone(), + version: selected.version, }, - solver_dependencies: BTreeMap::new(), + solver_dependencies, }) } @@ -834,8 +875,7 @@ impl<'a, R: PackageRegistry + ?Sized> ProjectDependencyGraphBuilder<'a, R> { ))) } else { Err(Report::msg(format!( - "dependency '{}' resolved to package '{}'", - expected_name, actual_name, + "dependency '{expected_name}' resolved to package '{actual_name}'", ))) } } @@ -1031,6 +1071,24 @@ struct GitCheckout { resolved_revision: Arc, } +fn package_requirements( + package: &MastPackage, +) -> BTreeMap { + package + .manifest + .dependencies() + .map(|dependency| { + ( + dependency.name.clone(), + PreassembledDependencyMetadata { + version: Version::new(dependency.version.clone(), dependency.digest), + kind: dependency.kind, + }, + ) + }) + .collect() +} + #[cfg(test)] mod tests { use alloc::{boxed::Box, string::ToString}; @@ -1056,7 +1114,7 @@ mod tests { impl TestRegistry { fn insert(&mut self, name: &str, version: Version) { - let record_version = version.clone(); + let record_version = version; self.insert_record( PackageId::from(name), PackageRecord::new(record_version, std::iter::empty()), @@ -1074,8 +1132,7 @@ mod tests { Ok(()) }, Entry::Occupied(_) => Err(Report::msg(format!( - "package '{}' version '{}' is already registered", - id, semver + "package '{id}' version '{semver}' is already registered" ))), } } @@ -1600,11 +1657,122 @@ mod tests { ProjectDependencyNodeProvenance::Preassembled { ref path, ref selected, + .. } if path == &package_path.canonicalize().unwrap() && *selected == Version::new("1.0.0".parse().unwrap(), digest) ); } + #[test] + fn preassembled_path_dependency_propagates_runtime_dependencies_into_resolution() { + let tempdir = TempDir::new().unwrap(); + let runtime_package = build_registry_test_package("runtime", "1.0.0"); + let runtime_version = + Version::new(runtime_package.version.clone(), runtime_package.digest()); + let dep_package = MastPackage::generate( + "dep".into(), + "1.0.0".parse().unwrap(), + TargetType::Library, + [miden_mast_package::Dependency { + name: PackageId::from("runtime"), + version: runtime_version.version.clone(), + kind: TargetType::Library, + digest: runtime_package.digest(), + }], + ); + let dep_package_path = tempdir.path().join("dep.masp"); + fs::write(&dep_package_path, dep_package.to_bytes()).unwrap(); + + let root_dir = tempdir.path().join("root"); + let root_manifest = write_package( + &root_dir, + "root", + "1.0.0", + Some("export.foo\nend\n"), + [Dependency::new( + Span::unknown("dep".into()), + DependencyVersionScheme::Path { + path: Span::unknown(Uri::from(dep_package_path.as_path())), + version: None, + }, + Linkage::Dynamic, + )], + ); + + let mut registry = TestRegistry::default(); + registry + .insert_record( + PackageId::from("runtime"), + PackageRecord::new(runtime_version.clone(), std::iter::empty()), + ) + .unwrap(); + + let graph = builder(®istry, &tempdir.path().join("git")) + .build_from_path(&root_manifest) + .unwrap(); + let dep = graph.get(&PackageId::from("dep")).unwrap(); + let runtime = graph.get(&PackageId::from("runtime")).unwrap(); + + assert_eq!( + dep.dependencies, + vec![ProjectDependencyEdge { + dependency: PackageId::from("runtime"), + linkage: Linkage::Dynamic, + }] + ); + assert_matches!( + runtime.provenance, + ProjectDependencyNodeProvenance::Registry { ref selected, .. } + if *selected == runtime_version + ); + } + + #[test] + fn preassembled_path_dependency_keeps_embedded_kernel_in_solver_requirements() { + let tempdir = TempDir::new().unwrap(); + let kernel_package = MastPackage::generate( + "kernelpkg".into(), + "1.0.0".parse().unwrap(), + TargetType::Kernel, + [], + ); + let kernel_version = Version::new(kernel_package.version.clone(), kernel_package.digest()); + let dep_package = MastPackage::generate( + "dep".into(), + "1.0.0".parse().unwrap(), + TargetType::Library, + [miden_mast_package::Dependency { + name: PackageId::from("kernelpkg"), + version: kernel_version.version.clone(), + kind: TargetType::Kernel, + digest: kernel_package.digest(), + }], + ); + + let dep_package_path = tempdir.path().join("dep.masp"); + fs::write(&dep_package_path, dep_package.to_bytes()).unwrap(); + + let registry = TestRegistry::default(); + let node = builder(®istry, &tempdir.path().join("git")) + .load_preassembled_dependency(&dep_package_path, "dep", None) + .unwrap(); + + assert_eq!( + node.graph_node.dependencies, + vec![ProjectDependencyEdge { + dependency: PackageId::from("kernelpkg"), + linkage: Linkage::Dynamic, + }] + ); + assert_eq!( + node.solver_dependencies, + BTreeMap::from([( + PackageId::from("kernelpkg"), + VersionRequirement::Exact(kernel_version), + )]) + ); + } + #[test] fn preassembled_path_dependency_validates_digest_requirement_against_artifact_digest() { let tempdir = TempDir::new().unwrap(); @@ -1877,10 +2045,10 @@ mod tests { let mut registry = TestRegistry::default(); let dep_id = PackageId::from("dep"); - let version010 = "0.1.0".parse::().unwrap(); - let version999 = "9.9.9".parse::().unwrap(); - registry.insert(&dep_id, Version::from(version010.clone())); - registry.insert(&dep_id, Version::from(version999.clone())); + let version010 = "0.1.0".parse::().unwrap(); + let version999 = "9.9.9".parse::().unwrap(); + registry.insert(&dep_id, Version::from(version010)); + registry.insert(&dep_id, Version::from(version999)); let graph = builder(®istry, &tempdir.path().join("git-cache")) .build_from_path(&app_manifest) .unwrap(); diff --git a/crates/project/src/lib.rs b/crates/project/src/lib.rs index 594ef15771..be289274ff 100644 --- a/crates/project/src/lib.rs +++ b/crates/project/src/lib.rs @@ -31,7 +31,6 @@ use miden_assembly_syntax::{ debuginfo::{SourceSpan, Span}, diagnostics::{Diagnostic, miette}, }; -pub use miden_core::LexicographicWord; pub use miden_mast_package::TargetType; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; diff --git a/crates/project/src/linkage.rs b/crates/project/src/linkage.rs index a5f1e2eab2..20e570a656 100644 --- a/crates/project/src/linkage.rs +++ b/crates/project/src/linkage.rs @@ -1,8 +1,16 @@ use alloc::string::{String, ToString}; use core::{fmt, str::FromStr}; +#[cfg(all(feature = "arbitrary", feature = "serde", test))] +use miden_core::serde::{Deserializable, Serializable}; + /// This represents the way in which a dependent will link against a dependency during assembly. #[derive(Default, Debug, Copy, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "arbitrary", derive(proptest_derive::Arbitrary))] +#[cfg_attr( + all(feature = "arbitrary", feature = "serde", test), + miden_test_serde_macros::serde_test(binary_serde(true)) +)] #[repr(u8)] pub enum Linkage { /// Link against the target package dynamically, i.e. it is expected that the package will be diff --git a/crates/project/src/package.rs b/crates/project/src/package.rs index c36e05ef4c..2922e0d41c 100644 --- a/crates/project/src/package.rs +++ b/crates/project/src/package.rs @@ -1,12 +1,15 @@ -use alloc::boxed::Box; +use alloc::{ + boxed::Box, + string::{String, ToString}, +}; #[cfg(feature = "std")] use std::path::Path; -#[cfg(feature = "std")] +#[cfg(all(feature = "std", feature = "serde"))] use miden_assembly_syntax::debuginfo::Spanned; use miden_mast_package::PackageId; -#[cfg(feature = "std")] +#[cfg(all(feature = "std", feature = "serde"))] use crate::ast::{ProjectFileError, WorkspaceFile}; use crate::*; @@ -212,6 +215,35 @@ impl Package { pub fn manifest_path(&self) -> Option<&Path> { self.manifest_path.as_deref() } + + /// Return the package model projection that affects artifact reuse for `target` under + /// `profile`. + pub fn build_provenance_projection(&self, target: &Target, profile: &Profile) -> String { + let Self { + #[cfg(feature = "std")] + manifest_path: _, + name, + version, + description: _, + dependencies: _, + lints: _, + metadata: _, + lib: _, + bins: _, + profiles: _, + } = self; + + let mut projection = String::new(); + projection.push_str("package:name:"); + projection.push_str(name.inner().as_ref()); + projection.push('\n'); + projection.push_str("package:version:"); + projection.push_str(version.inner().to_string().as_str()); + projection.push('\n'); + target.append_build_provenance_projection(&mut projection); + profile.append_build_provenance_projection(&mut projection); + projection + } } /// Parsing @@ -307,7 +339,7 @@ impl Package { Ok(Box::new(Self { manifest_path, - name: package_ast.package.name.clone().map(|id| id.into()), + name: package_ast.package.name.map(Into::into), version, description, dependencies, @@ -327,11 +359,11 @@ impl Package { /// The output of this function is not guaranteed to be identical to the way the original /// manifest (if one exists) was written, i.e. it may emit keys that are optional or that /// contain default or inherited values. - pub fn to_toml(&self) -> Result { + pub fn to_toml(&self) -> Result { let manifest_ast = ast::ProjectFile { source_file: None, package: ast::PackageTable { - name: self.name().map(|id| id.into_inner()), + name: self.name().map(PackageId::into_inner), detail: ast::PackageDetail { version: Some( self.version().map(|v| ast::parsing::MaybeInherit::Value(v.clone())), diff --git a/crates/project/src/profile.rs b/crates/project/src/profile.rs index cee72495b1..abfe138209 100644 --- a/crates/project/src/profile.rs +++ b/crates/project/src/profile.rs @@ -1,4 +1,4 @@ -use alloc::string::ToString; +use alloc::string::{String, ToString}; use core::borrow::Borrow; use miden_assembly_syntax::debuginfo::Spanned; @@ -196,6 +196,18 @@ impl Profile { { self.metadata.get(key) } + + /// Append the profile settings that affect package artifact reuse to `out`. + pub fn append_build_provenance_projection(&self, out: &mut String) { + let Self { name: _, debug, trim_paths, metadata: _ } = self; + + out.push_str("profile:debug:"); + out.push_str(if *debug { "true" } else { "false" }); + out.push('\n'); + out.push_str("profile:trim_paths:"); + out.push_str(if *trim_paths { "true" } else { "false" }); + out.push('\n'); + } } impl Extend<(Span>, Span)> for Profile { diff --git a/crates/project/src/target.rs b/crates/project/src/target.rs index 787ebaccb8..3a3ccca948 100644 --- a/crates/project/src/target.rs +++ b/crates/project/src/target.rs @@ -1,3 +1,5 @@ +use alloc::string::{String, ToString}; + use miden_assembly_syntax::Path; use crate::*; @@ -69,4 +71,25 @@ impl Target { pub const fn is_kernel(&self) -> bool { matches!(self.ty, TargetType::Kernel) } + + /// Append the selected target fields that affect package artifact reuse to `out`. + pub fn append_build_provenance_projection(&self, out: &mut String) { + let Self { ty, name, namespace, path } = self; + + out.push_str("target:kind:"); + out.push_str(ty.to_string().as_str()); + out.push('\n'); + out.push_str("target:name:"); + out.push_str(name.inner().as_ref()); + out.push('\n'); + out.push_str("target:namespace:"); + out.push_str(namespace.inner().as_str()); + out.push('\n'); + out.push_str("target:path:"); + match path.as_ref() { + Some(path) => out.push_str(path.inner().path()), + None => out.push_str(""), + } + out.push('\n'); + } } diff --git a/crates/project/src/workspace.rs b/crates/project/src/workspace.rs index 9b2c96a3b5..cdb75591c4 100644 --- a/crates/project/src/workspace.rs +++ b/crates/project/src/workspace.rs @@ -1,9 +1,7 @@ +#[cfg(all(feature = "std", feature = "serde"))] +use std::string::{String, ToString}; #[cfg(feature = "std")] -use std::{ - boxed::Box, - path::Path, - string::{String, ToString}, -}; +use std::{boxed::Box, path::Path}; #[cfg(all(feature = "std", feature = "serde"))] use miden_assembly_syntax::debuginfo::SourceManager; @@ -87,7 +85,7 @@ impl Workspace { let members = file.workspace.members.clone(); let mut workspace = Box::new(Workspace { - manifest_path: manifest_path.clone(), + manifest_path, members: Vec::with_capacity(members.len()), }); let mut seen_member_names = Map::::default(); @@ -104,13 +102,12 @@ impl Workspace { .into()); }; let relative_path = Path::new(member.as_str()); - let member_dir = - crate::absolutize_path(relative_path, workspace_root).map_err(|err| { - ProjectFileError::LoadWorkspaceMemberFailed { - source_file: source.clone(), - span: Label::new(member.span(), err.to_string()), - } - })?; + let member_dir = absolutize_path(relative_path, workspace_root).map_err(|err| { + ProjectFileError::LoadWorkspaceMemberFailed { + source_file: source.clone(), + span: Label::new(member.span(), err.to_string()), + } + })?; if member_dir.strip_prefix(workspace_root).is_err() { return Err(ProjectFileError::LoadWorkspaceMemberFailed { source_file: source.clone(), diff --git a/crates/test-serde-macros/Cargo.toml b/crates/test-serde-macros/Cargo.toml index 8c77843106..6f7e2331ee 100644 --- a/crates/test-serde-macros/Cargo.toml +++ b/crates/test-serde-macros/Cargo.toml @@ -17,8 +17,8 @@ edition.workspace = true proc-macro = true [dependencies] -proc-macro2 = "1.0" -quote = "1.0" +proc-macro2 = { workspace = true } +quote = { workspace = true } syn = { workspace = true, features = ["derive", "extra-traits", "full"] } proptest.workspace = true proptest-derive.workspace = true diff --git a/crates/test-serde-macros/src/lib.rs b/crates/test-serde-macros/src/lib.rs index 29eaf67982..d4b3910feb 100644 --- a/crates/test-serde-macros/src/lib.rs +++ b/crates/test-serde-macros/src/lib.rs @@ -155,10 +155,11 @@ pub fn serde_test(args: TokenStream, input: TokenStream) -> TokenStream { for (i, ty) in types.into_iter().enumerate() { let serde_test = if serde_test { let test_name = - Ident::new(&format!("test_serde_roundtrip_{}_{}", name, i), Span::mixed_site()); + Ident::new(&format!("test_serde_roundtrip_{name}_{i}"), Span::mixed_site()); quote! { #[cfg(all(feature = "arbitrary", feature = "serde", test))] proptest::proptest!{ + #![proptest_config(proptest::test_runner::Config::with_cases(100))] #[test] fn #test_name(obj in proptest::prelude::any::#ty()) { use alloc::string::ToString; @@ -182,6 +183,7 @@ pub fn serde_test(args: TokenStream, input: TokenStream) -> TokenStream { quote! { #[cfg(all(feature = "arbitrary", test))] proptest::proptest!{ + #![proptest_config(proptest::test_runner::Config::with_cases(100))] #[test] fn #test_name(obj in proptest::prelude::any::#ty()) { let bytes = obj.to_bytes(); diff --git a/crates/test-utils/Cargo.toml b/crates/test-utils/Cargo.toml index 82ec8d8fbd..2f9e4976c2 100644 --- a/crates/test-utils/Cargo.toml +++ b/crates/test-utils/Cargo.toml @@ -34,11 +34,11 @@ miden-verifier.workspace = true test-case = "3.2" [target.'cfg(target_family = "wasm")'.dependencies] -pretty_assertions = { version = "1.4", default-features = false, features = [ +pretty_assertions = { workspace = true, default-features = false, features = [ "alloc", ] } [target.'cfg(not(target_family = "wasm"))'.dependencies] env_logger.workspace = true -pretty_assertions = "1.4" +pretty_assertions = { workspace = true, features = ["std"] } proptest.workspace = true diff --git a/crates/test-utils/src/crypto.rs b/crates/test-utils/src/crypto.rs index 32ae4658fd..12a88914fe 100644 --- a/crates/test-utils/src/crypto.rs +++ b/crates/test-utils/src/crypto.rs @@ -6,8 +6,8 @@ pub use miden_core::crypto::{ dsa::*, hash::Poseidon2, merkle::{ - EmptySubtreeRoots, LeafIndex, MerkleError, MerklePath, MerkleStore, MerkleTree, Mmr, - MmrPeaks, NodeIndex, PartialMerkleTree, SimpleSmt, Smt, + EmptySubtreeRoots, InnerNodeInfo, LeafIndex, MerkleError, MerklePath, MerkleStore, + MerkleTree, Mmr, MmrPeaks, NodeIndex, PartialMerkleTree, SimpleSmt, Smt, }, }; @@ -28,5 +28,5 @@ pub fn init_merkle_leaves(values: &[u64]) -> Vec { } pub fn init_merkle_leaf(value: u64) -> Word { - [Felt::new(value), ZERO, ZERO, ZERO].into() + [Felt::new_unchecked(value), ZERO, ZERO, ZERO].into() } diff --git a/crates/test-utils/src/lib.rs b/crates/test-utils/src/lib.rs index 92792c68eb..780ab861c3 100644 --- a/crates/test-utils/src/lib.rs +++ b/crates/test-utils/src/lib.rs @@ -40,12 +40,10 @@ pub use miden_processor::{ #[cfg(not(target_family = "wasm"))] use miden_processor::{DefaultDebugHandler, trace::build_trace}; use miden_processor::{ - DefaultHost, ExecutionOutput, FastProcessor, Program, event::EventHandler, - trace::execution_tracer::TraceGenerationContext, + DefaultHost, ExecutionOutput, FastProcessor, Program, TraceBuildInputs, event::EventHandler, }; #[cfg(not(target_family = "wasm"))] pub use miden_prover::prove_sync; -use miden_prover::utils::range; pub use miden_prover::{ProvingOptions, prove}; pub use miden_verifier::verify; pub use pretty_assertions::{assert_eq, assert_ne, assert_str_eq}; @@ -91,6 +89,39 @@ proc truncate_stack end "; +// COMPILE CACHE +// ================================================================================================ + +/// Key for the process-local compile cache, keyed by all inputs that affect compilation output. +/// +/// The source manager identity is included so cached programs keep their debug/source mapping local +/// to the test context that produced them. +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[cfg(all(feature = "std", not(target_family = "wasm")))] +struct CompileCacheKey { + source_manager: usize, + source: SourceCacheKey, + kernel_source: Option, + add_modules: Vec<(String, String)>, + library_digests: Vec, +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[cfg(all(feature = "std", not(target_family = "wasm")))] +struct SourceCacheKey { + uri: String, + source: String, +} + +#[cfg(all(feature = "std", not(target_family = "wasm")))] +type CompileCacheValue = (Program, Option); + +#[cfg(all(feature = "std", not(target_family = "wasm")))] +type CompileCache = std::collections::HashMap; + +#[cfg(all(feature = "std", not(target_family = "wasm")))] +static COMPILE_CACHE: std::sync::Mutex> = std::sync::Mutex::new(None); + // TEST HANDLER // ================================================================================================ @@ -225,6 +256,63 @@ impl Test { } } + /// Adds kernel source to this test so it is assembled and linked during compilation. + #[track_caller] + pub fn with_kernel(self, kernel_source: impl ToString) -> Self { + self.with_kernel_source( + format!("kernel{}", core::panic::Location::caller().line()), + kernel_source, + ) + } + + /// Adds kernel source to this test so it is assembled and linked during compilation. + pub fn with_kernel_source( + mut self, + kernel_name: impl Into, + kernel_source: impl ToString, + ) -> Self { + self.kernel_source = Some(self.source_manager.load( + SourceLanguage::Masm, + kernel_name.into().into(), + kernel_source.to_string(), + )); + self + } + + /// Sets the stack inputs for this test using stack-ordered values. + #[track_caller] + pub fn with_stack_inputs(mut self, stack_inputs: impl AsRef<[u64]>) -> Self { + self.stack_inputs = StackInputs::try_from_ints(stack_inputs.as_ref().to_vec()).unwrap(); + self + } + + /// Adds a library to link in during assembly. + pub fn with_library(mut self, library: impl Into) -> Self { + self.libraries.push(library.into()); + self + } + + /// Adds a handler for a specific event when running the `Host`. + pub fn with_event_handler(mut self, event: EventName, handler: impl EventHandler) -> Self { + self.add_event_handler(event, handler); + self + } + + /// Adds handlers for specific events when running the `Host`. + pub fn with_event_handlers( + mut self, + handlers: Vec<(EventName, Arc)>, + ) -> Self { + self.add_event_handlers(handlers); + self + } + + /// Adds an extra module to link in during assembly. + pub fn with_module(mut self, path: impl AsRef, source: impl ToString) -> Self { + self.add_module(path, source); + self + } + /// Add an extra module to link in during assembly pub fn add_module(&mut self, path: impl AsRef, source: impl ToString) { self.add_modules.push((path.as_ref().into(), source.to_string())); @@ -281,13 +369,15 @@ impl Test { // execute the test let processor = FastProcessor::new(self.stack_inputs) .with_advice(self.advice_inputs.clone()) + .expect("test advice inputs should fit default advice map limits") .with_debugging(self.in_debug_mode) .with_tracing(self.in_debug_mode); let execution_output = processor.execute_sync(&program, &mut host).unwrap(); // validate the memory state - for (addr, mem_value) in - (range(mem_start_addr as usize, expected_mem.len())).zip(expected_mem.iter()) + for (addr, mem_value) in ((mem_start_addr as usize) + ..(mem_start_addr as usize + expected_mem.len())) + .zip(expected_mem.iter()) { let mem_state = execution_output .memory @@ -321,6 +411,26 @@ impl Test { Ok(()) } + /// Executes the test with the provided stack inputs and asserts the final stack state. + /// + /// This preserves the same execution coverage as [`expect_stack`](Self::expect_stack): traced + /// execution, step/resume execution comparison, and trace construction are all still run. + #[cfg(not(target_family = "wasm"))] + #[track_caller] + pub fn expect_stack_with_inputs(&self, stack_inputs: &[u64], final_stack: &[u64]) { + let trace = self + .execute_with_stack_inputs(stack_inputs) + .inspect_err(|_err| { + #[cfg(feature = "std")] + std::eprintln!("{}", PrintDiagnostic::new_without_color(_err)) + }) + .expect("failed to execute"); + + let result = trace.last_stack_state().as_int_vec(); + let expected = resize_to_min_stack_depth(final_stack); + assert_eq!(expected, result, "Expected stack to be {:?}, found {:?}", expected, result); + } + // UTILITY METHODS // -------------------------------------------------------------------------------------------- @@ -332,6 +442,18 @@ impl Test { pub fn compile(&self) -> Result<(Program, Option), Report> { use miden_assembly::{Assembler, ParseOptions, ast::ModuleKind}; + #[cfg(all(feature = "std", not(target_family = "wasm")))] + let cache_key = self.compile_cache_key(); + + #[cfg(all(feature = "std", not(target_family = "wasm")))] + { + let mut cache_guard = COMPILE_CACHE.lock().unwrap(); + let cache = cache_guard.get_or_insert_with(Default::default); + if let Some(cached) = cache.get(&cache_key) { + return Ok((cached.0.clone(), cached.1.clone())); + } + } + // Enable debug tracing to stderr via the MIDEN_LOG environment variable, if present #[cfg(not(target_family = "wasm"))] { @@ -366,17 +488,49 @@ impl Test { assembler.link_dynamic_library(library).unwrap(); } - Ok((assembler.assemble_program(self.source.clone())?, kernel_lib)) + let result = (assembler.assemble_program(self.source.clone())?, kernel_lib); + + #[cfg(all(feature = "std", not(target_family = "wasm")))] + { + let mut cache_guard = COMPILE_CACHE.lock().unwrap(); + let cache = cache_guard.get_or_insert_with(Default::default); + cache.insert(cache_key, (result.0.clone(), result.1.clone())); + } + + Ok(result) } /// Compiles the test's source to a Program and executes it with the tests inputs. Returns a /// resulting execution trace or error. /// - /// Internally, this also checks that the slow and fast processors agree on the stack - /// outputs. + /// Internally, this also checks that traced execution and step/resume execution agree on the + /// stack outputs. #[cfg(not(target_family = "wasm"))] #[track_caller] pub fn execute(&self) -> Result { + self.execute_with_stack_inputs_inner(self.stack_inputs) + } + + /// Compiles the test's source and executes it with the provided stack inputs. + /// + /// This uses the same traced execution, step/resume comparison, and trace construction path as + /// [`execute`](Self::execute). + #[cfg(not(target_family = "wasm"))] + #[track_caller] + pub fn execute_with_stack_inputs( + &self, + stack_inputs: &[u64], + ) -> Result { + let stack_inputs = StackInputs::try_from_ints(stack_inputs.to_vec()).unwrap(); + self.execute_with_stack_inputs_inner(stack_inputs) + } + + #[cfg(not(target_family = "wasm"))] + #[track_caller] + fn execute_with_stack_inputs_inner( + &self, + stack_inputs: StackInputs, + ) -> Result { // Note: we fix a large fragment size here, as we're not testing the fragment boundaries // with these tests (which are tested separately), but rather only the per-fragment trace // generation logic - though not too big so as to over-allocate memory. @@ -387,21 +541,22 @@ impl Test { let fast_stack_result = { let fast_processor = FastProcessor::new_with_options( - self.stack_inputs, + stack_inputs, self.advice_inputs.clone(), miden_processor::ExecutionOptions::default() .with_debugging(self.in_debug_mode) .with_core_trace_fragment_size(FRAGMENT_SIZE) .unwrap(), - ); - fast_processor.execute_for_trace_sync(&program, &mut host) + ) + .map_err(ExecutionError::advice_error_no_context)?; + fast_processor.execute_trace_inputs_sync(&program, &mut host) }; - // compare fast and slow processors' stack outputs - self.assert_result_with_step_execution(&fast_stack_result); + // Compare traced full execution and step/resume execution stack outputs. + self.assert_result_with_step_execution(stack_inputs, &fast_stack_result); - fast_stack_result.and_then(|(execution_output, trace_generation_ctx)| { - let trace = build_trace(execution_output, trace_generation_ctx, program.to_info())?; + fast_stack_result.and_then(|trace_inputs| { + let trace = build_trace(trace_inputs)?; assert_eq!(&program.hash(), trace.program_hash(), "inconsistent program hash"); Ok(trace) @@ -418,6 +573,7 @@ impl Test { let processor = FastProcessor::new(self.stack_inputs) .with_advice(self.advice_inputs.clone()) + .map_err(ExecutionError::advice_error_no_context)? .with_debugging(true) .with_tracing(true); @@ -439,6 +595,7 @@ impl Test { let processor = FastProcessor::new(self.stack_inputs) .with_advice(self.advice_inputs.clone()) + .map_err(ExecutionError::advice_error_no_context)? .with_debugging(true) .with_tracing(true); @@ -451,7 +608,7 @@ impl Test { Err(err) => { // If we get an error, we print the output as an error #[cfg(feature = "std")] - std::eprintln!("{}", debug_output); + std::eprintln!("{debug_output}"); Err(err) }, } @@ -468,11 +625,12 @@ impl Test { pub fn prove_and_verify(&self, pub_inputs: Vec, test_fail: bool) { let (program, mut host) = self.get_program_and_host(); let stack_inputs = StackInputs::try_from_ints(pub_inputs).unwrap(); - let (mut stack_outputs, proof) = miden_prover::prove_sync( + let (mut stack_outputs, proof) = prove_sync( &program, stack_inputs, self.advice_inputs.clone(), &mut host, + miden_processor::ExecutionOptions::default(), ProvingOptions::default(), ) .unwrap(); @@ -480,11 +638,9 @@ impl Test { let program_info = ProgramInfo::from(program); if test_fail { stack_outputs.as_mut()[0] += ONE; - assert!( - miden_verifier::verify(program_info, stack_inputs, stack_outputs, proof).is_err() - ); + assert!(verify(program_info, stack_inputs, stack_outputs, proof).is_err()); } else { - let result = miden_verifier::verify(program_info, stack_inputs, stack_outputs, proof); + let result = verify(program_info, stack_inputs, stack_outputs, proof); assert!(result.is_ok(), "error: {result:?}"); } } @@ -555,7 +711,8 @@ impl Test { #[cfg(not(target_family = "wasm"))] fn assert_result_with_step_execution( &self, - fast_result: &Result<(ExecutionOutput, TraceGenerationContext), ExecutionError>, + stack_inputs: StackInputs, + fast_result: &Result, ) { fn compare_results( left_result: Result, @@ -602,20 +759,46 @@ impl Test { let mut host = host.with_source_manager(self.source_manager.clone()); let fast_result_by_step = { - let fast_process = FastProcessor::new(self.stack_inputs) + let fast_process = FastProcessor::new(stack_inputs) .with_advice(self.advice_inputs.clone()) + .expect("test advice inputs should fit default advice map limits") .with_debugging(self.in_debug_mode) .with_tracing(self.in_debug_mode); fast_process.execute_by_step_sync(&program, &mut host) }; compare_results( - fast_result.as_ref().map(|(output, _)| output.stack), + fast_result.as_ref().map(|trace_inputs| *trace_inputs.stack_outputs()), &fast_result_by_step, - "fast processor", - "fast processor by step", + "traced execution", + "step/resume execution", ); } + + #[cfg(all(feature = "std", not(target_family = "wasm")))] + fn compile_cache_key(&self) -> CompileCacheKey { + CompileCacheKey { + source_manager: Arc::as_ptr(&self.source_manager) as usize, + source: SourceCacheKey::from_source_file(self.source.as_ref()), + kernel_source: self.kernel_source.as_deref().map(SourceCacheKey::from_source_file), + add_modules: self + .add_modules + .iter() + .map(|(path, source)| (path.to_string(), source.clone())) + .collect(), + library_digests: self.libraries.iter().map(|library| *library.digest()).collect(), + } + } +} + +#[cfg(all(feature = "std", not(target_family = "wasm")))] +impl SourceCacheKey { + fn from_source_file(source_file: &SourceFile) -> Self { + Self { + uri: source_file.uri().as_str().to_string(), + source: source_file.as_str().to_string(), + } + } } // HELPER FUNCTIONS @@ -656,7 +839,7 @@ pub fn build_expected_perm(values: &[u64]) -> [Felt; STATE_WIDTH] { // => state[0..12] = stack[0..12] in [RATE0,RATE1,CAPACITY] layout. let mut state = [ZERO; STATE_WIDTH]; for i in 0..STATE_WIDTH { - state[i] = Felt::new(values[i]); + state[i] = Felt::new_unchecked(values[i]); } // Apply the permutation @@ -670,7 +853,7 @@ pub fn build_expected_perm(values: &[u64]) -> [Felt; STATE_WIDTH] { } pub fn build_expected_hash(values: &[u64]) -> [Felt; 4] { - let digest = hash_elements(&values.iter().map(|&v| Felt::new(v)).collect::>()); + let digest = hash_elements(&values.iter().map(|&v| Felt::new_unchecked(v)).collect::>()); digest.into() } @@ -706,33 +889,45 @@ pub fn get_column_name(col_idx: usize) -> String { // Decoder columns i if i == DECODER_TRACE_OFFSET + ADDR_COL_IDX => "decoder_addr".to_string(), - i if range(DECODER_TRACE_OFFSET + OP_BITS_OFFSET, NUM_OP_BITS).contains(&i) => { + i if (DECODER_TRACE_OFFSET + OP_BITS_OFFSET + ..DECODER_TRACE_OFFSET + OP_BITS_OFFSET + NUM_OP_BITS) + .contains(&i) => + { format!("op_bits[{}]", i - (DECODER_TRACE_OFFSET + OP_BITS_OFFSET)) }, - i if range(DECODER_TRACE_OFFSET + HASHER_STATE_OFFSET, NUM_HASHER_COLUMNS).contains(&i) => { + i if (DECODER_TRACE_OFFSET + HASHER_STATE_OFFSET + ..DECODER_TRACE_OFFSET + HASHER_STATE_OFFSET + NUM_HASHER_COLUMNS) + .contains(&i) => + { format!("hasher_state[{}]", i - (DECODER_TRACE_OFFSET + HASHER_STATE_OFFSET)) }, i if i == DECODER_TRACE_OFFSET + IN_SPAN_COL_IDX => "in_span".to_string(), i if i == DECODER_TRACE_OFFSET + GROUP_COUNT_COL_IDX => "group_count".to_string(), i if i == DECODER_TRACE_OFFSET + OP_INDEX_COL_IDX => "op_index".to_string(), - i if range(DECODER_TRACE_OFFSET + OP_BATCH_FLAGS_OFFSET, NUM_OP_BATCH_FLAGS) + i if (DECODER_TRACE_OFFSET + OP_BATCH_FLAGS_OFFSET + ..DECODER_TRACE_OFFSET + OP_BATCH_FLAGS_OFFSET + NUM_OP_BATCH_FLAGS) .contains(&i) => { format!("op_batch_flag[{}]", i - (DECODER_TRACE_OFFSET + OP_BATCH_FLAGS_OFFSET)) }, - i if range(DECODER_TRACE_OFFSET + OP_BITS_EXTRA_COLS_OFFSET, NUM_OP_BITS_EXTRA_COLS) + i if (DECODER_TRACE_OFFSET + OP_BITS_EXTRA_COLS_OFFSET + ..DECODER_TRACE_OFFSET + OP_BITS_EXTRA_COLS_OFFSET + NUM_OP_BITS_EXTRA_COLS) .contains(&i) => { format!("op_bits_extra[{}]", i - (DECODER_TRACE_OFFSET + OP_BITS_EXTRA_COLS_OFFSET)) }, - i if range(DECODER_TRACE_OFFSET + OP_BITS_EXTRA_COLS_OFFSET, NUM_OP_BITS_EXTRA_COLS) + i if (DECODER_TRACE_OFFSET + OP_BITS_EXTRA_COLS_OFFSET + ..DECODER_TRACE_OFFSET + OP_BITS_EXTRA_COLS_OFFSET + NUM_OP_BITS_EXTRA_COLS) .contains(&i) => { format!("op_bits_extra[{}]", i - (DECODER_TRACE_OFFSET + OP_BITS_EXTRA_COLS_OFFSET)) }, // Stack columns - i if range(STACK_TRACE_OFFSET + STACK_TOP_OFFSET, MIN_STACK_DEPTH).contains(&i) => { + i if (STACK_TRACE_OFFSET + STACK_TOP_OFFSET + ..STACK_TRACE_OFFSET + STACK_TOP_OFFSET + MIN_STACK_DEPTH) + .contains(&i) => + { format!("stack[{}]", i - (STACK_TRACE_OFFSET + STACK_TOP_OFFSET)) }, i if i == STACK_TRACE_OFFSET + B0_COL_IDX => "stack_b0".to_string(), @@ -745,6 +940,6 @@ pub fn get_column_name(col_idx: usize) -> String { }, // Default case - _ => format!("unknown_col[{}]", col_idx), + _ => format!("unknown_col[{col_idx}]"), } } diff --git a/crates/test-utils/src/rand.rs b/crates/test-utils/src/rand.rs index fe65b52e00..9914625943 100644 --- a/crates/test-utils/src/rand.rs +++ b/crates/test-utils/src/rand.rs @@ -31,7 +31,7 @@ pub fn seeded_word(seed: &mut u64) -> Word { pub fn seeded_element(seed: &mut u64) -> Felt { *seed = (*seed).wrapping_add(0x9e37_79b9_7f4a_7c15); - Felt::new(splitmix64(*seed)) + Felt::new_unchecked(splitmix64(*seed)) } // HELPERS diff --git a/crates/utils-core-derive/Cargo.toml b/crates/utils-core-derive/Cargo.toml index 39d6498c71..b92550569d 100644 --- a/crates/utils-core-derive/Cargo.toml +++ b/crates/utils-core-derive/Cargo.toml @@ -16,6 +16,6 @@ edition.workspace = true proc-macro = true [dependencies] -proc-macro2 = "1.0" -quote = "1.0" +proc-macro2 = { workspace = true } +quote = { workspace = true } syn = { workspace = true, features = ["derive", "extra-traits", "full"] } diff --git a/crates/utils-core-derive/src/lib.rs b/crates/utils-core-derive/src/lib.rs index ea6cb204b4..ab6a936465 100644 --- a/crates/utils-core-derive/src/lib.rs +++ b/crates/utils-core-derive/src/lib.rs @@ -203,7 +203,7 @@ fn generate_method_impl_for_trait_method( "to_builder" => { generate_to_builder_method(enum_name, variant_names, variant_fields, builder_type) }, - _ => panic!("Unknown method: {}", method_name), + _ => panic!("Unknown method: {method_name}"), } } diff --git a/crates/utils-diagnostics/Cargo.toml b/crates/utils-diagnostics/Cargo.toml index 54a8ce666a..1d09caba8b 100644 --- a/crates/utils-diagnostics/Cargo.toml +++ b/crates/utils-diagnostics/Cargo.toml @@ -20,10 +20,9 @@ std = ["miette/fancy-no-syscall", "miette/std", "miden-crypto/std", "miden-debug [dependencies] miden-debug-types.workspace = true -miette = { package = "miden-miette", version = "8.0", default-features = false, features = [ +miette = { workspace = true, features = [ "fancy-no-syscall", "derive", ] } miden-crypto.workspace = true -paste.workspace = true tracing.workspace = true diff --git a/crates/utils-diagnostics/src/related.rs b/crates/utils-diagnostics/src/related.rs index 6a896f3d33..b2d75a3630 100644 --- a/crates/utils-diagnostics/src/related.rs +++ b/crates/utils-diagnostics/src/related.rs @@ -138,7 +138,7 @@ impl Diagnostic for RelatedLabel { if self.labels.is_empty() { None } else { - Some(Box::new(self.labels.iter().cloned().map(|l| l.into()))) + Some(Box::new(self.labels.iter().cloned().map(Into::into))) } } fn related<'a>(&'a self) -> Option + 'a>> { diff --git a/crates/utils-diagnostics/src/reporting.rs b/crates/utils-diagnostics/src/reporting.rs index 1374c4cbdd..2780902ba9 100644 --- a/crates/utils-diagnostics/src/reporting.rs +++ b/crates/utils-diagnostics/src/reporting.rs @@ -19,7 +19,7 @@ pub fn set_panic_hook() { pub type ReportHandlerOpts = miette::MietteHandlerOpts; #[cfg(feature = "std")] -pub type DefaultReportHandler = miette::GraphicalReportHandler; +pub type DefaultReportHandler = GraphicalReportHandler; #[cfg(not(feature = "std"))] pub type DefaultReportHandler = miette::DebugReportHandler; @@ -63,19 +63,19 @@ impl> PrintDiagnostic { } impl> fmt::Display for PrintDiagnostic { - fn fmt(&self, f: &mut fmt::Formatter) -> core::fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.handler.render_report(f, self.diag.as_ref()) } } impl> fmt::Display for PrintDiagnostic { - fn fmt(&self, f: &mut fmt::Formatter) -> core::fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.handler.render_report(f, self.diag.as_ref()) } } impl> fmt::Display for PrintDiagnostic { - fn fmt(&self, f: &mut fmt::Formatter) -> core::fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.handler.render_report(f, self.diag.as_ref()) } } diff --git a/crates/utils-indexing/Cargo.toml b/crates/utils-indexing/Cargo.toml index 44f03c0fc5..4b76274f80 100644 --- a/crates/utils-indexing/Cargo.toml +++ b/crates/utils-indexing/Cargo.toml @@ -12,9 +12,13 @@ authors.workspace = true homepage.workspace = true repository.workspace = true +[package.metadata.cargo-shear] +ignored = ["serde_json"] + [features] +arbitrary = ["std", "dep:proptest"] default = ["std"] -std = [] +std = ["proptest?/std"] serde = ["dep:serde"] [dependencies] @@ -23,6 +27,10 @@ miden-crypto.workspace = true thiserror.workspace = true # Optional dependencies +proptest = { workspace = true, optional = true } serde = { workspace = true, optional = true } -[dev-dependencies] \ No newline at end of file +[dev-dependencies] +miden-test-serde-macros.workspace = true +proptest.workspace = true +serde_json.workspace = true diff --git a/crates/utils-indexing/src/csr.rs b/crates/utils-indexing/src/csr.rs index f5c1fe1b79..a2e09ddfd5 100644 --- a/crates/utils-indexing/src/csr.rs +++ b/crates/utils-indexing/src/csr.rs @@ -9,6 +9,8 @@ use alloc::vec::Vec; use miden_crypto::utils::{ ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable, }; +#[cfg(feature = "arbitrary")] +use proptest::prelude::*; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; use thiserror::Error; @@ -45,6 +47,10 @@ use crate::{Idx, IndexVec, IndexedVecError}; /// ``` #[derive(Debug, Clone, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr( + all(feature = "arbitrary", test), + miden_test_serde_macros::serde_test(binary_serde(true), types(crate::SerdeTestId, u32)) +)] pub struct CsrMatrix { /// Flat storage of all data values. data: Vec, @@ -52,6 +58,31 @@ pub struct CsrMatrix { indptr: IndexVec, } +#[cfg(feature = "arbitrary")] +impl Arbitrary for CsrMatrix +where + I: Idx + 'static, + D: Arbitrary + 'static, + D::Strategy: 'static, +{ + type Parameters = D::Parameters; + type Strategy = BoxedStrategy; + + fn arbitrary_with(args: Self::Parameters) -> Self::Strategy { + let row = proptest::collection::vec(any_with::(args), 0..8); + + proptest::collection::vec(row, 0..16) + .prop_map(|rows| { + let mut matrix = Self::new(); + for row in rows { + matrix.push_row(row).expect("generated row count fits in u32"); + } + matrix + }) + .boxed() + } +} + impl Default for CsrMatrix { fn default() -> Self { Self::new() @@ -441,7 +472,7 @@ mod tests { csr.push_empty_row().unwrap(); csr.push_row([3]).unwrap(); - let items: alloc::vec::Vec<_> = csr.iter().collect(); + let items: Vec<_> = csr.iter().collect(); assert_eq!(items.len(), 3); assert_eq!(items[0], (TestRowId::from(0), &[1, 2][..])); assert_eq!(items[1], (TestRowId::from(1), &[][..])); @@ -454,7 +485,7 @@ mod tests { csr.push_row([10, 20]).unwrap(); csr.push_row([30]).unwrap(); - let items: alloc::vec::Vec<_> = csr.iter_enumerated().collect(); + let items: Vec<_> = csr.iter_enumerated().collect(); assert_eq!(items.len(), 3); assert_eq!(items[0], (TestRowId::from(0), 0, &10)); assert_eq!(items[1], (TestRowId::from(0), 1, &20)); diff --git a/crates/utils-indexing/src/lib.rs b/crates/utils-indexing/src/lib.rs index 6fb5dfbd6f..6b3bc02748 100644 --- a/crates/utils-indexing/src/lib.rs +++ b/crates/utils-indexing/src/lib.rs @@ -12,6 +12,8 @@ use alloc::{collections::BTreeMap, vec, vec::Vec}; use core::{fmt::Debug, marker::PhantomData, ops}; pub use csr::{CsrMatrix, CsrValidationError}; +#[cfg(feature = "arbitrary")] +use proptest::prelude::*; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; use thiserror::Error; @@ -24,6 +26,16 @@ pub enum IndexedVecError { TooManyItems, } +#[cfg(feature = "arbitrary")] +impl Arbitrary for IndexedVecError { + type Parameters = (); + type Strategy = BoxedStrategy; + + fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { + Just(Self::TooManyItems).boxed() + } +} + /// A trait for u32-backed, 0-based IDs. pub trait Idx: Copy + Eq + Ord + Debug + From + Into { /// Convert from this ID type to usize. @@ -60,16 +72,60 @@ macro_rules! newtype_id { }; } +#[cfg(test)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[repr(transparent)] +pub struct SerdeTestId(u32); + +#[cfg(test)] +impl From for SerdeTestId { + fn from(v: u32) -> Self { + Self(v) + } +} + +#[cfg(test)] +impl From for u32 { + fn from(v: SerdeTestId) -> Self { + v.0 + } +} + +#[cfg(test)] +impl Idx for SerdeTestId {} + /// A dense vector indexed by ID types. /// /// This provides O(1) access and storage for dense ID-indexed data. #[derive(Clone, Debug, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr( + all(feature = "arbitrary", test), + miden_test_serde_macros::serde_test(binary_serde(true), types(SerdeTestId, u32)) +)] pub struct IndexVec { raw: Vec, _m: PhantomData, } +#[cfg(feature = "arbitrary")] +impl Arbitrary for IndexVec +where + I: Idx + 'static, + T: Arbitrary + 'static, + T::Strategy: 'static, +{ + type Parameters = T::Parameters; + type Strategy = BoxedStrategy; + + fn arbitrary_with(args: Self::Parameters) -> Self::Strategy { + proptest::collection::vec(any_with::(args), 0..32) + .prop_map(|raw| Self::try_from(raw).expect("generated vector length fits in u32")) + .boxed() + } +} + impl Default for IndexVec { fn default() -> Self { Self { raw: Vec::new(), _m: PhantomData } @@ -293,7 +349,7 @@ where impl IntoIterator for IndexVec { type Item = T; - type IntoIter = alloc::vec::IntoIter; + type IntoIter = vec::IntoIter; fn into_iter(self) -> Self::IntoIter { self.raw.into_iter() diff --git a/crates/utils-sync/Cargo.toml b/crates/utils-sync/Cargo.toml index 47b933e07b..ccaed536ae 100644 --- a/crates/utils-sync/Cargo.toml +++ b/crates/utils-sync/Cargo.toml @@ -24,11 +24,10 @@ once_cell = { version = "1.21", default-features = false, features = ["alloc", " parking_lot = { version = "0.12", optional = true } [dev-dependencies] -loom = "0.7" -proptest.workspace = true +loom = { workspace = true } [target.'cfg(loom)'.dependencies] -loom = "0.7" +loom.workspace = true [lints.rust] unexpected_cfgs = { level = "warn", check-cfg = ['cfg(loom)'] } diff --git a/deny.toml b/deny.toml index 2079458345..a06f526b45 100644 --- a/deny.toml +++ b/deny.toml @@ -49,6 +49,7 @@ deny = [ #{ name = "ansi_term", version = "=0.11.0" }, ] skip = [ + # Allow duplicate spin cpufeatures { name = "cpufeatures" }, # Allow duplicate spin versions - transitively pulled by p3-dft and flume { name = "spin" }, diff --git a/docs/src/design/chiplets/hasher.md b/docs/src/design/chiplets/hasher.md index 46975e3711..8365755c63 100644 --- a/docs/src/design/chiplets/hasher.md +++ b/docs/src/design/chiplets/hasher.md @@ -5,514 +5,678 @@ sidebar_position: 2 # Hash chiplet -Miden VM "offloads" all hash-related computations to a separate _hash processor_. This chiplet supports executing the [Poseidon2](https://eprint.iacr.org/2023/323) hash function in the following settings: - -- A single permutation of Poseidon2. -- A simple 2-to-1 hash. -- A linear hash of $n$ field elements. -- Merkle path verification. +The hash chiplet executes all Poseidon2-based hashing performed by the VM. In the +current design it is split into two **sub-chiplets** that each own their own +chiplet-level selector in the shared chiplet tri-state selector system: + +1. **Controller** (`s_ctrl = 1`) records hash requests as compact `(input, output)` + row pairs and communicates with the rest of the VM via the chiplets bus. +2. **Permutation** (`s_perm = 1`) executes Poseidon2 permutations in a dedicated + compute region, using one packed 16-row cycle per unique input state. + +This separation lets the VM **deduplicate permutations**: if the same input +state is requested multiple times, the controller records multiple requests but +the permutation segment executes the permutation only once and carries the +request count as a multiplicity. + +The two physical selectors `s_ctrl` (= `chiplets[0]`) and `s_perm` +(the last chiplets column) partition hasher rows. The virtual selector +`s0 = 1 - s_ctrl - s_perm` covers all non-hasher rows and is subdivided by +`s1..s4` into the remaining chiplets (bitwise, memory, ACE, kernel ROM). The +transition rules `ctrl → ctrl | perm`, `perm → perm | s0`, `s0 → s0` enforce +the trace ordering. + +## Supported operations + +The chiplet supports: + +- a single Poseidon2 permutation (`HPERM` / full-state return), +- a 2-to-1 hash, +- sequential sponge hashing of many rate blocks, +- Merkle path verification, - Merkle root update. -The chiplet can be thought of as having a small instruction set of $11$ instructions. These instructions are listed below, and examples of how these instructions are used by the chiplet are described in the following sections. +These operations are encoded by the three **hasher-internal sub-selector** columns +`(s0, s1, s2)` on controller rows. These are the `ControllerCols` fields and live +in `chiplets[1..4]`. They are separate from the chiplet-level virtual +`s0 = 1 - s_ctrl - s_perm` (which is only ever an expression inside the chiplet +selector system, never a physical column or struct field). + +| Sub-selectors | Meaning | +|---------------|---------| +| `(1, 0, 0)` | sponge input / linear hash input | +| `(1, 0, 1)` | Merkle path verify input | +| `(1, 1, 0)` | Merkle update old-path input | +| `(1, 1, 1)` | Merkle update new-path input | +| `(0, 0, 0)` | return digest (HOUT) | +| `(0, 0, 1)` | return full state (SOUT) | +| `(0, 1, *)` | controller padding | + +On permutation rows these same physical columns are **not selectors**: they are +reused as witness columns `(w0, w1, w2)` for the packed internal rounds. + +## Trace layout + +Within the chiplets segment, the hasher occupies **20 columns** split between the +two sub-chiplets. The chiplet-level selectors `s_ctrl` (= `chiplets[0]`) and +`s_perm` (the separate 20th column) select which sub-chiplet owns +the current row. The remaining 19 columns (`chiplets[1..20]`) are a **union** +whose interpretation depends on which sub-chiplet is active. + +| Physical column(s) | Controller (`s_ctrl = 1`) | Permutation (`s_perm = 1`) | +|-------------------|---------------------------|----------------------------| +| `chiplets[0]` | `s_ctrl = 1` (controller gate) | `s_ctrl = 0` | +| `s_perm` | `s_perm = 0` | `s_perm = 1` (perm gate) | +| `chiplets[1]` | `s0` (input / output-or-pad) | `w0` (S-box witness) | +| `chiplets[2]` | `s1` (operation sub-selector) | `w1` (S-box witness) | +| `chiplets[3]` | `s2` (operation sub-selector) | `w2` (S-box witness) | +| `h0..h11` | Poseidon2 state `[RATE0, RATE1, CAPACITY]` | Poseidon2 state | +| `node_index` | Merkle node index | Request multiplicity | +| `mrupdate_id` | Domain separator for sibling table | Zero (enforced) | +| `is_boundary` | 1 on first/last controller row | Zero (enforced) | +| `direction_bit` | Merkle path direction bit | Zero (enforced) | + +The Poseidon2 state is stored in little-endian sponge order: + +```text +[h0..h11] = [RATE0(4), RATE1(4), CAPACITY(4)] +``` -| Instruction | Description | Cycles | Context | Notes | -| ----------- | ----------- | ------ | ------- | ----- | -| `HR` | Executes a single round of the VM's native hash function | $0$-$30$, $32$-$62$, $64$-$94$... (not $31$, $63$, $95$...) | Any | | -| `BP` | Initiates computation of a single permutation, a 2-to-1 hash, or a linear hash of many elements | Multiples of $32$ ($0$, $32$, $64$...) | Start of computation | Concurrent with `HR` | -| `MP` | Initiates Merkle path verification computation | Multiples of $32$ | Start of computation | Concurrent with `HR` | -| `MV` | Initiates Merkle path verification for the "old" node value | Multiples of $32$ | Merkle root update | Concurrent with `HR` | -| `MU` | Initiates Merkle path verification for the "new" node value | Multiples of $32$ | Merkle root update | Concurrent with `HR` | -| `HOUT` | Returns the "output" portion of the hasher state (indices $[0,4)$) | $32n-1$ ($31$, $63$, $95$...) | End of computation | | -| `SOUT` | Returns entire hasher state | $32n-1$ ($31$, $63$, $95$...) | End of computation | Only after `BP` | -| `ABP` | Absorbs a new set of elements into the hasher state | $32n-1$ ($31$, $63$, $95$...) | Linear hash (multi-block) | Only after `BP` | -| `MPA` | Absorbs the next Merkle path node into the hasher state | $32n-1$ ($31$, $63$, $95$...) | Merkle path verification | Only after `MP` | -| `MVA` | Absorbs the next Merkle path node into the hasher state during Merkle path verification for the "old" node value | $32n-1$ ($31$, $63$, $95$...) | Merkle root update | Only after `MV` | -| `MUA` | Absorbs the next Merkle path node into the hasher state during Merkle path verification for the "new" node value | $32n-1$ ($31$, $63$, $95$...) | Merkle root update | Only after `MU` | +`RATE0` (`h0..h3`) is always the digest word. -## Chiplet trace +In the constraint code, the union layout is modeled by two typed column structs +`ControllerCols` and `PermutationCols` that overlay the same `chiplets[1..20]` +range with sub-chiplet-specific field names (see +`air/src/constraints/chiplets/columns.rs`). -Execution trace table of the chiplet consists of $16$ trace columns and $3$ periodic columns. The structure of the table is such that a single permutation of the hash function can be computed using $32$ table rows. The layout of a single 32-row cycle is summarized below (rows omitted are identical permutation rows). +## Design invariants -| Row (mod 32) | $k_2$ | $k_1$ | $k_0$ | $s_0,s_1,s_2$ | RATE0 ($h_0..h_3$) | RATE1 ($h_4..h_7$) | CAP ($h_8..h_{11}$) | $i$ | -| --- | --- | --- | --- | --- | --- | --- | --- | --- | -| 0 | 1 | 0 | 0 | op-specific | input rate0 | input rate1 | input capacity | index | -| 1 | 0 | 0 | 0 | op-specific | permutation state | permutation state | permutation state | index | -| ... | ... | ... | ... | ... | ... | ... | ... | ... | -| 30 | 0 | 1 | 0 | op-specific | permutation state | permutation state | permutation state | index | -| 31 | 0 | 0 | 1 | op-specific | state (post-permutation) | state (post-permutation) | state (post-permutation) | index | +The current hasher design relies on a few invariants. -The meaning of the columns is as follows: +- **`s_ctrl` / `s_perm` are the authoritative sub-chiplet discriminators.** + Controller rows have `s_ctrl = 1, s_perm = 0`; permutation rows have + `s_ctrl = 0, s_perm = 1`. Non-hasher rows have `s_ctrl = s_perm = 0`. The + tri-state constraints in `selectors.rs` enforce booleanity of each selector and + of their sum, so at most one fires on any row. On controller rows, `s0/s1/s2` + are interpreted as sub-selectors; on permutation rows the same physical + columns hold S-box witnesses. -- Three periodic columns $k_0$, $k_1$, and $k_2$ are used to help select the instruction executed at a given row. All of these columns contain patterns which repeat every $32$ rows. For $k_0$ the pattern is $31$ zeros followed by $1$ one, helping us identify the last row in the cycle. For $k_1$ the pattern is $30$ zeros, $1$ one, and $1$ zero, which can be used to identify the second-to-last row in a cycle. For $k_2$ the pattern is $1$ one followed by $31$ zeros, which can identify the first row in the cycle. -- Three selector columns $s_0$, $s_1$, and $s_2$. These columns can contain only binary values (ones or zeros), and they are also used to help select the instruction to execute at a given row. -- Twelve hasher state columns $h_0, ..., h_{11}$. These columns are used to hold the hasher state for each round of the hash function permutation. The state is laid out as follows: - - The first eight columns ($h_0, ..., h_7$) are reserved for the rate elements of the state, arranged as two 4-element words (RATE0, RATE1). Once the permutation is complete, the hash output is located in the first rate word ($h_0, ..., h_3$). - - The last four columns ($h_8, ..., h_{11}$) are reserved for capacity elements of the state. When the state is initialized for hash computations, $h_8$ should be set to $0$ if the number of elements to be hashed is a multiple of the rate width ($8$). Otherwise, $h_8$ should be set to $1$. $h_9$ should be set to the domain value if a domain has been provided (as in the case of [control block hashing](../programs.md#program-hash-computation)). The remaining capacity lanes ($h_{10}$, $h_{11}$) are set to $0$. -- One index column $i$. This column is used to help with Merkle path verification and Merkle root update computations. +- **Trace ordering is enforced by selector transitions.** + The transitions `ctrl → ctrl | perm`, `perm → perm | s0`, and `s0 → s0` + guarantee that the controller section comes first, the permutation section + comes second, and any remaining chiplets follow in the `s0` region. -In addition to the columns described above, the chiplet relies on two running product columns which are used to facilitate multiset checks (similar to the ones described [here](https://hackmd.io/@relgabizon/ByFgSDA7D)). These columns are: +- **Only controller rows participate in the external chiplets interface.** + The controller is the only sub-chiplet that sends or receives hasher messages + on `b_chiplets`. The permutation segment is internal compute only. -- $b_{chip}$ - which is used to tie the chiplet table with the main VM's stack and decoder. That is, values representing inputs consumed by the chiplet and outputs produced by the chiplet are multiplied into $b_{chip}$, while the main VM stack (or decoder) divides them out of $b_{chip}$. Thus, if the sets of inputs and outputs between the main VM stack and hash chiplet are the same, the value of $b_{chip}$ should be equal to $1$ at the start and the end of the execution trace. -- $p_1$ - which is used to keep track of the _sibling_ table used for Merkle root update computations. Specifically, when a root for the old leaf value is computed, we add an entry for all sibling nodes to the table (i.e., we multiply $p_1$ by the values representing these entries). When the root for the new leaf value is computed, we remove the entries for the nodes from the table (i.e., we divide $p_1$ by the value representing these entries). Thus, if both computations used the same set of sibling nodes (in the same order), the sibling table should be empty by the time Merkle root update procedure completes (i.e., the value of $p_1$ would be $1$). +- **Permutation cycles are aligned.** + Entering the permutation segment can happen only at packed cycle row `0`, and + leaving the hasher while still in the permutation segment can happen only at + packed cycle row `15`. These alignment constraints live in `permutation/mod.rs` + and use the precomputed `next_is_first` and `is_last` flags from + [`ChipletFlags`]. -## Instruction flags +- **Multiplicity is cycle-wide.** + On permutation rows, the column physically shared with `node_index` is + interpreted as a multiplicity counter. It must stay constant within a cycle + so that one multiplicity is attached to the entire permutation. -As mentioned above, chiplet instructions are encoded using a combination of periodic and selector columns. These columns can be used to compute a binary flag for each instruction. Thus, when a flag for a given instruction is set to $1$, the chiplet executes this instruction. Formulas for computing instruction flags are listed below. +- **Witness reuse is explicit.** + On packed internal rows, `(s0, s1, s2)` carry witness values for + internal-round S-box outputs (`w0, w1, w2`). On row `11`, only `w0` is used. + Unused witness slots are constrained to zero. Similarly, `mrupdate_id`, + `is_boundary`, and `direction_bit` are forced to zero on permutation rows so + they cannot leak controller-side meaning into the permutation gate. -| Flag | Value | Notes | -| ---------- | ----------------------------------------------------- | ------------------------------------------------------------------------------------------------- | -| $f_{rpr}$ | $1 - k_0$ | Set to $1$ on the first $31$ steps of every $32$-step cycle. | -| $f_{bp}$ | $k_2 \cdot s_0 \cdot (1 - s_1) \cdot (1 - s_2)$ | Set to $1$ when selector flags are $(1, 0, 0)$ on rows which are multiples of $32$. | -| $f_{mp}$ | $k_2 \cdot s_0 \cdot (1 - s_1) \cdot s_2$ | Set to $1$ when selector flags are $(1, 0, 1)$ on rows which are multiples of $32$. | -| $f_{mv}$ | $k_2 \cdot s_0 \cdot s_1 \cdot (1 - s_2)$ | Set to $1$ when selector flags are $(1, 1, 0)$ on rows which are multiples of $32$. | -| $f_{mu}$ | $k_2 \cdot s_0 \cdot s_1 \cdot s_2$ | Set to $1$ when selector flags are $(1, 1, 1)$ on rows which are multiples of $32$. | -| $f_{hout}$ | $k_0 \cdot (1 - s_0) \cdot (1 - s_1) \cdot (1 - s_2)$ | Set to $1$ when selector flags are $(0, 0, 0)$ on rows which are $1$ less than a multiple of $32$. | -| $f_{sout}$ | $k_0 \cdot (1 - s_0) \cdot (1 - s_1) \cdot s_2$ | Set to $1$ when selector flags are $(0, 0, 1)$ on rows which are $1$ less than a multiple of $32$. | -| $f_{abp}$ | $k_0 \cdot s_0 \cdot (1 - s_1) \cdot (1 - s_2)$ | Set to $1$ when selector flags are $(1, 0, 0)$ on rows which are $1$ less than a multiple of $32$. | -| $f_{mpa}$ | $k_0 \cdot s_0 \cdot (1 - s_1) \cdot s_2$ | Set to $1$ when selector flags are $(1, 0, 1)$ on rows which are $1$ less than a multiple of $32$. | -| $f_{mva}$ | $k_0 \cdot s_0 \cdot s_1 \cdot (1 - s_2)$ | Set to $1$ when selector flags are $(1, 1, 0)$ on rows which are $1$ less than a multiple of $32$. | -| $f_{mua}$ | $k_0 \cdot s_0 \cdot s_1 \cdot s_2$ | Set to $1$ when selector flags are $(1, 1, 1)$ on rows which are $1$ less than a multiple of $32$. | +- **Merkle routing happens entirely in the controller region.** + Merkle-specific values (`node_index`, `direction_bit`, `mrupdate_id`) have + controller semantics only. The permutation segment does not carry Merkle + routing meaning. -A few additional notes about flag values: +- **Sibling-table balancing is partitioned by `mrupdate_id`.** + The old-path and new-path legs of a single `MRUPDATE` share the same + `mrupdate_id`, and different updates use different IDs. This prevents sibling + entries from unrelated updates from cancelling each other. -- With the exception of $f_{rpr}$, all flags are mutually exclusive. That is, if one flag is set to $1$, all other flats are set to $0$. -- With the exception of $f_{rpr}$, computing flag values involves $3$ multiplications, and thus the degree of these flags is $4$. -- We can also define a flag $f_{out} = k_0 \cdot (1 - s_0) \cdot (1 - s_1)$. This flag will be set to $1$ when either $f_{hout}=1$ or $f_{sout}=1$ in the current row. -- We can define a flag $f_{out}' = k_1 \cdot (1 - s_0') \cdot (1 - s_1')$. This flag will be set to $1$ when either $f_{hout}=1$ or $f_{sout}=1$ in the next row. +## Controller region -We also impose the following restrictions on how values in selector columns can be updated: +Each hash request is recorded as a pair of consecutive rows: -- Values in columns $s_1$ and $s_2$ must be copied over from one row to the next, unless $f_{out} = 1$ or $f_{out}' = 1$ indicating the `hout` or `sout` flag is set for the current or the next row. -- Value in $s_0$ must be set to $1$ if $f_{out}=1$ for the previous row, and to $0$ if any of the flags $f_{abp}$, $f_{mpa}$, $f_{mva}$, or $f_{mua}$ are set to $1$ for the previous row. +- **input row** (`s0 = 1`) contains the pre-permutation state, +- **output row** (`s0 = 0, s1 = 0`) contains the post-permutation state. -The above rules ensure that we must finish one computation before starting another, and we can't change the type of the computation before the computation is finished. +These two rows are the rows that participate in the chiplets bus. The controller +region is then padded to a multiple of `HASH_CYCLE_LEN = 16` before the +permutation segment begins. -## Computation examples +### Multi-batch sponge hashing -### Single permutation +Sequential hashing is represented as a chain of controller pairs: -Computing a single permutation of Poseidon2 hash function involves the following steps: +- first input row has `is_boundary = 1`, +- middle continuation rows have `is_boundary = 0`, +- final output row has `is_boundary = 1`. -1. Initialize hasher state with $12$ field elements. -2. Apply Poseidon2 permutation. -3. Return the entire hasher state as output. +Across continuation boundaries, the next input row overwrites the rate lanes but +must preserve the previous permutation's capacity word. This is enforced by the +AIR. -The chiplet accomplishes the above by executing the following instructions: +### Merkle operations -``` -[BP, HR] // init state and execute a hash round (concurrently) -HR HR HR HR HR HR HR HR HR HR // execute 10 more hash rounds -HR HR HR HR HR HR HR HR HR HR // execute 10 more hash rounds -HR HR HR HR HR HR HR HR HR HR // execute 10 more hash rounds -SOUT // return the entire state as output -``` +For Merkle verification / update, the controller also carries: -Execution trace for this computation would look as illustrated below. +- `node_index`, +- `direction_bit`, +- `mrupdate_id` (for the old/new path pairing used by `MRUPDATE`). -| Row (mod 32) | $k_2$ | $k_1$ | $k_0$ | $s_0,s_1,s_2$ | RATE0 ($h_0..h_3$) | RATE1 ($h_4..h_7$) | CAP ($h_8..h_{11}$) | $i$ | -| --- | --- | --- | --- | --- | --- | --- | --- | --- | -| 0 | 1 | 0 | 0 | BP | $a_0..a_3$ | $a_4..a_7$ | $a_8..a_{11}$ | $i$ | -| 1 | 0 | 0 | 0 | HR | permute | permute | permute | $i$ | -| ... | ... | ... | ... | ... | ... | ... | ... | ... | -| 31 | 0 | 0 | 1 | SOUT | $b_0..b_3$ | $b_4..b_7$ | $b_8..b_{11}$ | $i$ | +The controller AIR enforces: -In the above $\{a_0, ..., a_{11}\}$ is the input state of the hasher, and $\{b_0, ..., b_{11}\}$ is the output state of the hasher. +- index decomposition `idx = 2 * idx_next + direction_bit` on Merkle input rows, +- direction bit booleanity, +- continuity of the shifted index across non-final controller boundaries, +- zero capacity on Merkle input rows, +- digest routing into the correct rate half for the next path step. -### Simple 2-to-1 hash +## Permutation segment -Computing a 2-to-1 hash involves the following steps: +After the padded controller region, the chiplet appends one permutation cycle for + each unique input state. Each cycle has length **16**. -1. Initialize hasher state with $8$ field elements, setting the second capacity element to $domain$ if the domain is provided (as in the case of [control block hashing](../programs.md#program-hash-computation)) or else $0$, and the remaining capacity elements to $0$. -2. Apply Poseidon2 permutation. -3. Return elements $[0, 4)$ of the hasher state as output. +### Packed 16-row schedule -The chiplet accomplishes the above by executing the following instructions: +The 31-step Poseidon2 schedule -``` -[BP, HR] // init state and execute a hash round (concurrently) -HR HR HR HR HR HR HR HR HR HR // execute 10 more hash rounds -HR HR HR HR HR HR HR HR HR HR // execute 10 more hash rounds -HR HR HR HR HR HR HR HR HR HR // execute 10 more hash rounds -HOUT // return elements 0, 1, 2, 3 of the state as output (the digest) -``` +- init linear, +- 4 initial external rounds, +- 22 internal rounds, +- 4 terminal external rounds -Execution trace for this computation would look as illustrated below. +is packed into 16 rows as follows: -| Row (mod 32) | $k_2$ | $k_1$ | $k_0$ | $s_0,s_1,s_2$ | RATE0 ($h_0..h_3$) | RATE1 ($h_4..h_7$) | CAP ($h_8..h_{11}$) | $i$ | -| --- | --- | --- | --- | --- | --- | --- | --- | --- | -| 0 | 1 | 0 | 0 | BP | $a_0..a_3$ | $b_0..b_3$ | $0,\,domain,\,0,\,0$ | $i$ | -| 1 | 0 | 0 | 0 | HR | permute | permute | permute | $i$ | -| ... | ... | ... | ... | ... | ... | ... | ... | ... | -| 31 | 0 | 0 | 1 | HOUT | $c_0..c_3$ | unused | unused | $i$ | +| Row | Meaning | +|-----|---------| +| 0 | `init + ext1` | +| 1 | `ext2` | +| 2 | `ext3` | +| 3 | `ext4` | +| 4 | `int1 + int2 + int3` | +| 5 | `int4 + int5 + int6` | +| 6 | `int7 + int8 + int9` | +| 7 | `int10 + int11 + int12` | +| 8 | `int13 + int14 + int15` | +| 9 | `int16 + int17 + int18` | +| 10 | `int19 + int20 + int21` | +| 11 | `int22 + ext5` | +| 12 | `ext6` | +| 13 | `ext7` | +| 14 | `ext8` | +| 15 | boundary / final state | -In the above, we compute the following: +The state stored on each permutation row is the **pre-transition** state for +that packed step, and row 15 stores the final permutation output. -$$ -\{c_0, c_1, c_2, c_3\} \leftarrow hash(\{a_0, a_1, a_2, a_3\}, \{b_0, b_1, b_2, b_3\}) -$$ +### Periodic columns -### Linear hash of n elements +The AIR uses 16 periodic columns: -Computing a linear hash of $n$ elements consists of the following steps: +- 4 step-type selectors: + - `is_init_ext`, + - `is_ext`, + - `is_packed_int`, + - `is_int_ext`, +- 12 shared round-constant columns. -1. Initialize hasher state with the first $8$ elements, setting the first capacity register to $0$ if $n$ is a multiple of the rate width ($8$) or else $1$, and the remaining capacity elements to $0$. -2. Apply Poseidon2 permutation. -3. Absorb the next set of elements into the state (up to $8$ elements), while keeping capacity elements unchanged. -4. Repeat steps 2 and 3 until all $n$ elements have been absorbed. -5. Return elements $[0, 4)$ of the hasher state as output. +The packed schedule uses the shared round-constant columns as follows: -The chiplet accomplishes the above by executing the following instructions (for hashing $16$ elements): +- external rows use all 12 external round constants, +- packed-internal rows use `ark[0..2]` for the 3 internal round constants, +- row 11 uses terminal external constants, while the final internal constant is + embedded directly in the constraint. -``` -[BP, HR] // init state and execute a hash round (concurrently) -HR HR HR HR HR HR HR HR HR HR // execute 10 more hash rounds -HR HR HR HR HR HR HR HR HR HR // execute 10 more hash rounds -HR HR HR HR HR HR HR HR HR HR // execute 10 more hash rounds -ABP // absorb the next set of elements into the state -HR HR HR HR HR HR HR HR HR HR // execute 10 more hash rounds -HR HR HR HR HR HR HR HR HR HR // execute 10 more hash rounds -HR HR HR HR HR HR HR HR HR HR HR // execute 11 more hash rounds -HOUT // return elements 0, 1, 2, 3 of the state as output (the digest) -``` +### Witness columns on permutation rows -Execution trace for this computation would look as illustrated below. +On permutation rows, `(s0, s1, s2)` — the same physical columns that hold +the hasher-internal sub-selectors on controller rows — hold witness values +`(w0, w1, w2)`: -| Row (mod 32) | $k_2$ | $k_1$ | $k_0$ | $s_0,s_1,s_2$ | RATE0 ($h_0..h_3$) | RATE1 ($h_4..h_7$) | CAP ($h_8..h_{11}$) | $i$ | -| --- | --- | --- | --- | --- | --- | --- | --- | --- | -| 0 | 1 | 0 | 0 | BP | $a_0..a_3$ | $a_4..a_7$ | $p,\,0,\,0,\,0$ | $i$ | -| 1 | 0 | 0 | 0 | HR | permute | permute | permute | $i$ | -| ... | ... | ... | ... | ... | ... | ... | ... | ... | -| 31 | 0 | 0 | 1 | ABP | $b_0..b_3$ | $b_4..b_7$ | (carry) | $i$ | -| 32 | 1 | 0 | 0 | BP | $b_0..b_3$ | $b_4..b_7$ | (carry) | $i$ | -| ... | ... | ... | ... | ... | ... | ... | ... | ... | -| 63 | 0 | 0 | 1 | HOUT | $r_0..r_3$ | unused | unused | $i$ | +- rows `4..10`: `w0, w1, w2` are the three S-box outputs for the packed + internal rounds, +- row `11`: `w0` is the S-box output for the final internal round, +- all other permutation rows: unused witness slots are constrained to zero. -In the above, the value absorbed into hasher state between rows $31$ and $32$ is the next batch of -$8$ input elements, which overwrite the rate lanes. Thus, if we define these elements as $b_i$ for -$i \in [0, 8)$, the above computes the following: +Reusing these physical columns as witnesses keeps the packed internal rows +within the degree-9 budget. -$$ -\{r_0, r_1, r_2, r_3\} \leftarrow hash(a_0, ..., a_7, b_0, ..., b_7) -$$ +The chiplet-level selectors `s_ctrl` and `s_perm` are the authoritative +sub-chiplet discriminators: any consumer that needs to interpret the shared +columns as controller sub-selectors must first gate on `s_ctrl = 1`. The +constraint code does this by gating on `s_ctrl = 1` via the precomputed chiplet +selectors, while permutation rows access the same physical columns as witnesses. -### Verify Merkle path +## Buses -Verifying a Merkle path involves the following steps: +
-1. Initialize hasher state with the leaf and the first node of the path, setting all capacity elements to $0$s. - a. Also, initialize the index register to the leaf's index value. -2. Apply Poseidon2 permutation. - a. Make sure the index value doesn't change during this step. -3. Copy the result of the hash to the next row, and absorb the next node of the Merkle path into the hasher state. - a. Remove a single bit from the index, and use it to determine how to place the copied result and absorbed node in the state. -4. Repeat steps 2 and 3 until all nodes of the Merkle path have been absorbed. -5. Return elements $[0, 4)$ of the hasher state as output. - a. Also, make sure the index value has been reduced to $0$. +The hasher participates in three different lookup constructions. -The chiplet accomplishes the above by executing the following instructions (for Merkle tree of depth $3$): + -``` -[MP, HR] // init state and execute a hash round (concurrently) -HR HR HR HR HR HR HR HR HR HR // execute 10 more hash rounds -HR HR HR HR HR HR HR HR HR HR // execute 10 more hash rounds -HR HR HR HR HR HR HR HR HR HR // execute 10 more hash rounds -MPA // copy result & absorb the next node into the state -HR HR HR HR HR HR HR HR HR HR // execute 10 more hash rounds -HR HR HR HR HR HR HR HR HR HR // execute 10 more hash rounds -HR HR HR HR HR HR HR HR HR HR HR // execute 11 more hash rounds -HOUT // return elements 0, 1, 2, 3 of the state as output (the digest) -``` +### 1. Chiplets bus (`b_chiplets`) + +The controller region sends and receives the chiplets-bus messages used by: + +- the decoder, +- the stack, +- the recursive verifier. + +Examples: + +- sponge start: full 12-lane state, +- sponge continuation: rate only, +- Merkle input: selected leaf word, +- return digest / return state. + +Permutation rows do **not** touch this bus. + +### 2. Hasher permutation-link on `v_wiring` + +A LogUp running sum links the controller rows to the permutation segment: + +- controller input rows contribute `+1/msg_in`, +- controller output rows contribute `+1/msg_out`, +- permutation row 0 contributes `-m/msg_in`, +- permutation row 15 contributes `-m/msg_out`, + +where `m` is the multiplicity stored in `node_index` on permutation rows. + +This is the mechanism that makes permutation deduplication sound. + +Because `v_wiring` is a shared bus, the AIR also forces it to stay constant on +rows where none of its stacked contributors are active. In particular, on +bitwise rows, kernel-ROM rows, and trailing chiplet padding rows, the hasher-side +wiring relation contributes an `idle_flag * delta` term so those rows cannot let +`v_wiring` drift before the final boundary. -Suppose we have a Merkle tree as illustrated below. This Merkle tree has $4$ leaves, each of which consists of $4$ field elements. For example, leaf $a$ consists of elements $a_0, a_1, a_2, a_3$, leaf be consists of elements $b_0, b_1, b_2, b_3$ etc. + -![hash_merkle_tree](../../img/design/chiplets/hasher/hash_merkle_tree.png) +### 3. Hash-kernel virtual table (`b_hash_kernel`) -If we wanted to verify that leaf $d$ is in fact in the tree, we'd need to compute the following hashes: +During `MRUPDATE`, the chiplet inserts sibling entries on the old-path leg and +removes them on the new-path leg. The running product must balance, ensuring +that both legs use the same siblings. -$$ -r \leftarrow hash(e, hash(c, d)) -$$ +## Main AIR obligations -And if $r = g$, we can be convinced that $d$ is in fact in the tree at position $3$. Execution trace for this computation would look as illustrated below. +At a high level, the hasher AIR enforces: -| Row (mod 32) | $k_2$ | $k_1$ | $k_0$ | $s_0,s_1,s_2$ | RATE0 ($h_0..h_3$) | RATE1 ($h_4..h_7$) | CAP ($h_8..h_{11}$) | $i$ | -| --- | --- | --- | --- | --- | --- | --- | --- | --- | -| 0 | 1 | 0 | 0 | MP | $c_0..c_3$ | $d_0..d_3$ | $0,0,0,0$ | $3$ | -| 1 | 0 | 0 | 0 | HR | permute | permute | permute | $3$ | -| ... | ... | ... | ... | ... | ... | ... | ... | ... | -| 31 | 0 | 0 | 1 | MPA | $e_0..e_3$ | $f_0..f_3$ | $0,0,0,0$ | $3$ | -| 32 | 1 | 0 | 0 | MP | $e_0..e_3$ | $f_0..f_3$ | $0,0,0,0$ | $1$ | -| ... | ... | ... | ... | ... | ... | ... | ... | ... | -| 63 | 0 | 0 | 1 | HOUT | $g_0..g_3$ | unused | unused | $0$ | +- chiplet tri-state selector partition and transition rules for `s_ctrl` and + `s_perm` (in `selectors.rs`, shared with other chiplets), +- `s0/s1/s2` sub-selector booleanity on controller rows, +- well-formed controller `(input, output)` pairing (adjacency, output + non-adjacency, padding stability, first-row boundary), +- structural confinement on both sub-chiplets: `is_boundary`, `direction_bit`, + and `mrupdate_id` are zero on permutation rows, and `is_boundary` / + `direction_bit` are boolean on controller rows (`mrupdate_id` is a free + integer counter whose only controller-side rule is the progression below), +- packed Poseidon2 permutation transitions in the permutation segment, +- permutation cycle alignment (entry at cycle row 0, exit at cycle row 15) and + multiplicity constancy within a cycle, +- capacity preservation across sponge continuation boundaries, +- Merkle index decomposition, cross-step index continuity, direction-bit + forward propagation, digest routing, and capacity-zeroing rules, +- `mrupdate_id` progression on controller-to-controller transitions. -In the above, the prover provides values for nodes $c$ and $e$ non-deterministically. -The index $i$ remains constant throughout a permutation and is shifted at the `MPA` row, so it -changes only between cycles. +The high-degree Poseidon2 step constraints are gated by the degree-1 `s_perm` +selector and by periodic step selectors, which keeps the overall constraint +degree at the system's max of 9. -### Update Merkle root +## Detailed constraint structure -Updating a node in a Merkle tree (which also updates the root of the tree) can be simulated by verifying two Merkle paths: the path that starts with the old leaf and the path that starts with the new leaf. +The full set of constraints is split across: -Suppose we have the same Merkle tree as in the previous example, and we want to replace node $d$ with node $d'$. The computations we'd need to perform are: +- `air/src/constraints/chiplets/selectors.rs` — chiplet tri-state selector + system, booleanity, transition rules, precomputed `ChipletFlags`. +- `air/src/constraints/chiplets/hasher_control/` — controller sub-chiplet: + lifecycle, Merkle routing, capacity preservation, `mrupdate_id` progression. +- `air/src/constraints/chiplets/permutation/` — permutation sub-chiplet: cycle + alignment, multiplicity constancy, unused-column zeroing, packed Poseidon2 + step constraints. +- `air/src/constraints/chiplets/columns.rs` — `ControllerCols`, + `PermutationCols`, and `HasherPeriodicCols` definitions. -$$ -r \leftarrow hash(e, hash(c, d)) -r' \leftarrow hash(e, hash(c, d')) -$$ +This section does **not** attempt to describe every constraint. Instead, +it records the key structural constraints and representative formulas that +capture the key design decisions. -Then, as long as $r = g$, and the same values were used for $c$ and $e$ in both computations, we can be convinced that the new root of the tree is $r'$. +## Representative AIR formulas -The chiplet accomplishes the above by executing the following instructions: +The following formulas capture the most important structure of the current +hasher AIR. +### Controller selectors, lifecycle, and the tri-state selector system + +On **controller rows** (`s_ctrl = 1`), `s0/s1/s2` are ordinary sub-selectors. +On **permutation rows** (`s_perm = 1`), the same physical columns are witness +columns `w0/w1/w2`. The chiplet-level `s_ctrl` and `s_perm` are the authoritative +discriminators between the two sub-chiplets. + +The tri-state selector system in `selectors.rs` enforces: + +- booleanity of `s_ctrl`, `s_perm`, and their sum `s_ctrl + s_perm` (so at most + one can be 1 on any given row), +- transition rules: + - `s_ctrl = 1 → s_ctrl' + s_perm' = 1` (a controller row must be followed by + another controller row or the first permutation row), + - `s_perm = 1 → s_ctrl' = 0` (once in permutation, the hasher cannot return + to the controller), + - `s0 = 1 → s_ctrl' = 0 ∧ s_perm' = 0` (once in the non-hasher region, stay + there), +- a last-row invariant that forces `s_ctrl = s_perm = 0` on the final trace row, + so every chiplet's `is_active` flag vanishes there. + +Permutation cycle alignment (entry at cycle row 0, exit at cycle row 15) and +multiplicity constancy are enforced by the permutation sub-chiplet in +`permutation/mod.rs` using the precomputed `next_is_first` and `is_last` +flags from `ChipletFlags`. + +The first-row controller constraint is intentionally strong: + +```text +s_ctrl * s0 = 1 (on the first trace row) ``` -// verify the old merkle path -[MV, HR] // init state and execute a hash round (concurrently) -HR HR HR HR HR HR HR HR HR HR // execute 10 more hash rounds -HR HR HR HR HR HR HR HR HR HR // execute 10 more hash rounds -HR HR HR HR HR HR HR HR HR HR // execute 10 more hash rounds -MVA // copy result & absorb the next node into the state -HR HR HR HR HR HR HR HR HR HR // execute 10 more hash rounds -HR HR HR HR HR HR HR HR HR HR // execute 10 more hash rounds -HR HR HR HR HR HR HR HR HR HR HR // execute 11 more hash rounds -HOUT // return elements 0, 1, 2, 3 of the state as output (the digest) - -// verify the new merkle path -[MU, HR] // init state and execute a hash round (concurrently) -HR HR HR HR HR HR HR HR HR HR // execute 10 more hash rounds -HR HR HR HR HR HR HR HR HR HR // execute 10 more hash rounds -HR HR HR HR HR HR HR HR HR HR // execute 10 more hash rounds -MUA // copy result & absorb the next node into the state -HR HR HR HR HR HR HR HR HR HR // execute 10 more hash rounds -HR HR HR HR HR HR HR HR HR HR // execute 10 more hash rounds -HR HR HR HR HR HR HR HR HR HR HR // execute 11 more hash rounds -HOUT // return elements 0, 1, 2, 3 of the state as output (the digest) + +This forces the first hasher row to be a controller *input* row (`s_ctrl = 1` +AND `s0 = 1`). Because `s0` is a witness column on permutation rows, this +also rules out a permutation row masquerading as the first row. + +The controller structure is then completed by: + +- input-row adjacency: an input row must be followed by an output row, +- output non-adjacency: two controller output rows cannot be adjacent, +- padding stability: once controller padding begins, no new controller operation + can appear after it. + +### Packed Poseidon2 transition constraints + +The permutation segment uses four transition types plus a boundary row. + +#### 1. Row 0: merged init + first external round + +The packed row-0 transition is: + +```text +h_next = M_E(S(M_E(h) + ark)) ``` -The semantics of `MV` and `MU` instructions are similar to the semantics of `MP` instruction from the previous example (and `MVA` and `MUA` are similar to `MPA`) with one important difference: `MV*` instructions add the absorbed node (together with its index in the tree) to permutation column $p_1$, while `MU*` instructions remove the absorbed node (together with its index in the tree) from $p_1$. Thus, if the same nodes were used during both Merkle path verification, the state of $p_1$ should not change. This mechanism is used to ensure that the same internal nodes were used in both computations. +This merges the initial external linear layer with the first external round while +keeping only one S-box layer over affine expressions. + +#### 2. Rows 1-3 and 12-14: single external rounds + +Each such row enforces: + +```text +h_next = M_E(S(h + ark)) +``` -## AIR constraints +where `ark` is the row's external round-constant vector. -When describing AIR constraints, we adopt the following notation: for column $x$, we denote the value in the current row simply as $x$, and the value in the next row of the column as $x'$. Thus, all transition constraints described in this note work with two consecutive rows of the execution trace. +#### 3. Rows 4-10: packed triples of internal rounds -### Selector columns constraints +These rows use the shared physical columns `(s0, s1, s2)` as witnesses +`(w0, w1, w2)` for the three internal-round S-box outputs. If we define: -For selector columns, first we must ensure that only binary values are allowed in these columns. This can be done with the following constraints: +- `y^(0) = h`, +- `w_k = (y^(k)[0] + ark_k)^7` for `k in {0,1,2}`, +- `y^(k+1) = M_I(y^(k) with lane 0 replaced by w_k)`, -$$ -s_0^2 - s_0 = 0 \text{ | degree} = 2 -s_1^2 - s_1 = 0 \text{ | degree} = 2 -s_2^2 - s_2 = 0 \text{ | degree} = 2 -$$ +then the row enforces: -Next, we need to make sure that unless $f_{out}=1$ or $f_{out}'=1$, the values in columns $s_1$ and $s_2$ are copied over to the next row. This can be done with the following constraints: +- three witness equations `w_k - (y^(k)[0] + ark_k)^7 = 0`, and +- `h_next = y^(3)`. -$$ -(s_1' - s_1) \cdot (1 - f_{out}') \cdot (1 - f_{out}) = 0 \text{ | degree} = 7 -(s_2' - s_2) \cdot (1 - f_{out}') \cdot (1 - f_{out}) = 0 \text{ | degree} = 7 -$$ +This is the core packing idea: the witness equations carry the nonlinearity, +while the final next-state relation stays affine in the trace columns. -Next, we need to enforce that if any of $f_{abp}, f_{mpa}, f_{mva}, f_{mua}$ flags is set to $1$, the next value of $s_0$ is $0$. In all other cases, $s_0$ should be unconstrained. These flags will only be set for rows that are 1 less than a multiple of 32 (the last row of each cycle). This can be done with the following constraint: +#### 4. Row 11: merged final internal round + first terminal external round -$$ -s_0' \cdot (f_{abp} + f_{mpa} + f_{mva} + f_{mua})= 0 \text{ | degree} = 5 -$$ +Row 11 uses only `w0` as a witness: -Lastly, we need to make sure that no invalid combinations of flags are allowed. This can be done with the following constraints: +```text +w0 = (h[0] + ARK_INT[21])^7 +``` -$$ -k_0 \cdot (1 - s_0) \cdot s_1 = 0 \text{ | degree} = 3 -$$ +Then: -The above constraints enforce that on every step which is one less than a multiple of $32$, if $s_0 = 0$, then $s_1$ must also be set to $0$. Basically, if we set $s_0=0$, then we must make sure that either $f_{hout}=1$ or $f_{sout}=1$. +```text +y = M_I(h with lane 0 replaced by w0) +h_next = M_E(S(y + ark)) +``` -### Node index constraints +The internal round constant `ARK_INT[21]` is hard-coded in the constraint +rather than read from a periodic column: row 11 is the only row gated by +`is_int_ext`, so a periodic column would waste 15 zero slots to deliver one +value. -Node index column $i$ is relevant only for Merkle path verification and Merkle root update computations, but to simplify the overall constraint system, the same constraints will be imposed on this column for all computations. +#### 5. Row 15: boundary / final state -Overall, we want values in the index column to behave as follows: +The final row of the packed cycle stores the final permutation output and has no +next-state permutation-step constraint. -- When we start a new computation, we should be able to set $i$ to an arbitrary value. -- When a computation is finished, value in $i$ must be $0$. -- When we absorb a new node into the hasher state we must shift the value in $i$ by one bit to the right. -- In all other cases value in $i$ should not change. +### Unused witness zeroing -A shift by one bit to the right can be described with the following equation: $i = 2 \cdot i' + b$, where $b$ is the value of the bit which is discarded. Thus, as long as $b$ is a binary value, the shift to the right is performed correctly, and this can be enforced with the following constraint: +Because the physical columns that hold `s0/s1/s2` on controller rows become +witnesses `w0/w1/w2` on permutation rows, the AIR constrains unused witness +slots to zero: -$$ -b^2 - b = 0 -$$ +- rows `0..3` and `12..15`: `w0 = w1 = w2 = 0`, +- row `11`: `w1 = w2 = 0`. -Since we want to enforce this constraint only when a new node is absorbed into the hasher state, we'll define a flag for when this should happen as follows: +Similarly, `mrupdate_id`, `is_boundary`, and `direction_bit` are forced to +zero on all permutation rows (see `PermutationCols::unused_padding()`). -$$ -f_{an} = f_{mp} + f_{mv} + f_{mu} + f_{mpa} + f_{mva} + f_{mua} -$$ +These constraints are primarily defensive: they make permutation rows inert +with respect to any constraint that might read the shared columns as if they +were controller sub-selectors or routing metadata. -And then the full constraint would looks as follows: +### Sponge continuation capacity preservation -$$ -f_{an} \cdot (b^2 - b) = 0 \text{ | degree} = 6 -$$ +For multi-batch sponge hashing, the next controller input row overwrites the rate +lanes but must preserve the previous permutation's capacity word. The AIR +therefore enforces capacity equality across controller continuation boundaries: -Next, to make sure when a computation is finished $i=0$, we can use the following constraint: +- only when the next row is a controller sponge input, +- only when that next row is not a boundary row. -$$ -f_{out} \cdot i = 0 \text{ | degree} = 4 -$$ +This is the key invariant that makes `RESPAN` represent continued sponge +absorption rather than a fresh hash. -Finally, to make sure that the value in $i$ is copied over to the next row unless we are absorbing a new row or the computation is finished, we impose the following constraint: +### Merkle controller constraints -$$ -(1 - f_{an} - f_{out}) \cdot (i' - i) = 0 \text{ | degree} = 5 -$$ +Merkle operations are expressed entirely in the controller region. -To satisfy these constraints for computations not related to Merkle paths (i.e., 2-to-1 hash and liner hash of elements), we can set $i = 0$ at the start of the computation. This guarantees that $i$ will remain $0$ until the end of the computation. +The AIR enforces: -### Hasher state constraints +- index decomposition on Merkle input rows: -Hasher state columns $h_0, ..., h_{11}$ should behave as follows: +```text +idx = 2 * idx_next + direction_bit +``` -- For the first $31$ rows of every $32$-row cycle (i.e., when $k_0=0$), we need to apply [Poseidon2](https://eprint.iacr.org/2023/323) round constraints to the hasher state. For brevity, we omit these constraints from this note. -- On the $32$nd row of every $32$-row cycle, we apply the constraints based on which transition flag is set as described in the table below. +- direction-bit booleanity on Merkle input rows, +- `direction_bit = 0` on sponge input rows and `HOUT` output rows (confinement), +- continuity of the shifted index across non-final output → next-input + boundaries, +- zero capacity on Merkle input rows, +- `node_index = 0` on sponge input rows and on digest-return (`HOUT`) rows. -Specifically, when absorbing the next set of elements into the state during linear hash computation (i.e., $f_{abp} = 1$), the last $4$ elements (the capacity portion) are carried over to the next row. For $j \in [0, 4)$ this can be described as follows: +In addition, on non-final Merkle boundaries the output row carries the next +step's `direction_bit` (forward propagation), allowing the AIR to route the +current digest into either `RATE0` or `RATE1` of the next Merkle input row. -$$ -f_{abp} \cdot (h'_{j+8} - h_{j+8}) = 0 \text{ | degree} = 5 -$$ +A small degree optimization is used for the Merkle-next gate: instead of +computing the full `f_merkle_input_next` (degree 3) to detect that the next +row is a Merkle input, the routing constraints use a lightweight +`s1' + s2'` expression (degree 1) which is nonzero exactly on Merkle inputs +(`(0,1), (1,0), (1,1)`) and zero on sponge inputs. The non-unit value `2` +on MU rows is harmless because the constraint is gated by `on_output * (1 - +is_boundary)`, and the digest routing equation is linear in the gate. A +malicious prover cannot bypass routing by mislabeling a Merkle input as +sponge: the chiplets bus would then fire a sponge message with no matching +decoder request. -When absorbing the next node during Merkle path computation (i.e., $f_{mp} + f_{mv} + f_{mu}=1$), the result of the previous hash ($h_0, ..., h_3$) is copied over either to $(h_0', ..., h_3')$ or to $(h_4', ..., h_7')$ depending on the value of $b$, which is defined in the same way as in the previous section. For $j \in [0, 4)$ this can be described as follows: +### `mrupdate_id` and sibling-table soundness -$$ -(f_{mp} + f_{mv} + f_{mu}) \cdot ((1 - b) \cdot (h_{j}' - h_{j}) + b \cdot (h_{j + 4}' - h_{j})) = 0 \text{ | degree} = 6 -$$ +`MRUPDATE` executes two Merkle legs: -Note, that when a computation is completed (i.e., $f_{out}=1$), the next hasher state is unconstrained. +- old-path verification, +- new-path verification. -### Multiset check constraints +To prevent sibling entries from different `MRUPDATE` operations from cancelling +against each other, the chiplet introduces a dedicated `mrupdate_id` column. +The AIR enforces: -In this sections we describe constraints which enforce updates for [multiset check columns](../lookups/multiset.md) $b_{chip}$ and $p_1$. These columns can be updated only on rows which are multiples of $32$ or $1$ less than a multiple of $32$. On all other rows the values in the columns remain the same. +- `mrupdate_id` increments once per `MRUPDATE` start, +- it stays constant through the old/new legs of that same update, +- it is zero on all permutation rows. -To simplify description of the constraints, we define the following variables. Below, we denote random values sent by the verifier after the prover commits to the main execution trace as $\alpha_0$, $\alpha_1$, $\alpha_2$ etc. +Sibling-table messages on `b_hash_kernel` include `mrupdate_id`, so the running +product only balances if the old and new paths of the **same** update use the +same siblings. -$$ -m = op_{label} + 2^4 \cdot k_2 + 2^5 \cdot k_0 -v_h = \alpha_0 + \alpha_1 \cdot m + \alpha_2 \cdot (clk + 1) + \alpha_3 \cdot i -v_a = \sum_{j=0}^{3}(\alpha_{j+4} \cdot h_j) -v_b = \sum_{j=0}^{3}(\alpha_{j+8} \cdot h_{j+4}) -v_c = \sum_{j=0}^{3}(\alpha_{j+12} \cdot h_{j+8}) -v_d = \sum_{j=0}^{3}(\alpha_{j+4} \cdot h_{j+4}) -$$ +### Bus constraints -Message slot layout is fixed: slots $0..3$ use $\alpha_{4..7}$, slots $4..7$ use -$\alpha_{8..11}$, and slots $8..11$ use $\alpha_{12..15}$. For partial messages, -we place the payload into slots $0..7$ and set capacity slots $8..11$ to zero. -Leaf/output messages use only slots $0..3$. +The hasher participates in three different lookup relations. -In the above: +#### Chiplets bus (`b_chiplets`) -- $m$ is a _transition label_, composed of the [operation label](./index.md#operation-labels) and the periodic columns that uniquely identify each transition function. The values in the $k_0$ and $k_2$ periodic columns are included to identify the row in the hash cycle where the operation occurs. They serve to differentiate between operations that share selectors but occur at different rows in the cycle, such as `BP`, which uses $op_{linhash}$ at the first row in the cycle to initiate a linear hash, and `ABP`, which uses $op_{linhash}$ at the last row in the cycle to absorb new elements. -- $v_h$ is a _common header_ which is a combination of the transition label, a unique row address, and the node index. For the unique row address, the `clk` column from the system component is used, but we add $1$, because the system's `clk` column starts at $0$. -- $v_a$, $v_b$, $v_c$ are the rate0, rate1, and capacity words (4 elements each). -- $v_d$ reuses the rate0 alpha slice on the rate1 word. This is used for Merkle leaf encoding - when the right child is selected. For next-row values, $v_d'$ is defined the same way using $h'$. +Only controller rows contribute here. The chiplets bus carries the external VM +interface messages: -#### Chiplets bus constraints +- full-state sponge start, +- rate-only sponge continuation, +- selected Merkle leaf word, +- digest return, +- full-state return. -As described previously, the [chiplets bus](./index.md#chiplets-bus) $b_{chip}$, implemented as a running product column, is used to tie the hash chiplet with the main VM's stack and decoder. When receiving inputs from or returning results to the stack (or decoder), the hash chiplet multiplies $b_{chip}$ by their respective values. On the other side, when sending inputs to the hash chiplet or receiving results from the chiplet, the stack (or decoder) divides $b_{chip}$ by their values. +Permutation rows do not contribute. -In the section below we describe only the hash chiplet side of the constraints (i.e., multiplying $b_{chip}$ by relevant values). We define the values which are to be multiplied into $b_{chip}$ for each operation as follows: +#### Permutation-link LogUp on `v_wiring` -When starting a new simple or linear hash computation (i.e., $f_{bp}=1$) or when returning the entire state of the hasher ($f_{sout}=1$), the entire hasher state is included into $b_{chip}$: +The permutation-link relation binds controller requests to the permutation +segment by balancing: -$$ -v_{all} = v_h + v_a + v_b + v_c -$$ +- controller input rows against permutation row `0`, and +- controller output rows against permutation row `15`. -When starting a Merkle path computation (i.e., $f_{mp} + f_{mv} + f_{mu} = 1$), we include the leaf of the path into $b_{chip}$. The leaf is selected from the state based on value of $b$ (defined as in the previous section): +In common-denominator form, the hasher-side AIR enforces: -$$ -v_{leaf} = v_h + (1-b) \cdot v_a + b \cdot v_d -$$ +```text +hasher_flag * (delta * msg_in * msg_out + - msg_out * (f_in - f_p_in * m) + - msg_in * (f_out - f_p_out * m)) ++ idle_flag * delta +``` -When absorbing a new set of elements into the state while computing a linear hash (i.e., $f_{abp}=1$), we include the next rate (state slots $0..7$) into $b_{chip}$: +where `m` is the permutation multiplicity and `idle_flag` covers rows where the +shared `v_wiring` accumulator must propagate unchanged. -$$ -v_{abp} = v_h + v_a' + v_b' -$$ +This is the core mechanism for memoization. -When a computation is complete (i.e., $f_{hout}=1$), we include the first rate word of the hasher state (the result) into $b_{chip}$: +#### Hash-kernel virtual table (`b_hash_kernel`) -$$ -v_{res} = v_h + v_a -$$ +The hasher uses this running product for two logically separate purposes: -Using the above values, we can describe the constraints for updating column $b_{chip}$ as follows. +- sibling-table balancing for `MRUPDATE`, +- precompile transcript state tracking for `LOG_PRECOMPILE`. -$$ -b_{chip}' = b_{chip} \cdot ((f_{bp} + f_{sout}) \cdot v_{all} + (f_{mp} + f_{mv} + f_{mu}) \cdot v_{leaf} + f_{abp} \cdot v_{abp} + f_{hout} \cdot v_{res} + -1 - (f_{bp} + f_{mp} + f_{mv} + f_{mu} + f_{abp} + f_{out})) -$$ +For the sibling-table part, the old-path leg inserts siblings and the new-path +leg removes them. Because the entries are keyed by `(mrupdate_id, node_index, +sibling_word)`, unrelated updates cannot cancel each other. -The above constraint reduces to the following under various flag conditions: +## Implementation map -| Condition | Applied constraint | -| -------------- | ------------------------------------- | -| $f_{bp} = 1$ | $b_{chip}' = b_{chip} \cdot v_{all}$ | -| $f_{sout} = 1$ | $b_{chip}' = b_{chip} \cdot v_{all}$ | -| $f_{mp} = 1$ | $b_{chip}' = b_{chip} \cdot v_{leaf}$ | -| $f_{mv} = 1$ | $b_{chip}' = b_{chip} \cdot v_{leaf}$ | -| $f_{mu} = 1$ | $b_{chip}' = b_{chip} \cdot v_{leaf}$ | -| $f_{abp} = 1$ | $b_{chip}' = b_{chip} \cdot v_{abp}$ | -| $f_{hout} = 1$ | $b_{chip}' = b_{chip} \cdot v_{res}$ | -| Otherwise | $b_{chip}' = b_{chip}$ | +The hasher design is implemented across the following files: -Note that the degree of the above constraint is $7$. +- `air/src/constraints/chiplets/selectors.rs` + Chiplet-level tri-state selector system (`s_ctrl`, `s_perm`, virtual `s0`, + `s1..s4`), booleanity, transition rules, last-row invariant, and precomputed + `ChipletFlags` (`is_active`, `is_transition`, `is_last`, `next_is_first`) for + every chiplet. -#### Sibling table constraints +- `air/src/constraints/chiplets/hasher_control/mod.rs` + Controller sub-chiplet entry point: first-row boundary, sub-selector + booleanity, input/output/padding adjacency, `mrupdate_id` progression, + RESPAN capacity preservation. -_Note: Although this table is described independently, it is implemented as part of the [chiplets virtual table](../chiplets/index.md#chiplets-virtual-table), which combines all virtual tables required by any of the chiplets into a single master table._ +- `air/src/constraints/chiplets/hasher_control/flags.rs` + Pre-computed `ControllerFlags` struct: sub-operation flags + (`on_sponge`, `on_merkle_input`, `on_hout`, `on_sout`, `on_padding`) and + next-row flags used by transition constraints. -As mentioned previously, the sibling table (represented by running column $p_1$) is used to keep track of sibling nodes used during Merkle root update computations. For this computation, we need to enforce the following rules: +- `air/src/constraints/chiplets/hasher_control/merkle.rs` + Merkle index decomposition, direction-bit booleanity/confinement/forward + propagation, zero-capacity rule for Merkle inputs, cross-step index + continuity, and digest routing. -- When computing the old Merkle root, whenever a new sibling node is absorbed into the hasher state (i.e., $f_{mv} + f_{mva} = 1$), an entry for this sibling should be included into $p_1$. -- When computing the new Merkle root, whenever a new sibling node is absorbed into the hasher state (i.e., $f_{mu} + f_{mua} = 1$), the entry for this sibling should be removed from $p_1$. +- `air/src/constraints/chiplets/permutation/mod.rs` + Permutation sub-chiplet entry point: Poseidon2 step gating, cycle alignment + (entry at row 0, exit at row 15), multiplicity constancy, and structural + zeroing of unused metadata columns. -To simplify the description of the constraints, we use variables $v_a$ and $v_b$ defined above and define the value representing an entry in the sibling table as follows: +- `air/src/constraints/chiplets/permutation/state.rs` + Packed 16-row Poseidon2 transition constraints and unused-witness zeroing. -$$ -v_{sib0} = \alpha_0 + \alpha_3 \cdot i + v_b +- `air/src/constraints/chiplets/columns.rs` + `ControllerCols`, `PermutationCols`, and `HasherPeriodicCols` (including the + packed 16-row schedule and round-constant encoding). -v_{sib1} = \alpha_0 + \alpha_3 \cdot i + v_a +- `air/src/constraints/chiplets/bus/chiplets.rs` + Hasher messages visible to the rest of the VM via `b_chiplets`. -v_{sibling} = (1-b) \cdot v_{sib0} + b \cdot v_{sib1} -$$ +- `air/src/constraints/chiplets/bus/wiring.rs` + Controller-to-permutation perm-link relation on the shared `v_wiring` + column. -Using the above value, we can define the constraint for updating $p_1$ as follows: +- `air/src/constraints/chiplets/bus/hash_kernel.rs` + Sibling-table balancing and `log_precompile`-related hasher interactions + on `b_hash_kernel`. -$$ -p_1' \cdot \left( (f_{mv} + f_{mva}) \cdot v_{sibling} + 1 - (f_{mv} + f_{mva}) \right) = -p_1 \cdot \left( (f_{mu} + f_{mua}) \cdot v_{sibling} + 1 - (f_{mu} + f_{mua}) \right) -$$ +- `processor/src/trace/chiplets/hasher/trace.rs` + Trace generation for the controller and packed permutation segment. -The above constraint reduces to the following under various flag conditions: +- `processor/src/trace/chiplets/aux_trace/hasher_perm.rs` + Auxiliary trace generation for the perm-link running sum. -| Condition | Applied constraint | -| ------------- | ------------------------------ | -| $f_{mv} = 1$ | $p_1' \cdot v_{sibling} = p_1$ | -| $f_{mva} = 1$ | $p_1' \cdot v_{sibling} = p_1$ | -| $f_{mu} = 1$ | $p_1' = p_1 \cdot v_{sibling}$ | -| $f_{mua} = 1$ | $p_1' = p_1 \cdot v_{sibling}$ | -| Otherwise | $p_1' = p_1$ | +## Soundness-critical design points -Note that the degree of the above constraint is $7$. +A few aspects of the packed design are especially important: -To make sure computation of the old Merkle root is immediately followed by the computation of the new Merkle root, we impose the following constraint: +1. **Controller/permutation separation.** Only controller rows can interact with + the external chiplets bus; only permutation rows can satisfy the packed + Poseidon2 transition constraints. +2. **Cycle alignment.** The permutation segment can start only at cycle row 0 and + can end only at cycle row 15. +3. **Multiplicity constancy.** `node_index` is constant inside a permutation + cycle, so a single multiplicity is attached to the whole cycle. +4. **Witness reuse hardening.** Unused witness slots are forced to zero, and the + first-row controller constraint explicitly forbids a permutation row from + masquerading as the first controller row. -$$ -(f_{bp} + f_{mp} + f_{mv}) \cdot (1 - p_1) = 0 \text{ | degree} = 5 -$$ +## References -The above means that whenever we start a new computation which is not the computation of the new Merkle root, the sibling table must be empty. Thus, after the hash chiplet computes the old Merkle root, the only way to clear the table is to compute the new Merkle root. +Implementation files: -Together with boundary constraints enforcing that $p_1=1$ at the first and last rows of the running product column which implements the sibling table, the above constraints ensure that if a node was included into $p_1$ as a part of computing the old Merkle root, the same node must be removed from $p_1$ as a part of computing the new Merkle root. These two boundary constraints are described as part of the [chiplets virtual table constraints](../chiplets/index.md#chiplets-virtual-table-constraints). +- `air/src/constraints/chiplets/selectors.rs` +- `air/src/constraints/chiplets/columns.rs` +- `air/src/constraints/chiplets/hasher_control/mod.rs` +- `air/src/constraints/chiplets/hasher_control/flags.rs` +- `air/src/constraints/chiplets/hasher_control/merkle.rs` +- `air/src/constraints/chiplets/permutation/mod.rs` +- `air/src/constraints/chiplets/permutation/state.rs` +- `air/src/constraints/chiplets/bus/chiplets.rs` +- `air/src/constraints/chiplets/bus/wiring.rs` +- `air/src/constraints/chiplets/bus/hash_kernel.rs` +- `processor/src/trace/chiplets/hasher/trace.rs` +- `processor/src/trace/chiplets/aux_trace/hasher_perm.rs` diff --git a/docs/src/design/chiplets/index.md b/docs/src/design/chiplets/index.md index 2472a6c878..f841ba994d 100644 --- a/docs/src/design/chiplets/index.md +++ b/docs/src/design/chiplets/index.md @@ -23,7 +23,7 @@ The execution trace of the Chiplets module is generated by stacking the executio Each chiplet is identified within the Chiplets module by one or more chiplet selector columns which cause its constraints to be selectively applied. -The result is an execution trace of 18 trace columns, which allows space for the widest chiplet component (the hash chiplet) and a column to select for it. +The result is an execution trace of 21 trace columns, which allows space for the widest chiplet component (the hash chiplet, at 20 internal columns) plus the shared chiplet selector prefix. ![chiplets](../../img/design/chiplets/chiplets.png) @@ -43,9 +43,9 @@ The resulting order is as follows: | Chiplet | Cycle Length | Internal Degree | Chiplet Selector Degree | Total Degree | Columns | Chiplet Selector Flag | | --------------- | :----------: | :-------------: | :---------------------: | :----------: | :-----: | --------------------- | -| Hash chiplet | 32 | 8 | 1 | 9 | 17 | $\{0\}$ | +| Hash chiplet | 16 | 8 | 1 | 9 | 20 | $\{0\}$ | | Bitwise chiplet | 8 | 3 | 2 | 5 | 13 | $\{1, 0\}$ | -| Memory | - | 6 | 3 | 9 | 12 | $\{1, 1, 0\}$ | +| Memory | - | 6 | 3 | 9 | 17 | $\{1, 1, 0\}$ | | ACE | - | 5 | 4 | 9 | 16 | $\{1, 1, 1, 0\}$ | | Kernel ROM | - | 3 | 5 | 8 | 5 | $\{1, 1, 1, 1, 0\}$ | | Padding | - | - | - | - | - | $\{1, 1, 1, 1, 1\}$ | @@ -58,7 +58,7 @@ This is true for any transition constraints that are applied at every row and se This requires the following adjustments for each chiplet. -**In the hash chiplet:** there is no conflict, and therefore no change, since all constraints are periodic. +**In the hash chiplet:** the permutation-step constraints are periodic, while the controller constraints explicitly confine the controller/permutation boundary. The controller region is padded to a multiple of the 16-row cycle before the permutation segment begins, so no extra inter-chiplet alignment rows are required. **In the bitwise chiplet:** there is no conflict, and therefore no change, since all constraints are periodic. diff --git a/docs/src/design/chiplets/kernel_rom.md b/docs/src/design/chiplets/kernel_rom.md index 4ff902ffac..d3b8cc2b44 100644 --- a/docs/src/design/chiplets/kernel_rom.md +++ b/docs/src/design/chiplets/kernel_rom.md @@ -12,108 +12,50 @@ More background about Miden VM execution contexts can be found [here](../../user ## Kernel ROM trace -The kernel ROM table consists of five columns. -The following example table shows the execution trace of the kernel ROM with procedure digests $a, b, c$, which were called 1, 2, and 0 times, respectively. -Each digest is included once to respond to the initialization request by the public inputs, and then repeated for each call made by the decoder. +The kernel ROM table consists of five columns, with exactly one row per declared kernel procedure. +The following example table shows the execution trace for three procedures with digests $a, b, c$, called 1, 2, and 0 times respectively. -| $s_{first}$ | $r_0$ | $r_1$ | $r_2$ | $r_3$ | -|-------------|-------|-------|-------|-------| -| 1 | $a_0$ | $a_1$ | $a_2$ | $a_3$ | -| 0 | $a_0$ | $a_1$ | $a_2$ | $a_3$ | -| 1 | $b_0$ | $b_1$ | $b_2$ | $b_3$ | -| 0 | $b_0$ | $b_1$ | $b_2$ | $b_3$ | -| 0 | $b_0$ | $b_1$ | $b_2$ | $b_3$ | -| 1 | $c_0$ | $c_1$ | $c_2$ | $c_3$ | +| $m$ | $r_0$ | $r_1$ | $r_2$ | $r_3$ | +|-----|-------|-------|-------|-------| +| 1 | $a_0$ | $a_1$ | $a_2$ | $a_3$ | +| 2 | $b_0$ | $b_1$ | $b_2$ | $b_3$ | +| 0 | $c_0$ | $c_1$ | $c_2$ | $c_3$ | -The meaning of columns in the above is as follows: +Column meanings: -- Column $s_{first}$ specifies the start of a block of rows with identical kernel procedure digests. -- $r_0, ..., r_3$ contain the digests of the kernel procedures. The values in these columns can change only when $s_{first}$ is set to 1 in the next row. Otherwise, the values in the $r$ columns remain the same. +- $m$ is the CALL-label multiplicity — the number of times the procedure was invoked by a `SYSCALL`. It may be zero for procedures declared in the kernel but never called. +- $r_0, \ldots, r_3$ contain the digest of the kernel procedure. -## Constraints +## Main-trace constraints -We first define the selector flag $f_{krom}$ that is active in all rows of the kernel ROM chiplet. +The kernel ROM chiplet has **no main-trace shape constraints** under the all-LogUp layout. +Earlier designs carried a binary "first-row-of-block" selector, a digest-contiguity rule, and an entry-row anchor to shape the trace for a permutation argument. +LogUp replaces those with multiset equality under a random challenge $\alpha$, so any prover assignment to $(m, r_0, \ldots, r_3)$ that balances the chiplets bus is sound; no extra shape constraints are required. ->$$ -> f_{krom} = s_0 \cdot s_1 \cdot s_2 \cdot s_3 \cdot (1 - s_4) \text{ | degree} = 5 ->$$ +## Chiplets bus constraints -where $s_i$ are the chiplet selector flags. Refer to the [chiplets order](./index.md#chiplets-order) for more information. - -The following constraints are required to enforce the correctness of the kernel ROM trace. - -The $s_{first}$ column is a selector indicating the start of a new digest included in the kernel ROM chiplet trace. -In this row, the chiplet responds to a bus request made by the verifier to ensure consistency with the set of kernel procedure digests given as public inputs. - -As $s_{first}$ is a selector, it must be binary. - -> $$ -> f_{krom} \cdot (s_{first}^2 - s_{first}) = 0 \text{ | degree} = 7 -> $$ - - -The flag $s_{first}$ must be set to be 1 in the first row of the kernel ROM chiplet. -Otherwise, the digest in this row would not be matched with one of the input procedure roots. -This constraint is enforced in the last row of the previous trace, using selector columns from the [chiplets](index.md) module. -More precisely, we use the virtual $f_{ACE}$ flag, which is active in all rows of the ACE chiplet (which comes right before this chiplet), -along with the selector $s_3$ which transitions from 0 to 1 in the last row, allowing us to target the first row of the kernel ROM trace. - -> $$ -> f_{ACE} \cdot s_{3}' \cdot (1 - s_{4}') \cdot (s_{first}' - 1) = 0 \text{ | degree} = 7 -> $$ - -The contiguity of the digests in a block is ensured by enforcing equality between digests across two consecutive rows, whenever the next row is not the start of a new block. -That is, when $s_{first}' = 0$, it must hold that $r_i = r_i'$. -We disable this constraint in the last row of the kernel ROM chiplet trace by using the kernel ROM chiplet selector $s_4'$, since the latter transitions from 0 to 1 in the first row of the next chiplet. - -For $i \in \{0,1,2,3\}$, - -> $$ -> f_{krom} \cdot (1 - s_4') \cdot (1 - s_{first}') \cdot (r_i' - r_i) = 0 \text{ | degree} = 8 -> $$ - -### Chiplets bus constraints - -The kernel ROM chiplet must ensure that all kernel procedure digests requested by the decoder correspond to one of the digests provided by the verifier through public inputs. -This is achieved by making use of the chiplet bus $b_{bus}$, responding to requests made by the decoder and by the verifier through public inputs. - -In the first row of each new block of hashes in the kernel ROM chiplet trace (i.e., when $s_{first} = 1$), the chiplet responds to a message $v_{init}$ requested by the verifier. -Since these initialization messages must match, the set of digests across all blocks must be equal to the set of procedure digests provided by the verifier (though not necessarily in the same order). - -Whenever a digest is requested by the decoder during program block hashing of the [`SYSCALL` operation](../decoder/constraints.md#block-hash-computation-constraints), a new row is added to the trace after the first row which is used to respond to one of the initialization requests made by the verifier using public inputs. -The chiplet responds to the request with a message $v_{call}$. - -In other words, the selector $s_{first}$ indicates whether the chiplet should respond to the decoder or the verifier initialization requests. -If a digest is requested $n$ times by the decoder, the same digest appears in a single block of length $n+1$. - -The variables $v_{init}$ and $v_{call}$ representing the bus messages contain reduced bus messages containing a kernel procedure digest. -Denoting the random values received from the verifier as $\alpha_0, \alpha_1$, etc., this can be defined as +The kernel ROM chiplet emits two fractions on the chiplets bus $b_{chip}$ per active row, gated by the selector flag $f_{krom}$. +Let $$ \begin{aligned} -\tilde{r} &= \sum_{i=0}^3 (\alpha_{i + 2} \cdot r_i) -v_{init} &= \alpha_0 + \alpha_1 \cdot \textsf{KERNEL\_PROC\_INIT} + \tilde{r} +\tilde{r} &= \sum_{i=0}^{3} \alpha_{i+2} \cdot r_i \\ +v_{init} &= \alpha_0 + \alpha_1 \cdot \textsf{KERNEL\_PROC\_INIT} + \tilde{r} \\ v_{call} &= \alpha_0 + \alpha_1 \cdot \textsf{KERNEL\_PROC\_CALL} + \tilde{r} \end{aligned} $$ -Here, $\textsf{KERNEL\_PROC\_INIT}$ and $\textsf{KERNEL\_PROC\_CALL}$ are the unique [operation labels](./index.md#operation-labels) for the kernel ROM bus message. +denote the two encoded bus messages for a row's digest. Here $\textsf{KERNEL\_PROC\_INIT}$ and $\textsf{KERNEL\_PROC\_CALL}$ are the unique [operation labels](./index.md#operation-labels), and $\alpha_i$ are challenges received from the verifier. -Each row of the kernel ROM chiplet trace responds to either a procedure digest initialization or decoder call request. -Since the $s_{first}$ column defines which type of response is sent to the bus, it is used to combine both requests into a single constraint given by +The chiplet contributes to $b_{chip}$ via > $$ -> b'_{chip} = b_{chip} \cdot (s_{first} \cdot v_{init} + (1 - s_{first}) \cdot v_{call}) \text{ | degree} = 3. +> f_{krom} \cdot \left( -\frac{1}{v_{init}} + \frac{m}{v_{call}} \right) > $$ -The above simplifies to - -- $s_{first} = 1$: $b'_{chip} = b_{chip} \cdot v_{init}$, when responding to a $\textsf{KERNEL\_PROC\_INIT}$ request. -- $s_{first} = 0$: $b'_{chip} = b_{chip} \cdot v_{call}$, when responding to a $\textsf{KERNEL\_PROC\_CALL}$ request. - -The kernel procedure digests initialization requests are implemented by imposing a boundary constraint in the first row of the $b_{chip}$ column. -This is described in the [chiplets bus constraints](../chiplets/index.md#chiplets-bus-constraints). +- The **INIT term** removes exactly one fraction per declared procedure. It is balanced by the public-input boundary term the verifier injects on $b_{chip}$ (one add per kernel procedure digest read from public inputs). This anchors every chiplet row to a declared procedure: a forged row would leave an unmatched INIT remove. +- The **CALL term** contributes $m$ fractions. Each `SYSCALL` in the decoder emits one matching remove on $b_{chip}$. Bus balance forces $m$ to equal the true syscall count for that procedure. -By using the bus to initialize the kernel ROM procedure digest in this way, the verifier only learns which procedures can be invoked but doesn't learn how often they were called, if at all. +The full set of constraints applied to $b_{chip}$ (including the public-input boundary term for INIT) is described in the [chiplets bus constraints](../chiplets/index.md#chiplets-bus-constraints). -The full set of constraints applied to the $b_{chip}$ are described as part of the [chiplets bus constraints](../chiplets/index.md#chiplets-bus-constraints). +By using the bus this way, the verifier only learns which procedures can be invoked, not how often they were called — the multiplicity $m$ is a private witness that only reaches the verifier through the bus balance. diff --git a/docs/src/design/decoder/constraints.md b/docs/src/design/decoder/constraints.md index 76f58a7f50..069cfe666f 100644 --- a/docs/src/design/decoder/constraints.md +++ b/docs/src/design/decoder/constraints.md @@ -68,10 +68,10 @@ Also, when `REPEAT` operation is executed, the value in $h_4$ column (the `is_lo > f_{repeat} \cdot (1 - h_4) = 0 \text{ | degree} = 5 > $$ -When `RESPAN` operation is executed, we need to make sure that the block ID is incremented by $32$: +When `RESPAN` operation is executed, we need to make sure that the block ID is incremented by $2$: > $$ -> f_{respan} \cdot (a' - a - 32) = 0 \text{ | degree} = 5 +> f_{respan} \cdot (a' - a - 2) = 0 \text{ | degree} = 5 > $$ When `END` operation is executed and we are exiting a *loop* block (i.e., `is_loop`, value which is stored in $h_5$, is $1$), the value at the top of the operand stack must be $0$: @@ -139,9 +139,9 @@ When the value in `in_span` column is set to $1$, control flow operations cannot ## Block hash computation constraints As described [previously](./index.md#program-block-hashing), when the VM starts executing a new block, it also initiates computation of the block's hash. There are two separate methodologies for computing block hashes. -For *join* and *split* blocks, the hash is computed directly from the hashes of the block's children. The prover provides these child hashes non-deterministically by populating registers $h_0,..., h_7$. For *loop* blocks, only the loop body hash is provided in $h_0..h_3$ and the remaining registers $h_4..h_7$ are set to $0$ (padding to a full 8-element rate). For *dyn*, only the second half of the hasher registers ($h_4,\dots,h_7$) are forced to $0$, while the first half holds the callee digest read from memory; thus the input is not all zeros. The hasher is initialized using the hash chiplet, and we use the address of the hasher as the block's ID. The result of the hash is available $31$ rows down in the hasher table (i.e., at row with index equal to block ID plus $31$). We read the result from the hasher table at the time the `END` operation is executed for a given block. +For *join* and *split* blocks, the hash is computed directly from the hashes of the block's children. The prover provides these child hashes non-deterministically by populating registers $h_0,..., h_7$. For *loop* blocks, only the loop body hash is provided in $h_0..h_3$ and the remaining registers $h_4..h_7$ are set to $0$ (padding to a full 8-element rate). For *dyn*, only the second half of the hasher registers ($h_4,\dots,h_7$) are forced to $0$, while the first half holds the callee digest read from memory; thus the input is not all zeros. The hasher is initialized using the hash chiplet, and we use the address of the controller input row as the block's ID. The result of the hash is then available in the paired controller output row at block ID plus $1$, and we read that result when the `END` operation is executed for the block. -For *basic* blocks, the hash is computed by absorbing a linear sequence of instructions (organized into operation groups and batches) into the hasher and then returning the result. The prover provides operation batches non-deterministically by populating registers $h_0, ..., h_7$. Similarly to other blocks, the hasher is initialized using the hash chiplet at the start of the block, and we use the address of the hasher as the ID of the first operation batch in the block. As we absorb additional operation batches into the hasher (by executing `RESPAN` operation), the batch address is incremented by $32$. This moves the "pointer" into the hasher table $32$ rows down with every new batch. We read the result from the hasher table at the time the `END` operation is executed for a given block. +For *basic* blocks, the hash is computed by absorbing a linear sequence of instructions (organized into operation groups and batches) into the hasher and then returning the result. The prover provides operation batches non-deterministically by populating registers $h_0, ..., h_7$. Similarly to other blocks, the hasher is initialized using the hash chiplet at the start of the block, and we use the address of the first controller input row as the ID of the first operation batch in the block. As we absorb additional operation batches into the hasher (by executing `RESPAN`), the next batch starts at the next controller input row, so the batch address is incremented by $2$. We read the result from the controller output row corresponding to the final batch when the `END` operation is executed for the block. ### Chiplets bus constraints @@ -182,13 +182,13 @@ $$ $$ h_{respan} = -\alpha_0 + \alpha_1 \cdot L_{respan} + \alpha_2 \cdot (a' - 1) +\alpha_0 + \alpha_1 \cdot L_{respan} + \alpha_2 \cdot a' + \sum_{i=0}^7(\alpha_{4+i} \cdot h_i) $$ $$ h_{end} = -\alpha_0 + \alpha_1 \cdot L_{end} + \alpha_2 \cdot (a + 31) +\alpha_0 + \alpha_1 \cdot L_{end} + \alpha_2 \cdot (a + 1) + \sum_{i=0}^3(\alpha_{4+i} \cdot h_i) $$ @@ -452,11 +452,13 @@ $$ When `END` operation is executed, the hash of the completed block is removed from the block hash table. We differentiate between the first and second child of a `JOIN` by looking at -the next opcode: if the next operation is not `END`, `REPEAT`, or `HALT`, then this block -is the first child and `is_first_child = 1`. The `is_loop_body` flag is read from $h_4$. +the next opcode: if the next operation is not `END`, `REPEAT`, `RESPAN`, or `HALT`, then this +block is the first child and `is_first_child = 1`. `RESPAN` is included defensively — no single +constraint forbids `END → RESPAN`, so excluding it would let an adversarial trace inject a +false-positive `is_first_child = 1`. The `is_loop_body` flag is read from $h_4$. $$ -u_{end} = f_{end} \cdot m(a', h_0..h_3, 1 - (f_{end}' + f_{repeat}' + f_{halt}'), h_4) \text{ | } \text{degree} = 8 +u_{end} = f_{end} \cdot m(a', h_0..h_3, 1 - (f_{end}' + f_{repeat}' + f_{respan}' + f_{halt}'), h_4) \text{ | } \text{degree} = 8 $$ Using the above definitions, we can describe the constraint for updating the block hash table as follows: @@ -520,7 +522,7 @@ When we are inside a *basic* block, values in block address columns (denoted as > sp \cdot (a' - a) = 0 \text{ | degree} = 2 > $$ -Notice that this constraint does not apply when we execute any of the control flow operations. For such operations, the prover sets the value of the $a$ column non-deterministically, except for the `RESPAN` operation. For the `RESPAN` operation the value in the $a$ column is incremented by $32$, which is enforced by a constraint described previously. +Notice that this constraint does not apply when we execute any of the control flow operations. For such operations, the prover sets the value of the $a$ column non-deterministically, except for the `RESPAN` operation. For the `RESPAN` operation the value in the $a$ column is incremented by $2$, which is enforced by a constraint described previously. Notice also that this constraint implies that when the next operation is the `END` operation, the value in the $a$ column must also be copied over to the next row. This is exactly the behavior we want to enforce so that when the `END` operation is executed, the block address is set to the address of the current span batch. diff --git a/docs/src/design/decoder/index.md b/docs/src/design/decoder/index.md index 5edd45ac4a..68e91d5e85 100644 --- a/docs/src/design/decoder/index.md +++ b/docs/src/design/decoder/index.md @@ -133,8 +133,8 @@ These registers have the following meanings: To compute hashes of program blocks, the decoder relies on the [hash chiplet](../chiplets/hasher.md). Specifically, the decoder needs to perform two types of hashing operations: -1. A simple 2-to-1 hash, where we provide a sequence of $8$ field elements, and get back $4$ field elements representing the result. Computing such a hash requires $32$ rows in the hash chiplet. -2. A sequential hash of $n$ elements. Computing such a hash requires multiple absorption steps, and at each step $8$ field elements are absorbed into the hasher. Thus, computing a sequential hash of $n$ elements requires $32 \cdot \lceil {n/8} \rceil$ rows in the hash chiplet. At the end, we also get $4$ field elements representing the result. +1. A simple 2-to-1 hash, where we provide a sequence of $8$ field elements and get back $4$ field elements representing the result. In the controller/permutation split hasher design, this is represented by one controller pair plus one packed 16-row permutation cycle for the corresponding input state. +2. A sequential hash of $n$ elements. This requires multiple absorption steps, and at each step $8$ field elements are absorbed into the hasher. At the controller level, each absorbed batch contributes one `(input, output)` controller pair, so the controller addresses for successive batches advance by $2$. To make hashing requests to the hash chiplet and to read the results from it, we will need to divide out relevant values from the [chiplets bus](../chiplets/index.md#chiplets-bus) column $b_{chip}$ as described below. @@ -154,7 +154,7 @@ where: To read the $4$-element result ($u_0, ..., u_3$), we need to divide $b_{chip}$ by the following value: $$ -\alpha_0 + \alpha_1 \cdot m_{hout} + \alpha_2 \cdot (r + 31) + \sum_{i=0}^3 (\alpha_{i+4} \cdot u_i) +\alpha_0 + \alpha_1 \cdot m_{hout} + \alpha_2 \cdot (r + 1) + \sum_{i=0}^3 (\alpha_{i+4} \cdot u_i) $$ where: @@ -172,7 +172,7 @@ $$ This also absorbs the first $8$ elements of the sequence into the hasher state. Then, to absorb the next sequence of $8$ elements (e.g., $v_8, ..., v_{15}$), we need to divide $b_{chip}$ by the following value: $$ -\alpha_0 + \alpha_1 \cdot m_{abp} + \alpha_2 \cdot (r + 31) + \sum_{i=0}^7 (\alpha_{i+4} \cdot v_{i + 8}) +\alpha_0 + \alpha_1 \cdot m_{abp} + \alpha_2 \cdot (r + 2) + \sum_{i=0}^7 (\alpha_{i+4} \cdot v_{i + 8}) $$ Where $m_{abp}$ is a label indicating absorption of more elements into the hasher state. Value of this label is computed based on hash chiplet selector flags according to the methodology described [here](../chiplets/hasher.md#multiset-check-constraints). @@ -180,10 +180,10 @@ Where $m_{abp}$ is a label indicating absorption of more elements into the hashe We can keep absorbing elements into the hasher in the similar manner until all elements have been absorbed. Then, to read the result (e.g., $u_0, ..., u_3$), we need to divide $b_{chip}$ by the following value: $$ -\alpha_0 + \alpha_1 \cdot m_{hout} + \alpha_2 \cdot (r + \lceil n / 8 \rceil \cdot 32 - 1) + \sum_{i=0}^3 (\alpha_{i+4} \cdot u_i) +\alpha_0 + \alpha_1 \cdot m_{hout} + \alpha_2 \cdot (r + 2 \cdot \lceil n / 8 \rceil - 1) + \sum_{i=0}^3 (\alpha_{i+4} \cdot u_i) $$ -Thus, for example, if $n = 14$, the result of the hash will be available at hasher row $r + 63$. +Thus, for example, if $n = 14$, the result of the hash is available at controller output row $r + 3$ (two absorbed batches). ### Control flow tables @@ -394,7 +394,7 @@ When the VM executes an `END` operation, it does the following: - in the above, the `x_next` variables denote the column `x` in the next row - else, we remove a row `(blk, prnt, f1, 0, 0, 0, 0, 0)` 2. Removes a tuple `(prnt, current_block_hash, nxt, f0)` from the block hash table, where $nxt=0$ if the next operation is either `END` or `REPEAT`, and $1$ otherwise. -3. Reads the hash result from the hash chiplet (as described [here](#program-block-hashing)) using `blk + 31` as row address in the auxiliary hashing table. +3. Reads the hash result from the hash chiplet (as described [here](#program-block-hashing)) using `blk + 1` as the controller output row address. 4. If $h_5 = 1$ (i.e., we are exiting a *loop* block), pops the value off the top of the stack and verifies that the value is $0$. 5. Verifies that `group_count` register is set to $0$. @@ -438,14 +438,14 @@ In the above diagram, `g0_op0` is the first operation of the new operation batch When the VM executes a `RESPAN` operation, it does the following: -1. Increments block address by $32$. +1. Increments block address by $2$. 2. Removes the tuple `(blk, prnt, 0, 0...)` from the block stack table. -3. Adds the tuple `(blk+32, prnt, 0, 0...)` to the block stack table. +3. Adds the tuple `(blk+2, prnt, 0, 0...)` to the block stack table. 4. Absorbs values in registers $h_0, ..., h_7$ into the hasher state of the hash chiplet (as described [here](#sequential-hash)). 5. Sets the `in_span` register to $1$. -6. Adds groups of the operation batch, as specified by op batch flags (see [here](#operation-batch-flags)) to the op group table using `blk+32` as batch ID. +6. Adds groups of the operation batch, as specified by op batch flags (see [here](#operation-batch-flags)) to the op group table using `blk+2` as batch ID. -The net result of the above is that we incremented the ID of the current block by $32$ and added the next set of operation groups to the op group table. +The net result of the above is that we incremented the ID of the current block by $2$ (the next controller input row) and added the next set of operation groups to the op group table. #### CALL operation @@ -650,9 +650,9 @@ First, after the `SPAN` operation is executed, the op group table will look as f Notice that while the same groups ($g_1, ..., g_7$) are added to the table, their positions now reflect the total number of groups in the *basic* block. -Second, executing a `RESPAN` operation increments hasher address by $32$. This is done because absorbing additional $8$ elements into the hasher state requires $32$ more rows in the auxiliary hasher table. +Second, executing a `RESPAN` operation increments the hasher controller address by $2$. This is done because each absorbed batch is represented by one controller pair `(input, output)`, so the next batch starts at the next controller input row. -Incrementing value of `addr` register actually changes the ID of the *basic* block (though, for a *basic* block, it may be more appropriate to view values in this column as IDs of individual operation batches). This means that we also need to update the block stack table. Specifically, we need to remove row `(blk, prnt, 0)` from it, and replace it with row `(blk + 32, prnt, 0)`. To perform this operation, the prover sets the value of $h_1` in the next row to `prnt`. +Incrementing value of `addr` register actually changes the ID of the *basic* block (though, for a *basic* block, it may be more appropriate to view values in this column as IDs of individual operation batches). This means that we also need to update the block stack table. Specifically, we need to remove row `(blk, prnt, 0)` from it, and replace it with row `(blk + 2, prnt, 0)`. To perform this operation, the prover sets the value of $h_1` in the next row to `prnt`. Executing a `RESPAN` operation also adds groups $g_9, g_{10}, g_{11}$ to the op group table, which now would look as follows: @@ -660,7 +660,7 @@ Executing a `RESPAN` operation also adds groups $g_9, g_{10}, g_{11}$ to the op Then, the execution of the second batch proceeds in a manner similar to the first batch: we remove operations from the current op group, execute them, and when the value of the op group reaches $0$, we start executing the next group in the batch. Thus, by the time we get to the `END` operation, the op group table should be empty. -When executing the `END` operation, the hash of the *basic* block will be read from hasher row at address `addr + 31`, which, in our example, will be equal to `blk + 63`. +When executing the `END` operation, the hash of the *basic* block will be read from the paired controller output row at address `addr + 1`, which, in our example, will be equal to `blk + 3` after one `RESPAN`. #### Handling immediate values diff --git a/docs/src/design/index.md b/docs/src/design/index.md index 81705a1364..f2745bcf98 100644 --- a/docs/src/design/index.md +++ b/docs/src/design/index.md @@ -40,7 +40,7 @@ Miden VM consists of several interconnected components, each providing a specifi The above components are connected via **buses**, which are implemented using [lookup arguments](./lookups/index.md). We also use [multiset check lookups](./lookups/multiset.md) internally within components to describe **virtual tables**. ## VM execution trace -The execution trace of Miden VM consists of $71$ main trace columns, $2$ buses, and $5$ virtual tables, as shown in the diagram below. +The execution trace of Miden VM consists of $72$ main trace columns and $8$ auxiliary columns (running products / LogUp accumulators), as shown in the diagram below. ![vm_trace.png](../img/design/vm_trace.png) diff --git a/docs/src/design/stack/crypto_ops.md b/docs/src/design/stack/crypto_ops.md index e8bdc1412b..0fae3d08d6 100644 --- a/docs/src/design/stack/crypto_ops.md +++ b/docs/src/design/stack/crypto_ops.md @@ -24,7 +24,7 @@ v_{input} = \alpha_0 + \alpha_1 \cdot op_{linhash} + \alpha_2 \cdot h_0 + \sum_{ $$ $$ -v_{output} = \alpha_0 + \alpha_1 \cdot op_{retstate} + \alpha_2 \cdot (h_0 + 31) + \sum_{j=0}^{11} (\alpha_{j+4} \cdot s_j') +v_{output} = \alpha_0 + \alpha_1 \cdot op_{retstate} + \alpha_2 \cdot (h_0 + 1) + \sum_{j=0}^{11} (\alpha_{j+4} \cdot s_j') $$ In the above, $op_{linhash}$ and $op_{retstate}$ are the unique [operation labels](../chiplets/index.md#operation-labels) for initiating a linear hash and reading the full state of the hasher respectively. Also note that the term for $\alpha_3$ is missing from the above expressions because for Poseidon2 permutation computation the index column is expected to be set to $0$. @@ -35,7 +35,7 @@ $$ b_{chip}' \cdot v_{input} \cdot v_{output} = b_{chip} \text{ | degree} = 3 $$ -The above constraint enforces that the specified input and output rows must be present in the trace of the hash chiplet, and that they must be exactly $31$ rows apart. +The above constraint enforces that the specified input and output controller rows must be present in the trace of the hash chiplet. In the controller/permutation split design these rows are consecutive, so their addresses differ by exactly $1$. The effect of this operation on the rest of the stack is: * **No change** starting from position $12$. @@ -62,7 +62,7 @@ v_{input} = \alpha_0 + \alpha_1 \cdot op_{mpver} + \alpha_2 \cdot h_0 + \alpha_3 $$ $$ -v_{output} = \alpha_0 + \alpha_1 \cdot op_{rethash} + \alpha_2 \cdot (h_0 + 32 \cdot s_4 - 1) + \sum_{j=0}^3\alpha_{j + 4} \cdot s_{6 + j} +v_{output} = \alpha_0 + \alpha_1 \cdot op_{rethash} + \alpha_2 \cdot (h_0 + 2 \cdot s_4 - 1) + \sum_{j=0}^3\alpha_{j + 4} \cdot s_{6 + j} $$ In the above, $op_{mpver}$ and $op_{rethash}$ are the unique [operation labels](../chiplets/index.md#operation-labels) for initiating a Merkle path verification computation and reading the hash result respectively. The sum expression for inputs computes the value of the leaf node, while the sum expression for the output computes the value of the tree root. @@ -73,7 +73,7 @@ $$ b_{chip}' \cdot v_{input} \cdot v_{output} = b_{chip} \text{ | degree} = 3 $$ -The above constraint enforces that the specified input and output rows must be present in the trace of the hash chiplet, and that they must be exactly $32 \cdot d - 1$ rows apart, where $d$ is the depth of the node. +The above constraint enforces that the specified input and output controller rows must be present in the trace of the hash chiplet, and that they must be exactly $2 \cdot d - 1$ rows apart, where $d$ is the depth of the node. Each Merkle level contributes one controller pair `(input, output)`. The effect of this operation on the rest of the stack is: * **No change** starting from position $0$. @@ -101,15 +101,15 @@ v_{inputold} = \alpha_0 + \alpha_1 \cdot op_{mruold} + \alpha_2 \cdot h_0 + \alp $$ $$ -v_{outputold} = \alpha_0 + \alpha_1 \cdot op_{rethash} + \alpha_2 \cdot (h_0 + 32 \cdot s_4 - 1) + \sum_{j=0}^3\alpha_{j + 4} \cdot s_{6 + j} +v_{outputold} = \alpha_0 + \alpha_1 \cdot op_{rethash} + \alpha_2 \cdot (h_0 + 2 \cdot s_4 - 1) + \sum_{j=0}^3\alpha_{j + 4} \cdot s_{6 + j} $$ $$ -v_{inputnew} = \alpha_0 + \alpha_1 \cdot op_{mrunew} + \alpha_2 \cdot (h_0 + 32 \cdot s_4) + \alpha_3 \cdot s_5 + \sum_{j=0}^3\alpha_{j + 4} \cdot s_{10 + j} +v_{inputnew} = \alpha_0 + \alpha_1 \cdot op_{mrunew} + \alpha_2 \cdot (h_0 + 2 \cdot s_4) + \alpha_3 \cdot s_5 + \sum_{j=0}^3\alpha_{j + 4} \cdot s_{10 + j} $$ $$ -v_{outputnew} = \alpha_0 + \alpha_1 \cdot op_{rethash} + \alpha_2 \cdot (h_0 + 2 \cdot 32 \cdot s_4 - 1) + \sum_{j=0}^3\alpha_{j + 4} \cdot s_{j}' +v_{outputnew} = \alpha_0 + \alpha_1 \cdot op_{rethash} + \alpha_2 \cdot (h_0 + 4 \cdot s_4 - 1) + \sum_{j=0}^3\alpha_{j + 4} \cdot s_{j}' $$ In the above, the first two expressions correspond to inputs and outputs for verifying the Merkle path between the old node value and the old tree root, while the last two expressions correspond to inputs and outputs for verifying the Merkle path between the new node value and the new tree root. The hash chiplet ensures the same set of sibling nodes are used in both of these computations. @@ -120,7 +120,7 @@ The $op_{mruold}$, $op_{mrunew}$, and $op_{rethash}$ are the unique [operation l > b_{chip}' \cdot v_{inputold} \cdot v_{outputold} \cdot v_{inputnew} \cdot v_{outputnew} = b_{chip} \text{ | degree} = 5 > $$ -The above constraint enforces that the specified input and output rows for both, the old and the new node/root combinations, must be present in the trace of the hash chiplet, and that they must be exactly $32 \cdot d - 1$ rows apart, where $d$ is the depth of the node. It also ensures that the computation for the old node/root combination is immediately followed by the computation for the new node/root combination. +The above constraint enforces that the specified input and output controller rows for both the old and the new node/root combinations must be present in the trace of the hash chiplet. The old-path output is $2 \cdot d - 1$ rows after the old-path input, the new-path input starts immediately after that at offset $2 \cdot d$, and the new-path output is $4 \cdot d - 1$ rows after the initial old-path input. It also ensures that the computation for the old node/root combination is immediately followed by the computation for the new node/root combination. The effect of this operation on the rest of the stack is: * **No change** for positions starting from $4$. @@ -434,7 +434,7 @@ $$ v_{\text{input}} = \alpha_0 + \alpha_1 \cdot op_{linhash} + \alpha_2 \cdot h_0 + \sum_{i=0}^{3} \alpha_{i+4} \cdot \mathsf{COMM}_i + \sum_{i=0}^{3} \alpha_{i+8} \cdot \mathsf{TAG}_i + \sum_{i=0}^{3} \alpha_{i+12} \cdot \mathsf{CAP}_{\text{prev},i}. $$ -Thirty-one rows later, the `op_retstate` response provides the permuted state `[R0, R1, CAP_{next}]` (with R0 on top). Denote the stack after the instruction by $s'_i$; the top twelve elements are `[R0, R1, CAP_NEXT]`. Thus +One controller row later, the `op_retstate` response provides the permuted state `[R0, R1, CAP_{next}]` (with R0 on top). Denote the stack after the instruction by $s'_i$; the top twelve elements are `[R0, R1, CAP_NEXT]`. Thus $$ \begin{aligned} @@ -448,7 +448,7 @@ $$ and the response message is $$ -v_{\text{output}} = \alpha_0 + \alpha_1 \cdot op_{retstate} + \alpha_2 \cdot (h_0 + 31) + \sum_{i=0}^{3} \alpha_{i+4} \cdot \mathsf{R}_0{}_i + \sum_{i=0}^{3} \alpha_{i+8} \cdot \mathsf{R}_1{}_i + \sum_{i=0}^{3} \alpha_{i+12} \cdot \mathsf{CAP}^{\text{next}}_i. +v_{\text{output}} = \alpha_0 + \alpha_1 \cdot op_{retstate} + \alpha_2 \cdot (h_0 + 1) + \sum_{i=0}^{3} \alpha_{i+4} \cdot \mathsf{R}_0{}_i + \sum_{i=0}^{3} \alpha_{i+8} \cdot \mathsf{R}_1{}_i + \sum_{i=0}^{3} \alpha_{i+12} \cdot \mathsf{CAP}^{\text{next}}_i. $$ Using the above values, we can describe the constraint for the chiplet bus column as follows: @@ -457,7 +457,7 @@ $$ b_{chip}' \cdot v_{input} \cdot v_{output} = b_{chip} $$ -The above constraint enforces that the specified input and output rows must be present in the trace of the hash chiplet, and that they must be exactly 31 rows apart. The Poseidon2 permutation outputs `[R0, R1, CAP]` (with R0 on top); on the stack, the VM stores these words as `[R0, R1, CAP]`. +The above constraint enforces that the specified input and output controller rows must be present in the trace of the hash chiplet. In the controller/permutation split design these two controller rows are consecutive, so their addresses differ by exactly 1. The Poseidon2 permutation outputs `[R0, R1, CAP]` (with R0 on top); on the stack, the VM stores these words as `[R0, R1, CAP]`. Given the similarity with the `HPERM` opcode which sends the same message, albeit from different variables in the trace, it should be possible to combine the bus constraint in a way that avoids increasing the degree of the overall bus expression. diff --git a/docs/src/design/stack/system_ops.md b/docs/src/design/stack/system_ops.md index 84e9c3de9e..141b164016 100644 --- a/docs/src/design/stack/system_ops.md +++ b/docs/src/design/stack/system_ops.md @@ -64,3 +64,5 @@ $$ The effect on the rest of the stack is: * **Right shift** starting from position $0$. + +**WARNING:** This is a best effort instruction, since given the same program, changes in NOOP padding (which do not change the program commitment) will change the number of rows in the trace (and hence the value of `clk` at various points in the program). Hence, the value returned by `CLK` should be treated as non-deterministic and attacker-controlled (up to the amount of padding allowed by the padding-related constraints). diff --git a/docs/src/design/stack/u32_ops.md b/docs/src/design/stack/u32_ops.md index 2d17cb4184..909197092b 100644 --- a/docs/src/design/stack/u32_ops.md +++ b/docs/src/design/stack/u32_ops.md @@ -121,6 +121,10 @@ $$ s_1' = h_2 \text{ | degree} = 1 $$ +$$ +h_3 = 0 \text{ | degree} = 1 +$$ + In addition to the above constraints, we also need to verify that values in $h_0, ..., h_3$ are smaller than $2^{16}$, which we can do using 16-bit range checks as described [previously](#range-checks). The effect of this operation on the rest of the stack is: @@ -148,6 +152,10 @@ $$ s_1' = h_2 \text{ | degree} = 1 $$ +$$ +h_3 = 0 \text{ | degree} = 1 +$$ + In addition to the above constraints, we also need to verify that values in $h_0, ..., h_3$ are smaller than $2^{16}$, which we can do using 16-bit range checks as described [previously](#range-checks). The effect of this operation on the rest of the stack is: diff --git a/docs/src/performance.md b/docs/src/performance.md index 451749107b..4a08fa752c 100644 --- a/docs/src/performance.md +++ b/docs/src/performance.md @@ -5,71 +5,54 @@ sidebar_position: 4 # Performance -> **Note:** The benchmark data in this document is currently outdated. The proving stack has recently -transitioned from Winterfell to Plonky3, and these numbers should be refreshed. - -The benchmarks below should be viewed only as a rough guide for expected future performance. The reasons for this are twofold: -1. Not all constraints have been implemented yet, and we expect that there will be some slowdown once constraint evaluation is completed. -2. Many optimizations have not been applied yet, and we expect that there will be some speedup once we dedicate some time to performance optimizations. - -Overall, we don't expect the benchmarks to change significantly, but there will definitely be some deviation from the below numbers in the future. +The benchmarks below should be viewed only as a rough guide for expected future performance. The reasons that many optimizations have not been applied yet, and we expect that there will be some speedup once we dedicate some time to performance optimizations. A few general notes on performance: -* Execution time is dominated by proof generation time. In fact, the time needed to run the program is usually under 1% of the time needed to generate the proof. -* Proof verification time is really fast. In most cases it is under 1 ms, but sometimes gets as high as 2 ms or 3 ms. -* Proof generation process is dynamically adjustable. In general, there is a trade-off between execution time, proof size, and security level (i.e. for a given security level, we can reduce proof size by increasing execution time, up to a point). -* Both proof generation and proof verification times are greatly influenced by the hash function used in the STARK protocol. In the benchmarks below, we use BLAKE3, which is a really fast hash function. +- Execution time is dominated by proof generation time. In fact, the time needed to run the program is usually under 0.01% of the time needed to generate the proof. +- Proof verification time is really fast. In most cases it is under 1 ms, but sometimes gets as high as 2 ms or 3 ms. +- Proof generation process is dynamically adjustable. In general, there is a trade-off between execution time, proof size, and security level (i.e. for a given security level, we can reduce proof size by increasing execution time, up to a point). +- Both proof generation and proof verification times are greatly influenced by the hash function used in the STARK protocol. In the benchmarks below, we use BLAKE3, which is a really fast hash function. ## Single-core prover performance -When executed on a single CPU core, the current version of Miden VM operates at around 20 - 25 KHz. In the benchmarks below, the VM executes a Fibonacci calculator program on Apple M1 Pro CPU in a single thread. The generated proofs have a target security level of 96 bits. - -| VM cycles | Execution time | Proving time | RAM consumed | Proof size | -| :-------------: | :------------: | :----------: | :-----------: | :--------: | -| 210 | 1 ms | 60 ms | 20 MB | 46 KB | -| 212 | 2 ms | 180 ms | 52 MB | 56 KB | -| 214 | 8 ms | 680 ms | 240 MB | 65 KB | -| 216 | 28 ms | 2.7 sec | 950 MB | 75 KB | -| 218 | 81 ms | 11.4 sec | 3.7 GB | 87 KB | -| 220 | 310 ms | 47.5 sec | 14 GB | 100 KB | -As can be seen from the above, proving time roughly doubles with every doubling in the number of cycles, but proof size grows much slower. +When executed on a single CPU core, the current version of Miden VM operates at around 20 - 25 KHz. In the benchmarks below, the VM executes a [Blake3 example](miden-vm/masm-examples/hashing/blake3_1to1/) program on Apple M4 Max CPU in a single thread. The generated proofs have a target security level of 96 bits. -We can also generate proofs at a higher security level. The cost of doing so is roughly doubling of proving time and roughly 40% increase in proof size. In the benchmarks below, the same Fibonacci calculator program was executed on Apple M1 Pro CPU at 128-bit target security level: +| VM cycles | Execution time | Proving time | RAM consumed | Proof size | +| :------------: | :------------: | :----------: | :----------: | :--------: | +| 214 | 0.3 ms | 885 ms | 200 MB | 80 KB | +| 216 | 0.7 ms | 3.6 sec | 750 MB | 100 KB | +| 218 | 1.2 ms | 14.7 sec | 2.9 GB | 116 KB | +| 220 | 11.1 ms | 59 sec | 11 GB | 136 KB | -| VM cycles | Execution time | Proving time | RAM consumed | Proof size | -| :-------------: | :------------: | :----------: | :-----------: | :--------: | -| 210 | 1 ms | 120 ms | 30 MB | 61 KB | -| 212 | 2 ms | 460 ms | 106 MB | 77 KB | -| 214 | 8 ms | 1.4 sec | 500 MB | 90 KB | -| 216 | 27 ms | 4.9 sec | 2.0 GB | 103 KB | -| 218 | 81 ms | 20.1 sec | 8.0 GB | 121 KB | -| 220 | 310 ms | 90.3 sec | 20.0 GB | 138 KB | +As can be seen from the above, proving time roughly doubles with every doubling in the number of cycles, but proof size grows much slower. ## Multi-core prover performance -STARK proof generation is massively parallelizable. Thus, by taking advantage of multiple CPU cores we can dramatically reduce proof generation time. For example, when executed on an 8-core CPU (Apple M1 Pro), the current version of Miden VM operates at around 100 KHz. And when executed on a 64-core CPU (Amazon Graviton 3), the VM operates at around 250 KHz. -In the benchmarks below, the VM executes the same Fibonacci calculator program for 220 cycles at 96-bit target security level: +STARK proof generation is massively parallelizable. Thus, by taking advantage of multiple CPU cores we can dramatically reduce proof generation time. For example, when executed on an 16-core CPU (Apple M4 Max), the current version of Miden VM operates at around 170 KHz. And when executed on a 64-core CPU (Amazon Graviton 4), the VM operates at around 200 KHz. + +In the benchmarks below, the VM executes the same Blake3 example program for 220 cycles at 96-bit target security level: | Machine | Execution time | Proving time | Execution % | Implied Frequency | | ------------------------------ | :------------: | :----------: | :---------: | :---------------: | -| Apple M1 Pro (16 threads) | 310 ms | 7.0 sec | 4.2% | 140 KHz | -| Apple M2 Max (16 threads) | 280 ms | 5.8 sec | 4.5% | 170 KHz | -| AMD Ryzen 9 5950X (16 threads) | 270 ms | 10.0 sec | 2.6% | 100 KHz | -| Amazon Graviton 3 (64 threads) | 330 ms | 3.6 sec | 8.5% | 265 KHz | - -### Recursive proofs -Proofs in the above benchmarks are generated using BLAKE3 hash function. While this hash function is very fast, it is not very efficient to execute in Miden VM. Thus, proofs generated using BLAKE3 are not well-suited for recursive proof verification. To support efficient recursive proofs, we need to use an arithmetization-friendly hash function. Miden VM natively supports Poseidon2, which is one such hash function. One of the downsides of arithmetization-friendly hash functions is that they are considerably slower than regular hash functions. - -In the benchmarks below we execute the same Fibonacci calculator program for 220 cycles at 96-bit target security level using Poseidon2 hash function instead of BLAKE3: - -| Machine | Execution time | Proving time | Proving time (HW) | -| ------------------------------ | :------------: | :----------: | :---------------: | -| Apple M1 Pro (16 threads) | 310 ms | 94.3 sec | 42.0 sec | -| Apple M2 Max (16 threads) | 280 ms | 75.1 sec | 20.9 sec | -| AMD Ryzen 9 5950X (16 threads) | 270 ms | 59.3 sec | | -| Amazon Graviton 3 (64 threads) | 330 ms | 21.7 sec | 14.9 sec | - -In the above, proof generation on some platforms can be hardware-accelerated. Specifically: - -* On Apple M1/M2 platforms the built-in GPU is used for a part of proof generation process. +| Apple M1 Pro (16 threads) | 14.5 ms | 14.7 sec | 0.1% | 70 KHz | +| Apple M4 Max (16 threads) | 6 ms | 5.9 sec | 0.2% | 170 KHz | +| Amazon Graviton 4 (64 threads) | 11 ms | 4.9 sec | 0.2% | 205 KHz | +| AMD EPYC 9R45 (64 threads) | 7.5 ms | 3.7 sec | 0.2% | 270 KHz | +| AMD Ryzen 9 9950X (16 threads) | 7.2 ms | 7.2 sec | 0.1% | 145 KHz | +| AMD Ryzen 9 9950X (32 threads) | 6.5 ms | 6.5 sec | 0.1% | 161 KHz | + +## Recursion-friendly proofs + +Proofs in the above benchmarks are generated using BLAKE3 hash function. While this hash function is very fast, it is not very efficient to execute in Miden VM. Thus, proofs generated using BLAKE3 are not well-suited for recursive proof verification. To support efficient recursive proofs, we need to use an arithmetization-friendly hash function. Miden VM natively supports Poseidon2, which is one such hash function. One of the downsides of arithmetization-friendly hash functions is that they are noticeably slower than regular hash functions. + +In the benchmarks below we execute the same Blake3 example program for 220 cycles at 96-bit target security level using Poseidon2 hash function instead of BLAKE3: + +| Machine | Execution time | Proving time | Slowdown vs BLAKE3 | +| ------------------------------ | :------------: | :----------: | :----------------: | +| Apple M1 Pro (16 threads) | 14.5 ms | 31.9 sec | 2.2x | +| Apple M4 Max (16 threads) | 6 ms | 10.1 sec | 1.7x | +| Amazon Graviton 4 (64 threads) | 11 ms | 7.7 sec | 1.6x | +| AMD EPYC 9R45 (64 threads) | 7.5 ms | 6.9 sec | 1.9x | +| AMD Ryzen 9 9950X (16 threads) | 7.2 ms | 16.0 sec | 2.2x | +| AMD Ryzen 9 9950X (32 threads) | 6.5 ms | 12.9 sec | 2.0x | diff --git a/docs/src/user_docs/assembly/code_organization.md b/docs/src/user_docs/assembly/code_organization.md index 915d48e46f..50ca7b0932 100644 --- a/docs/src/user_docs/assembly/code_organization.md +++ b/docs/src/user_docs/assembly/code_organization.md @@ -384,6 +384,15 @@ end Note that nothing currently validates that a `u8` value passed as an instance of `Level` is actually one of those three constants, that is up to you. Instead, the `enum` syntax is intended to provide more semantic information for readers of the code, and to better express the relationship between the type and the constants in question. +Because enum variants are expanded into module-level constants, variant names must be unique across all enums (and constants) within the same module. For example, the following will produce a compile-time error because `OK` is defined by both enums: + +``` +enum Status : u8 { OK, ERR } +enum Health : u8 { OK, CRIT } # error: symbol conflict for `OK` +``` + +If you need similar variant names in different enums, consider placing each enum in its own module, or choosing distinct names for the variants. + #### Type signatures Procedure type signatures are expressed using familiar function type syntax, e.g.: diff --git a/docs/src/user_docs/assembly/cryptographic_operations.md b/docs/src/user_docs/assembly/cryptographic_operations.md index 2663e3601a..d17c0fa915 100644 --- a/docs/src/user_docs/assembly/cryptographic_operations.md +++ b/docs/src/user_docs/assembly/cryptographic_operations.md @@ -7,7 +7,7 @@ sidebar_position: 9 Miden assembly provides a set of instructions for performing common cryptographic operations. These instructions are listed in the table below. ### Hashing and Merkle trees -[Poseidon2](https://eprint.iacr.org/2023/323) is the native hash function of Miden VM. The parameters of the hash function were chosen to provide 128-bit security level against preimage and collision attacks. The function operates over a 12-element state (rate 8, capacity 4). Internally, a permutation is modeled as 31 step transitions, but the VM exposes it as a single-cycle `hperm` operation for efficient hashing. +[Poseidon2](https://eprint.iacr.org/2023/323) is the native hash function of Miden VM. The parameters of the hash function were chosen to provide 128-bit security level against preimage and collision attacks. The function operates over a 12-element state (rate 8, capacity 4). Internally, the hasher chiplet tracks the permutation as 31 Poseidon2 step transitions packed into a 16-row cycle, but the VM exposes it as a single-cycle `hperm` operation for efficient hashing. | Instruction | Stack_input | Stack_output | Notes | | -------------------------------- | ------------------ | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | @@ -100,7 +100,8 @@ The following instructions are designed mainly for use in recursive verification | eval_circuit
- *(1 cycle)* | [ptr, n_read, n_eval, ...] | [ptr, n_read, n_eval, ...] | Evaluates an arithmetic circuit, and checks that its output is equal to zero. `ptr` specifies the memory address at which the circuit description is stored with the number of input extension field elements specified by `n_read` and the number of evaluation gates, encoded as base field elements, specified by `n_eval`. | | horner_eval_base
- *(1 cycle)* | [c7, c6, c5, c4, c3, c2, c1, c0, - , - , - , - , - , alpha_addr, acc1, acc0, ...] | [c7, c6, c5, c4, c3, c2, c1, c0, - , - , - , - , - , alpha_addr, acc1', acc0', ...] | Performs 8 steps of the Horner evaluation method to update the accumulator using evaluation point `alpha` read from memory at `alpha_addr` and `alpha_addr + 1`. Computes `acc' = (((((((acc * alpha + c0) * alpha + c1) * alpha + c2) * alpha + c3) * alpha + c4) * alpha + c5) * alpha + c6) * alpha + c7`. | | horner_eval_ext
- *(1 cycle)* | [c3_1, c3_0, c2_1, c2_0, c1_1, c1_0, c0_1, c0_0, - , - , - , - , - , alpha_addr, acc1, acc0, ...] | [c3_1, c3_0, c2_1, c2_0, c1_1, c1_0, c0_1, c0_0, - , - , - , - , - , alpha_addr, acc1', acc0', ...] | Performs 4 steps of the Horner evaluation method on a polynomial with coefficients over the quadratic extension field using evaluation point `alpha` read from memory at `alpha_addr` and `alpha_addr + 1`. Computes `acc' = (((acc * alpha + c0) * alpha + c1) * alpha + c2) * alpha + c3` where coefficients are extension field elements `c0 = (c0_1, c0_0)`, `c1 = (c1_1, c1_0)`, `c2 = (c2_1, c2_0)`, `c3 = (c3_1, c3_0)`. | -| log_precompile
- *(1 cycle)* | [COMM, TAG, ...] | [R1, R0, CAP_NEXT, ...] | Absorbs words `TAG` and `COMM` into the precompile sponge.
The hasher computes `[CAP_NEXT, R0, R1] = Poseidon2([CAP_PREV, TAG, COMM])` and updates the processor's precompile sponge capacity.
The top 3 stack words are replaced with `[R1, R0, CAP_NEXT]`, and callers typically drop them right away. | +| log_precompile
- *(1 cycle)* | [COMM, TAG, PAD, ...] | [R0, R1, CAP_NEXT, ...] | Absorbs words `TAG` and `COMM` into the precompile sponge.
The hasher computes `[R0, R1, CAP_NEXT] = Poseidon2([COMM, TAG, CAP_PREV])` and updates the processor's precompile sponge capacity. The `PAD` word on the stack is required as scratch space for the capacity input.
The top 3 stack words are replaced with `[R0, R1, CAP_NEXT]`, and callers typically drop them right away. | +| crypto_stream
- *(1 cycle)* | [rate(8), cap(4), src_ptr, dst_ptr, ...] | [ciphertext(8), cap(4), src_ptr+8, dst_ptr+8, ...] | Performs one Poseidon2-sponge keystream step against memory: loads two words from `src_ptr`, adds the rate (top 8 stack elements) element-wise to produce ciphertext, writes ciphertext to `dst_ptr`, replaces the rate on the stack with the ciphertext, preserves capacity, and increments both pointers by 8. Used as the primitive underlying `miden::core::crypto::aead`. | ### FRI folding diff --git a/docs/src/user_docs/assembly/field_operations.md b/docs/src/user_docs/assembly/field_operations.md index 53acaf5624..1ab540d2e4 100644 --- a/docs/src/user_docs/assembly/field_operations.md +++ b/docs/src/user_docs/assembly/field_operations.md @@ -28,19 +28,21 @@ The message is hashed and turned into a field element. If the error code is omit ### Arithmetic and Boolean operations -The arithmetic operations below are performed in a 64-bit [prime field](https://en.wikipedia.org/wiki/Finite_field) defined by modulus $p = 2^{64} - 2^{32} + 1$. This means that overflow happens after a value exceeds $p$. Also, the result of divisions may appear counter-intuitive because divisions are defined via inversions. +The arithmetic operations below are performed in a 64-bit [prime field](https://en.wikipedia.org/wiki/Finite_field) defined by modulus $p = 2^{64} - 2^{32} + 1$. This means that overflow happens after a value exceeds $p$. + +> **Warning:** `div` performs *field division*, not integer floor division. Field division computes $a \cdot b^{-1} \bmod p$, which bears no relation to $\lfloor a / b \rfloor$ and will produce unexpected results for most integer use cases. For integer floor division, use [`u32div`](./u32_operations.md) instead. | Instruction | Stack_input | Stack_output | Notes | | ------------------------------------------------------------------------------ | ----------- | ------------- | ------------------------------------------------------------------------------------------------------------ | | add
- *(1 cycle)*
add.*b*
- *(1-2 cycle)* | [b, a, ...] | [c, ...] | $c \leftarrow (a + b) \mod p$ | | sub
- *(2 cycles)*
sub.*b*
- *(2 cycles)* | [b, a, ...] | [c, ...] | $c \leftarrow (a - b) \mod p$ | | mul
- *(1 cycle)*
mul.*b*
- *(2 cycles)* | [b, a, ...] | [c, ...] | $c \leftarrow (a \cdot b) \mod p$ | -| div
- *(2 cycles)*
div.*b*
- *(2 cycles)* | [b, a, ...] | [c, ...] | $c \leftarrow (a \cdot b^{-1}) \mod p$
Fails if $b = 0$ | +| div
- *(2 cycles)*
div.*b*
- *(2 cycles)* | [b, a, ...] | [c, ...] | $c \leftarrow (a \cdot b^{-1}) \mod p$
Fails if $b = 0$
**Note:** this is field division, not integer floor division. Use [`u32div`](./u32_operations.md) for floor division. | | neg
- *(1 cycle)* | [a, ...] | [b, ...] | $b \leftarrow -a \mod p$ | | inv
- *(1 cycle)* | [a, ...] | [b, ...] | $b \leftarrow a^{-1} \mod p$
Fails if $a = 0$ | | pow2
- *(16 cycles)* | [a, ...] | [b, ...] | $b \leftarrow 2^a$
Fails if $a > 63$ | | exp.*uxx*
- *(9 + xx cycles)*
exp.*b*
- *(9 + log2(b) cycles)* | [b, a, ...] | [c, ...] | $c \leftarrow a^b$
Fails if xx is outside [0, 63)
exp is equivalent to exp.u64 and needs 73 cycles | -| ilog2
- *(44 cycles)* | [a, ...] | [b, ...] | $b \leftarrow \lfloor{log_2{a}}\rfloor$
Fails if $a = 0 $ | +| ilog2
- *(66 cycles)* | [a, ...] | [b, ...] | $b \leftarrow \lfloor{log_2{a}}\rfloor$
Fails if $a = 0 $ | | not
- *(1 cycle)* | [a, ...] | [b, ...] | $b \leftarrow 1 - a$
Fails if $a > 1$ | | and
- *(1 cycle)* | [b, a, ...] | [c, ...] | $c \leftarrow a \cdot b$
Fails if $max(a, b) > 1$ | | or
- *(1 cycle)* | [b, a, ...] | [c, ...] | $c \leftarrow a + b - a \cdot b$
Fails if $max(a, b) > 1$ | @@ -56,7 +58,7 @@ The arithmetic operations below are performed in a 64-bit [prime field](https:// | lte
- *(18 cycles)*
lte.*b*
- *(19 cycles)* | [b, a, ...] | [c, ...] | $c \leftarrow \begin{cases} 1, & \text{if}\ a \le b 0, & \text{otherwise}\ \end{cases}$ | | gt
- *(16 cycles)*
gt.*b*
- *(17 cycles)* | [b, a, ...] | [c, ...] | $c \leftarrow \begin{cases} 1, & \text{if}\ a > b 0, & \text{otherwise}\ \end{cases}$ | | gte
- *(17 cycles)*
gte.*b*
- *(18 cycles)* | [b, a, ...] | [c, ...] | $c \leftarrow \begin{cases} 1, & \text{if}\ a \ge b 0, & \text{otherwise}\ \end{cases}$ | -| is_odd
- *(5 cycles)* | [a, ...] | [b, ...] | $b \leftarrow \begin{cases} 1, & \text{if}\ a \text{ is odd} 0, & \text{otherwise}\ \end{cases}$ | +| is_odd
- *(6 cycles)* | [a, ...] | [b, ...] | $b \leftarrow \begin{cases} 1, & \text{if}\ a \text{ is odd} 0, & \text{otherwise}\ \end{cases}$ | | eqw
- *(15 cycles)* | [A, B, ...] | [c, A, B, ...] | $c \leftarrow \begin{cases} 1, & \text{if}\ a_i = b_i \; \forall i \in \{0, 1, 2, 3\} 0, & \text{otherwise}\ \end{cases}$ | ### Extension Field Operations diff --git a/docs/src/user_docs/assembly/instruction_reference.md b/docs/src/user_docs/assembly/instruction_reference.md index be4c25f2aa..114b6a8683 100644 --- a/docs/src/user_docs/assembly/instruction_reference.md +++ b/docs/src/user_docs/assembly/instruction_reference.md @@ -20,7 +20,7 @@ This page provides a comprehensive reference for Miden Assembly instructions. | `eq`
`eq.b` | `[b, a, ...]` | `[c, ...]` | 1
1-2 | $$c = \begin{cases} 1, & \text{if } a = b 0, & \text{otherwise} \end{cases}$$ | | `neq`
`neq.b` | `[b, a, ...]` | `[c, ...]` | 2
2-3 | $$c = \begin{cases} 1, & \text{if } a \neq b 0, & \text{otherwise} \end{cases}$$ | | `eqw` | `[A, B, ...]` | `[c, A, B, ...]` | 15 | $$c = \begin{cases} 1, & \text{if } a_i = b_i\ \forall i \in \{0,1,2,3\} 0, & \text{otherwise} \end{cases}$$ | -| `is_odd` | `[a, ...]` | `[b, ...]` | 5 | $$b = \begin{cases} 1, & \text{if $a$ is odd} 0, & \text{otherwise} \end{cases}$$ | +| `is_odd` | `[a, ...]` | `[b, ...]` | 6 | $$b = \begin{cases} 1, & \text{if $a$ is odd} 0, & \text{otherwise} \end{cases}$$ | ### Assertions and Tests @@ -40,12 +40,12 @@ _Note: Assertions can be parameterized with an error message (e.g., assert.err=" | `add`
`add.b` | `[b, a, ...]` | `[c, ...]` | 1
1-2 | $c = (a + b) \bmod p$ | | `sub`
`sub.b` | `[b, a, ...]` | `[c, ...]` | 2
2 | $c = (a - b) \bmod p$ | | `mul`
`mul.b` | `[b, a, ...]` | `[c, ...]` | 1
2 | $c = (a \cdot b) \bmod p$ | -| `div`
`div.b` | `[b, a, ...]` | `[c, ...]` | 2
2 | $c = (a \cdot b^{-1}) \bmod p$. Fails if $b = 0$. | +| `div`
`div.b` | `[b, a, ...]` | `[c, ...]` | 2
2 | $c = (a \cdot b^{-1}) \bmod p$. Fails if $b = 0$. **Field division** — not integer floor division. Use `u32div` for floor division. | | `neg` | `[a, ...]` | `[b, ...]` | 1 | $b = -a \bmod p$ | | `inv` | `[a, ...]` | `[b, ...]` | 1 | $b = a^{-1} \bmod p$. Fails if $a = 0$. | | `pow2` | `[a, ...]` | `[b, ...]` | 16 | $b = 2^a$. Fails if $a > 63$. | | `exp.uxx`
`exp.b` | `[b, a, ...]` | `[c, ...]` | 9+xx
9+log2(b) | $c = a^b$. Fails if $xx$ is outside $[0, 63)$. `exp` is `exp.u64` (73 cycles). | -| `ilog2` | `[a, ...]` | `[b, ...]` | 44 | $b = \lfloor \log_2(a) \rfloor$. Fails if $a = 0$. | +| `ilog2` | `[a, ...]` | `[b, ...]` | 66 | $b = \lfloor \log_2(a) \rfloor$. Fails if $a = 0$. | | `not` | `[a, ...]` | `[b, ...]` | 1 | $b = 1 - a$. Fails if $a > 1$. | | `and` | `[b, a, ...]` | `[c, ...]` | 1 | $c = a \cdot b$. Fails if $\max(a, b) > 1$. | | `or` | `[b, a, ...]` | `[c, ...]` | 1 | $c = a + b - a \cdot b$. Fails if $\max(a, b) > 1$. | @@ -98,7 +98,7 @@ _Note: Assertions can be parameterized with an error message (e.g., assert.err=" | `u32wrapping_mul`
`u32wrapping_mul.b` | `[b, a, ...]` | `[c, ...]` | 2
3-4 | $c = (a \cdot b) \bmod 2^{32}$. Undefined if $\max(a,b) \geq 2^{32}$. | | `u32widening_madd` | `[b, a, c, ...]` | `[d, e, ...]` | 1 | $d = (a \cdot b+c) \bmod 2^{32}$, $e = \lfloor(a \cdot b+c) / 2^{32}\rfloor$. Undefined if $\max(a,b,c) \geq 2^{32}$. | | `u32wrapping_madd` | `[b, a, c, ...]` | `[d, ...]` | 3 | $d = (a \cdot b+c) \bmod 2^{32}$. Undefined if $\max(a,b,c) \geq 2^{32}$. | -| `u32div`
`u32div.b` | `[b, a, ...]` | `[d, c, ...]` | 2
3-4 | $c = \lfloor a/b \rfloor$, $d = a \bmod b$. Fails if $b=0$. Undefined if $\max(a,b) \geq 2^{32}$. | +| `u32div`
`u32div.b` | `[b, a, ...]` | `[c, ...]` | 2
3-4 | $c = \lfloor a/b \rfloor$. Fails if $b=0$. Undefined if $\max(a,b) \geq 2^{32}$. | | `u32mod`
`u32mod.b` | `[b, a, ...]` | `[c, ...]` | 3
4-5 | $c = a \bmod b$. Fails if $b=0$. Undefined if $\max(a,b) \geq 2^{32}$. | | `u32divmod`
`u32divmod.b` | `[b, a, ...]` | `[d, c, ...]` | 1
2-3 | $c = \lfloor a/b \rfloor$, $d = a \bmod b$. Fails if $b=0$. Undefined if $\max(a,b) \geq 2^{32}$. | @@ -110,14 +110,14 @@ _Note: Assertions can be parameterized with an error message (e.g., assert.err=" | `u32or`
`u32or.b` | `[b, a, ...]` | `[c, ...]` | 6
7 | Bitwise OR. Fails if $\max(a,b) \geq 2^{32}$. | | `u32xor`
`u32xor.b` | `[b, a, ...]` | `[c, ...]` | 1
2 | Bitwise XOR. Fails if $\max(a,b) \geq 2^{32}$. | | `u32not`
`u32not.a` | `[a, ...]` | `[b, ...]` | 5
6 | Bitwise NOT. Fails if $a \geq 2^{32}$. | -| `u32shl`
`u32shl.b` | `[b, a, ...]` | `[c, ...]` | 18
3 | $c = (a \cdot 2^b) \bmod 2^{32}$. Undefined if $a \geq 2^{32}$ or $b > 31$. | -| `u32shr`
`u32shr.b` | `[b, a, ...]` | `[c, ...]` | 18
3 | $c = \lfloor a / 2^b \rfloor$. Undefined if $a \geq 2^{32}$ or $b > 31$. | +| `u32shl`
`u32shl.b` | `[b, a, ...]` | `[c, ...]` | 19
4 | $c = (a \cdot 2^b) \bmod 2^{32}$. Undefined if $a \geq 2^{32}$ or $b > 31$. | +| `u32shr`
`u32shr.b` | `[b, a, ...]` | `[c, ...]` | 20
5 | $c = \lfloor a / 2^b \rfloor$. Undefined if $a \geq 2^{32}$ or $b > 31$. | | `u32rotl`
`u32rotl.b` | `[b, a, ...]` | `[c, ...]` | 18
3 | Rotate left. Undefined if $a \geq 2^{32}$ or $b > 31$. | -| `u32rotr`
`u32rotr.b` | `[b, a, ...]` | `[c, ...]` | 23
3 | Rotate right. Undefined if $a \geq 2^{32}$ or $b > 31$. | -| `u32popcnt` | `[a, ...]` | `[b, ...]` | 33 | Population count (Hamming weight). Undefined if $a \geq 2^{32}$. | -| `u32clz` | `[a, ...]` | `[b, ...]` | 42 | Count leading zeros. Undefined if $a \geq 2^{32}$. | +| `u32rotr`
`u32rotr.b` | `[b, a, ...]` | `[c, ...]` | 22
3 | Rotate right. Undefined if $a \geq 2^{32}$ or $b > 31$. | +| `u32popcnt` | `[a, ...]` | `[b, ...]` | 32 | Population count (Hamming weight). Undefined if $a \geq 2^{32}$. | +| `u32clz` | `[a, ...]` | `[b, ...]` | 48 | Count leading zeros. Undefined if $a \geq 2^{32}$. | | `u32ctz` | `[a, ...]` | `[b, ...]` | 34 | Count trailing zeros. Undefined if $a \geq 2^{32}$. | -| `u32clo` | `[a, ...]` | `[b, ...]` | 41 | Count leading ones. Undefined if $a \geq 2^{32}$. | +| `u32clo` | `[a, ...]` | `[b, ...]` | 40 | Count leading ones. Undefined if $a \geq 2^{32}$. | | `u32cto` | `[a, ...]` | `[b, ...]` | 33 | Count trailing ones. Undefined if $a \geq 2^{32}$. | ### Comparison Operations @@ -186,9 +186,10 @@ Instructions for moving data between the stack and other sources like program co | Instruction | Stack Input | Stack Output | Cycles | Notes | | ------------ | ---------------- | ---------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `adv_push.n` | `[ ... ]` | `[a, ...]` | n | Pops `n` values from advice stack to operand stack (1st popped is deepest). Valid `n` in `1..=16`. Fails if advice stack has `< n` values. | +| `adv_push` | `[ ... ]` | `[a, ...]` | 1 | Pops 1 value from advice stack and pushes onto operand stack. Fails if advice stack is empty. | +| `adv_pushw` | `[ ... ]` | `[A, ...]` | 5 | Equivalent to `padw adv_loadw`. Pushes a word from advice onto the stack (grows by 4). Fails if advice stack has `< 4` values. | | `adv_loadw` | `[0,0,0,0, ...]` | `[A, ...]` | 1 | Pops word `A` (4 elements) from advice stack, overwrites top word of operand stack. Fails if advice stack has `< 4` values. | -| `adv_pipe` | `[C,B,A,a,...]` | `[E,D,A,a',...]` | 1 | Pops 2 words `[D,E]` from advice stack. Overwrites top 2 words of operand stack. Writes `[D,E]` to memory at `a` and `a+1`. `a' ← a+2`. Fails if advice stack has `< 8` values. | +| `adv_pipe` | `[A,B,C,a,...]` | `[A',B',C,a+8,...]` | 1 | Pops 2 words from advice stack, overwrites top 2 words (positions 0-7). C (positions 8-11) unchanged. Writes both words to memory at `a` and `a+4`. `a' = a+8`. Fails if advice stack has `< 8` values. | #### Injecting into Advice Provider (System Events - 3 cycles) @@ -220,11 +221,11 @@ Memory is 0-initialized. Addresses are absolute `[0, 2^32)`. Locals are stored a | Instruction | Stack Input | Stack Output | Cycles | Notes | | ---------------------------------------- | -------------------- | ---------------- | ------------ |--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `mem_load`
`mem_load.a` | `[a, ... ]` | `[v, ... ]` | 1
2 | `v ← mem[a]`. Pushes element from `mem[a]`. If `a` on stack, it's popped. Fails if `a >= 2^32`. | -| `mem_loadw_be`
`mem_loadw_be.a` | `[a, 0,0,0,0,...]` | `[A, ... ]` | 1
2 | `A ← mem[a..a+3]` (word, big-endian). Overwrites top 4 stack elements (`mem[a+3]` is top). If `a` on stack, it's popped. Fails if `a >= 2^32` or `a` not multiple of 4. | -| `mem_loadw_le`
`mem_loadw_le.a` | `[a, 0,0,0,0,...]` | `[A, ... ]` | 4
5 | `A ← mem[a..a+3]` (word, little-endian). Overwrites top 4 stack elements (`mem[a]` is top). Equivalent to `mem_loadw_be reversew`. If `a` on stack, it's popped. Fails if `a >= 2^32` or `a` not multiple of 4. | +| `mem_loadw_be`
`mem_loadw_be.a` | `[a, 0,0,0,0,...]` | `[A, ... ]` | 4
5 | `A ← mem[a..a+3]` (word, big-endian). Overwrites top 4 stack elements (`mem[a+3]` is top). Equivalent to `mem_loadw_le reversew`. If `a` on stack, it's popped. Fails if `a >= 2^32` or `a` not multiple of 4. | +| `mem_loadw_le`
`mem_loadw_le.a` | `[a, 0,0,0,0,...]` | `[A, ... ]` | 1
2 | `A ← mem[a..a+3]` (word, little-endian). Overwrites top 4 stack elements (`mem[a]` is top). If `a` on stack, it's popped. Fails if `a >= 2^32` or `a` not multiple of 4. | | `mem_store`
`mem_store.a` | `[a, v, ... ]` | `[ ... ]` | 2
3-4 | `mem[a] ← v`. Pops `v` to `mem[a]`. If `a` on stack, it's popped. Fails if `a >= 2^32`. | -| `mem_storew_be`
`mem_storew_be.a` | `[a, A, ... ]` | `[A, ... ]` | 1
2-3 | `mem[a..a+3] ← A`. Stores word `A` in big-endian order (top stack element at `mem[a+3]`). If `a` on stack, it's popped. Fails if `a >= 2^32` or `a` not multiple of 4. | -| `mem_storew_le`
`mem_storew_le.a` | `[a, A, ... ]` | `[A, ... ]` | 9
8-9 | `mem[a..a+3] ← A`. Stores word `A` in little-endian order (top stack element at `mem[a]`). Equivalent to `reversew mem_storew_be reversew`. If `a` on stack, it's popped. Fails if `a >= 2^32` or `a` not multiple of 4. | +| `mem_storew_be`
`mem_storew_be.a` | `[a, A, ... ]` | `[A, ... ]` | 9
8-9 | `mem[a..a+3] ← A`. Stores word `A` in big-endian order (top stack element at `mem[a+3]`). Equivalent to `reversew mem_storew_le reversew`. If `a` on stack, it's popped. Fails if `a >= 2^32` or `a` not multiple of 4. | +| `mem_storew_le`
`mem_storew_le.a` | `[a, A, ... ]` | `[A, ... ]` | 1
2-3 | `mem[a..a+3] ← A`. Stores word `A` in little-endian order (top stack element at `mem[a]`). If `a` on stack, it's popped. Fails if `a >= 2^32` or `a` not multiple of 4. | | `mem_stream` | `[R0, R1, C, a, ...]` | `[D, E, C, a', ...]` | 1 | `[D, E] ← [mem[a..a+3], mem[a+4..a+7]]`. `a' ← a+8`. Reads 2 sequential words from memory, replacing R0 and R1 of the sponge state. | #### Procedure Locals (Context-Specific) @@ -234,11 +235,11 @@ Locals are not 0-initialized. Max $2^{16}$ locals per procedure, $2^{31} - 1$ to | Instruction | Stack Input | Stack Output | Cycles | Notes | | ----------------- | ---------------- | ------------ | ------ | ------------------------------------------------------------------------------------------------------------- | | `loc_load.i` | `[ ... ]` | `[v, ... ]` | 5-6 | `v ← local[i]`. Pushes element from local memory at index `i`. | -| `loc_loadw_be.i` | `[0,0,0,0, ...]` | `[A, ... ]` | 5-6 | `A ← local[i..i+3]`. Reads word in big-endian order, `local[i+3]` is top of stack. Fails if `i` not multiple of 4. | -| `loc_loadw_le.i` | `[0,0,0,0, ...]` | `[A, ... ]` | 9-10 | `A ← local[i..i+3]`. Reads word in little-endian order, `local[i]` is top of stack. Equivalent to `loc_loadw_be reversew`. Fails if `i` not multiple of 4. | +| `loc_loadw_be.i` | `[0,0,0,0, ...]` | `[A, ... ]` | 6-7 | `A ← local[i..i+3]`. Reads word in big-endian order, `local[i+3]` is top of stack. Equivalent to `loc_loadw_le reversew`. Fails if `i` not multiple of 4. | +| `loc_loadw_le.i` | `[0,0,0,0, ...]` | `[A, ... ]` | 3-4 | `A ← local[i..i+3]`. Reads word in little-endian order, `local[i]` is top of stack. Fails if `i` not multiple of 4. | | `loc_store.i` | `[v, ... ]` | `[ ... ]` | 6-7 | `local[i] ← v`. Pops `v` to local memory at index `i`. | -| `loc_storew_be.i` | `[A, ... ]` | `[A, ... ]` | 5-6 | `local[i..i+3] ← A`. Stores word in big-endian order, top stack element at `local[i+3]`. | -| `loc_storew_le.i` | `[A, ... ]` | `[A, ... ]` | 13-14 | `local[i..i+3] ← A`. Stores word in little-endian order, top stack element at `local[i]`. Equivalent to `reversew loc_storew_be reversew`. | +| `loc_storew_be.i` | `[A, ... ]` | `[A, ... ]` | 9-10 | `local[i..i+3] ← A`. Stores word in big-endian order, top stack element at `local[i+3]`. Equivalent to `reversew loc_storew_le reversew`. | +| `loc_storew_le.i` | `[A, ... ]` | `[A, ... ]` | 3-4 | `local[i..i+3] ← A`. Stores word in little-endian order, top stack element at `local[i]`. | ## Cryptographic Operations @@ -255,6 +256,7 @@ Common cryptographic operations, including hashing and Merkle tree manipulations | `mtree_set` | `[d, i, R, V', ...]` | `[V, R', ...]` | 30 | Updates node in tree `R` at `d,i` to `V'`. Returns old value `V` and new root `R'`. Both trees in advice provider. | | `mtree_merge` | `[L, R, ...]` | `[M, ...]` | 16 | Merges Merkle trees with roots `L` (left) and `R` (right) into new tree `M`. Input trees retained. | | `mtree_verify` | `[V, d, i, R, ...]` | `[V,d,i,R,...]` | 1 | Verifies Merkle path for node `V` at depth `d`, index `i` for tree `R` (from advice provider).
_Can be parameterized with `err` code (e.g., `mtree_verify.err=123`). Default error code is 0._ | +| `crypto_stream` | `[rate(8), cap(4), src_ptr, dst_ptr, ...]` | `[ciphertext(8), cap(4), src_ptr+8, dst_ptr+8, ...]` | 1 | Poseidon2-sponge keystream step against memory: loads two words from `src_ptr`, adds the rate (top 8 stack elements) element-wise to produce ciphertext, writes ciphertext to `dst_ptr`, replaces rate on stack with ciphertext, preserves capacity, increments both pointers by 8. Primitive used by `miden::core::crypto::aead`. | ## Flow Control Operations @@ -327,7 +329,7 @@ Instructions for communicating with the host through events and tracing. | `emit.` | `[...]` | `[...]` | 3 | Emits an event with the specified `event_id` to the host. The net effect on the operand stack is no change (internally expands to `push. emit drop`). Immediate `event_id` must be defined via `const.ID=event("...")` or inlined as `emit.event("...")`. Events allow programs to communicate contextual information to the host for triggering appropriate actions. Example: `emit.event("foo")` or `emit.MY_EVENT` | | `emit` | `[event_id, ...]` | `[event_id, ...]` | 1 | Emits an event using the `event_id` from the top of the stack. The stack remains unchanged as the event_id is read without consuming it. This instruction reads the event ID from the stack but does not modify the stack depth. Example: with `push.1230` on stack, `emit` reads the event ID 1230 and executes the corresponding event handler. Note that event IDs in the range `0..256` are reserved for system events. | | `trace.` | `[...]` | `[...]` | 0 | Emits a trace with the specified `trace_id` to the host. Does not change the state of the operand stack. The `trace_id` can be any 32-bit value specified either directly or via a [named constant](./code_organization.md#constants). Only active when programs are run with tracing flag (`-t` or `--trace`), otherwise ignored. Example: `trace.123` or `trace.TRACE_ID_1` | -| `log_precompile` | `[COMM, TAG, PAD, ...]` | `[R1, R0, CAP_NEXT, ...]` | 1 | Absorbs a precompile commitment into the transcript used for deferred verification. Takes a precompile commitment (`TAG` and `COMM`) from the stack and performs an Poseidon2 permutation to update the transcript capacity (sponge capacity). Outputs `[R1, R0, CAP_NEXT]`; callers normally drop all three words immediately. See “Precompile flow” for initialization details. | +| `log_precompile` | `[COMM, TAG, PAD, ...]` | `[R0, R1, CAP_NEXT, ...]` | 1 | Absorbs a precompile commitment into the transcript used for deferred verification. Takes a precompile commitment (`TAG` and `COMM`) from the stack and performs an Poseidon2 permutation to update the transcript capacity (sponge capacity). Outputs `[R0, R1, CAP_NEXT]`; callers normally drop all three words immediately. See “Precompile flow” for initialization details. | ## Debugging Operations diff --git a/docs/src/user_docs/assembly/io_operations.md b/docs/src/user_docs/assembly/io_operations.md index dec614ca89..7d38d8561c 100644 --- a/docs/src/user_docs/assembly/io_operations.md +++ b/docs/src/user_docs/assembly/io_operations.md @@ -66,11 +66,12 @@ As mentioned above, nondeterministic inputs are provided to the VM via the advic | Instruction | Stack_input | Stack_output | Notes | | ----------------------------------- | ------------------ | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| adv_push._n_
- _(n cycles)_ | [ ... ] | [a, ... ] | $a \leftarrow advstack.pop()$
Pops $n$ values from the advice stack and pushes them onto the operand stack. Valid for $n \in \{1, ..., 16\}$.
Fails if the advice stack has fewer than $n$ values. | +| adv_push
- _(1 cycle)_ | [ ... ] | [a, ... ] | $a \leftarrow advstack.pop()$
Pops a single value from the advice stack and pushes it onto the operand stack.
Fails if the advice stack is empty. | +| adv_pushw
- _(5 cycles)_ | [ ... ] | [A, ... ] | Equivalent to `padw adv_loadw`.
Pushes a word (4 elements) from the advice stack onto the operand stack (grows stack by 4).
Fails if the advice stack has fewer than $4$ values. | | adv_loadw
- _(1 cycle)_ | [0, 0, 0, 0, ... ] | [A, ... ] | $A \leftarrow advstack.pop(4)$
Pop the next word (4 elements) from the advice stack and overwrites the first word of the operand stack (4 elements) with them.
Fails if the advice stack has fewer than $4$ values. | -| adv_pipe
- _(1 cycle)_ | [A, B, C, a, ... ] | [D, E, C, a', ... ] | $[D, E] \leftarrow [adv\_stack.pop(4), adv\_stack.pop(4)]$
$a' \leftarrow a + 8$
Pops the next two words from the advice stack, overwrites R0 and R1 of the sponge state and also writes these words into memory at address $a$ and $a + 4$.
Fails if the advice stack has fewer than $8$ values. | +| adv_pipe
- _(1 cycle)_ | [A, B, C, a, ... ] | [A', B', C, a+8, ... ] | Pops two words $A', B'$ from the advice stack. Overwrites the top two words of the operand stack (positions 0-7) with them. The third word $C$ (positions 8-11) is unchanged. Writes both words to memory at addresses $a$ and $a + 4$, then increments $a$ by 8.
Fails if the advice stack has fewer than $8$ values. | -> **Note**: The opcodes above always push data onto the operand stack so that the first element is placed deepest in the stack. For example, if the data on the stack is `a,b,c,d` and you use the opcode `adv_push.4`, the data will be `d,c,b,a` on your stack. This is also the behavior of the other opcodes. +> **Note**: When using multiple sequential `adv_push` instructions (e.g., `repeat.n adv_push end`), data is pushed so that the first element is placed deepest in the stack. For example, if the advice stack contains `a,b,c,d` and you use `repeat.4 adv_push end`, the operand stack will be `d,c,b,a`. The second category injects new data into the advice provider. These operations are called _system events_ and they affect only the advice provider state. That is, the state of all other VM components (e.g., stack, memory) are unaffected. Handling system events uses the same mechanism as standard events using `emit` (i.e., these instructions are executed in $3$ cycles). System events use direct numeric event IDs in the reserved range 0-255, while user-defined events use string-based `EventId::from_name()` derivation with unique, descriptive names following hierarchical naming conventions to avoid conflicts. @@ -98,13 +99,11 @@ Memory is guaranteed to be initialized to zeros. Thus, when reading from memory | Instruction | Stack_input | Stack_output | Notes | | ------------------------------------------------------------------------------------- | --------------------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | mem_load
- _(1 cycle)_
mem_load._a_
- _(2 cycles)_ | [a, ... ] | [v, ... ] | $v \leftarrow mem[a]$
Reads the field element from memory at address _a_, and pushes it onto the stack. If $a$ is provided via the stack, it is removed from the stack first.
Fails if $a \ge 2^{32}$ | -| mem_loadw
- _(1 cycle)_
mem_loadw._a_
- _(2 cycles)_ | [a, 0, 0, 0, 0, ... ] | [A, ... ] | $A \leftarrow mem[a..(a+4)]$
Reads a word from memory starting at address $a$ and overwrites top four stack elements with it, in reverse order, such that `mem[a+3]` is on top of the stack. If $a$ is provided via the stack, it is removed from the stack first.
Fails if $a \ge 2^{32}$, or if $a$ is not a multiple of 4 | -| mem_loadw_be
- _(1 cycles)_
mem_loadw_be._a_
- _(2 cycles)_ | [a, 0, 0, 0, 0, ... ] | [A, ... ] | $A \leftarrow mem[a..(a+4)]$
Reads a word from memory starting at address $a$ and overwrites top four stack elements with it in big-endian (reversed) order, such that `mem[a+3]` is on top of the stack. Equivalent to `mem_loadw`. If $a$ is provided via the stack, it is removed from the stack first.
Fails if $a \ge 2^{32}$, or if $a$ is not a multiple of 4 | -| mem_loadw_le
- _(4 cycles)_
mem_loadw_le._a_
- _(5 cycles)_ | [a, 0, 0, 0, 0, ... ] | [A, ... ] | $A \leftarrow mem[a..(a+4)]$
Reads a word from memory starting at address $a$ and overwrites top four stack elements with it in little-endian (memory) order, such that `mem[a]` is on top of the stack. Equivalent to `mem_loadw reversew`. If $a$ is provided via the stack, it is removed from the stack first.
Fails if $a \ge 2^{32}$, or if $a$ is not a multiple of 4 | +| mem_loadw_be
- _(4 cycles)_
mem_loadw_be._a_
- _(5 cycles)_ | [a, 0, 0, 0, 0, ... ] | [A, ... ] | $A \leftarrow mem[a..(a+4)]$
Reads a word from memory starting at address $a$ and overwrites top four stack elements with it in big-endian (reversed) order, such that `mem[a+3]` is on top of the stack. Equivalent to `mem_loadw_le reversew`. If $a$ is provided via the stack, it is removed from the stack first.
Fails if $a \ge 2^{32}$, or if $a$ is not a multiple of 4 | +| mem_loadw_le
- _(1 cycle)_
mem_loadw_le._a_
- _(2 cycles)_ | [a, 0, 0, 0, 0, ... ] | [A, ... ] | $A \leftarrow mem[a..(a+4)]$
Reads a word from memory starting at address $a$ and overwrites top four stack elements with it in little-endian (memory) order, such that `mem[a]` is on top of the stack. If $a$ is provided via the stack, it is removed from the stack first.
Fails if $a \ge 2^{32}$, or if $a$ is not a multiple of 4 | | mem_store
- _(2 cycles)_
mem_store._a_
- _(3-4 cycles)_ | [a, v, ... ] | [ ... ] | $v \rightarrow mem[a]$
Pops the top element off the stack and stores it in memory at address $a$. If $a$ is provided via the stack, it is removed from the stack first.
Fails if $a \ge 2^{32}$ | -| mem_storew
- _(1 cycle)_
mem_storew._a_
- _(2-3 cycles)_ | [a, A, ... ] | [A, ... ] | $A \rightarrow mem[a..(a+4)]$
Stores the top four elements of the stack in reverse order in memory starting at address $a$, such that the first element of `A` is placed at `mem[a+3]`. If $a$ is provided via the stack, it is removed from the stack first.
Fails if $a \ge 2^{32}$, or if $a$ is not a multiple of 4 | -| mem_storew_be
- _(1 cycles)_
mem_storew_be._a_
- _(2-3 cycles)_ | [a, A, ... ] | [A, ... ] | $A \rightarrow mem[a..(a+4)]$
Stores the top four elements of the stack in big-endian (reversed) order in memory starting at address $a$, such that the top of stack is placed at `mem[a+3]`. Equivalent to `mem_storew`. If $a$ is provided via the stack, it is removed from the stack first.
Fails if $a \ge 2^{32}$, or if $a$ is not a multiple of 4 | -| mem_storew_le
- _(9 cycles)_
mem_storew_le._a_
- _(8-9 cycles)_ | [a, A, ... ] | [A, ... ] | $A \rightarrow mem[a..(a+4)]$
Stores the top four elements of the stack in little-endian (memory) order in memory starting at address $a$, such that the top of stack is placed at `mem[a]`. Equivalent to `reversew mem_storew_be reversew`. If $a$ is provided via the stack, it is removed from the stack first.
Fails if $a \ge 2^{32}$, or if $a$ is not a multiple of 4 | +| mem_storew_be
- _(9 cycles)_
mem_storew_be._a_
- _(8-9 cycles)_ | [a, A, ... ] | [A, ... ] | $A \rightarrow mem[a..(a+4)]$
Stores the top four elements of the stack in big-endian (reversed) order in memory starting at address $a$, such that the top of stack is placed at `mem[a+3]`. Equivalent to `reversew mem_storew_le reversew`. If $a$ is provided via the stack, it is removed from the stack first.
Fails if $a \ge 2^{32}$, or if $a$ is not a multiple of 4 | +| mem_storew_le
- _(1 cycle)_
mem_storew_le._a_
- _(2-3 cycles)_ | [a, A, ... ] | [A, ... ] | $A \rightarrow mem[a..(a+4)]$
Stores the top four elements of the stack in little-endian (memory) order in memory starting at address $a$, such that the top of stack is placed at `mem[a]`. If $a$ is provided via the stack, it is removed from the stack first.
Fails if $a \ge 2^{32}$, or if $a$ is not a multiple of 4 | | mem_stream
- _(1 cycle)_ | [A, B, C, a, ... ] | [D, E, C, a', ... ] | $[D, E] \leftarrow [mem[a..(a+4)], mem[(a+4)..(a+8)]]$
$a' \leftarrow a + 8$
Read two sequential words from memory starting at address $a$ and overwrites R0 and R1 of the sponge state. | The second way to access memory is via procedure locals using the instructions listed below. These instructions are available only in procedure context. The number of locals available to a given procedure must be specified at [procedure declaration](./code_organization.md#procedures) time, and trying to access more locals than was declared will result in a compile-time error. A procedure can have at most $2^{16}$ locals, and the total number of locals available to all procedures at runtime is limited to $2^{31} - 1$. The assembler internally always rounds up the number of declared locals to the nearest multiple of 4. @@ -114,11 +113,11 @@ The second way to access memory is via procedure locals using the instructions l | Instruction | Stack_input | Stack_output | Notes | | -------------------------------------------- | ------------------ | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | loc_load._i_
- _(3-4 cycles)_ | [ ... ] | [v, ... ] | $v \leftarrow local[i]$
Reads a field element from local memory at index _i_, and pushes it onto the stack. | -| loc_loadw_be._i_
- _(3-4 cycles)_ | [0, 0, 0, 0, ... ] | [A, ... ] | $A \leftarrow local[i..(i+4)]$
Reads a word from local memory starting at index $i$ in big-endian (reversed) order, such that `local[i+3]` is placed at the top of the stack. Fails if $i$ is not a multiple of 4. | -| loc_loadw_le._i_
- _(7-8 cycles)_ | [0, 0, 0, 0, ... ] | [A, ... ] | $A \leftarrow local[i..(i+4)]$
Reads a word from local memory starting at index $i$ in little-endian (memory) order, such that `local[i]` is placed at the top of the stack. Equivalent to `loc_loadw_be reversew`. Fails if $i$ is not a multiple of 4. | +| loc_loadw_be._i_
- _(6-7 cycles)_ | [0, 0, 0, 0, ... ] | [A, ... ] | $A \leftarrow local[i..(i+4)]$
Reads a word from local memory starting at index $i$ in big-endian (reversed) order, such that `local[i+3]` is placed at the top of the stack. Equivalent to `loc_loadw_le reversew`. Fails if $i$ is not a multiple of 4. | +| loc_loadw_le._i_
- _(3-4 cycles)_ | [0, 0, 0, 0, ... ] | [A, ... ] | $A \leftarrow local[i..(i+4)]$
Reads a word from local memory starting at index $i$ in little-endian (memory) order, such that `local[i]` is placed at the top of the stack. Fails if $i$ is not a multiple of 4. | | loc_store._i_
- _(4-5 cycles)_ | [v, ... ] | [ ... ] | $v \rightarrow local[i]$
Pops the top element off the stack and stores it in local memory at index $i$. | -| loc_storew_be._i_
- _(3-4 cycles)_ | [A, ... ] | [A, ... ] | $A \rightarrow local[i..(i+4)]$
Stores the top four elements of the stack in local memory in big-endian (reversed) order starting at index $i$, such that the top of stack is placed at `local[i+3]`. | -| loc_storew_le._i_
- _(11-12 cycles)_ | [A, ... ] | [A, ... ] | $A \rightarrow local[i..(i+4)]$
Stores the top four elements of the stack in local memory in little-endian (memory) order starting at index $i$, such that the top of stack is placed at `local[i]`. Equivalent to `reversew loc_storew_be reversew`. | +| loc_storew_be._i_
- _(9-10 cycles)_ | [A, ... ] | [A, ... ] | $A \rightarrow local[i..(i+4)]$
Stores the top four elements of the stack in local memory in big-endian (reversed) order starting at index $i$, such that the top of stack is placed at `local[i+3]`. Equivalent to `reversew loc_storew_le reversew`. | +| loc_storew_le._i_
- _(3-4 cycles)_ | [A, ... ] | [A, ... ] | $A \rightarrow local[i..(i+4)]$
Stores the top four elements of the stack in local memory in little-endian (memory) order starting at index $i$, such that the top of stack is placed at `local[i]`. | Unlike regular memory, procedure locals are not guaranteed to be initialized to zeros. Thus, when working with locals, one must assume that before a local memory address has been written to, it contains "garbage". diff --git a/docs/src/user_docs/assembly/u32_operations.md b/docs/src/user_docs/assembly/u32_operations.md index 54ee8c6367..fbf77a900e 100644 --- a/docs/src/user_docs/assembly/u32_operations.md +++ b/docs/src/user_docs/assembly/u32_operations.md @@ -95,7 +95,7 @@ The message is hashed and turned into a field element. If the error code is omit | u32wrapping_mul
- *(2 cycles)*
u32wrapping_mul.*b*
- *(3-4 cycles)* | [b, a, ...] | [c, ...] | $c \leftarrow (a \cdot b) \mod 2^{32}$
Undefined if $max(a, b) \ge 2^{32}$ | | u32widening_madd
- *(1 cycle)* | [b, a, c, ...] | [d, e, ...] | $d \leftarrow (a \cdot b + c) \mod 2^{32}$
$e \leftarrow \lfloor(a \cdot b + c) / 2^{32}\rfloor$
Undefined if $max(a, b, c) \ge 2^{32}$ | | u32wrapping_madd
- *(3 cycles)* | [b, a, c, ...] | [d, ...] | $d \leftarrow (a \cdot b + c) \mod 2^{32}$
Undefined if $max(a, b, c) \ge 2^{32}$ | -| u32div
- *(2 cycles)*
u32div.*b*
- *(3-4 cycles)* | [b, a, ...] | [d, c, ...] | $c \leftarrow \lfloor a / b\rfloor$
$d \leftarrow a \mod b$
Fails if $b = 0$
Undefined if $max(a, b) \ge 2^{32}$ | +| u32div
- *(2 cycles)*
u32div.*b*
- *(3-4 cycles)* | [b, a, ...] | [c, ...] | $c \leftarrow \lfloor a / b\rfloor$
Fails if $b = 0$
Undefined if $max(a, b) \ge 2^{32}$ | | u32mod
- *(3 cycles)*
u32mod.*b*
- *(4-5 cycles)* | [b, a, ...] | [c, ...] | $c \leftarrow a \mod b$
Fails if $b = 0$
Undefined if $max(a, b) \ge 2^{32}$ | | u32divmod
- *(1 cycle)*
u32divmod.*b*
- *(2-3 cycles)* | [b, a, ...] | [d, c, ...] | $c \leftarrow \lfloor a / b\rfloor$
$d \leftarrow a \mod b$
Fails if $b = 0$
Undefined if $max(a, b) \ge 2^{32}$ | @@ -104,17 +104,17 @@ The message is hashed and turned into a field element. If the error code is omit | Instruction | Stack_input | Stack_output | Notes | | ------------------------------------------------------------------------------------- | -------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------ | | u32and
- *(1 cycle)*
u32and.*b*
- *(2 cycles)* | [b, a, ...] | [c, ...] | Computes $c$ as a bitwise `AND` of binary representations of $a$ and $b$.
Fails if $max(a,b) \ge 2^{32}$ | -| u32or
- *(6 cycle)s*
u32or.*b*
- *(7 cycles)* | [b, a, ...] | [c, ...] | Computes $c$ as a bitwise `OR` of binary representations of $a$ and $b$.
Fails if $max(a,b) \ge 2^{32}$ | +| u32or
- *(6 cycles)*
u32or.*b*
- *(7 cycles)* | [b, a, ...] | [c, ...] | Computes $c$ as a bitwise `OR` of binary representations of $a$ and $b$.
Fails if $max(a,b) \ge 2^{32}$ | | u32xor
- *(1 cycle)*
u32xor.*b*
- *(2 cycles)* | [b, a, ...] | [c, ...] | Computes $c$ as a bitwise `XOR` of binary representations of $a$ and $b$.
Fails if $max(a,b) \ge 2^{32}$ | | u32not
- *(5 cycles)*
u32not.*a*
- *(6 cycles)* | [a, ...] | [b, ...] | Computes $b$ as a bitwise `NOT` of binary representation of $a$.
Fails if $a \ge 2^{32}$ | -| u32shl
- *(18 cycles)*
u32shl.*b*
- *(3 cycles)* | [b, a, ...] | [c, ...] | $c \leftarrow (a \cdot 2^b) \mod 2^{32}$
Undefined if $a \ge 2^{32}$ or $b > 31$ | -| u32shr
- *(18 cycles)*
u32shr.*b*
- *(3 cycles)* | [b, a, ...] | [c, ...] | $c \leftarrow \lfloor a/2^b \rfloor$
Undefined if $a \ge 2^{32}$ or $b > 31$ | +| u32shl
- *(19 cycles)*
u32shl.*b*
- *(4 cycles)* | [b, a, ...] | [c, ...] | $c \leftarrow (a \cdot 2^b) \mod 2^{32}$
Undefined if $a \ge 2^{32}$ or $b > 31$ | +| u32shr
- *(20 cycles)*
u32shr.*b*
- *(5 cycles)* | [b, a, ...] | [c, ...] | $c \leftarrow \lfloor a/2^b \rfloor$
Undefined if $a \ge 2^{32}$ or $b > 31$ | | u32rotl
- *(18 cycles)*
u32rotl.*b*
- *(3 cycles)* | [b, a, ...] | [c, ...] | Computes $c$ by rotating a 32-bit representation of $a$ to the left by $b$ bits.
Undefined if $a \ge 2^{32}$ or $b > 31$ | -| u32rotr
- *(23 cycles)*
u32rotr.*b*
- *(3 cycles)* | [b, a, ...] | [c, ...] | Computes $c$ by rotating a 32-bit representation of $a$ to the right by $b$ bits.
Undefined if $a \ge 2^{32}$ or $b > 31$ | -| u32popcnt
- *(33 cycles)* | [a, ...] | [b, ...] | Computes $b$ by counting the number of set bits in $a$ (hamming weight of $a$).
Undefined if $a \ge 2^{32}$ | -| u32clz
- *(42 cycles)* | [a, ...] | [b, ...] | Computes $b$ as a number of leading zeros of $a$.
Undefined if $a \ge 2^{32}$ | +| u32rotr
- *(22 cycles)*
u32rotr.*b*
- *(3 cycles)* | [b, a, ...] | [c, ...] | Computes $c$ by rotating a 32-bit representation of $a$ to the right by $b$ bits.
Undefined if $a \ge 2^{32}$ or $b > 31$ | +| u32popcnt
- *(32 cycles)* | [a, ...] | [b, ...] | Computes $b$ by counting the number of set bits in $a$ (hamming weight of $a$).
Undefined if $a \ge 2^{32}$ | +| u32clz
- *(48 cycles)* | [a, ...] | [b, ...] | Computes $b$ as a number of leading zeros of $a$.
Undefined if $a \ge 2^{32}$ | | u32ctz
- *(34 cycles)* | [a, ...] | [b, ...] | Computes $b$ as a number of trailing zeros of $a$.
Undefined if $a \ge 2^{32}$ | -| u32clo
- *(41 cycles)* | [a, ...] | [b, ...] | Computes $b$ as a number of leading ones of $a$.
Undefined if $a \ge 2^{32}$ | +| u32clo
- *(40 cycles)* | [a, ...] | [b, ...] | Computes $b$ as a number of leading ones of $a$.
Undefined if $a \ge 2^{32}$ | | u32cto
- *(33 cycles)* | [a, ...] | [b, ...] | Computes $b$ as a number of trailing ones of $a$.
Undefined if $a \ge 2^{32}$ | diff --git a/docs/src/user_docs/core_lib/collections.md b/docs/src/user_docs/core_lib/collections.md index e1dcaed63f..aeec62e80e 100644 --- a/docs/src/user_docs/core_lib/collections.md +++ b/docs/src/user_docs/core_lib/collections.md @@ -15,12 +15,14 @@ Module `miden::core::collections::mmr` contains procedures for manipulating [Mer The following procedures are available to read data from and make updates to a Merkle Mountain Range. -| Procedure | Description | -| ----------- | ------------- | -| get | Loads the leaf at the absolute position `pos` in the MMR onto the stack. Valid range for `pos` is between $0$ and $2^{32} - 1$ (both inclusive). Inputs: `[pos, mmr_ptr, ...]`. Output: `[N, ...]`. Where `N` is the leaf loaded from the MMR whose memory location starts at `mmr_ptr`. | -| add | Adds a new leaf to the MMR. This will update the MMR peaks in the VM's memory and the advice provider with any merged nodes. Inputs: `[N, mmr_ptr, ...]`. Outputs: `[...]`. Where `N` is the leaf added to the MMR whose memory locations starts at `mmr_ptr`. | -| pack | Computes a commitment to the given MMR and copies the MMR to the Advice Map using the commitment as a key. Inputs: `[mmr_ptr, ...]`. Outputs: `[HASH, ...]`. | -| unpack | Writes the MMR who's peaks hash to `HASH` to the memory location pointed to by `mmr_ptr`. Inputs: `[HASH, mmr_ptr, ...]`. Outputs: `[...]`. Where: `HASH` is the MMR peak hash, the hash is expected to be padded to an even length and to have a minimum size of 16 elements. The advice map must contain a key with `HASH`, and its value is `[num_leaves, 0, 0, 0] \|\| hash_data`, and hash_data is the data used to computed `HASH`. `mmr_ptr` is the memory location where the MMR data will be written, starting with the MMR forest (the total count of its leaves) followed by its peaks. The memory location must be word-aligned. | +| Procedure | Description | +| ---------------------------- | ------------- | +| get | Loads the element at the absolute position `pos` in the MMR onto the stack. Valid range for `pos` is between $0$ and $2^{32} - 1$ (both inclusive), and `pos` must refer to an existing leaf: `pos < num_leaves`, where `num_leaves` is stored at `mmr_ptr[0]`. The procedure fails instead of returning an empty or sentinel word when `pos` is outside the current MMR. Inputs: `[pos, mmr_ptr, ...]`. Output: `[EL, ...]`. Where `EL` is the element loaded from the MMR whose memory location starts at `mmr_ptr`. | +| add | Adds a new element to the MMR. This will update the MMR peaks in the VM's memory and the advice provider with any merged nodes. Inputs: `[EL, mmr_ptr, ...]`. Outputs: `[...]`. Where `EL` is the element added to the MMR whose memory location starts at `mmr_ptr`.

Cycles: `145 + 39 * peak_merges` | +| pack | Computes a commitment to the given MMR and copies the MMR to the Advice Map using the commitment as a key. Inputs: `[mmr_ptr, ...]`. Outputs: `[HASH, ...]`.

Cycles: `128 + 3 * num_peaks` | +| unpack | Writes the MMR whose peaks hash to `HASH` to the memory location pointed to by `mmr_ptr`. Inputs: `[HASH, mmr_ptr, ...]`. Outputs: `[...]`. Where: `HASH` is the MMR peak hash, the hash is expected to be padded to an even length and to have a minimum size of 16 elements. The advice map must contain a key with `HASH`, and its value is `[num_leaves, 0, 0, 0] \|\| hash_data`, and hash_data is the data used to compute `HASH`. `mmr_ptr` is the memory location where the MMR data will be written, starting with the MMR forest (the total count of its leaves) followed by its peaks. The memory location must be word-aligned.

Cycles: `162 + 9 * extra_peak_pair` | +| num_leaves_to_num_peaks | Given the number of leaves in an MMR, computes the number of peaks (i.e. the number of set bits in `num_leaves`).

Inputs: `[num_leaves, ...]`
Outputs: `[num_peaks, ...]`

Cycles: 67 | +| num_peaks_to_message_size | Given the number of peaks, computes the size of the hashing message used when computing the MMR commitment (rounded up to the next even length, with a minimum of 16).

Inputs: `[num_peaks, ...]`
Outputs: `[message_size, ...]`

Cycles: 19 | `mmr_ptr` is a pointer to the `mmr` data structure, which is defined as: 1. `mmr_ptr[0]` contains the number of leaves in the MMR diff --git a/docs/src/user_docs/core_lib/crypto/aead.md b/docs/src/user_docs/core_lib/crypto/aead.md index c21606cb19..1aeddc90b8 100644 --- a/docs/src/user_docs/core_lib/crypto/aead.md +++ b/docs/src/user_docs/core_lib/crypto/aead.md @@ -29,14 +29,14 @@ Associated data (AD) is currently **not supported**. Only empty AD is handled, w Encrypts plaintext data from memory using the `crypto_stream` instruction. This procedure encrypts plaintext and automatically adds a padding block at the end. **Inputs:** -- Operand stack: `[nonce(4), key(4), src_ptr, dst_ptr, num_blocks, ...]` +- Operand stack: `[key(4), nonce(4), src_ptr, dst_ptr, num_blocks, ...]` **Outputs:** - Operand stack: `[tag(4), ...]` Where: -- `nonce` is the initialization vector (4 elements / 1 word) - `key` is the encryption key (4 elements / 1 word) +- `nonce` is the initialization vector (4 elements / 1 word) - `src_ptr` points to plaintext in memory (must be word-aligned) - `dst_ptr` points to where ciphertext will be written (must be word-aligned) - `num_blocks` is the number of 8-element plaintext data blocks (padding is NOT included) @@ -71,14 +71,14 @@ The padding block is automatically added and encrypted. The tag is stored right Decrypts and authenticates ciphertext using non-deterministic advice. This procedure implements AEAD decryption with automatic tag verification and automatic padding handling. **Inputs:** -- Operand stack: `[nonce(4), key(4), src_ptr, dst_ptr, num_blocks, ...]` +- Operand stack: `[key(4), nonce(4), src_ptr, dst_ptr, num_blocks, ...]` **Outputs:** - Operand stack: `[]` (empty stack on success, halts on failure) Where: -- `nonce` is the initialization vector (4 elements) - `key` is the decryption key (4 elements) +- `nonce` is the initialization vector (4 elements) - `src_ptr` points to ciphertext + encrypted_padding + tag in memory (word-aligned) - `dst_ptr` points to where plaintext will be written (word-aligned) - `num_blocks` is the number of 8-element plaintext data blocks (padding is NOT included) @@ -94,9 +94,9 @@ Input at `src_ptr`: Output at `dst_ptr`: ``` -[plaintext_block_0(8), ..., plaintext_block_n(8), padding(8)] +[plaintext_block_0(8), ..., plaintext_block_n(8)] ``` -Length: `(num_blocks + 1) * 8` elements +Length: `num_blocks * 8` elements. The padding block is authenticated but **not** written to the plaintext output. **Decryption Flow:** 1. Computes tag location: `src_ptr + (num_blocks + 1) * 8` diff --git a/docs/src/user_docs/core_lib/crypto/dsa.md b/docs/src/user_docs/core_lib/crypto/dsa.md index 24a16434f3..ebc47076a1 100644 --- a/docs/src/user_docs/core_lib/crypto/dsa.md +++ b/docs/src/user_docs/core_lib/crypto/dsa.md @@ -28,8 +28,8 @@ The module exposes the following procedures: | Procedure | Description | |--------------------------|-------------| -| verify | High-level signature verification. Verifies an secp256k1 ECDSA signature given a public key commitment and the original message. The public key and signature are provided via the advice stack.

**Stack inputs:** `[PK_COMM, MSG, ...]`
**Advice stack inputs:** `[PK[9], SIG[17], ...]`
**Outputs:** `[...]`

Where `PK_COMM` is the Poseidon2 hash of the compressed public key, `MSG` is the 32-byte message (as a word), `PK[9]` is the compressed secp256k1 public key (33 bytes packed as 9 felts), and `SIG[17]` is the signature (66 bytes packed as 17 felts).

The procedure traps if the public key does not hash to `PK_COMM` or if the signature is invalid. | -| verify_prehash | Low-level signature verification with pre-hashed message. This procedure is intended for manual signature verification where the caller has already computed the message digest. The caller provides pointers to the public key, message digest, and signature in memory.

**Stack inputs:** `[pk_ptr, digest_ptr, sig_ptr, ...]`
**Outputs:** `[result, ...]`

Where:
- `pk_ptr`: word-aligned memory address containing the 33-byte compressed secp256k1 public key
- `digest_ptr`: word-aligned memory address containing the 32-byte message digest (typically from Keccak256)
- `sig_ptr`: word-aligned memory address containing the 66-byte signature
- `result`: 1 if the signature is valid, 0 if invalid

All data must be stored in memory as packed u32 values (little-endian). | +| verify | High-level signature verification. Verifies an secp256k1 ECDSA signature given a public key commitment and the original message. The public key and signature are provided via the advice stack.

**Stack inputs:** `[PK_COMM, MSG, ...]`
**Advice stack inputs:** `[PK[9], SIG[17], ...]`
**Outputs:** `[...]`

Where `PK_COMM` is the Poseidon2 hash of the compressed public key, `MSG` is the 32-byte message (as a word), `PK[9]` is the compressed secp256k1 public key (33 bytes packed as 9 felts), and `SIG[17]` is the signature (65 bytes packed as 17 felts).

The procedure traps if the public key does not hash to `PK_COMM` or if the signature is invalid. | +| verify_prehash | Low-level signature verification with pre-hashed message. This procedure is intended for manual signature verification where the caller has already computed the message digest. The caller provides pointers to the public key, message digest, and signature in memory.

**Stack inputs:** `[pk_ptr, digest_ptr, sig_ptr, ...]`
**Outputs:** `[result, ...]`

Where:
- `pk_ptr`: word-aligned memory address containing the 33-byte compressed secp256k1 public key
- `digest_ptr`: word-aligned memory address containing the 32-byte message digest (typically from Keccak256)
- `sig_ptr`: word-aligned memory address containing the 65-byte signature
- `result`: 1 if the signature is valid, 0 if invalid

All data must be stored in memory as packed u32 values (little-endian). | ### Data Encoding diff --git a/docs/src/user_docs/core_lib/crypto/hashes.md b/docs/src/user_docs/core_lib/crypto/hashes.md index 7fd84ff568..0aa9bf6d24 100644 --- a/docs/src/user_docs/core_lib/crypto/hashes.md +++ b/docs/src/user_docs/core_lib/crypto/hashes.md @@ -41,6 +41,7 @@ Module `miden::core::crypto::hashes::sha256` contains procedures for computing h | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | hash | Computes SHA256 1-to-1 hash.

Input: 32-bytes stored in the first 8 elements of the stack (32 bits per element).

Output: A 32-byte digest stored in the first 8 elements of stack (32 bits per element). | | merge | Computes SHA256 2-to-1 hash.

Input: 64-bytes stored in the first 16 elements of the stack (32 bits per element).

Output: A 32-byte digest stored in the first 8 elements of stack (32 bits per element). | +| hash_bytes | Given a memory address and a message length in bytes, computes its SHA256 digest. There must be space for writing the padding after the message in memory, and the padding space must be all zeros before the procedure is called.

Input: `[addr, len, ...]`
Output: `[dig0, dig1, ..., dig7, ...]`

Panics if any loaded message word is not a valid 32-bit unsigned integer or padding range checks fail. | ## SHA512 Module `miden::core::crypto::hashes::sha512` contains procedures for computing hashes using the SHA512 hash function. @@ -58,16 +59,16 @@ Module `miden::core::crypto::hashes::poseidon2` contains procedures for computin | Procedure | Description | |---------------------------------|-----------------------------------------------------| -| init_no_padding | Prepares the top of the stack with the hasher initial state.

This procedures does not handle padding, therefore, the user is expected to consume an amount of data which is a multiple of the rate (2 words).

**Inputs:** `[]`
**Outputs:** `[PERM, PERM, PERM, ...]`

Cycles: 12 | +| init_no_padding | Prepares the top of the stack with the hasher initial state.

This procedures does not handle padding, therefore, the user is expected to consume an amount of data which is a multiple of the rate (2 words).

**Inputs:** `[]`
**Outputs:** `[R0, R1, C, ...]`

Cycles: 12 | | squeeze_digest | Given the hasher state, returns the hash output (digest).

**Inputs:** `[R0, R1, C, ...]`
**Outputs:** `[DIGEST, ...]`

Where:

  • `R0` is the first rate word / digest (positions 0-3, on top of stack).
  • `R1` is the second rate word (positions 4-7).
  • `C` is the capacity word (positions 8-11).
  • `DIGEST = R0`.

Cycles: 9 | | copy_digest | Copies the digest (R0) to the top of the stack.

It is expected to have the hasher state at the top of the stack at the beginning of the procedure execution.

**Inputs:** `[R0, R1, C, ...]`
**Outputs:** `[DIGEST, R0, R1, C, ...]`

Where:
  • `R0` is the first rate word / digest (positions 0-3, on top of stack).
  • `R1` is the second rate word (positions 4-7).
  • `C` is the capacity word (positions 8-11).
  • `DIGEST = R0`.

Cycles: 4 | | absorb_double_words_from_memory | Hashes the memory `start_addr` to `end_addr` given a Poseidon2 state specified by 3 words.

This requires that `end_addr = start_addr + 8n` where n = 0, 1, 2, ..., otherwise the procedure will enter an infinite loop.

**Inputs:** `[R0, R1, C, start_addr, end_addr, ...]`
**Outputs:** `[R0', R1', C', end_addr, end_addr ...]`

Where:
  • `R0` is the first rate word / digest (positions 0-3, on top of stack).
  • `R1` is the second rate word (positions 4-7).
  • `C` is the capacity word (positions 8-11).

Cycles: 4 + 3 * words, where `words` is the `start_addr - end_addr` | | hash_double_words | Hashes the pairs of words in the memory from `start_addr` to `end_addr`.

This procedure requires that `end_addr = start_addr + 8n` where $n = \{0, 1, 2 ...\}$ (i.e. we must always hash some number of double words), otherwise the procedure will enter an infinite loop.

**Inputs:** `[start_addr, end_addr, ...]`
**Outputs:** `[HASH, ...]`

Where:
  • `HASH` is the cumulative hash of the provided memory values.

Cycles: 37 + 3 * words, where `words` is the `start_addr - end_addr` | -| hash_words | Hashes the memory `start_addr` to `end_addr`, handles odd number of elements.

Requires `start_addr < end_addr`, `end_addr` is not inclusive.

**Inputs:** `[start_addr, end_addr, ...]`
**Outputs:** `[H, ...]`

Cycles:
  • even words: 49 cycles + 3 * words
  • odd words: 61 cycles + 3 * words
| +| hash_words | Hashes the memory `start_addr` to `end_addr`, handles odd number of elements.

Requires `start_addr < end_addr`, `end_addr` is not inclusive.

**Inputs:** `[start_addr, end_addr, ...]`
**Outputs:** `[H, ...]`

Cycles:
  • even words: 53 cycles + 3 * words
  • odd words: 65 cycles + 3 * words
| | prepare_hasher_state | Computes the hasher state required for the `hash_elements_with_state` procedure.

Depending on the provided `pad_inputs_flag`, this procedure instantiates the hasher state using different values for capacity element:
- If `pad_inputs_flag` equals $1$ the capacity element will be assigned to $0$. This will essentially "pad" the hashing values with zeroes to the next multiple of $8$.
- If `pad_inputs_flag` equals $0$ the capacity element will be assigned to the remainder of the division of elements number by $8$ ($num\_elements\%8$).

Inputs: `[ptr, num_elements, pad_inputs_flag]`
Outputs: `[R0, R1, C, ptr, end_pairs_addr, num_elements%8]`

Where R0, R1, C are three words representing the hasher state (R0 on top). | | hash_elements_with_state | Computes hash of `Felt` values starting at the specified memory address using the provided hasher state.

This procedure divides the hashing process into two parts: hashing pairs of words using `absorb_double_words_from_memory` procedure and hashing the remaining values using the `hperm` instruction.

Inputs: `[R0, R1, C, ptr, end_pairs_addr, num_elements%8]`
Outputs: `[HASH]`

Where R0, R1, C are three words representing the hasher state (R0 on top). | -| hash_elements | Computes hash of `Felt` values starting at the specified memory address.

Notice that this procedure does not pad the elements to hash to the next multiple of 8.

This procedure divides the hashing process into two parts: hashing pairs of words using
`absorb_double_words_from_memory` procedure and hashing the remaining values using the `hperm`
instruction.

**Inputs:** `[ptr, num_elements]`
**Outputs:** `[HASH]`

Where:
  • `ptr` is the memory address of the first element to be hashed. This address must be word-aligned - i.e., divisible by 4.
  • `num_elements` is the number of elements to be hashed.
  • `HASH` is the resulting hash of the provided memory values.

Cycles:
  • If number of elements divides by $8$: 47 cycles + 3 * words
  • Else: 180 cycles + 3 * words

Panics if:
  • number of inputs equals $0$.
| -| pad_and_hash_elements | Computes hash of `Felt` values starting at the specified memory address.

Notice that this procedure essentially pads the elements to be hashed to the next multiple of 8 by setting the capacity element to 0.

This procedure divides the hashing process into two parts: hashing pairs of words using
`absorb_double_words_from_memory` procedure and hashing the remaining values using the `hperm`
instruction.

**Inputs:** `[ptr, num_elements]`
**Outputs:** `[HASH]`

Where:
  • `ptr` is the memory address of the first element to be hashed. This address must be word-aligned - i.e., divisible by 4.
  • `num_elements` is the number of elements to be hashed.
  • `HASH` is the resulting hash of the provided memory values.

Cycles:
  • If number of elements divides by $8$: 47 cycles + 3 * words
  • Else: 180 cycles + 3 * words

Panics if:
  • number of inputs equals $0$.
| +| hash_elements | Computes hash of `Felt` values starting at the specified memory address.

Notice that this procedure does not pad the elements to hash to the next multiple of 8.

This procedure divides the hashing process into two parts: hashing pairs of words using
`absorb_double_words_from_memory` procedure and hashing the remaining values using the `hperm`
instruction.

**Inputs:** `[ptr, num_elements]`
**Outputs:** `[HASH]`

Where:
  • `ptr` is the memory address of the first element to be hashed. This address must be word-aligned - i.e., divisible by 4.
  • `num_elements` is the number of elements to be hashed.
  • `HASH` is the resulting hash of the provided memory values.

Cycles:
  • If number of elements divides by $8$: 52 cycles + 3 * words
  • Else: 185 cycles + 3 * words

Panics if:
  • number of inputs equals $0$.
| +| pad_and_hash_elements | Computes hash of `Felt` values starting at the specified memory address.

Notice that this procedure essentially pads the elements to be hashed to the next multiple of 8 by setting the capacity element to 0.

This procedure divides the hashing process into two parts: hashing pairs of words using
`absorb_double_words_from_memory` procedure and hashing the remaining values using the `hperm`
instruction.

**Inputs:** `[ptr, num_elements]`
**Outputs:** `[HASH]`

Where:
  • `ptr` is the memory address of the first element to be hashed. This address must be word-aligned - i.e., divisible by 4.
  • `num_elements` is the number of elements to be hashed.
  • `HASH` is the resulting hash of the provided memory values.

Cycles:
  • If number of elements divides by $8$: 52 cycles + 3 * words
  • Else: 185 cycles + 3 * words

Panics if:
  • number of inputs equals $0$.
| | hash | Computes Poseidon2 hash of a single 256-bit input (1 word = 4 field elements).

**Inputs:** `[A]`
**Outputs:** `[B]`

Where:
  • A is the word to be hashed.
  • B is the resulting hash, computed as `Poseidon2(A)`.

Cycles: 19 | -| merge | Merges two words (256-bit digests) via Poseidon2 hash.

**Inputs:** `[B, A]`
**Outputs:** `[C]`

Where:
  • A and B are the words to be merged.
  • C is the resulting hash, computed as `Poseidon2(A \|\| B)`.

Cycles: 16 | +| merge | Merges two words (256-bit digests) via Poseidon2 hash.

**Inputs:** `[A, B]`
**Outputs:** `[C]`

Where:
  • A and B are the words to be merged.
  • C is the resulting hash, computed as `Poseidon2(A \|\| B)`.

Cycles: 16 | | permute | Performs Poseidon2 permutation on the hasher state.

**Inputs:** `[R0, R1, C]`
**Outputs:** `[R0', R1', C']`

Where:
  • R0, R1, C are three words representing the hasher state (R0 on top).
  • R0', R1', C' are the permuted state words.

Cycles: 1 | diff --git a/docs/src/user_docs/core_lib/index.md b/docs/src/user_docs/core_lib/index.md index 5712aed7c1..91c64e597f 100644 --- a/docs/src/user_docs/core_lib/index.md +++ b/docs/src/user_docs/core_lib/index.md @@ -46,6 +46,7 @@ Currently, Miden core library contains just a few modules, which are listed belo | [miden::core::crypto::hashes::sha256](./crypto/hashes.md#sha256) | Contains procedures for computing hashes using SHA256 hash function. | | [miden::core::crypto::hashes::sha512](./crypto/hashes.md#sha512) | Contains procedures for computing hashes using SHA512 hash function. | | [miden::core::math::u64](./math/u64.md) | Contains procedures for working with 64-bit unsigned integers. | +| [miden::core::math::u128](./math/u128.md) | Contains procedures for working with 128-bit unsigned integers. | | [miden::core::math::u256](./math/u256.md) | Contains procedures for working with 256-bit unsigned integers. | | [miden::core::mem](./mem.md) | Contains procedures for working with random access memory. | | [miden::core::sys](./sys.md) | Contains system-level utility procedures. | diff --git a/docs/src/user_docs/core_lib/math/u128.md b/docs/src/user_docs/core_lib/math/u128.md new file mode 100644 index 0000000000..af4dc3e7e8 --- /dev/null +++ b/docs/src/user_docs/core_lib/math/u128.md @@ -0,0 +1,69 @@ +--- +title: "Unsigned 128-bit Integer Operations" +sidebar_position: 2 +--- + +# Unsigned 128-bit integer operations + +Module `miden::core::math::u128` contains a set of procedures which can be used to perform unsigned 128-bit integer operations. These operations fall into the following categories: + +* **Arithmetic operations** - addition, subtraction, multiplication, division. +* **Comparison operations** - equality, less than, greater than etc. +* **Bitwise operations** - binary AND, OR, XOR, NOT, bit shifts and rotations, leading/trailing zero/one counts. + +When placed on the stack, a 128-bit integer is encoded using four 32-bit limbs (elements) in little-endian limb order: the least-significant limb is on top of the stack. For example, a u128 value `a` with limbs `a0..a3` would be positioned on the stack like so: +``` +[a0, a1, a2, a3, ...] +``` +where `a0` is the least-significant 32-bit limb and `a3` is the most significant. + +:::note +The procedures in this module assume that the input values are represented using valid 32-bit limbs, but this is not checked. Using invalid inputs may produce undefined results. +::: + +## Arithmetic operations + +| Procedure | Description | +|-----------------|-------------| +| wrapping_add | Performs addition of two unsigned 128-bit integers discarding the overflow.

**Stack transition:** `[b0..b3, a0..a3, ...] -> [c0..c3, ...]`
where `c = (a + b) % 2^128` | +| overflowing_add | Performs addition of two unsigned 128-bit integers preserving the overflow.

**Stack transition:** `[b0..b3, a0..a3, ...] -> [overflow, c0..c3, ...]`
where `c = (a + b) % 2^128` | +| widening_add | Performs addition of two unsigned 128-bit integers preserving the overflow with sum on top.

**Stack transition:** `[b0..b3, a0..a3, ...] -> [c0..c3, overflow, ...]`
where `c = (a + b) % 2^128` | +| wrapping_sub | Performs subtraction of two unsigned 128-bit integers discarding the underflow.

**Stack transition:** `[b0..b3, a0..a3, ...] -> [c0..c3, ...]`
where `c = (a - b) % 2^128` | +| overflowing_sub | Performs subtraction of two unsigned 128-bit integers preserving the underflow.

**Stack transition:** `[b0..b3, a0..a3, ...] -> [underflow, c0..c3, ...]`
where `c = (a - b) % 2^128` | +| wrapping_mul | Performs multiplication of two unsigned 128-bit integers discarding the overflow.

**Stack transition:** `[b0..b3, a0..a3, ...] -> [c0..c3, ...]`
where `c = (a * b) % 2^128` | +| overflowing_mul | Performs multiplication of two unsigned 128-bit integers preserving the overflow.

**Stack transition:** `[b0..b3, a0..a3, ...] -> [overflow, c0..c3, ...]`
where `c = (a * b) % 2^128` | +| widening_mul | Performs multiplication of two unsigned 128-bit integers preserving the overflow with sum on top.

**Stack transition:** `[b0..b3, a0..a3, ...] -> [c0..c3, overflow, ...]`
where `c = (a * b) % 2^128` | +| div | Performs division of two unsigned 128-bit integers discarding the remainder.

**Stack transition:** `[b0..b3, a0..a3, ...] -> [q0..q3, ...]`
where `q = a / b`. Fails if `b = 0`. | +| mod | Performs modulo operation of two unsigned 128-bit integers.

**Stack transition:** `[b0..b3, a0..a3, ...] -> [r0..r3, ...]`
where `r = a % b`. Fails if `b = 0`. | +| divmod | Performs divmod operation of two unsigned 128-bit integers.

**Stack transition:** `[b0..b3, a0..a3, ...] -> [r0..r3, q0..q3, ...]`
where `q = a / b`, `r = a % b`. Fails if `b = 0`. | + +## Comparison operations + +| Procedure | Description | +|-----------|-------------| +| eq | Performs equality comparison of two unsigned 128-bit integers.

**Stack transition:** `[b0..b3, a0..a3, ...] -> [c, ...]`
where `c = 1` when `a == b`, and `0` otherwise. | +| neq | Performs inequality comparison of two unsigned 128-bit integers.

**Stack transition:** `[b0..b3, a0..a3, ...] -> [c, ...]`
where `c = 1` when `a != b`, and `0` otherwise. | +| eqz | Checks if an unsigned 128-bit integer equals zero.

**Stack transition:** `[a0..a3, ...] -> [c, ...]`
where `c = 1` when `a == 0`, and `0` otherwise. | +| lt | Performs less-than comparison of two unsigned 128-bit integers.

**Stack transition:** `[b0..b3, a0..a3, ...] -> [c, ...]`
where `c = 1` when `a < b`, and `0` otherwise. | +| gt | Performs greater-than comparison of two unsigned 128-bit integers.

**Stack transition:** `[b0..b3, a0..a3, ...] -> [c, ...]`
where `c = 1` when `a > b`, and `0` otherwise. | +| lte | Performs less-than-or-equal comparison of two unsigned 128-bit integers.

**Stack transition:** `[b0..b3, a0..a3, ...] -> [c, ...]`
where `c = 1` when `a <= b`, and `0` otherwise. | +| gte | Performs greater-than-or-equal comparison of two unsigned 128-bit integers.

**Stack transition:** `[b0..b3, a0..a3, ...] -> [c, ...]`
where `c = 1` when `a >= b`, and `0` otherwise. | +| min | Computes the minimum of two unsigned 128-bit integers.

**Stack transition:** `[b0..b3, a0..a3, ...] -> [c0..c3, ...]`
where `c = min(a, b)`. | +| max | Computes the maximum of two unsigned 128-bit integers.

**Stack transition:** `[b0..b3, a0..a3, ...] -> [c0..c3, ...]`
where `c = max(a, b)`. | + +## Bitwise operations + +| Procedure | Description | +|-----------|-------------| +| and | Performs bitwise AND of two unsigned 128-bit integers.

**Stack transition:** `[b0..b3, a0..a3, ...] -> [c0..c3, ...]`
where `c = a AND b` | +| or | Performs bitwise OR of two unsigned 128-bit integers.

**Stack transition:** `[b0..b3, a0..a3, ...] -> [c0..c3, ...]`
where `c = a OR b` | +| xor | Performs bitwise XOR of two unsigned 128-bit integers.

**Stack transition:** `[b0..b3, a0..a3, ...] -> [c0..c3, ...]`
where `c = a XOR b` | +| not | Performs bitwise NOT of an unsigned 128-bit integer.

**Stack transition:** `[a0..a3, ...] -> [c0..c3, ...]`
where `c = NOT(a)` | +| shl | Performs left shift of one unsigned 128-bit integer. The shift amount `n` must be in the range `[0, 128)`, otherwise it will result in an error.

**Stack transition:** `[n, a0..a3, ...] -> [c0..c3, ...]`
where `c = (a << n) mod 2^128` | +| shr | Performs right shift of one unsigned 128-bit integer. The shift amount `n` must be in the range `[0, 128)`, otherwise it will result in an error.

**Stack transition:** `[n, a0..a3, ...] -> [c0..c3, ...]`
where `c = a >> n` | +| rotl | Performs left rotation of one unsigned 128-bit integer. The rotation amount `n` must be in the range `[0, 128)`, otherwise it will result in an error.

**Stack transition:** `[n, a0..a3, ...] -> [c0..c3, ...]`
where `c = a` rotated left by `n` bits. | +| rotr | Performs right rotation of one unsigned 128-bit integer. The rotation amount `n` must be in the range `[0, 128)`, otherwise it will result in an error.

**Stack transition:** `[n, a0..a3, ...] -> [c0..c3, ...]`
where `c = a` rotated right by `n` bits. | +| clz | Counts the number of leading zeros of an unsigned 128-bit integer.

**Stack transition:** `[a0..a3, ...] -> [count, ...]`
where `count` is the number of leading zero bits in `a` (`0..=128`). | +| ctz | Counts the number of trailing zeros of an unsigned 128-bit integer.

**Stack transition:** `[a0..a3, ...] -> [count, ...]`
where `count` is the number of trailing zero bits in `a` (`0..=128`). | +| clo | Counts the number of leading ones of an unsigned 128-bit integer.

**Stack transition:** `[a0..a3, ...] -> [count, ...]`
where `count` is the number of leading one bits in `a` (`0..=128`). | +| cto | Counts the number of trailing ones of an unsigned 128-bit integer.

**Stack transition:** `[a0..a3, ...] -> [count, ...]`
where `count` is the number of trailing one bits in `a` (`0..=128`). | diff --git a/docs/src/user_docs/core_lib/math/u256.md b/docs/src/user_docs/core_lib/math/u256.md index ebc7b77357..5d2d9b2cc3 100644 --- a/docs/src/user_docs/core_lib/math/u256.md +++ b/docs/src/user_docs/core_lib/math/u256.md @@ -1,6 +1,6 @@ --- title: "Unsigned 256-bit Integer Operations" -sidebar_position: 2 +sidebar_position: 3 --- # Unsigned 256-bit integer operations @@ -13,14 +13,14 @@ Module `miden::core::math::u256` contains a set of procedures which can be used A `u256` value is represented as a struct with two `u128` components: ``` -pub type u256 = struct { hi: u128, lo: u128 } +pub type u256 = struct { lo: u128, hi: u128 } ``` -When placed on the stack, a 256-bit integer is encoded using eight 32-bit limbs (elements). The least-significant limb is assumed to be deeper in the stack. For example, a u256 value consisting of limbs `[a7, a6, a5, a4, a3, a2, a1, a0]` would be positioned on the stack like so: +When placed on the stack, a 256-bit integer is encoded using eight 32-bit limbs (elements) in little-endian limb order: the least-significant limb is on top of the stack. For example, a u256 value `a` with limbs `a0..a7` would be positioned on the stack like so: ``` -[a7, a6, a5, a4, a3, a2, a1, a0, ...] +[a0, a1, a2, a3, a4, a5, a6, a7, ...] ``` -where `a0` is the least significant 32-bit limb and `a7` is the most significant. +where `a0` is the least-significant 32-bit limb and `a7` is the most significant. :::note The procedures in this module assume that the input values are represented using valid 32-bit limbs, but this is not checked. Using invalid inputs may produce undefined results. @@ -28,23 +28,26 @@ The procedures in this module assume that the input values are represented using ## Arithmetic operations -| Procedure | Description | -|---------------|-------------| -| wrapping_add | Performs addition of two unsigned 256-bit integers discarding the overflow.

**Stack transition:** `[b7..b0, a7..a0, ...] -> [c7..c0, ...]`
where `c = (a + b) % 2^256` | -| wrapping_sub | Performs subtraction of two unsigned 256-bit integers discarding the underflow.

**Stack transition:** `[b7..b0, a7..a0, ...] -> [c7..c0, ...]`
where `c = (a - b) % 2^256` | -| wrapping_mul | Performs multiplication of two unsigned 256-bit integers discarding the overflow.

**Stack transition:** `[b7..b0, a7..a0, ...] -> [c7..c0, ...]`
where `c = (a * b) % 2^256` | +| Procedure | Description | +|-----------------|-------------| +| wrapping_add | Performs addition of two unsigned 256-bit integers discarding the overflow.

**Stack transition:** `[b0..b7, a0..a7, ...] -> [c0..c7, ...]`
where `c = (a + b) % 2^256` | +| overflowing_add | Performs addition of two unsigned 256-bit integers preserving the overflow.

**Stack transition:** `[b0..b7, a0..a7, ...] -> [overflow, c0..c7, ...]`
where `c = (a + b) % 2^256` | +| widening_add | Performs addition of two unsigned 256-bit integers preserving the overflow with sum on top.

**Stack transition:** `[b0..b7, a0..a7, ...] -> [c0..c7, overflow, ...]`
where `c = (a + b) % 2^256` | +| wrapping_sub | Performs subtraction of two unsigned 256-bit integers discarding the underflow.

**Stack transition:** `[b0..b7, a0..a7, ...] -> [c0..c7, ...]`
where `c = (a - b) % 2^256` | +| overflowing_sub | Performs subtraction of two unsigned 256-bit integers preserving the underflow.

**Stack transition:** `[b0..b7, a0..a7, ...] -> [underflow, c0..c7, ...]`
where `c = (a - b) % 2^256` | +| wrapping_mul | Performs multiplication of two unsigned 256-bit integers discarding the overflow.

**Stack transition:** `[b0..b7, a0..a7, ...] -> [c0..c7, ...]`
where `c = (a * b) % 2^256` | ## Comparison operations | Procedure | Description | |-----------|-------------| -| eq | Checks equality of two unsigned 256-bit integers.

**Stack transition:** `[b7..b0, a7..a0, ...] -> [c, ...]`
where `c = 1` when `a == b`, and `0` otherwise. | -| eqz | Checks if an unsigned 256-bit integer equals zero.

**Stack transition:** `[a7..a0, ...] -> [c, ...]`
where `c = 1` when `a == 0`, and `0` otherwise. | +| eq | Checks equality of two unsigned 256-bit integers.

**Stack transition:** `[b0..b7, a0..a7, ...] -> [c, ...]`
where `c = 1` when `a == b`, and `0` otherwise. | +| eqz | Checks if an unsigned 256-bit integer equals zero.

**Stack transition:** `[a0..a7, ...] -> [c, ...]`
where `c = 1` when `a == 0`, and `0` otherwise. | ## Bitwise operations | Procedure | Description | |-----------|-------------| -| and | Performs bitwise AND of two unsigned 256-bit integers.

**Stack transition:** `[b7..b0, a7..a0, ...] -> [c7..c0, ...]`
where `c = a AND b` | -| or | Performs bitwise OR of two unsigned 256-bit integers.

**Stack transition:** `[b7..b0, a7..a0, ...] -> [c7..c0, ...]`
where `c = a OR b` | -| xor | Performs bitwise XOR of two unsigned 256-bit integers.

**Stack transition:** `[b7..b0, a7..a0, ...] -> [c7..c0, ...]`
where `c = a XOR b` | +| and | Performs bitwise AND of two unsigned 256-bit integers.

**Stack transition:** `[b0..b7, a0..a7, ...] -> [c0..c7, ...]`
where `c = a AND b` | +| or | Performs bitwise OR of two unsigned 256-bit integers.

**Stack transition:** `[b0..b7, a0..a7, ...] -> [c0..c7, ...]`
where `c = a OR b` | +| xor | Performs bitwise XOR of two unsigned 256-bit integers.

**Stack transition:** `[b0..b7, a0..a7, ...] -> [c0..c7, ...]`
where `c = a XOR b` | diff --git a/docs/src/user_docs/core_lib/math/u64.md b/docs/src/user_docs/core_lib/math/u64.md index 4b7ecc3c98..e8743a6c6e 100644 --- a/docs/src/user_docs/core_lib/math/u64.md +++ b/docs/src/user_docs/core_lib/math/u64.md @@ -24,9 +24,9 @@ Many of the procedures listed below (e.g., `overflowing_add`, `wrapping_add`, `l | overflowing_add | Performs addition of two unsigned 64-bit integers preserving the overflow. The input values are assumed to be represented using 32-bit limbs, but this is not checked. The stack transition looks as follows: [b_lo, b_hi, a_lo, a_hi, ...] -> [overflow, c_lo, c_hi, ...], where c = (a + b) % 2^64. This takes 5 cycles.| | widening_add | Performs addition of two unsigned 64-bit integers preserving the overflow, with sum on top. The input values are assumed to be represented using 32-bit limbs, but this is not checked. The stack transition looks as follows: [b_lo, b_hi, a_lo, a_hi, ...] -> [c_lo, c_hi, overflow, ...], where c = (a + b) % 2^64. This takes 6 cycles.| | wrapping_add | Performs addition of two unsigned 64-bit integers discarding the overflow. The input values are assumed to be represented using 32-bit limbs, but this is not checked. The stack transition looks as follows: [b_lo, b_hi, a_lo, a_hi, ...] -> [c_lo, c_hi, ...], where c = (a + b) % 2^64. This takes 6 cycles.| -| overflowing_sub | Performs subtraction of two unsigned 64-bit integers preserving the overflow. The input values are assumed to be represented using 32-bit limbs, but this is not checked. The stack transition looks as follows: [b_lo, b_hi, a_lo, a_hi, ...] -> [underflow, c_lo, c_hi, ...], where c = (a - b) % 2^64. This takes 15 cycles. | -| wrapping_sub | Performs subtraction of two unsigned 64-bit integers discarding the overflow. The input values are assumed to be represented using 32-bit limbs, but this is not checked. The stack transition looks as follows: [b_lo, b_hi, a_lo, a_hi, ...] -> [c_lo, c_hi, ...], where c = (a - b) % 2^64. This takes 11 cycles. | -| widening_mul | Performs multiplication of two unsigned 64-bit integers preserving the overflow as a 128-bit result. The input values are assumed to be represented using 32-bit limbs, but this is not checked. The stack transition looks as follows: [b_lo, b_hi, a_lo, a_hi, ...] -> [c_lo, c_mid_lo, c_mid_hi, c_hi, ...], where c = a * b is represented as a 128-bit value split into 4 32-bit limbs. This takes 22 cycles.| +| overflowing_sub | Performs subtraction of two unsigned 64-bit integers preserving the overflow. The input values are assumed to be represented using 32-bit limbs, but this is not checked. The stack transition looks as follows: [b_lo, b_hi, a_lo, a_hi, ...] -> [underflow, c_lo, c_hi, ...], where c = (a - b) % 2^64. This takes 14 cycles. | +| wrapping_sub | Performs subtraction of two unsigned 64-bit integers discarding the overflow. The input values are assumed to be represented using 32-bit limbs, but this is not checked. The stack transition looks as follows: [b_lo, b_hi, a_lo, a_hi, ...] -> [c_lo, c_hi, ...], where c = (a - b) % 2^64. This takes 12 cycles. | +| widening_mul | Performs multiplication of two unsigned 64-bit integers preserving the overflow as a 128-bit result. The input values are assumed to be represented using 32-bit limbs, but this is not checked. The stack transition looks as follows: [b_lo, b_hi, a_lo, a_hi, ...] -> [c_lo, c_mid_lo, c_mid_hi, c_hi, ...], where c = a * b is represented as a 128-bit value split into 4 32-bit limbs. This takes 23 cycles.| | wrapping_mul | Performs multiplication of two unsigned 64-bit integers discarding the overflow. The input values are assumed to be represented using 32-bit limbs, but this is not checked. The stack transition looks as follows: [b_lo, b_hi, a_lo, a_hi, ...] -> [c_lo, c_hi, ...], where c = (a * b) % 2^64. This takes 15 cycles. | | div | Performs division of two unsigned 64-bit integers discarding the remainder. The input values are assumed to be represented using 32-bit limbs, but this is not checked. The stack transition looks as follows: [b_lo, b_hi, a_lo, a_hi, ...] -> [c_lo, c_hi, ...], where c = a // b. This takes 56 cycles. | | mod | Performs modulo operation of two unsigned 64-bit integers. The input values are assumed to be represented using 32-bit limbs, but this is not checked. The stack transition looks as follows: [b_lo, b_hi, a_lo, a_hi, ...] -> [c_lo, c_hi, ...], where c = a % b. This takes 58 cycles. | @@ -36,15 +36,15 @@ Many of the procedures listed below (e.g., `overflowing_add`, `wrapping_add`, `l | Procedure | Description | | ------------------ | ------------- | -| lt | Performs less-than comparison of two unsigned 64-bit integers. The input values are assumed to be represented using 32-bit limbs, but this is not checked. The stack transition looks as follows: [b_lo, b_hi, a_lo, a_hi, ...] -> [c, ...], where c = 1 when `a < b`, and 0 otherwise. This takes 12 cycles. | +| lt | Performs less-than comparison of two unsigned 64-bit integers. The input values are assumed to be represented using 32-bit limbs, but this is not checked. The stack transition looks as follows: [b_lo, b_hi, a_lo, a_hi, ...] -> [c, ...], where c = 1 when `a < b`, and 0 otherwise. This takes 13 cycles. | | gt | Performs greater-than comparison of two unsigned 64-bit integers. The input values are assumed to be represented using 32-bit limbs, but this is not checked. The stack transition looks as follows: [b_lo, b_hi, a_lo, a_hi, ...] -> [c, ...], where c = 1 when a > b, and 0 otherwise. This takes 13 cycles. | | lte | Performs less-than-or-equal comparison of two unsigned 64-bit integers. The input values are assumed to be represented using 32-bit limbs, but this is not checked. The stack transition looks as follows: [b_lo, b_hi, a_lo, a_hi, ...] -> [c, ...], where c = 1 when `a <= b`, and 0 otherwise. This takes 14 cycles. | | gte | Performs greater-than-or-equal comparison of two unsigned 64-bit integers. The input values are assumed to be represented using 32-bit limbs, but this is not checked. The stack transition looks as follows: [b_lo, b_hi, a_lo, a_hi, ...] -> [c, ...], where c = 1 when a >= b, and 0 otherwise. This takes 13 cycles. | -| eq | Performs equality comparison of two unsigned 64-bit integers. The input values are assumed to be represented using 32-bit limbs, but this is not checked. The stack transition looks as follows: [b_lo, b_hi, a_lo, a_hi, ...] -> [c, ...], where c = 1 when a == b, and 0 otherwise. This takes 5 cycles. | -| neq | Performs inequality comparison of two unsigned 64-bit integers. The input values are assumed to be represented using 32-bit limbs, but this is not checked. The stack transition looks as follows: [b_lo, b_hi, a_lo, a_hi, ...] -> [c, ...], where c = 1 when a != b, and 0 otherwise. This takes 5 cycles. | +| eq | Performs equality comparison of two unsigned 64-bit integers. The input values are assumed to be represented using 32-bit limbs, but this is not checked. The stack transition looks as follows: [b_lo, b_hi, a_lo, a_hi, ...] -> [c, ...], where c = 1 when a == b, and 0 otherwise. This takes 6 cycles. | +| neq | Performs inequality comparison of two unsigned 64-bit integers. The input values are assumed to be represented using 32-bit limbs, but this is not checked. The stack transition looks as follows: [b_lo, b_hi, a_lo, a_hi, ...] -> [c, ...], where c = 1 when a != b, and 0 otherwise. This takes 8 cycles. | | eqz | Performs comparison to zero of an unsigned 64-bit integer. The input value is assumed to be represented using 32-bit limbs, but this is not checked. The stack transition looks as follows: [a_lo, a_hi, ...] -> [c, ...], where c = 1 when a == 0, and 0 otherwise. This takes 4 cycles. | -| min | Compares two unsigned 64-bit integers and drops the larger one from the stack. The input values are assumed to be represented using 32-bit limbs, but this is not checked. The stack transition looks as follows: [b_lo, b_hi, a_lo, a_hi, ...] -> [c_lo, c_hi, ...], where c = min(a, b). This takes 23 cycles. | -| max | Compares two unsigned 64-bit integers and drops the smaller one from the stack. The input values are assumed to be represented using 32-bit limbs, but this is not checked. The stack transition looks as follows: [b_lo, b_hi, a_lo, a_hi, ...] -> [c_lo, c_hi, ...], where c = max(a, b). This takes 24 cycles. | +| min | Compares two unsigned 64-bit integers and drops the larger one from the stack. The input values are assumed to be represented using 32-bit limbs, but this is not checked. The stack transition looks as follows: [b_lo, b_hi, a_lo, a_hi, ...] -> [c_lo, c_hi, ...], where c = min(a, b). This takes 27 cycles. | +| max | Compares two unsigned 64-bit integers and drops the smaller one from the stack. The input values are assumed to be represented using 32-bit limbs, but this is not checked. The stack transition looks as follows: [b_lo, b_hi, a_lo, a_hi, ...] -> [c_lo, c_hi, ...], where c = max(a, b). This takes 27 cycles. | ## Bitwise operations | Procedure | Description | @@ -53,9 +53,9 @@ Many of the procedures listed below (e.g., `overflowing_add`, `wrapping_add`, `l | or | Performs bitwise OR of two unsigned 64-bit integers. The input values are assumed to be represented using 32-bit limbs, but this is not checked. The stack transition looks as follows: [b_lo, b_hi, a_lo, a_hi, ...] -> [c_lo, c_hi, ...], where c = a OR b. This takes 5 cycles. | | xor | Performs bitwise XOR of two unsigned 64-bit integers. The input values are assumed to be represented using 32-bit limbs, but this is not checked. The stack transition looks as follows: [b_lo, b_hi, a_lo, a_hi, ...] -> [c_lo, c_hi, ...], where c = a XOR b. This takes 5 cycles. | | shl | Performs left shift of one unsigned 64-bit integer. The input value to be shifted is assumed to be represented using 32-bit limbs, but this is not checked. The shift value n should be in the range [0, 64), otherwise it will result in an error. The stack transition looks as follows: [n, a_lo, a_hi, ...] -> [c_lo, c_hi, ...], where `c = (a << n) mod 2^64`. This takes 21 cycles.| -| shr | Performs right shift of one unsigned 64-bit integer. The input value to be shifted is assumed to be represented using 32-bit limbs, but this is not checked. The shift value n should be in the range [0, 64), otherwise it will result in an error. The stack transition looks as follows: [n, a_lo, a_hi, ...] -> [c_lo, c_hi, ...], where c = a >> n. This takes 44 cycles. | -| rotl | Performs left rotation of one unsigned 64-bit integer. The input value to be rotated is assumed to be represented using 32-bit limbs, but this is not checked. The rotation amount n should be in the range [0, 64), otherwise it will result in an error. The stack transition looks as follows: [n, a_lo, a_hi, ...] -> [c_lo, c_hi, ...], where `c = a <<< n` (rotate left). This takes 35 cycles. | -| rotr | Performs right rotation of one unsigned 64-bit integer. The input value to be rotated is assumed to be represented using 32-bit limbs, but this is not checked. The rotation amount n should be in the range [0, 64), otherwise it will result in an error. The stack transition looks as follows: [n, a_lo, a_hi, ...] -> [c_lo, c_hi, ...], where c = a >>> n (rotate right). This takes 44 cycles. | +| shr | Performs right shift of one unsigned 64-bit integer. The input value to be shifted is assumed to be represented using 32-bit limbs, but this is not checked. The shift value n should be in the range [0, 64), otherwise it will result in an error. The stack transition looks as follows: [n, a_lo, a_hi, ...] -> [c_lo, c_hi, ...], where c = a >> n. This takes 60 or 61 cycles, depending on n. | +| rotl | Performs left rotation of one unsigned 64-bit integer. The input value to be rotated is assumed to be represented using 32-bit limbs, but this is not checked. The rotation amount n should be in the range [0, 64), otherwise it will result in an error. The stack transition looks as follows: [n, a_lo, a_hi, ...] -> [c_lo, c_hi, ...], where `c = a <<< n` (rotate left). This takes 46 cycles. | +| rotr | Performs right rotation of one unsigned 64-bit integer. The input value to be rotated is assumed to be represented using 32-bit limbs, but this is not checked. The rotation amount n should be in the range [0, 64), otherwise it will result in an error. The stack transition looks as follows: [n, a_lo, a_hi, ...] -> [c_lo, c_hi, ...], where c = a >>> n (rotate right). This takes 60 cycles. | | clz | Counts the number of leading zeros of one unsigned 64-bit integer. The input value is assumed to be represented using 32-bit limbs, but this is not checked. The stack transition looks as follows: [n_lo, n_hi, ...] -> [clz, ...], where clz is the number of leading zeros of value n. This takes 48 cycles. | | ctz | Counts the number of trailing zeros of one unsigned 64-bit integer. The input value is assumed to be represented using 32-bit limbs, but this is not checked. The stack transition looks as follows: [n_lo, n_hi, ...] -> [ctz, ...], where ctz is the number of trailing zeros of value n. This takes 41 cycles. | | clo | Counts the number of leading ones of one unsigned 64-bit integer. The input value is assumed to be represented using 32-bit limbs, but this is not checked. The stack transition looks as follows: [n_lo, n_hi, ...] -> [clo, ...], where clo is the number of leading ones of value n. This takes 47 cycles. | diff --git a/docs/src/user_docs/core_lib/mem.md b/docs/src/user_docs/core_lib/mem.md index c4d55f749b..dcfb9100b2 100644 --- a/docs/src/user_docs/core_lib/mem.md +++ b/docs/src/user_docs/core_lib/mem.md @@ -13,4 +13,4 @@ Module `miden::core::mem` contains a set of utility procedures for working with | `pipe_double_words_to_memory` | Copies an even number of words from the advice_stack to memory.

**Inputs:** `[R0, R1, C, write_ptr, end_ptr]`
**Outputs:** `[R0', R1', C', write_ptr]`

Where R0, R1, C are the Poseidon2 hasher state (R0 on top).

Notice that the `end_ptr - write_ptr` value must be positive and a multiple of 8.

Total cycles: $9 + 6 * num\_word\_pairs$ | | `pipe_words_to_memory` | Copies an arbitrary number of words from the advice stack to memory.

**Inputs:** `[num_words, write_ptr]`
**Outputs:** `[R0, R1, C, write_ptr']`

Where R0, R1, C are the final Poseidon2 hasher state (R0 on top).

Total cycles:
  • Even `num_words`: $43 + 9 * num\_words / 2$
  • Odd `num_words`: $60 + 9 * round\_down(num\_words / 2)$
| | `pipe_preimage_to_memory` | Moves an arbitrary number of words from the advice stack to memory and asserts it matches the commitment.

**Inputs:** `[num_words, write_ptr, COMMITMENT]`
**Outputs:** `[write_ptr']`

Total cycles:
  • Even `num_words`: $62 + 9 * num\_words / 2$
  • Odd `num_words`: $79 + 9 * round\_down(num\_words / 2)$
| -| `pipe_double_words_preimage_to_memory` | Moves an even number of words from the advice stack to memory and asserts it matches the commitment.

**Inputs:** `[num_words, write_ptr, COMMITMENT]`
**Outputs:** `[write_ptr']`

Total cycles: $56 + 3 * num\_words / 2$ | +| `pipe_double_words_preimage_to_memory` | Moves an even number of words from the advice stack to memory and asserts it matches the commitment.

**Inputs:** `[num_words, write_ptr, COMMITMENT]`
**Outputs:** `[write_ptr']`

Total cycles: $56 + 3 * num\_words$ | diff --git a/docs/src/user_docs/core_lib/pcs/fri.md b/docs/src/user_docs/core_lib/pcs/fri.md index cd11a5763d..50f768fcbb 100644 --- a/docs/src/user_docs/core_lib/pcs/fri.md +++ b/docs/src/user_docs/core_lib/pcs/fri.md @@ -12,4 +12,4 @@ Module `miden::core::pcs::fri::frie2f4` contains procedures for verifying FRI pr | Procedure | Description | | ----------- | ------------- | -| verify | Verifies a FRI proof where the proof was generated over the quadratic extension of the base field and layer folding was performed using folding factor 4.

Input: `[query_start_ptr, query_end_ptr, layer_ptr, rem_ptr, g, ...]`>
Output: `[...]`

- `query_start_ptr` is a pointer to a list of tuples of the form `(e0, e1, p, 0)` where `p` is a query index at the first layer and `(e0, e1)` is an extension field element corresponding to the value of the first layer at index p.
- `query_end_ptr` is a pointer to the first empty memory address after the last `(e0, e1, p, 0)` tuple.
- `layer_ptr` is a pointer to the first layer commitment denoted throughout the code by C. `layer_ptr + 1` points to the first `(alpha0, alpha1, t_depth, d_size)` where `d_size` is the size of initial domain divided by 4, `t_depth` is the depth of the Merkle tree commitment to the first layer and `(alpha0, alpha1)` is the first challenge used in folding the first layer. Both `t_depth` and `d_size` are expected to be smaller than 2^32. Otherwise, the result of this procedure is undefined.
- `rem_ptr` is a pointer to the first tuple of two consecutive degree 2 extension field elements making up the remainder codeword. This codeword can be of length either 32 or 64.

The memory referenced above is used contiguously, as follows:
`[layer_ptr ... rem_ptr ... query_start_ptr ... query_end_ptr]`

This means for example that:
1. `rem_ptr - 1` points to the last `(alpha0, alpha1, t_depth, d_size)` tuple.
2. The length of the remainder codeword is `2 * (rem_ptr - query_start_ptr)`.

Cycles: for domains of size `2^n` where:
- `n` is even: 12 + 6 + num_queries * (40 + num_layers * 76 + 69) + 2626
- `n` is odd: 12 + 6 + num_queries * (40 + num_layers * 76 + 69) + 1356 | +| verify | Verifies a FRI proof where the proof was generated over the quadratic extension of the base field and layer folding was performed using folding factor 4.

Input: `[...]`
Output: `[...]`

Cycles:
- Polynomial degree less than 64: `24 + num_queries * (107 + num_layers * 80)`
- Polynomial degree less than 128: `24 + num_queries * (140 + num_layers * 80)` | diff --git a/docs/src/user_docs/core_lib/stark.md b/docs/src/user_docs/core_lib/stark.md index 2ef3f3f94d..fabf1cc256 100644 --- a/docs/src/user_docs/core_lib/stark.md +++ b/docs/src/user_docs/core_lib/stark.md @@ -12,6 +12,7 @@ These helpers expose constants, memory layout pointers, and routines shared acro | Module | Description | | --- | --- | +| `miden::core::stark` | Top-level entry point that re-exports `verifier::verify`; the public STARK verification procedure. | | `miden::core::stark::constants` | Defines memory layout constants and general constants used by the verifier. | | `miden::core::stark::random_coin` | Contains procedures for sampling and updating the Poseidon2-based random coin used throughout the verifier. | | `miden::core::stark::deep_queries` | Implements helper procedures for constructing DEEP queries. | diff --git a/docs/src/user_docs/core_lib/sys.md b/docs/src/user_docs/core_lib/sys.md index 8930fbf111..dc417384ea 100644 --- a/docs/src/user_docs/core_lib/sys.md +++ b/docs/src/user_docs/core_lib/sys.md @@ -6,6 +6,8 @@ sidebar_position: 7 # System procedures Module `miden::core::sys` contains a set of system-level utility procedures. -| Procedure | Description | -| -------------- | ------------- | -| truncate_stack | Removes elements deep in the stack until the depth of the stack is exactly 16. The elements are removed in such a way that the top 16 elements of the stack remain unchanged. If the stack would otherwise contain more than 16 elements at the end of execution, then adding a call to this function at the end will reduce the size of the public inputs that are shared with the verifier.
Input: Stack with 16 or more elements.
Output: Stack with only the original top 16 elements. | +| Procedure | Description | +| ---------------------- | ------------- | +| truncate_stack | Removes elements deep in the stack until the depth of the stack is exactly 16. The elements are removed in such a way that the top 16 elements of the stack remain unchanged. If the stack would otherwise contain more than 16 elements at the end of execution, then adding a call to this function at the end will reduce the size of the public inputs that are shared with the verifier.
Input: Stack with 16 or more elements.
Output: Stack with only the original top 16 elements.

Cycles: `17 + 11 * overflow_words`, where `overflow_words` is the number of words to drop. | +| drop_stack_top | Drops the top 16 values from the stack.

Input: Stack with 16 or more elements.
Output: Stack with the top 16 elements removed. | +| log_precompile_request | Logs a precompile commitment and removes the helper words produced by the underlying `log_precompile` instruction.

Input: `[COMM, TAG, ...]`
Output: `[...]` (top three helper words `R0`, `R1`, `CAP_NEXT` are dropped internally)

Cycles: 1 (plus cost of the underlying `log_precompile` instruction). | diff --git a/docs/src/user_docs/core_lib/sys_vm.md b/docs/src/user_docs/core_lib/sys_vm.md index eeb01757da..5d02aed6cf 100644 --- a/docs/src/user_docs/core_lib/sys_vm.md +++ b/docs/src/user_docs/core_lib/sys_vm.md @@ -11,6 +11,7 @@ Namespace `miden::core::sys::vm` contains low-level helper procedures that are p | Module | Description | | --- | --- | +| `miden::core::sys::vm::aux_trace` | Procedures for observing the auxiliary execution trace in the recursive verifier. | | `miden::core::sys::vm::constraints_eval` | Procedures that perform the constraints evaluation check and manage its associated parameters. | | `miden::core::sys::vm::deep_queries` | Utilities that construct the DEEP queries needed during proof verification. | | `miden::core::sys::vm::mod` | Entry-point procedures that orchestrate the overall recursive verification flow. | diff --git a/docs/src/user_docs/core_lib/word.md b/docs/src/user_docs/core_lib/word.md index 98a7cc8a9c..7b2e0a4435 100644 --- a/docs/src/user_docs/core_lib/word.md +++ b/docs/src/user_docs/core_lib/word.md @@ -11,11 +11,12 @@ See [Terms and notations](./index.md#terms-and-notations) for more information. | Procedure | Description | | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | reverse | Reverses order of the first four elements on the stack.

Inputs: `[a, b, c, d, ...]`
Outputs: `[d, c, b, a, ...]`

Cycles: 3 | +| store_word_u32s_le | Writes the components of a word to memory as eight u32 limbs in little-endian order.

Inputs: `[w0, w1, w2, w3, out_ptr, ...]`
Outputs: `[...]`

Where:
- `w*` are the felts of the input word. Each felt is split into a low and high 32-bit limb.
- `out_ptr` is an element address in memory.
- Memory layout after the call: `[w0_lo, w0_hi, w1_lo, w1_hi, w2_lo, w2_hi, w3_lo, w3_hi]`.

Cycles: 22 | | eqz | Returns a boolean indicating whether the input word `[0, 0, 0, 0]`.

Inputs: `[INPUT_WORD]`
Outputs: `[is_word_empty]`

Where:
- `INPUT_WORD` is the word to compare against `[0, 0, 0, 0]`.
- `is_word_empty` is a boolean indicating whether `INPUT_WORD` is all zeros.

Cycles: 10 | | testz | Returns a boolean indicating whether the input word `[0, 0, 0, 0]` Unlike `eqz`, this does not consume the inputs.

Inputs: `[INPUT_WORD]`
Outputs: `[is_word_empty, INPUT_WORD]`

Where:
- `INPUT_WORD` is the word to compare against `[0, 0, 0, 0]`.
- `is_word_empty` is a boolean indicating whether `INPUT_WORD` is all zeros.

Cycles: 11 | -| gt | Returns true if `LHS` is strictly greater than `RHS`, false otherwise.

It compares words using the same ordering as Merkle tree key comparison. This implementation avoids branching for performance reasons.

Inputs: `[RHS, LHS]`
Outputs: `[is_lhs_greater]`

Cycles: 121 | -| gte | Returns true if `LHS` is greater than or equal to `RHS`.

Inputs: `[RHS, LHS]`
Outputs: `[is_lhs_greater_or_equal]`

Cycles: 118 | -| lt | Returns true if `LHS` is strictly less than `RHS`, false otherwise.

The implementation avoids branching for performance reasons.

From an implementation standpoint this is exactly the same as `word::gt` except it uses `lt` rather than `gt`. See its docs for details.

Inputs: `[RHS, LHS]`
Outputs: `[is_lhs_lesser]`

Cycles: 117 | -| lte | Returns true if `LHS` is strictly less than or equal to `RHS`, false otherwise.

Inputs: `[RHS, LHS]`
Outputs: `[is_lhs_less_or_equal]`

Cycles: 122 | +| gt | Returns true if `LHS` is strictly greater than `RHS`, false otherwise.

It compares words using the same ordering as Merkle tree key comparison. This implementation avoids branching for performance reasons.

Inputs: `[RHS, LHS]`
Outputs: `[is_lhs_greater]`

Cycles: 133 | +| gte | Returns true if `LHS` is greater than or equal to `RHS`.

Inputs: `[RHS, LHS]`
Outputs: `[is_lhs_greater_or_equal]`

Cycles: 130 | +| lt | Returns true if `LHS` is strictly less than `RHS`, false otherwise.

The implementation avoids branching for performance reasons.

From an implementation standpoint this is exactly the same as `word::gt` except it uses `lt` rather than `gt`. See its docs for details.

Inputs: `[RHS, LHS]`
Outputs: `[is_lhs_lesser]`

Cycles: 129 | +| lte | Returns true if `LHS` is strictly less than or equal to `RHS`, false otherwise.

Inputs: `[RHS, LHS]`
Outputs: `[is_lhs_less_or_equal]`

Cycles: 134 | | eq | Returns true if `LHS` is exactly equal to `RHS`, false otherwise.

The implementation does not branch, and always performs the same number of comparisons.

This is currently equivalent the `eqw` instruction.

Inputs: `[RHS, LHS]`.
Outputs: `[lhs_eq_rhs]`

Cycles: 13 | | test_eq | Returns true if `LHS` is exactly equal to `RHS`, false otherwise. Preserves stack inputs.

Like `word::eq`, the implementation does not branch, and always performs the same number of comparisons.

Inputs: `[RHS, LHS]`
Outputs: `[lhs_eq_rhs, RHS, LHS]`

Cycles: 15 | diff --git a/miden-core-fuzz/Cargo.lock b/miden-core-fuzz/Cargo.lock new file mode 100644 index 0000000000..c1b000e2de --- /dev/null +++ b/miden-core-fuzz/Cargo.lock @@ -0,0 +1,2521 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aead" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +dependencies = [ + "crypto-common", + "generic-array", +] + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" + +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "ascii-canvas" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef1e3e699d84ab1b0911a1010c5c106aa34ae89aeac103be5ce0c3859db1e891" +dependencies = [ + "term", +] + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base64ct" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" + +[[package]] +name = "bit-set" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" + +[[package]] +name = "bitflags" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" + +[[package]] +name = "blake3" +version = "1.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0aa83c34e62843d924f905e0f5c866eb1dd6545fc4d719e803d9ba6030371fce" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", + "cpufeatures 0.3.0", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bumpalo" +version = "3.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" + +[[package]] +name = "cc" +version = "1.2.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d16d90359e986641506914ba71350897565610e87ce0ad9e6f28569db3dd5c6d" +dependencies = [ + "find-msvc-tools", + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "chacha20" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures 0.2.17", +] + +[[package]] +name = "chacha20poly1305" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35" +dependencies = [ + "aead", + "chacha20", + "cipher", + "poly1305", + "zeroize", +] + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", + "zeroize", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "constant_time_eq" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + +[[package]] +name = "critical-section" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" + +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "typenum", +] + +[[package]] +name = "curve25519-dalek" +version = "4.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if", + "cpufeatures 0.2.17", + "curve25519-dalek-derive", + "digest", + "fiat-crypto", + "rustc_version 0.4.1", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "der" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "derive_more" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" +dependencies = [ + "proc-macro2", + "quote", + "rustc_version 0.4.1", + "syn 2.0.117", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "dissimilar" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aeda16ab4059c5fd2a83f2b9c9e9c981327b18aa8e3b313f7e6563799d4f093e" + +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "pkcs8", + "signature", +] + +[[package]] +name = "ed25519-dalek" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9" +dependencies = [ + "curve25519-dalek", + "ed25519", + "serde", + "sha2", + "subtle", + "zeroize", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest", + "ff", + "generic-array", + "group", + "hkdf", + "pkcs8", + "rand_core 0.6.4", + "sec1", + "subtle", + "zeroize", +] + +[[package]] +name = "ena" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eabffdaee24bd1bf95c5ef7cec31260444317e72ea56c4c91750e8b7ee58d5f1" +dependencies = [ + "log", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "erased-serde" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2add8a07dd6a8d93ff627029c51de145e12686fbc36ecb298ac22e74cf02dec" +dependencies = [ + "serde", + "serde_core", + "typeid", +] + +[[package]] +name = "ff" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "fixedbitset" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" + +[[package]] +name = "flume" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" +dependencies = [ + "futures-core", + "futures-sink", + "nanorand", + "spin 0.9.8", +] + +[[package]] +name = "futures" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" + +[[package]] +name = "futures-io" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" + +[[package]] +name = "futures-sink" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" + +[[package]] +name = "futures-task" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" + +[[package]] +name = "futures-util" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +dependencies = [ + "futures-core", + "futures-sink", + "futures-task", + "pin-project-lite", + "slab", +] + +[[package]] +name = "generator" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52f04ae4152da20c76fe800fa48659201d5cf627c5149ca0b707b69d7eef6cf9" +dependencies = [ + "cc", + "cfg-if", + "libc", + "log", + "rustversion", + "windows-link", + "windows-result", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", +] + +[[package]] +name = "glob" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "hashbrown" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51" + +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "indenter" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "964de6e86d545b246d84badc0fef527924ace5134f30641c203ef52ba83f58d5" + +[[package]] +name = "indexmap" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "inout" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +dependencies = [ + "generic-array", +] + +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom 0.3.4", + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.97" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1840c94c045fbcf8ba2812c95db44499f7c64910a912551aaaa541decebcacf" +dependencies = [ + "cfg-if", + "futures-util", + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "k256" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "once_cell", + "sha2", + "signature", +] + +[[package]] +name = "keccak" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb26cec98cce3a3d96cbb7bced3c4b16e3d13f27ec56dbd62cbc8f39cfb9d653" +dependencies = [ + "cpufeatures 0.2.17", +] + +[[package]] +name = "lalrpop" +version = "0.22.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba4ebbd48ce411c1d10fb35185f5a51a7bfa3d8b24b4e330d30c9e3a34129501" +dependencies = [ + "ascii-canvas", + "bit-set", + "ena", + "itertools", + "lalrpop-util", + "petgraph", + "regex", + "regex-syntax", + "sha3", + "string_cache", + "term", + "unicode-xid", + "walkdir", +] + +[[package]] +name = "lalrpop-util" +version = "0.22.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5baa5e9ff84f1aefd264e6869907646538a52147a755d494517a8007fb48733" +dependencies = [ + "rustversion", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.186" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" + +[[package]] +name = "libfuzzer-sys" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f12a681b7dd8ce12bff52488013ba614b869148d54dd79836ab85aafdd53f08d" +dependencies = [ + "arbitrary", + "cc", +] + +[[package]] +name = "libm" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "loom" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "419e0dc8046cb947daa77eb95ae174acfbddb7673b4151f56d1eed8e93fbfaca" +dependencies = [ + "cfg-if", + "generator", + "scoped-tls", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "matchers" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" +dependencies = [ + "regex-automata", +] + +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "miden-assembly" +version = "0.23.0" +dependencies = [ + "log", + "miden-assembly-syntax", + "miden-core", + "miden-mast-package", + "miden-package-registry", + "miden-project", + "proptest", + "smallvec", + "thiserror", +] + +[[package]] +name = "miden-assembly-syntax" +version = "0.23.0" +dependencies = [ + "aho-corasick", + "lalrpop", + "lalrpop-util", + "log", + "miden-core", + "miden-debug-types", + "miden-utils-diagnostics", + "midenc-hir-type", + "proptest", + "regex", + "rustc_version 0.4.1", + "semver 1.0.28", + "serde", + "smallvec", + "thiserror", +] + +[[package]] +name = "miden-core" +version = "0.23.0" +dependencies = [ + "derive_more", + "log", + "miden-crypto", + "miden-debug-types", + "miden-formatting", + "miden-utils-core-derive", + "miden-utils-indexing", + "miden-utils-sync", + "num-derive", + "num-traits", + "serde", + "thiserror", +] + +[[package]] +name = "miden-core-fuzz" +version = "0.0.0" +dependencies = [ + "libfuzzer-sys", + "miden-assembly", + "miden-assembly-syntax", + "miden-core", + "miden-mast-package", + "miden-package-registry", + "miden-project", + "serde_json", + "toml", +] + +[[package]] +name = "miden-crypto" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72ae084a6d15d5d862760bcbdbb5caad41415ed455cd7ab2b53a012d21a431ed" +dependencies = [ + "blake3", + "cc", + "chacha20poly1305", + "curve25519-dalek", + "der", + "ed25519-dalek", + "flume", + "hkdf", + "k256", + "miden-crypto-derive", + "miden-field", + "miden-lifted-stark", + "miden-serde-utils", + "num", + "num-complex", + "once_cell", + "p3-blake3", + "p3-challenger", + "p3-dft", + "p3-goldilocks", + "p3-keccak", + "p3-matrix", + "p3-maybe-rayon", + "p3-symmetric", + "p3-util", + "rand 0.9.4", + "rand_chacha", + "rand_core 0.9.5", + "rand_hc", + "serde", + "sha2", + "sha3", + "subtle", + "thiserror", + "x25519-dalek", +] + +[[package]] +name = "miden-crypto-derive" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8523f6ac9b28782ca759920e536164e7eab7dbfaf9132721ca3e325c060df73" +dependencies = [ + "quote", + "syn 2.0.117", +] + +[[package]] +name = "miden-debug-types" +version = "0.23.0" +dependencies = [ + "memchr", + "miden-crypto", + "miden-formatting", + "miden-miette", + "miden-utils-indexing", + "miden-utils-sync", + "paste", + "proptest", + "serde", + "serde_spanned", + "thiserror", +] + +[[package]] +name = "miden-field" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b8a48ba526c353bf583bba18ddf62ad4846945e85fcaf44614633276416b5d9" +dependencies = [ + "miden-serde-utils", + "num-bigint", + "p3-challenger", + "p3-field", + "p3-goldilocks", + "p3-util", + "paste", + "rand 0.10.1", + "serde", + "subtle", + "thiserror", +] + +[[package]] +name = "miden-formatting" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e392e0a8c34b32671012b439de35fa8987bf14f0f8aac279b97f8b8cc6e263b" +dependencies = [ + "unicode-width 0.1.14", +] + +[[package]] +name = "miden-lifted-air" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a00d97ada3bfd70d6cc4f1a13ced8cb509f72fb16b1b28c292366aee846d3220" +dependencies = [ + "p3-air", + "p3-field", + "p3-matrix", + "p3-util", + "thiserror", +] + +[[package]] +name = "miden-lifted-stark" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab3601a30d39e08a31ecc5b5215c87b11623942d9610aebccda89a4a5bf757c4" +dependencies = [ + "miden-lifted-air", + "miden-stark-transcript", + "miden-stateful-hasher", + "p3-challenger", + "p3-dft", + "p3-field", + "p3-goldilocks", + "p3-matrix", + "p3-maybe-rayon", + "p3-symmetric", + "p3-util", + "rand 0.10.1", + "serde", + "thiserror", + "tracing", +] + +[[package]] +name = "miden-mast-package" +version = "0.23.0" +dependencies = [ + "miden-assembly-syntax", + "miden-core", + "miden-debug-types", + "serde", + "thiserror", +] + +[[package]] +name = "miden-miette" +version = "8.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eef536978f24a179d94fa2a41e4f92b28e7d8aab14b8d23df28ad2a3d7098b20" +dependencies = [ + "cfg-if", + "futures", + "indenter", + "lazy_static", + "miden-miette-derive", + "owo-colors", + "regex", + "rustc_version 0.2.3", + "rustversion", + "serde_json", + "spin 0.9.8", + "strip-ansi-escapes", + "syn 2.0.117", + "textwrap", + "thiserror", + "trybuild", + "unicode-width 0.1.14", +] + +[[package]] +name = "miden-miette-derive" +version = "8.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86a905f3ea65634dd4d1041a4f0fd0a3e77aa4118341d265af1a94339182222f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "miden-package-registry" +version = "0.23.0" +dependencies = [ + "miden-assembly-syntax", + "miden-core", + "miden-mast-package", + "proptest", + "pubgrub", + "serde", + "smallvec", + "thiserror", +] + +[[package]] +name = "miden-project" +version = "0.23.0" +dependencies = [ + "miden-assembly-syntax", + "miden-core", + "miden-mast-package", + "miden-package-registry", + "proptest", + "serde", + "serde-untagged", + "thiserror", + "toml", +] + +[[package]] +name = "miden-serde-utils" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d899afcfbf85c851522f2dff73db1064116486fb8e0ebce0ade44ce72dadc075" +dependencies = [ + "p3-field", + "p3-goldilocks", +] + +[[package]] +name = "miden-stark-transcript" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c0e1f55bdff89f12ec6fc3881660a0d51d4e77f66026ab0e6ddcbd098a16f2f" +dependencies = [ + "p3-challenger", + "p3-field", + "serde", + "thiserror", +] + +[[package]] +name = "miden-stateful-hasher" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0069bab01139a5660c7189589c95dfedf8449514d03641fd3f9d049e1b031f9" +dependencies = [ + "p3-field", + "p3-symmetric", +] + +[[package]] +name = "miden-utils-core-derive" +version = "0.23.0" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "miden-utils-diagnostics" +version = "0.23.0" +dependencies = [ + "miden-crypto", + "miden-debug-types", + "miden-miette", + "tracing", +] + +[[package]] +name = "miden-utils-indexing" +version = "0.23.0" +dependencies = [ + "miden-crypto", + "proptest", + "serde", + "thiserror", +] + +[[package]] +name = "miden-utils-sync" +version = "0.23.0" +dependencies = [ + "lock_api", + "loom", + "once_cell", + "parking_lot", +] + +[[package]] +name = "midenc-hir-type" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ff0511aa2201f7098995e38a3c97a319d379c3b2d26fb83677b21b71f61a7b4" +dependencies = [ + "miden-formatting", + "miden-serde-utils", + "serde", + "serde_repr", + "smallvec", + "thiserror", +] + +[[package]] +name = "nanorand" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3" +dependencies = [ + "getrandom 0.2.17", +] + +[[package]] +name = "new_debug_unreachable" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" + +[[package]] +name = "nu-ansi-term" +version = "0.50.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "num" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" +dependencies = [ + "critical-section", + "portable-atomic", +] + +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "owo-colors" +version = "4.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d211803b9b6b570f68772237e415a029d5a50c65d382910b879fb19d3271f94d" + +[[package]] +name = "p3-air" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f2ec9cbfc642fc5173817287c3f8b789d07743b5f7e812d058b7a03e344f9ab" +dependencies = [ + "p3-field", + "p3-matrix", + "tracing", +] + +[[package]] +name = "p3-blake3" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b667f43b19499dd939c9e2553aa95688936a88360d50117dae3c8848d07dbc70" +dependencies = [ + "blake3", + "p3-symmetric", + "p3-util", +] + +[[package]] +name = "p3-challenger" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a0b490c745a7d2adeeafff06411814c8078c432740162332b3cd71be0158a76" +dependencies = [ + "p3-field", + "p3-maybe-rayon", + "p3-monty-31", + "p3-symmetric", + "p3-util", + "tracing", +] + +[[package]] +name = "p3-dft" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55301e91544440254977108b85c32c09d7ea05f2f0dd61092a2825339906a4a7" +dependencies = [ + "itertools", + "p3-field", + "p3-matrix", + "p3-maybe-rayon", + "p3-util", + "spin 0.10.0", + "tracing", +] + +[[package]] +name = "p3-field" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85affca7fc983889f260655c4cf74163eebb94605f702e4b6809ead707cba54f" +dependencies = [ + "itertools", + "num-bigint", + "p3-maybe-rayon", + "p3-util", + "paste", + "rand 0.10.1", + "serde", + "tracing", +] + +[[package]] +name = "p3-goldilocks" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ca1081f5c47b940f2d75a11c04f62ea1cc58a5d480dd465fef3861c045c63cd" +dependencies = [ + "num-bigint", + "p3-challenger", + "p3-dft", + "p3-field", + "p3-mds", + "p3-poseidon1", + "p3-poseidon2", + "p3-symmetric", + "p3-util", + "paste", + "rand 0.10.1", + "serde", +] + +[[package]] +name = "p3-keccak" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebcf27615ece1995e4fcf4c69740f1cf515d1481367a20b4b3ce7f4f1b8d70f7" +dependencies = [ + "p3-symmetric", + "p3-util", + "tiny-keccak", +] + +[[package]] +name = "p3-matrix" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53428126b009071563d1d07305a9de8be0d21de00b57d2475289ee32ffca6577" +dependencies = [ + "itertools", + "p3-field", + "p3-maybe-rayon", + "p3-util", + "rand 0.10.1", + "serde", + "tracing", +] + +[[package]] +name = "p3-maybe-rayon" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "082bf467011c06c768c579ec6eb9accb5e1e62108891634cc770396e917f978a" + +[[package]] +name = "p3-mds" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35209e6214102ea6ec6b8cb1b9c15a9b8e597a39f9173597c957f123bced81b3" +dependencies = [ + "p3-dft", + "p3-field", + "p3-symmetric", + "p3-util", + "rand 0.10.1", +] + +[[package]] +name = "p3-monty-31" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffa8c99ec50c035020bbf5457c6a729ba6a975719c1a8dd3f16421081e4f650c" +dependencies = [ + "itertools", + "num-bigint", + "p3-dft", + "p3-field", + "p3-matrix", + "p3-maybe-rayon", + "p3-mds", + "p3-poseidon1", + "p3-poseidon2", + "p3-symmetric", + "p3-util", + "paste", + "rand 0.10.1", + "serde", + "spin 0.10.0", + "tracing", +] + +[[package]] +name = "p3-poseidon1" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a018b618e3fa0aec8be933b1d8e404edd23f46991f6bf3f5c2f3f95e9413fe9" +dependencies = [ + "p3-field", + "p3-symmetric", + "rand 0.10.1", +] + +[[package]] +name = "p3-poseidon2" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "256a668a9ba916f8767552f13d0ba50d18968bc74a623bfdafa41e2970c944d0" +dependencies = [ + "p3-field", + "p3-mds", + "p3-symmetric", + "p3-util", + "rand 0.10.1", +] + +[[package]] +name = "p3-symmetric" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c60a71a1507c13611b0f2b0b6e83669fd5b76f8e3115bcbced5ccfdf3ca7807" +dependencies = [ + "itertools", + "p3-field", + "p3-util", + "serde", +] + +[[package]] +name = "p3-util" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8b766b9e9254bf3fa98d76e42cf8a5b30628c182dfd5272d270076ee12f0fc0" +dependencies = [ + "serde", + "transpose", +] + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "petgraph" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772" +dependencies = [ + "fixedbitset", + "indexmap", +] + +[[package]] +name = "phf_shared" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "poly1305" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" +dependencies = [ + "cpufeatures 0.2.17", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "portable-atomic" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "precomputed-hash" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" + +[[package]] +name = "priority-queue" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93980406f12d9f8140ed5abe7155acb10bb1e69ea55c88960b9c2f117445ef96" +dependencies = [ + "equivalent", + "indexmap", + "serde", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "proptest" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b45fcc2344c680f5025fe57779faef368840d0bd1f42f216291f0dc4ace4744" +dependencies = [ + "bitflags", + "num-traits", + "rand 0.9.4", + "rand_chacha", + "rand_xorshift", + "regex-syntax", + "unarray", +] + +[[package]] +name = "pubgrub" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f5df7e552bc7edd075f5783a87fbfc21d6a546e32c16985679c488c18192d83" +dependencies = [ + "indexmap", + "log", + "priority-queue", + "rustc-hash", + "thiserror", + "version-ranges", +] + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "rand" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" +dependencies = [ + "rand_chacha", + "rand_core 0.9.5", +] + +[[package]] +name = "rand" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207" +dependencies = [ + "rand_core 0.10.1", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.5", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.17", +] + +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom 0.3.4", +] + +[[package]] +name = "rand_core" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" + +[[package]] +name = "rand_hc" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b363d4f6370f88d62bf586c80405657bde0f0e1b8945d47d2ad59b906cb4f54" +dependencies = [ + "rand_core 0.6.4", +] + +[[package]] +name = "rand_xorshift" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a" +dependencies = [ + "rand_core 0.9.5", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + +[[package]] +name = "rustc-hash" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver 0.9.0", +] + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver 1.0.28", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" +dependencies = [ + "serde", + "serde_core", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde-untagged" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9faf48a4a2d2693be24c6289dbe26552776eb7737074e6722891fadbe6c5058" +dependencies = [ + "erased-serde", + "serde", + "serde_core", + "typeid", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_repr" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "serde_spanned" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26" +dependencies = [ + "serde_core", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures 0.2.17", + "digest", +] + +[[package]] +name = "sha3" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77fd7028345d415a4034cf8777cd4f8ab1851274233b45f84e3d955502d93874" +dependencies = [ + "digest", + "keccak", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core 0.6.4", +] + +[[package]] +name = "siphasher" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e" + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +dependencies = [ + "serde", +] + +[[package]] +name = "smawk" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + +[[package]] +name = "spin" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5fe4ccb98d9c292d56fec89a5e07da7fc4cf0dc11e156b41793132775d3e591" +dependencies = [ + "lock_api", +] + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "strength_reduce" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe895eb47f22e2ddd4dabc02bce419d2e643c8e3b585c78158b349195bc24d82" + +[[package]] +name = "string_cache" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf776ba3fa74f83bf4b63c3dcbbf82173db2632ed8452cb2d891d33f459de70f" +dependencies = [ + "new_debug_unreachable", + "parking_lot", + "phf_shared", + "precomputed-hash", +] + +[[package]] +name = "strip-ansi-escapes" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a8f8038e7e7969abb3f1b7c2a811225e9296da208539e0f79c5251d6cac0025" +dependencies = [ + "vte", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "target-triple" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "591ef38edfb78ca4771ee32cf494cb8771944bee237a9b91fc9c1424ac4b777b" + +[[package]] +name = "term" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8c27177b12a6399ffc08b98f76f7c9a1f4fe9fc967c784c5a071fa8d93cf7e1" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "textwrap" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c13547615a44dc9c452a8a534638acdf07120d4b6847c8178705da06306a3057" +dependencies = [ + "smawk", + "unicode-linebreak", + "unicode-width 0.2.2", +] + +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "thread_local" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "toml" +version = "1.1.2+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81f3d15e84cbcd896376e6730314d59fb5a87f31e4b038454184435cd57defee" +dependencies = [ + "indexmap", + "serde_core", + "serde_spanned", + "toml_datetime", + "toml_parser", + "toml_writer", + "winnow", +] + +[[package]] +name = "toml_datetime" +version = "1.1.1+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_parser" +version = "1.1.2+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" +dependencies = [ + "winnow", +] + +[[package]] +name = "toml_writer" +version = "1.1.1+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db" + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex-automata", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "transpose" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad61aed86bc3faea4300c7aee358b4c6d0c8d6ccc36524c96e4c92ccf26e77e" +dependencies = [ + "num-integer", + "strength_reduce", +] + +[[package]] +name = "trybuild" +version = "1.0.116" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47c635f0191bd3a2941013e5062667100969f8c4e9cd787c14f977265d73616e" +dependencies = [ + "dissimilar", + "glob", + "serde", + "serde_derive", + "serde_json", + "target-triple", + "termcolor", + "toml", +] + +[[package]] +name = "typeid" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" + +[[package]] +name = "typenum" +version = "1.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de" + +[[package]] +name = "unarray" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-linebreak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" + +[[package]] +name = "unicode-width" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + +[[package]] +name = "unicode-width" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "universal-hash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +dependencies = [ + "crypto-common", + "subtle", +] + +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + +[[package]] +name = "version-ranges" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e9bd4e9c9ff6a2a9b5969462ba26216af3e010df0377dad8320ab515262ef8" +dependencies = [ + "smallvec", +] + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "vte" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "231fdcd7ef3037e8330d8e17e61011a2c244126acc0a982f4040ac3f9f0bc077" +dependencies = [ + "memchr", +] + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.3+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.120" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df52b6d9b87e0c74c9edfa1eb2d9bf85e5d63515474513aa50fa181b3c4f5db1" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.120" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b1041f495fb322e64aca85f5756b2172e35cd459376e67f2a6c9dffcedb103" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.120" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dcd0ff20416988a18ac686d4d4d0f6aae9ebf08a389ff5d29012b05af2a1b41" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn 2.0.117", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.120" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49757b3c82ebf16c57d69365a142940b384176c24df52a087fb748e2085359ea" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "winnow" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ee1708bef14716a11bae175f579062d4554d95be2c6829f518df847b7b3fdd0" + +[[package]] +name = "wit-bindgen" +version = "0.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + +[[package]] +name = "x25519-dalek" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277" +dependencies = [ + "curve25519-dalek", + "rand_core 0.6.4", +] + +[[package]] +name = "zerocopy" +version = "0.8.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "zeroize" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/miden-core-fuzz/Cargo.toml b/miden-core-fuzz/Cargo.toml index 9d05e66626..56dc58ef14 100644 --- a/miden-core-fuzz/Cargo.toml +++ b/miden-core-fuzz/Cargo.toml @@ -23,10 +23,26 @@ features = ["std", "serde"] path = "../crates/assembly-syntax" features = ["std", "serde"] +[dependencies.miden-assembly] +path = "../crates/assembly" +features = ["std"] + [dependencies.miden-mast-package] path = "../crates/mast-package" features = ["std"] +[dependencies.miden-package-registry] +path = "../crates/package-registry" +features = ["std", "serde", "resolver"] + +[dependencies.miden-project] +path = "../crates/project" +features = ["std", "serde"] + +[dependencies.toml] +version = "1.0" +features = ["parse", "display", "serde"] + # Fuzz targets - each is a separate binary [[bin]] name = "mast_forest_deserialize" @@ -49,6 +65,13 @@ test = false doc = false bench = false +[[bin]] +name = "serialized_mast_forest_new" +path = "fuzz_targets/serialized_mast_forest_new.rs" +test = false +doc = false +bench = false + [[bin]] name = "basic_block_data" path = "fuzz_targets/basic_block_data.rs" @@ -175,6 +198,13 @@ test = false doc = false bench = false +[[bin]] +name = "package_semantic_deserialize" +path = "fuzz_targets/package_semantic_deserialize.rs" +test = false +doc = false +bench = false + [[bin]] name = "package_serde_deserialize" path = "fuzz_targets/package_serde_deserialize.rs" @@ -188,3 +218,24 @@ path = "fuzz_targets/mast_forest_serde_deserialize.rs" test = false doc = false bench = false + +[[bin]] +name = "project_toml_parse" +path = "fuzz_targets/project_toml_parse.rs" +test = false +doc = false +bench = false + +[[bin]] +name = "project_load" +path = "fuzz_targets/project_load.rs" +test = false +doc = false +bench = false + +[[bin]] +name = "project_assemble" +path = "fuzz_targets/project_assemble.rs" +test = false +doc = false +bench = false diff --git a/miden-core-fuzz/README.md b/miden-core-fuzz/README.md index 277177d0d8..5103504080 100644 --- a/miden-core-fuzz/README.md +++ b/miden-core-fuzz/README.md @@ -101,7 +101,7 @@ cargo +nightly fuzz run operation_deserialize --fuzz-dir miden-core-fuzz cargo +nightly fuzz run operation_serde_deserialize --fuzz-dir miden-core-fuzz ``` -**`execution_proof_deserialize`** — Tests `ExecutionProof::read_from_bytes`. +**`execution_proof_deserialize`** — Tests `ExecutionProof::from_bytes` and `ExecutionProof::read_from_bytes`. ```bash cargo +nightly fuzz run execution_proof_deserialize --fuzz-dir miden-core-fuzz diff --git a/miden-core-fuzz/corpus/project_assemble/debug_profile b/miden-core-fuzz/corpus/project_assemble/debug_profile new file mode 100644 index 0000000000..1d566547a2 --- /dev/null +++ b/miden-core-fuzz/corpus/project_assemble/debug_profile @@ -0,0 +1,2 @@ +[metadata] +purpose = "exercise debug-enabled project assembly" diff --git a/miden-core-fuzz/corpus/project_assemble/empty_snippet b/miden-core-fuzz/corpus/project_assemble/empty_snippet new file mode 100644 index 0000000000..47e8704ac8 --- /dev/null +++ b/miden-core-fuzz/corpus/project_assemble/empty_snippet @@ -0,0 +1 @@ +# empty snippet diff --git a/miden-core-fuzz/corpus/project_assemble/release_trim_paths b/miden-core-fuzz/corpus/project_assemble/release_trim_paths new file mode 100644 index 0000000000..e04f0f506d --- /dev/null +++ b/miden-core-fuzz/corpus/project_assemble/release_trim_paths @@ -0,0 +1,2 @@ +[lints] +unused-imports = "allow" diff --git a/miden-core-fuzz/corpus/project_load/inherited_workspace b/miden-core-fuzz/corpus/project_load/inherited_workspace new file mode 100644 index 0000000000..5fd5d0d468 --- /dev/null +++ b/miden-core-fuzz/corpus/project_load/inherited_workspace @@ -0,0 +1,10 @@ +[package] +name = "workspace-member" +version.workspace = true +description.workspace = true + +[lib] +path = "lib.masm" + +[dependencies] +shared-dep.workspace = true diff --git a/miden-core-fuzz/corpus/project_load/kernel_package b/miden-core-fuzz/corpus/project_load/kernel_package new file mode 100644 index 0000000000..4f36c6b4e4 --- /dev/null +++ b/miden-core-fuzz/corpus/project_load/kernel_package @@ -0,0 +1,11 @@ +[package] +name = "mykernel" +version = "2.0.0" + +[lib] +kind = "kernel" +path = "kernel/mod.masm" + +[[bin]] +name = "entry" +path = "bin/entry.masm" diff --git a/miden-core-fuzz/corpus/project_load/package_with_bins b/miden-core-fuzz/corpus/project_load/package_with_bins new file mode 100644 index 0000000000..52fe67b1da --- /dev/null +++ b/miden-core-fuzz/corpus/project_load/package_with_bins @@ -0,0 +1,11 @@ +[package] +name = "myapp" +version = "0.1.0" + +[[bin]] +name = "main" +path = "bin/main.masm" + +[[bin]] +name = "helper" +path = "bin/helper.masm" diff --git a/miden-core-fuzz/corpus/project_load/package_with_deps b/miden-core-fuzz/corpus/project_load/package_with_deps new file mode 100644 index 0000000000..9ef860bd50 --- /dev/null +++ b/miden-core-fuzz/corpus/project_load/package_with_deps @@ -0,0 +1,12 @@ +[package] +name = "myproject" +version = "0.5.0" + +[lib] +path = "lib.masm" + +[dependencies] +stdlib = { version = "1.0.0" } +local-dep = { path = "../local-dep", linkage = "static" } +remote-dep = { git = "https://github.com/example/repo", branch = "main" } +workspace-dep.workspace = true diff --git a/miden-core-fuzz/corpus/project_load/package_with_lib b/miden-core-fuzz/corpus/project_load/package_with_lib new file mode 100644 index 0000000000..39254d2bec --- /dev/null +++ b/miden-core-fuzz/corpus/project_load/package_with_lib @@ -0,0 +1,8 @@ +[package] +name = "mylib" +version = "1.0.0" +description = "A simple library" + +[lib] +namespace = "mylib" +path = "lib.masm" diff --git a/miden-core-fuzz/corpus/project_load/package_with_metadata b/miden-core-fuzz/corpus/project_load/package_with_metadata new file mode 100644 index 0000000000..75dc0c2566 --- /dev/null +++ b/miden-core-fuzz/corpus/project_load/package_with_metadata @@ -0,0 +1,14 @@ +[package] +name = "metadata-example" +version = "0.1.0" +description = "Example with metadata" + +[lib] +path = "lib.masm" + +[package.metadata.custom] +key = "value" +number = 42 + +[lints.miden] +unused = "warn" diff --git a/miden-core-fuzz/corpus/project_load/package_with_profile b/miden-core-fuzz/corpus/project_load/package_with_profile new file mode 100644 index 0000000000..984ef24e3b --- /dev/null +++ b/miden-core-fuzz/corpus/project_load/package_with_profile @@ -0,0 +1,14 @@ +[package] +name = "profiled" +version = "0.1.0" + +[lib] +path = "lib.masm" + +[profile.release] +debug = false +trim-paths = true + +[profile.custom] +inherits = "dev" +debug = true diff --git a/miden-core-fuzz/corpus/project_load/simple_package b/miden-core-fuzz/corpus/project_load/simple_package new file mode 100644 index 0000000000..517a262fe8 --- /dev/null +++ b/miden-core-fuzz/corpus/project_load/simple_package @@ -0,0 +1,3 @@ +[package] +name = "simple" +version = "0.1.0" diff --git a/miden-core-fuzz/corpus/project_load/workspace_manifest b/miden-core-fuzz/corpus/project_load/workspace_manifest new file mode 100644 index 0000000000..67a73e0486 --- /dev/null +++ b/miden-core-fuzz/corpus/project_load/workspace_manifest @@ -0,0 +1,10 @@ +[workspace] +members = ["crate-a", "crate-b", "crate-c"] + +[workspace.package] +version = "0.1.0" +description = "A workspace example" + +[workspace.dependencies] +foo = { path = "crate-a" } +bar = { version = "1.0.0", linkage = "static" } diff --git a/miden-core-fuzz/corpus/project_toml_parse/inherited_workspace b/miden-core-fuzz/corpus/project_toml_parse/inherited_workspace new file mode 100644 index 0000000000..5fd5d0d468 --- /dev/null +++ b/miden-core-fuzz/corpus/project_toml_parse/inherited_workspace @@ -0,0 +1,10 @@ +[package] +name = "workspace-member" +version.workspace = true +description.workspace = true + +[lib] +path = "lib.masm" + +[dependencies] +shared-dep.workspace = true diff --git a/miden-core-fuzz/corpus/project_toml_parse/kernel_package b/miden-core-fuzz/corpus/project_toml_parse/kernel_package new file mode 100644 index 0000000000..4f36c6b4e4 --- /dev/null +++ b/miden-core-fuzz/corpus/project_toml_parse/kernel_package @@ -0,0 +1,11 @@ +[package] +name = "mykernel" +version = "2.0.0" + +[lib] +kind = "kernel" +path = "kernel/mod.masm" + +[[bin]] +name = "entry" +path = "bin/entry.masm" diff --git a/miden-core-fuzz/corpus/project_toml_parse/package_with_bins b/miden-core-fuzz/corpus/project_toml_parse/package_with_bins new file mode 100644 index 0000000000..52fe67b1da --- /dev/null +++ b/miden-core-fuzz/corpus/project_toml_parse/package_with_bins @@ -0,0 +1,11 @@ +[package] +name = "myapp" +version = "0.1.0" + +[[bin]] +name = "main" +path = "bin/main.masm" + +[[bin]] +name = "helper" +path = "bin/helper.masm" diff --git a/miden-core-fuzz/corpus/project_toml_parse/package_with_deps b/miden-core-fuzz/corpus/project_toml_parse/package_with_deps new file mode 100644 index 0000000000..9ef860bd50 --- /dev/null +++ b/miden-core-fuzz/corpus/project_toml_parse/package_with_deps @@ -0,0 +1,12 @@ +[package] +name = "myproject" +version = "0.5.0" + +[lib] +path = "lib.masm" + +[dependencies] +stdlib = { version = "1.0.0" } +local-dep = { path = "../local-dep", linkage = "static" } +remote-dep = { git = "https://github.com/example/repo", branch = "main" } +workspace-dep.workspace = true diff --git a/miden-core-fuzz/corpus/project_toml_parse/package_with_lib b/miden-core-fuzz/corpus/project_toml_parse/package_with_lib new file mode 100644 index 0000000000..39254d2bec --- /dev/null +++ b/miden-core-fuzz/corpus/project_toml_parse/package_with_lib @@ -0,0 +1,8 @@ +[package] +name = "mylib" +version = "1.0.0" +description = "A simple library" + +[lib] +namespace = "mylib" +path = "lib.masm" diff --git a/miden-core-fuzz/corpus/project_toml_parse/package_with_metadata b/miden-core-fuzz/corpus/project_toml_parse/package_with_metadata new file mode 100644 index 0000000000..75dc0c2566 --- /dev/null +++ b/miden-core-fuzz/corpus/project_toml_parse/package_with_metadata @@ -0,0 +1,14 @@ +[package] +name = "metadata-example" +version = "0.1.0" +description = "Example with metadata" + +[lib] +path = "lib.masm" + +[package.metadata.custom] +key = "value" +number = 42 + +[lints.miden] +unused = "warn" diff --git a/miden-core-fuzz/corpus/project_toml_parse/package_with_profile b/miden-core-fuzz/corpus/project_toml_parse/package_with_profile new file mode 100644 index 0000000000..984ef24e3b --- /dev/null +++ b/miden-core-fuzz/corpus/project_toml_parse/package_with_profile @@ -0,0 +1,14 @@ +[package] +name = "profiled" +version = "0.1.0" + +[lib] +path = "lib.masm" + +[profile.release] +debug = false +trim-paths = true + +[profile.custom] +inherits = "dev" +debug = true diff --git a/miden-core-fuzz/corpus/project_toml_parse/simple_package b/miden-core-fuzz/corpus/project_toml_parse/simple_package new file mode 100644 index 0000000000..517a262fe8 --- /dev/null +++ b/miden-core-fuzz/corpus/project_toml_parse/simple_package @@ -0,0 +1,3 @@ +[package] +name = "simple" +version = "0.1.0" diff --git a/miden-core-fuzz/corpus/project_toml_parse/workspace_manifest b/miden-core-fuzz/corpus/project_toml_parse/workspace_manifest new file mode 100644 index 0000000000..67a73e0486 --- /dev/null +++ b/miden-core-fuzz/corpus/project_toml_parse/workspace_manifest @@ -0,0 +1,10 @@ +[workspace] +members = ["crate-a", "crate-b", "crate-c"] + +[workspace.package] +version = "0.1.0" +description = "A workspace example" + +[workspace.dependencies] +foo = { path = "crate-a" } +bar = { version = "1.0.0", linkage = "static" } diff --git a/miden-core-fuzz/fuzz_targets/execution_proof_deserialize.rs b/miden-core-fuzz/fuzz_targets/execution_proof_deserialize.rs index 5aa43d5943..c006d73c61 100644 --- a/miden-core-fuzz/fuzz_targets/execution_proof_deserialize.rs +++ b/miden-core-fuzz/fuzz_targets/execution_proof_deserialize.rs @@ -8,6 +8,7 @@ use libfuzzer_sys::fuzz_target; use miden_core::{proof::ExecutionProof, serde::Deserializable}; fuzz_target!(|data: &[u8]| { + let _ = ExecutionProof::from_bytes(data); let _ = ExecutionProof::read_from_bytes(data); let _ = Vec::::read_from_bytes(data); let _ = Option::::read_from_bytes(data); diff --git a/miden-core-fuzz/fuzz_targets/mast_forest_deserialize.rs b/miden-core-fuzz/fuzz_targets/mast_forest_deserialize.rs index fb5acef3af..0517ce8930 100644 --- a/miden-core-fuzz/fuzz_targets/mast_forest_deserialize.rs +++ b/miden-core-fuzz/fuzz_targets/mast_forest_deserialize.rs @@ -11,13 +11,15 @@ use libfuzzer_sys::fuzz_target; use miden_core::{mast::MastForest, serde::Deserializable}; fuzz_target!(|data: &[u8]| { + let budget = data.len().saturating_mul(64); + // Primary target: raw MastForest deserialization // This should never panic - all errors should be returned as Result::Err let _ = MastForest::read_from_bytes(data); // Also test Vec deserialization (tests length prefix handling) - let _ = Vec::::read_from_bytes(data); + let _ = Vec::::read_from_bytes_with_budget(data, budget); // Test Option deserialization - let _ = Option::::read_from_bytes(data); + let _ = Option::::read_from_bytes_with_budget(data, budget); }); diff --git a/miden-core-fuzz/fuzz_targets/mast_forest_validate.rs b/miden-core-fuzz/fuzz_targets/mast_forest_validate.rs index b06e4c1ffe..290e8d2b36 100644 --- a/miden-core-fuzz/fuzz_targets/mast_forest_validate.rs +++ b/miden-core-fuzz/fuzz_targets/mast_forest_validate.rs @@ -3,7 +3,8 @@ //! This target tests the full untrusted deserialization pipeline: //! 1. UntrustedMastForest::read_from_bytes (budgeted deserialization) //! 2. UntrustedMastForest::validate() (structural + hash validation) -//! 3. UntrustedMastForest::read_from_bytes_with_budget with small budget +//! 3. Budgeted parsing-only and parsing+validation entry points +//! 4. Flag-returning variants for callers that need serializer intent bits //! //! The validation path should never panic on any input. //! @@ -12,11 +13,39 @@ #![no_main] use libfuzzer_sys::fuzz_target; -use miden_core::mast::UntrustedMastForest; +use miden_core::{mast::UntrustedMastForest, serde::DeserializationError}; fuzz_target!(|data: &[u8]| { + let validate_untrusted = |result: Result| { + if let Ok(untrusted) = result { + let _ = untrusted.validate(); + } + }; + let validate_untrusted_with_flags = + |result: Result<(UntrustedMastForest, u8), DeserializationError>| { + if let Ok((untrusted, _flags)) = result { + let _ = untrusted.validate(); + } + }; + // Test the full untrusted deserialization + validation pipeline let Ok(untrusted) = UntrustedMastForest::read_from_bytes(data) else { + // Even if the default path rejects early, exercise the explicit-budget variants too. + validate_untrusted(UntrustedMastForest::read_from_bytes_with_budget(data, 64)); + validate_untrusted_with_flags(UntrustedMastForest::read_from_bytes_with_budget_and_flags( + data, 64, + )); + validate_untrusted(UntrustedMastForest::read_from_bytes_with_budgets( + data, + data.len(), + data.len(), + )); + validate_untrusted_with_flags(UntrustedMastForest::read_from_bytes_with_budgets_and_flags( + data, + data.len(), + data.len(), + )); + validate_untrusted_with_flags(UntrustedMastForest::read_from_bytes_with_flags(data)); return; }; @@ -25,5 +54,19 @@ fuzz_target!(|data: &[u8]| { // Test budgeted deserialization with a very small budget // This should reject most inputs early without panicking - let _ = UntrustedMastForest::read_from_bytes_with_budget(data, 64); + validate_untrusted(UntrustedMastForest::read_from_bytes_with_budget(data, 64)); + validate_untrusted_with_flags(UntrustedMastForest::read_from_bytes_with_budget_and_flags( + data, 64, + )); + validate_untrusted(UntrustedMastForest::read_from_bytes_with_budgets( + data, + data.len(), + data.len(), + )); + validate_untrusted_with_flags(UntrustedMastForest::read_from_bytes_with_budgets_and_flags( + data, + data.len(), + data.len(), + )); + validate_untrusted_with_flags(UntrustedMastForest::read_from_bytes_with_flags(data)); }); diff --git a/miden-core-fuzz/fuzz_targets/mast_node_info.rs b/miden-core-fuzz/fuzz_targets/mast_node_info.rs index caa89a7e7c..f84f3e8ada 100644 --- a/miden-core-fuzz/fuzz_targets/mast_node_info.rs +++ b/miden-core-fuzz/fuzz_targets/mast_node_info.rs @@ -1,21 +1,32 @@ //! Fuzz target for MastNodeInfo deserialization. //! -//! MastNodeInfo is a fixed-width structure (8 bytes type + 32 bytes digest = 40 bytes). -//! This tests the MastNodeType discriminant parsing and payload extraction. +//! MastNodeInfo is a fixed-width structure (8 bytes node entry + 32 bytes digest = 40 bytes). +//! This target exercises `MastNodeEntry` decoding plus `MastNodeInfo` materialization through the +//! serialized-view API. //! //! Run with: cargo +nightly fuzz run mast_node_info --fuzz-dir miden-core-fuzz #![no_main] use libfuzzer_sys::fuzz_target; +use miden_core::mast::SerializedMastForest; -// Note: MastNodeInfo is pub(crate), so we test via the full deserialization path -// with crafted inputs that exercise node info parsing specifically. +fuzz_target!(|data: &[u8]| { + let Ok(view) = SerializedMastForest::new(data) else { + return; + }; -use miden_core::{mast::MastForest, serde::Deserializable}; + if view.node_count() == 0 { + return; + } -fuzz_target!(|data: &[u8]| { - // MastNodeInfo is internal, but we can exercise it through MastForest - // The fuzzer will find inputs that reach the node info parsing code - let _ = MastForest::read_from_bytes(data); + let last = view.node_count() - 1; + + let _ = view.node_entry_at(0); + let _ = view.node_info_at(0); + let _ = view.node_digest_at(0); + + let _ = view.node_entry_at(last); + let _ = view.node_info_at(last); + let _ = view.node_digest_at(last); }); diff --git a/miden-core-fuzz/fuzz_targets/package_deserialize.rs b/miden-core-fuzz/fuzz_targets/package_deserialize.rs index eefe5f8cd5..57459768e6 100644 --- a/miden-core-fuzz/fuzz_targets/package_deserialize.rs +++ b/miden-core-fuzz/fuzz_targets/package_deserialize.rs @@ -9,7 +9,9 @@ use miden_core::serde::Deserializable; use miden_mast_package::Package; fuzz_target!(|data: &[u8]| { + let budget = data.len().saturating_mul(64); + let _ = Package::read_from_bytes(data); - let _ = Vec::::read_from_bytes(data); - let _ = Option::::read_from_bytes(data); + let _ = Vec::::read_from_bytes_with_budget(data, budget); + let _ = Option::::read_from_bytes_with_budget(data, budget); }); diff --git a/miden-core-fuzz/fuzz_targets/package_semantic_deserialize.rs b/miden-core-fuzz/fuzz_targets/package_semantic_deserialize.rs new file mode 100644 index 0000000000..4c830d79f2 --- /dev/null +++ b/miden-core-fuzz/fuzz_targets/package_semantic_deserialize.rs @@ -0,0 +1,54 @@ +//! Fuzz target for semantic Package deserialization checks. +//! +//! This target starts from binary `Package` deserialization, then exercises package APIs that +//! interpret decoded sections, runtime dependencies, and package kind. +//! +//! Run with: cargo +nightly fuzz run package_semantic_deserialize --fuzz-dir miden-core-fuzz + +#![no_main] + +use libfuzzer_sys::fuzz_target; +use miden_core::serde::{Deserializable, SliceReader}; +use miden_mast_package::{ + Package, SectionId, TargetType, + debug_info::{DebugFunctionsSection, DebugSourcesSection, DebugTypesSection}, +}; + +fuzz_target!(|data: &[u8]| { + let Ok(package) = Package::read_from_bytes(data) else { + return; + }; + + validate_debug_sections(&package); + + let _ = package.kernel_runtime_dependency(); + let _ = package.try_embedded_kernel_package(); + + // These conversion helpers borrow the package, despite the `try_into_*` names. + match package.kind { + TargetType::Executable => { + let _ = package.try_into_program(); + }, + TargetType::Kernel => { + let _ = package.kernel_module_info(); + let _ = package.to_kernel(); + let _ = package.try_into_kernel_library(); + }, + _ => (), + } +}); + +fn validate_debug_sections(package: &Package) { + for section in &package.sections { + if section.id == SectionId::DEBUG_SOURCES { + let mut reader = SliceReader::new(section.data.as_ref()); + let _ = DebugSourcesSection::read_from(&mut reader); + } else if section.id == SectionId::DEBUG_FUNCTIONS { + let mut reader = SliceReader::new(section.data.as_ref()); + let _ = DebugFunctionsSection::read_from(&mut reader); + } else if section.id == SectionId::DEBUG_TYPES { + let mut reader = SliceReader::new(section.data.as_ref()); + let _ = DebugTypesSection::read_from(&mut reader); + } + } +} diff --git a/miden-core-fuzz/fuzz_targets/project_assemble.rs b/miden-core-fuzz/fuzz_targets/project_assemble.rs new file mode 100644 index 0000000000..907c27de2b --- /dev/null +++ b/miden-core-fuzz/fuzz_targets/project_assemble.rs @@ -0,0 +1,317 @@ +//! Fuzz target for assembling Miden projects from a filesystem tree. +//! +//! This target exercises `ProjectAssembler::assemble` on controlled library, executable, and +//! kernel project layouts. It also reads emitted debug sections and converts assembled executable +//! and kernel packages through the public package APIs. +//! +//! Run with: cargo +nightly fuzz run project_assemble --fuzz-dir miden-core-fuzz + +#![no_main] + +use std::{ + fs, + path::{Path, PathBuf}, + sync::atomic::{AtomicU64, Ordering}, +}; + +use libfuzzer_sys::fuzz_target; +use miden_assembly::{Assembler, ProjectTargetSelector}; +use miden_core::serde::{Deserializable, SliceReader}; +use miden_mast_package::{ + Package as MastPackage, SectionId, TargetType, + debug_info::{DebugFunctionsSection, DebugSourcesSection, DebugTypesSection}, +}; +use miden_package_registry::InMemoryPackageRegistry; + +const MAX_MANIFEST_SNIPPET_LEN: usize = 40 * 1024; +const EXECUTABLE_TARGET: &str = "main"; + +static NEXT_DIR_ID: AtomicU64 = AtomicU64::new(0); + +struct TempProjectTree { + root: PathBuf, +} + +impl TempProjectTree { + fn new() -> std::io::Result { + let id = NEXT_DIR_ID.fetch_add(1, Ordering::Relaxed); + let root = std::env::temp_dir() + .join(format!("miden-project-assemble-fuzz-{}-{id}", std::process::id())); + + let _ = fs::remove_dir_all(&root); + fs::create_dir_all(&root)?; + + Ok(Self { root }) + } + + fn path(&self, path: impl AsRef) -> PathBuf { + self.root.join(path) + } +} + +impl Drop for TempProjectTree { + fn drop(&mut self) { + let _ = fs::remove_dir_all(&self.root); + } +} + +fuzz_target!(|data: &[u8]| { + if data.len() > MAX_MANIFEST_SNIPPET_LEN { + return; + } + let Ok(snippet) = core::str::from_utf8(data) else { + return; + }; + let Ok(tree) = TempProjectTree::new() else { + return; + }; + let metadata_value = toml::Value::String(snippet.to_owned()).to_string(); + + match scenario_index(data, 8) { + 0 => assemble_library_project(&tree, &metadata_value, "dev"), + 1 => assemble_library_project(&tree, &metadata_value, "release"), + 2 => assemble_executable_project(&tree, &metadata_value, "dev"), + 3 => assemble_executable_project(&tree, &metadata_value, "release"), + 4 => assemble_kernel_project(&tree, &metadata_value, ProjectTargetSelector::Library, "dev"), + 5 => assemble_kernel_project( + &tree, + &metadata_value, + ProjectTargetSelector::Library, + "release", + ), + 6 => assemble_kernel_project( + &tree, + &metadata_value, + ProjectTargetSelector::Executable(EXECUTABLE_TARGET), + "dev", + ), + _ => assemble_kernel_project( + &tree, + &metadata_value, + ProjectTargetSelector::Executable(EXECUTABLE_TARGET), + "release", + ), + } +}); + +fn assemble_library_project(tree: &TempProjectTree, metadata_value: &str, profile: &str) { + let manifest_path = tree.path("library/miden-project.toml"); + if write_file( + &manifest_path, + &format!( + r#"[package] +name = "libpkg" +version = "1.0.0" +description = "library fuzz package" + +[package.metadata.fuzz] +input = {metadata_value} + +[lib] +path = "lib.masm" + +[profile.dev] +debug = true + +[profile.release] +debug = true +trim-paths = true +"#, + ), + ) + .is_err() + || write_file( + &tree.path("library/lib.masm"), + r#"pub proc helper + push.1 + push.2 + add +end +"#, + ) + .is_err() + { + return; + } + + assemble_project(&manifest_path, ProjectTargetSelector::Library, profile); +} + +fn assemble_executable_project(tree: &TempProjectTree, metadata_value: &str, profile: &str) { + let manifest_path = tree.path("executable/miden-project.toml"); + if write_file( + &manifest_path, + &format!( + r#"[package] +name = "apppkg" +version = "1.0.0" +description = "executable fuzz package" + +[package.metadata.fuzz] +input = {metadata_value} + +[lib] +path = "lib.masm" + +[[bin]] +name = "main" +path = "main.masm" + +[profile.dev] +debug = true + +[profile.release] +debug = true +trim-paths = true +"#, + ), + ) + .is_err() + || write_file( + &tree.path("executable/lib.masm"), + r#"pub proc helper + push.3 +end +"#, + ) + .is_err() + || write_file( + &tree.path("executable/main.masm"), + r#"use $exec::lib + +begin + exec.lib::helper + drop +end +"#, + ) + .is_err() + { + return; + } + + assemble_project(&manifest_path, ProjectTargetSelector::Executable(EXECUTABLE_TARGET), profile); +} + +fn assemble_kernel_project( + tree: &TempProjectTree, + metadata_value: &str, + target: ProjectTargetSelector<'_>, + profile: &str, +) { + let manifest_path = tree.path("kernel/miden-project.toml"); + if write_file( + &manifest_path, + &format!( + r#"[package] +name = "kernelpkg" +version = "1.0.0" +description = "kernel fuzz package" + +[package.metadata.fuzz] +input = {metadata_value} + +[lib] +kind = "kernel" +path = "kernel.masm" + +[[bin]] +name = "main" +path = "main.masm" + +[profile.dev] +debug = true + +[profile.release] +debug = true +trim-paths = true +"#, + ), + ) + .is_err() + || write_file( + &tree.path("kernel/kernel.masm"), + r#"pub proc foo + caller +end +"#, + ) + .is_err() + || write_file( + &tree.path("kernel/main.masm"), + r#"begin + syscall.foo +end +"#, + ) + .is_err() + { + return; + } + + assemble_project(&manifest_path, target, profile); +} + +fn assemble_project(manifest_path: &Path, target: ProjectTargetSelector<'_>, profile: &str) { + let assembler = Assembler::default(); + let mut registry = InMemoryPackageRegistry::default(); + + let Ok(mut project_assembler) = assembler.for_project_at_path(manifest_path, &mut registry) + else { + return; + }; + let Ok(package) = project_assembler.assemble(target, profile) else { + return; + }; + + validate_package(&package); +} + +fn validate_package(package: &MastPackage) { + validate_debug_sections(package); + + // These conversion helpers borrow the package, despite the `try_into_*` names. + match package.kind { + TargetType::Executable => { + let _ = package.try_into_program(); + let _ = package.try_embedded_kernel_package(); + }, + TargetType::Kernel => { + let _ = package.try_into_kernel_library(); + let _ = package.to_kernel(); + let _ = package.kernel_module_info(); + }, + _ if package.is_library() => { + let _ = package.kernel_runtime_dependency(); + }, + _ => (), + } +} + +fn validate_debug_sections(package: &MastPackage) { + for section in &package.sections { + if section.id == SectionId::DEBUG_SOURCES { + let mut reader = SliceReader::new(section.data.as_ref()); + let _ = DebugSourcesSection::read_from(&mut reader); + } else if section.id == SectionId::DEBUG_FUNCTIONS { + let mut reader = SliceReader::new(section.data.as_ref()); + let _ = DebugFunctionsSection::read_from(&mut reader); + } else if section.id == SectionId::DEBUG_TYPES { + let mut reader = SliceReader::new(section.data.as_ref()); + let _ = DebugTypesSection::read_from(&mut reader); + } + } +} + +fn write_file(path: &Path, contents: &str) -> std::io::Result<()> { + if let Some(parent) = path.parent() { + fs::create_dir_all(parent)?; + } + fs::write(path, contents) +} + +fn scenario_index(data: &[u8], count: usize) -> usize { + data.iter() + .fold(0usize, |acc, byte| acc.wrapping_mul(31).wrapping_add(*byte as usize)) + % count +} diff --git a/miden-core-fuzz/fuzz_targets/project_load.rs b/miden-core-fuzz/fuzz_targets/project_load.rs new file mode 100644 index 0000000000..0d1ccbfa97 --- /dev/null +++ b/miden-core-fuzz/fuzz_targets/project_load.rs @@ -0,0 +1,221 @@ +//! Fuzz target for loading Miden project manifests from a filesystem tree. +//! +//! This target exercises `Package::load` and `Project::load`, including workspace-member loading +//! and workspace inheritance. It does not assemble MASM sources. +//! +//! Run with: cargo +nightly fuzz run project_load --fuzz-dir miden-core-fuzz + +#![no_main] + +use std::{ + fs, + path::{Path, PathBuf}, + sync::atomic::{AtomicU64, Ordering}, +}; + +use libfuzzer_sys::fuzz_target; +use miden_assembly_syntax::debuginfo::{DefaultSourceManager, SourceManagerExt}; +use miden_project::{Package, Project}; + +const MAX_MANIFEST_LEN: usize = 40 * 1024; + +static NEXT_DIR_ID: AtomicU64 = AtomicU64::new(0); + +struct TempProjectTree { + root: PathBuf, +} + +impl TempProjectTree { + fn new() -> std::io::Result { + let id = NEXT_DIR_ID.fetch_add(1, Ordering::Relaxed); + let root = std::env::temp_dir() + .join(format!("miden-project-load-fuzz-{}-{id}", std::process::id())); + + let _ = fs::remove_dir_all(&root); + fs::create_dir_all(&root)?; + + Ok(Self { root }) + } + + fn path(&self, path: impl AsRef) -> PathBuf { + self.root.join(path) + } +} + +impl Drop for TempProjectTree { + fn drop(&mut self) { + let _ = fs::remove_dir_all(&self.root); + } +} + +fuzz_target!(|data: &[u8]| { + if data.len() > MAX_MANIFEST_LEN { + return; + } + let Ok(manifest) = core::str::from_utf8(data) else { + return; + }; + let Ok(tree) = TempProjectTree::new() else { + return; + }; + + let source_manager = DefaultSourceManager::default(); + + match scenario_index(data, 5) { + 0 => load_standalone_package(&tree, &source_manager, manifest), + 1 => load_standalone_project(&tree, &source_manager, manifest), + 2 => load_fuzzed_workspace(&tree, &source_manager, manifest), + 3 => load_inherited_workspace_member(&tree, &source_manager, manifest), + _ => load_project_reference(&tree, &source_manager, manifest), + } +}); + +fn load_standalone_package( + tree: &TempProjectTree, + source_manager: &DefaultSourceManager, + manifest: &str, +) { + let manifest_path = tree.path("standalone/miden-project.toml"); + if write_file(&manifest_path, manifest).is_err() { + return; + } + + if let Ok(source) = source_manager.load_file(&manifest_path) { + let _ = Package::load(source); + } +} + +fn load_standalone_project( + tree: &TempProjectTree, + source_manager: &DefaultSourceManager, + manifest: &str, +) { + let manifest_path = tree.path("standalone/miden-project.toml"); + if write_file(&manifest_path, manifest).is_err() { + return; + } + + if scenario_index(manifest.as_bytes(), 2) == 0 { + let _ = Project::load(tree.path("standalone"), source_manager); + } else { + let _ = Project::load(&manifest_path, source_manager); + } +} + +fn load_fuzzed_workspace( + tree: &TempProjectTree, + source_manager: &DefaultSourceManager, + manifest: &str, +) { + let workspace_manifest = tree.path("fuzzed-workspace/miden-project.toml"); + let workspace_member = tree.path("fuzzed-workspace/app/miden-project.toml"); + + if write_file(&workspace_manifest, manifest).is_err() + || write_file( + &workspace_member, + r#"[package] +name = "app" +version = "0.1.0" + +[lib] +path = "lib.masm" +"#, + ) + .is_err() + || write_file( + &tree.path("fuzzed-workspace/app/lib.masm"), + r#"pub proc helper + push.1 +end +"#, + ) + .is_err() + { + return; + } + + if scenario_index(manifest.as_bytes(), 2) == 0 { + let _ = Project::load(tree.path("fuzzed-workspace"), source_manager); + } else { + let _ = Project::load(&workspace_manifest, source_manager); + } +} + +fn load_inherited_workspace_member( + tree: &TempProjectTree, + source_manager: &DefaultSourceManager, + manifest: &str, +) { + let member_manifest = write_inherited_workspace(tree, manifest); + let Ok(member_manifest) = member_manifest else { + return; + }; + + if scenario_index(manifest.as_bytes(), 2) == 0 { + let _ = Project::load(tree.path("inherited-workspace/app"), source_manager); + } else { + let _ = Project::load(&member_manifest, source_manager); + } +} + +fn load_project_reference( + tree: &TempProjectTree, + source_manager: &DefaultSourceManager, + manifest: &str, +) { + if write_inherited_workspace(tree, manifest).is_err() { + return; + } + let workspace_manifest = tree.path("inherited-workspace/miden-project.toml"); + + if scenario_index(manifest.as_bytes(), 2) == 0 { + let _ = Project::load_project_reference( + "app", + tree.path("inherited-workspace"), + source_manager, + ); + } else { + let _ = Project::load_project_reference("app", &workspace_manifest, source_manager); + } +} + +fn write_inherited_workspace(tree: &TempProjectTree, manifest: &str) -> std::io::Result { + let workspace_manifest = tree.path("inherited-workspace/miden-project.toml"); + let member_manifest = tree.path("inherited-workspace/app/miden-project.toml"); + + write_file( + &workspace_manifest, + r#"[workspace] +members = ["app"] + +[workspace.package] +version = "1.0.0" +description = "workspace defaults" + +[workspace.dependencies] +shared = { version = "1.0.0" } +"#, + )?; + write_file(&member_manifest, manifest)?; + write_file( + &tree.path("inherited-workspace/app/lib.masm"), + r#"pub proc helper + push.1 +end +"#, + )?; + Ok(member_manifest) +} + +fn scenario_index(data: &[u8], count: usize) -> usize { + data.iter() + .fold(0usize, |acc, byte| acc.wrapping_mul(31).wrapping_add(*byte as usize)) + % count +} + +fn write_file(path: &Path, contents: &str) -> std::io::Result<()> { + if let Some(parent) = path.parent() { + fs::create_dir_all(parent)?; + } + fs::write(path, contents) +} diff --git a/miden-core-fuzz/fuzz_targets/project_toml_parse.rs b/miden-core-fuzz/fuzz_targets/project_toml_parse.rs new file mode 100644 index 0000000000..347b569833 --- /dev/null +++ b/miden-core-fuzz/fuzz_targets/project_toml_parse.rs @@ -0,0 +1,41 @@ +//! Fuzz target for Project TOML manifest parsing. +//! +//! This target fuzzes the `miden_project::ast::MidenProject` TOML parsing, +//! which is used to parse `miden-project.toml` manifest files. +//! +//! Run with: cargo +nightly fuzz run project_toml_parse --fuzz-dir miden-core-fuzz + +#![no_main] + +use std::sync::Arc; + +use libfuzzer_sys::fuzz_target; +use miden_assembly_syntax::debuginfo::{SourceFile, SourceId, SourceLanguage}; +use miden_project::{ + Uri, + ast::{MidenProject, PackageConfig, PackageTable, ProjectFile, WorkspaceFile}, +}; + +fuzz_target!(|data: &[u8]| { + // Try to parse the data as a TOML string + if let Ok(toml_str) = core::str::from_utf8(data) { + let source_file = Arc::new(SourceFile::new( + SourceId::default(), + SourceLanguage::Other("toml"), + Uri::new("fuzz://miden-project.toml"), + toml_str, + )); + + // Exercise the production manifest parser, including validation and source-span setup. + let _ = MidenProject::parse(source_file); + + // Attempt to parse as MidenProject AST (workspace or package manifest) + let _ = toml::from_str::(toml_str); + + // Also try parsing individual components + let _ = toml::from_str::(toml_str); + let _ = toml::from_str::(toml_str); + let _ = toml::from_str::(toml_str); + let _ = toml::from_str::(toml_str); + } +}); diff --git a/miden-core-fuzz/fuzz_targets/serialized_mast_forest_new.rs b/miden-core-fuzz/fuzz_targets/serialized_mast_forest_new.rs new file mode 100644 index 0000000000..6f86ca60b4 --- /dev/null +++ b/miden-core-fuzz/fuzz_targets/serialized_mast_forest_new.rs @@ -0,0 +1,35 @@ +//! Fuzz target for SerializedMastForest structural inspection. +//! +//! This target focuses on the trusted inspection path exposed by +//! `SerializedMastForest::new()`. It exercises layout scanning and cheap random-access helpers +//! without going through full trusted or untrusted materialization. +//! +//! Run with: cargo +nightly fuzz run serialized_mast_forest_new --fuzz-dir miden-core-fuzz + +#![no_main] + +use libfuzzer_sys::fuzz_target; +use miden_core::mast::SerializedMastForest; + +fuzz_target!(|data: &[u8]| { + let Ok(view) = SerializedMastForest::new(data) else { + return; + }; + + let _ = view.is_hashless(); + let _ = view.is_stripped(); + let root_count = view.procedure_root_count(); + let node_count = view.node_count(); + + if root_count > 0 { + let last_root = root_count - 1; + let _ = view.procedure_root_at(0); + let _ = view.procedure_root_at(last_root); + } + + if node_count > 0 { + let last_node = node_count - 1; + let _ = view.node_entry_at(0); + let _ = view.node_entry_at(last_node); + } +}); diff --git a/miden-vm/Cargo.toml b/miden-vm/Cargo.toml index b7b854c563..cdcc1b0c20 100644 --- a/miden-vm/Cargo.toml +++ b/miden-vm/Cargo.toml @@ -49,6 +49,7 @@ name = "miden-cli" path = "tests/integration/main.rs" [features] +arbitrary = ["std", "dep:proptest"] concurrent = ["miden-prover/concurrent", "std"] default = ["std"] executable = ["dep:hex", "dep:clap", "dep:tracing-subscriber", "internal", "serde", "std"] @@ -60,6 +61,7 @@ std = [ "miden-processor/std", "miden-prover/std", "miden-verifier/std", + "proptest?/std", "serde?/std", "serde_json?/std", ] @@ -70,7 +72,6 @@ internal = ["dep:hex", "serde", "std"] # Miden dependencies miden-assembly.workspace = true miden-core.workspace = true -miden-crypto.workspace = true miden-debug-types.workspace = true miden-processor.workspace = true miden-prover.workspace = true @@ -79,24 +80,26 @@ miden-core-lib.workspace = true miden-verifier.workspace = true # External dependencies -clap = { version = "4.5", features = ["derive"], optional = true } +clap = { workspace = true, optional = true } hex = { version = "0.4", optional = true } serde = { workspace = true, optional = true } serde_json = { workspace = true, optional = true } +proptest = { workspace = true, optional = true } tracing.workspace = true tracing-subscriber = { version = "0.3", optional = true, features = ["std", "env-filter"] } tracing-forest = { version = "0.2", optional = true, features = ["ansi", "smallvec"] } [dev-dependencies] assert_cmd = { version = "2.1" } -bincode = { version = "1.3" } +bincode = { workspace = true } criterion = { workspace = true, features = ["async_tokio"] } escargot = { version = "0.5" } +miden-crypto.workspace = true miden-processor = { workspace = true, features = ["testing"] } +miden-lifted-stark.workspace = true +miden-test-serde-macros.workspace = true miden-utils-testing.workspace = true -num-bigint = { version = "0.4" } predicates = { version = "3.1" } -pretty_assertions = { version = "1.4" } +proptest.workspace = true tokio = { workspace = true, features = ["rt", "rt-multi-thread"] } -rand_chacha = { version = "0.9" } walkdir = { version = "2.5" } diff --git a/miden-vm/README.md b/miden-vm/README.md index 8489d5dcb4..214f8882c5 100644 --- a/miden-vm/README.md +++ b/miden-vm/README.md @@ -36,14 +36,20 @@ Miden crate exposes several functions which can be used to execute programs, gen ### Executing programs -To execute a program on Miden VM, you can use `execute()` which takes the following arguments: +To execute a program on Miden VM, you can use `execute()`. The sync `execute_sync()` variant is +also available for sync callers. These functions take the following arguments: - `program: &Program` - a reference to a Miden program to be executed. - `stack_inputs: StackInputs` - a set of public inputs with which to execute the program. -- `host: Host` - an instance of a `Host` which can be used to supply non-deterministic inputs to the VM and receive messages from the VM. +- `advice_inputs: AdviceInputs` - the private inputs used to build the advice provider; use `AdviceInputs::default()` when no private inputs are needed. +- `host` - an instance of `Host` for `execute()` or `SyncHost` for `execute_sync()`, used to supply non-deterministic inputs to the VM and receive messages from the VM. - `options: ExecutionOptions` - a set of options for executing the specified program (e.g., max allowed number of cycles). -The function returns a `Result` which will contain the execution trace of the program if the execution was successful, or an error, if the execution failed. Internally, the VM then passes this execution trace to the prover to generate a proof of a correct execution of the program. +The function returns a `Result` which will contain the final stack +state and other execution outputs if the execution was successful, or an error if the execution +failed. If you need an execution trace, use `FastProcessor::execute_trace_inputs()` / +`FastProcessor::execute_trace_inputs_sync()` and pass the returned `TraceBuildInputs` bundle to +`trace::build_trace()`. For example: @@ -74,17 +80,22 @@ let mut host = DefaultHost::default(); let exec_options = ExecutionOptions::default(); // execute the program with no inputs -let trace = execute_sync(&program, stack_inputs, advice_inputs.clone(), &mut host, exec_options).unwrap(); +let output = + execute_sync(&program, stack_inputs, advice_inputs.clone(), &mut host, exec_options).unwrap(); ``` ### Proving program execution -To execute a program on Miden VM and generate a proof that the program was executed correctly, you can use the `prove()` function. This function takes the following arguments: +To execute a program on Miden VM and generate a proof that the program was executed correctly, you +can use the `prove_sync()` function. The async `prove()` variant is also available for async +callers. `prove_sync()` takes the following arguments: - `program: &Program` - a reference to a Miden program to be executed. - `stack_inputs: StackInputs` - a set of public inputs with which to execute the program. +- `advice_inputs: AdviceInputs` - the initial nondeterministic inputs available to the VM. - `host: Host` - an instance of a `Host` which can be used to supply non-deterministic inputs to the VM and receive messages from the VM. -- `options: ProvingOptions` - config parameters for proof generation. The default options target 96-bit security level. +- `execution_options: ExecutionOptions` - VM execution parameters such as cycle limits and trace fragmentation. +- `options: ProvingOptions` - proof-generation parameters. The default options target 96-bit security level. If the program is executed successfully, the function returns a tuple with 2 elements: @@ -101,7 +112,7 @@ use miden_vm::{ advice::AdviceInputs, assembly::DefaultSourceManager, field::PrimeField64, - Assembler, DefaultHost, ProvingOptions, Program, prove_sync, StackInputs + Assembler, DefaultHost, ExecutionOptions, ProvingOptions, Program, prove_sync, StackInputs }; // instantiate the assembler @@ -116,6 +127,7 @@ let (outputs, proof) = prove_sync( StackInputs::default(), // we won't provide any inputs AdviceInputs::default(), // we don't need any initial advice inputs &mut DefaultHost::default(), // we'll be using a default host + ExecutionOptions::default(), // we'll use default VM execution options ProvingOptions::default(), // we'll be using default options ) .unwrap(); @@ -217,6 +229,7 @@ let (outputs, proof) = miden_vm::prove_sync( stack_inputs, AdviceInputs::default(), // without initial advice inputs &mut host, + miden_vm::ExecutionOptions::default(), // use default VM execution options ProvingOptions::default(), // use default proving options ) .unwrap(); diff --git a/miden-vm/benches/build_trace.rs b/miden-vm/benches/build_trace.rs index f110750ef9..e02788275c 100644 --- a/miden-vm/benches/build_trace.rs +++ b/miden-vm/benches/build_trace.rs @@ -3,12 +3,12 @@ use std::hint::black_box; use criterion::{BatchSize, Criterion, criterion_group, criterion_main}; use miden_core_lib::CoreLibrary; use miden_processor::{ExecutionOptions, FastProcessor, advice::AdviceInputs, trace}; -use miden_vm::{Assembler, DefaultHost, StackInputs, execute, internal::InputFile}; +use miden_vm::{Assembler, DefaultHost, StackInputs, internal::InputFile}; use tokio::runtime::Runtime; use walkdir::WalkDir; /// The size of each trace fragment (in rows) when executing programs for trace generation. -const TRACE_FRAGMENT_SIZE: usize = 4096; +const TRACE_FRAGMENT_SIZE: usize = 1024; /// Benchmark the execution of all the masm examples in the `masm-examples` directory. fn build_trace(c: &mut Criterion) { @@ -72,57 +72,15 @@ fn build_trace(c: &mut Criterion) { ExecutionOptions::default() .with_core_trace_fragment_size(TRACE_FRAGMENT_SIZE) .unwrap(), - ); + ) + .expect("processor advice inputs should fit advice map limits"); (host, program.clone(), processor) }, |(mut host, program, processor)| async move { - let (execution_output, trace_generation_context) = - processor.execute_for_trace(&program, &mut host).await.unwrap(); - - let trace = trace::build_trace( - execution_output, - trace_generation_context, - program.to_info(), - ) - .unwrap(); - black_box(trace); - }, - BatchSize::SmallInput, - ); - }); - - // LEGACY EXECUTE - // -------------------------------- - group.bench_function(format!("{file_stem}_legacy"), |bench| { - let mut assembler = Assembler::default(); - assembler - .link_dynamic_library(CoreLibrary::default()) - .expect("failed to load core library"); - - let program = assembler - .assemble_program(&source) - .expect("Failed to compile test source."); - - bench.to_async(Runtime::new().unwrap()).iter_batched( - || { - let host = DefaultHost::default() - .with_library(&CoreLibrary::default()) - .unwrap(); - let advice_inputs = advice_inputs.clone(); - - (host, stack_inputs, advice_inputs, program.clone()) - }, - |(mut host, stack_inputs, advice_inputs, program)| async move { - let trace = execute( - &program, - stack_inputs, - advice_inputs, - &mut host, - ExecutionOptions::default(), - ) - .await - .unwrap(); + let trace_inputs = + processor.execute_trace_inputs(&program, &mut host).await.unwrap(); + let trace = trace::build_trace(trace_inputs).unwrap(); black_box(trace); }, BatchSize::SmallInput, diff --git a/miden-vm/benches/program_execution_fast.rs b/miden-vm/benches/program_execution_fast.rs index 88de523654..eb222348cd 100644 --- a/miden-vm/benches/program_execution_fast.rs +++ b/miden-vm/benches/program_execution_fast.rs @@ -56,8 +56,9 @@ fn program_execution_fast(c: &mut Criterion) { .with_library(&CoreLibrary::default()) .unwrap(); - let processor = - FastProcessor::new(stack_inputs).with_advice(advice_inputs.clone()); + let processor = FastProcessor::new(stack_inputs) + .with_advice(advice_inputs.clone()) + .expect("advice inputs should fit advice map limits"); (host, program.clone(), processor) }, diff --git a/miden-vm/benches/program_execution_for_trace.rs b/miden-vm/benches/program_execution_for_trace.rs index 807a3e9991..9efc8ab9a1 100644 --- a/miden-vm/benches/program_execution_for_trace.rs +++ b/miden-vm/benches/program_execution_for_trace.rs @@ -68,13 +68,14 @@ fn program_execution_for_trace(c: &mut Criterion) { ExecutionOptions::default() .with_core_trace_fragment_size(TRACE_FRAGMENT_SIZE) .unwrap(), - ); + ) + .expect("processor advice inputs should fit advice map limits"); (host, program.clone(), processor) }, |(mut host, program, processor)| async move { let out = - processor.execute_for_trace(&program, &mut host).await.unwrap(); + processor.execute_trace_inputs(&program, &mut host).await.unwrap(); black_box(out); }, BatchSize::SmallInput, diff --git a/miden-vm/masm-examples/hashing/blake3_1to1/blake3_1to1.masm b/miden-vm/masm-examples/hashing/blake3_1to1/blake3_1to1.masm index 3fa0bec8b9..621dee08a9 100644 --- a/miden-vm/masm-examples/hashing/blake3_1to1/blake3_1to1.masm +++ b/miden-vm/masm-examples/hashing/blake3_1to1/blake3_1to1.masm @@ -3,7 +3,7 @@ use miden::core::sys begin # Push the number of iterations on the stack, and assess if we should loop - adv_push.1 dup neq.0 + adv_push dup neq.0 # => [0 or 1, num_iters_left, HASH_INPUTS_1, HASH_INPUTS_2] while.true diff --git a/miden-vm/masm-examples/merkle_store/merkle_store.masm b/miden-vm/masm-examples/merkle_store/merkle_store.masm index a96bd23006..2ecd590086 100644 --- a/miden-vm/masm-examples/merkle_store/merkle_store.masm +++ b/miden-vm/masm-examples/merkle_store/merkle_store.masm @@ -1,38 +1,59 @@ begin # push the root of the Partial Merkle Tree on the stack - push.[16822663461127792392, 13353258177390434098, 2416982434710942653, 7676447709976871076] + push.[12598010592505582824, 868370131607961867, 13428921982874124294, 13514551084444143236] + # => [PMT_ROOT] # get value at depth = 2, index = 0 from the Partial Merkle Tree; this value should be 20 push.0.2 + # => [2, 0, PMT_ROOT] mtree_get + # => [PMT_VALUE, PMT_ROOT] + # check that returned value is equal to 20 push.[20,0,0,0] + # => [EXPECTED_VALUE, PMT_VALUE, PMT_ROOT] assert_eqw + # => [PMT_ROOT] dropw + # => [] # push the root of the Sparse Merkle Tree on the stack - push.[11789474913582628944, 10542203670838121629, 14970381554615752019, 10887162719400902293] + push.[7504381463224585554, 3191971290185126131, 213169417210918065, 17616398227807096838] + # => [SMT_ROOT] # get value at depth = 64, index = 1 from the Sparse Merkle Tree; this value should be 21 push.1.64 + # => [64, 1, SMT_ROOT] mtree_get + # => [SMT_VALUE, SMT_ROOT] + # check that returned value is equal to 21 push.[21,0,0,0] + # => [EXPECTED_VALUE, SMT_VALUE, SMT_ROOT] assert_eqw + # => [SMT_ROOT] dropw + # => [] # push the root of the Merkle Tree on the stack - push.[937566728702260333, 10423322521195732810, 16243291006317403500, 12736773875258955401] + push.[6611496865107420098, 2171421300812663290, 5052678114877406371, 9772299691978421006] + # => [MT_ROOT] # get value at depth = 2, index = 2 from the Merkle Tree; this value should be 22 push.2.2 + # => [2, 2, MT_ROOT] mtree_get + # => [MT_VALUE, MT_ROOT] + # check that returned value is equal to 22 push.[22,0,0,0] + # => [EXPECTED_VALUE, MT_VALUE, MT_ROOT] assert_eqw + # => [MT_ROOT] dropw + # => [] end diff --git a/miden-vm/src/cli/data.rs b/miden-vm/src/cli/data.rs index eddaa3c4cf..9da41eebeb 100644 --- a/miden-vm/src/cli/data.rs +++ b/miden-vm/src/cli/data.rs @@ -15,6 +15,8 @@ use miden_assembly::{ use miden_core::{Felt, field::QuotientMap}; use miden_core_lib::CoreLibrary; use miden_vm::{ExecutionProof, Program, StackOutputs, Word, serde::SliceReader}; +#[cfg(feature = "arbitrary")] +use proptest::prelude::*; use serde::{Deserialize, Serialize}; use tracing::instrument; @@ -25,11 +27,24 @@ use tracing::instrument; // ================================================================================================ /// Output file struct -#[derive(Deserialize, Serialize, Debug)] +#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] +#[cfg_attr(all(feature = "arbitrary", test), miden_test_serde_macros::serde_test)] pub struct OutputFile { pub stack: Vec, } +#[cfg(feature = "arbitrary")] +impl Arbitrary for OutputFile { + type Parameters = (); + type Strategy = BoxedStrategy; + + fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { + proptest::collection::vec(any::().prop_map(|value| value.to_string()), 0..32) + .prop_map(|stack| Self { stack }) + .boxed() + } +} + /// Helper methods to interact with the output file impl OutputFile { /// Returns a new [OutputFile] from the specified outputs vectors @@ -102,7 +117,7 @@ pub struct ProgramFile { impl ProgramFile { /// Reads the masm file at the specified path and parses it into a [ProgramFile]. pub fn read(path: impl AsRef) -> Result { - let source_manager = Arc::new(miden_assembly::DefaultSourceManager::default()); + let source_manager = Arc::new(DefaultSourceManager::default()); Self::read_with(path, source_manager) } } diff --git a/miden-vm/src/cli/prove.rs b/miden-vm/src/cli/prove.rs index b9f8b04f29..b4fea9c427 100644 --- a/miden-vm/src/cli/prove.rs +++ b/miden-vm/src/cli/prove.rs @@ -69,16 +69,18 @@ pub struct ProveCmd { } impl ProveCmd { - pub fn get_proof_options(&self) -> Result { - let exec_options = ExecutionOptions::new( + pub fn get_execution_options(&self) -> Result { + ExecutionOptions::new( Some(self.max_cycles), self.expected_cycles, ExecutionOptions::DEFAULT_CORE_TRACE_FRAGMENT_SIZE, self.trace, !self.release, ) - .map_err(|err| Report::msg(format!("{err}")))?; + .map_err(|err| Report::msg(format!("{err}"))) + } + pub fn get_proof_options(&self) -> Result { let hash_fn = HashFunction::try_from(self.hasher.as_str()) .map_err(|err| Report::msg(format!("{err}")))?; let proving_options = match self.security.as_str() { @@ -89,7 +91,7 @@ impl ProveCmd { ))); }, }; - Ok(proving_options.with_execution_options(exec_options)) + Ok(proving_options) } pub fn execute(&self) -> Result<(), Report> { println!("==============================================================================="); @@ -143,6 +145,7 @@ impl ProveCmd { let stack_inputs = input_data.parse_stack_inputs().map_err(Report::msg)?; let advice_inputs = input_data.parse_advice_inputs().map_err(Report::msg)?; + let execution_options = self.get_execution_options()?; let proving_options = self.get_proof_options()?; // execute program and generate proof @@ -151,6 +154,7 @@ impl ProveCmd { stack_inputs, advice_inputs, &mut host, + execution_options, proving_options, ) .wrap_err("Failed to prove program")?; diff --git a/miden-vm/src/cli/run.rs b/miden-vm/src/cli/run.rs index cd64156662..f4fada33ab 100644 --- a/miden-vm/src/cli/run.rs +++ b/miden-vm/src/cli/run.rs @@ -152,16 +152,13 @@ fn run_masp_program(params: &RunCmd) -> Result<(ExecutionTrace, [u8; 32]), Repor ) .map_err(|err| Report::msg(format!("{err}")))?; - let processor = FastProcessor::new(stack_inputs) - .with_advice(advice_inputs) - .with_options(exec_options); + let processor = FastProcessor::new_with_options(stack_inputs, advice_inputs, exec_options) + .map_err(|err| Report::msg(format!("{err}")))?; - let (execution_output, trace_generation_context) = processor - .execute_for_trace_sync(&program, &mut host) + let trace_inputs = processor + .execute_trace_inputs_sync(&program, &mut host) .wrap_err("Failed to execute program")?; - - let trace = build_trace(execution_output, trace_generation_context, program.to_info()) - .wrap_err("Failed to build trace")?; + let trace = build_trace(trace_inputs).wrap_err("Failed to build trace")?; Ok((trace, program_hash)) } @@ -221,16 +218,13 @@ fn run_masm_program(params: &RunCmd) -> Result<(ExecutionTrace, [u8; 32]), Repor ) .map_err(|err| Report::msg(format!("{err}")))?; - let processor = FastProcessor::new(stack_inputs) - .with_advice(advice_inputs) - .with_options(exec_options); + let processor = FastProcessor::new_with_options(stack_inputs, advice_inputs, exec_options) + .map_err(|err| Report::msg(format!("{err}")))?; - let (execution_output, trace_generation_context) = processor - .execute_for_trace_sync(&program, &mut host) + let trace_inputs = processor + .execute_trace_inputs_sync(&program, &mut host) .wrap_err("Failed to execute program")?; - - let trace = build_trace(execution_output, trace_generation_context, program.to_info()) - .wrap_err("Failed to build trace")?; + let trace = build_trace(trace_inputs).wrap_err("Failed to build trace")?; Ok((trace, program_hash)) } diff --git a/miden-vm/src/lib.rs b/miden-vm/src/lib.rs index 7674db94b4..dad0e7c14c 100644 --- a/miden-vm/src/lib.rs +++ b/miden-vm/src/lib.rs @@ -13,13 +13,14 @@ pub use miden_core::proof::{ExecutionProof, HashFunction}; #[cfg(not(target_family = "wasm"))] pub use miden_processor::execute_sync; pub use miden_processor::{ - DefaultHost, ExecutionError, ExecutionOptions, Host, Kernel, Program, ProgramInfo, StackInputs, - ZERO, advice, crypto, execute, field, operation::Operation, serde, trace::ExecutionTrace, - utils, + BaseHost, DefaultHost, ExecutionError, ExecutionOptions, ExecutionOutput, FastProcessor, + FutureMaybeSend, Host, Kernel, Program, ProgramInfo, StackInputs, SyncHost, TraceBuildInputs, + TraceGenerationContext, ZERO, advice, crypto, execute, field, operation::Operation, serde, + trace, trace::ExecutionTrace, utils, }; +pub use miden_prover::{InputError, ProvingOptions, StackOutputs, TraceProvingInputs, Word, prove}; #[cfg(not(target_family = "wasm"))] -pub use miden_prover::prove_sync; -pub use miden_prover::{InputError, ProvingOptions, StackOutputs, Word, prove}; +pub use miden_prover::{prove_from_trace_sync, prove_sync}; pub use miden_verifier::VerificationError; // (private) exports diff --git a/miden-vm/src/main.rs b/miden-vm/src/main.rs index 09bf434c12..30af705457 100644 --- a/miden-vm/src/main.rs +++ b/miden-vm/src/main.rs @@ -1,3 +1,5 @@ +extern crate alloc; + use std::ffi::{OsStr, OsString}; use clap::{FromArgMatches, Parser, Subcommand}; diff --git a/miden-vm/tests/integration/air/chiplets/hasher.rs b/miden-vm/tests/integration/air/chiplets/hasher.rs index eadad530bf..b77ccfd6a0 100644 --- a/miden-vm/tests/integration/air/chiplets/hasher.rs +++ b/miden-vm/tests/integration/air/chiplets/hasher.rs @@ -26,7 +26,7 @@ fn mtree_get() { let index = 3usize; let (leaves, store) = init_merkle_store(&[1, 2, 3, 4, 5, 6, 7, 8]); - let tree = MerkleTree::new(leaves.clone()).unwrap(); + let tree = MerkleTree::new(leaves).unwrap(); let stack_inputs = [ tree.depth() as u64, @@ -78,8 +78,8 @@ fn mtree_merge() { let leaves_a = init_merkle_store(&[1, 2, 3, 4, 5, 6, 7, 8]).0; let leaves_b = init_merkle_store(&[9, 10, 11, 12, 13, 14, 15, 16]).0; - let tree_a = MerkleTree::new(leaves_a.clone()).unwrap(); - let tree_b = MerkleTree::new(leaves_b.clone()).unwrap(); + let tree_a = MerkleTree::new(leaves_a).unwrap(); + let tree_b = MerkleTree::new(leaves_b).unwrap(); let root_a = tree_a.root(); let root_b = tree_b.root(); let root_merged = Poseidon2::merge(&[root_a, root_b]); @@ -119,8 +119,8 @@ fn mtree_merge_then_get() { // the hmerge output. let leaves_a = init_merkle_store(&[1, 2, 3, 4, 5, 6, 7, 8]).0; let leaves_b = init_merkle_store(&[9, 10, 11, 12, 13, 14, 15, 16]).0; - let tree_a = MerkleTree::new(leaves_a.clone()).unwrap(); - let tree_b = MerkleTree::new(leaves_b.clone()).unwrap(); + let tree_a = MerkleTree::new(leaves_a).unwrap(); + let tree_b = MerkleTree::new(leaves_b).unwrap(); let root_a = tree_a.root(); let root_b = tree_b.root(); diff --git a/miden-vm/tests/integration/cli/cli_test.rs b/miden-vm/tests/integration/cli/cli_test.rs index 9b1dd8f786..7f1a153a7c 100644 --- a/miden-vm/tests/integration/cli/cli_test.rs +++ b/miden-vm/tests/integration/cli/cli_test.rs @@ -112,7 +112,7 @@ fn cli_bundle_kernel_noexports() { cmd.arg("bundle") .arg("./tests/integration/cli/data/lib_noexports") .arg("--kernel") - .arg("./tests/integration/cli/data/kernel_main.masm") + .arg("./tests/integration/cli/data/kernel_noexports.masm") .arg("--output") .arg(output_file.as_path()); cmd.assert().success(); diff --git a/miden-vm/tests/integration/cli/data/adv_map.masm b/miden-vm/tests/integration/cli/data/adv_map.masm index 5d3a6351c6..15e9e332fc 100644 --- a/miden-vm/tests/integration/cli/data/adv_map.masm +++ b/miden-vm/tests/integration/cli/data/adv_map.masm @@ -5,21 +5,21 @@ adv_map C([3,4,5,6]) = [4] begin push.A adv.push_mapval - adv_push.1 + adv_push push.2 assert_eq dropw push.0x0200000000000000030000000000000004000000000000000500000000000000 adv.push_mapval - adv_push.1 + adv_push push.3 assert_eq dropw push.C adv.push_mapval - adv_push.1 + adv_push push.4 assert_eq dropw diff --git a/miden-vm/tests/integration/cli/data/kernel_noexports.masm b/miden-vm/tests/integration/cli/data/kernel_noexports.masm new file mode 100644 index 0000000000..72596bc8bc --- /dev/null +++ b/miden-vm/tests/integration/cli/data/kernel_noexports.masm @@ -0,0 +1,8 @@ +proc internal_proc + caller + drop +end + +pub proc kernel_proc + exec.internal_proc +end diff --git a/miden-vm/tests/integration/exec.rs b/miden-vm/tests/integration/exec.rs index 27143afa4b..6c74b07046 100644 --- a/miden-vm/tests/integration/exec.rs +++ b/miden-vm/tests/integration/exec.rs @@ -50,7 +50,7 @@ fn advice_map_loaded_before_execution() { let key = Word::new([ONE, ONE, ONE, ONE]); let value = vec![ONE, ONE]; - let mut mast_forest = mast_forest.clone(); + let mut mast_forest = mast_forest; mast_forest.advice_map_mut().insert(key, value); let program_with_advice_map = Program::new(mast_forest.into(), program_without_advice_map.entrypoint()); diff --git a/miden-vm/tests/integration/flow_control/mod.rs b/miden-vm/tests/integration/flow_control/mod.rs index cd182a7674..5dff7a4628 100644 --- a/miden-vm/tests/integration/flow_control/mod.rs +++ b/miden-vm/tests/integration/flow_control/mod.rs @@ -2,9 +2,8 @@ use alloc::sync::Arc; use miden_assembly::{Assembler, PathBuf, Report, ast::ModuleKind}; use miden_core_lib::CoreLibrary; -use miden_debug_types::{SourceLanguage, SourceManager}; use miden_processor::{ExecutionError, Word, operation::OperationError}; -use miden_utils_testing::{StackInputs, Test, build_test, expect_exec_error_matches, push_inputs}; +use miden_utils_testing::{build_debug_test, build_test, expect_exec_error_matches, push_inputs}; use miden_vm::Module; // SIMPLE FLOW CONTROL TESTS @@ -240,14 +239,7 @@ fn simple_syscall() { syscall.foo end"; - // TODO: update and use macro? - let mut test = Test::new(&format!("test{}", line!()), program_source, false); - test.stack_inputs = StackInputs::try_from_ints([1, 2]).unwrap(); - test.kernel_source = Some(test.source_manager.load( - SourceLanguage::Masm, - format!("kernel{}", line!()).into(), - kernel_source.to_string(), - )); + let test = build_test!(program_source, &[1, 2]).with_kernel(kernel_source); test.expect_stack(&[3]); test.check_constraints(); @@ -273,16 +265,9 @@ fn simple_syscall_2() { syscall.bar end"; - // TODO: update and use macro? - let mut test = Test::new(&format!("test{}", line!()), program_source, false); // Stack [1, 2, 3, 2, 2] with 1 on top // foo(1+2=3), foo(3+3=6), bar(6*2=12), bar(12*2=24) => 24 - test.stack_inputs = StackInputs::try_from_ints([1, 2, 3, 2, 2]).unwrap(); - test.kernel_source = Some(test.source_manager.load( - SourceLanguage::Masm, - format!("kernel{}", line!()).into(), - kernel_source.to_string(), - )); + let test = build_test!(program_source, &[1, 2, 3, 2, 2]).with_kernel(kernel_source); test.expect_stack(&[24]); test.check_constraints(); @@ -354,12 +339,7 @@ fn call_in_syscall() { call.new_ctx end"; - let mut test = Test::new(&format!("test{}", line!()), program_source, false); - test.kernel_source = Some(test.source_manager.load( - SourceLanguage::Masm, - format!("kernel{}", line!()).into(), - kernel_source.to_string(), - )); + let test = build_test!(program_source).with_kernel(kernel_source); test.expect_stack(&[]); test.check_constraints(); @@ -393,13 +373,7 @@ fn root_context_separate_overflows() { drop swap.15 end"; - let mut test = Test::new(&format!("test{}", line!()), program_source, false); - test.stack_inputs = StackInputs::try_from_ints([100]).unwrap(); - test.kernel_source = Some(test.source_manager.load( - SourceLanguage::Masm, - format!("kernel{}", line!()).into(), - kernel_source.to_string(), - )); + let test = build_test!(program_source, &[100]).with_kernel(kernel_source); test.expect_stack(&[100]); test.check_constraints(); } @@ -447,10 +421,7 @@ fn simple_dyn_exec() { 3, ]; - let test = Test { - stack_inputs: StackInputs::try_from_ints(stack_init).unwrap(), - ..Test::new(&format!("test{}", line!()), program_source, true) - }; + let test = build_debug_test!(program_source).with_stack_inputs(stack_init); test.expect_stack(&[6]); @@ -481,16 +452,16 @@ fn dynexec_with_procref() { swap drop end"; - let mut test = build_test!(program_source, &[]); - test.libraries.push(CoreLibrary::default().library().clone()); - test.add_module( - "external::module", - "\ - pub proc func - u32wrapping_add.1 - end - ", - ); + let test = build_test!(program_source, &[]) + .with_library(CoreLibrary::default().library().clone()) + .with_module( + "external::module", + "\ + pub proc func + u32wrapping_add.1 + end + ", + ); test.expect_stack(&[4]); } @@ -540,12 +511,11 @@ fn simple_dyncall() { 3, ]; - let mut test = Test { - stack_inputs: StackInputs::try_from_ints(stack_init).unwrap(), - libraries: vec![CoreLibrary::default().into()], - ..Test::new(&format!("test{}", line!()), program_source, false) - }; - test.add_event_handlers(CoreLibrary::default().handlers()); + let core_lib = CoreLibrary::default(); + let test = build_test!(program_source) + .with_stack_inputs(stack_init) + .with_library(core_lib.library().clone()) + .with_event_handlers(core_lib.handlers()); test.expect_stack(&[6]); @@ -582,13 +552,7 @@ fn dyncall_with_syscall_and_caller() { movupw.3 dropw movupw.3 dropw end"; - // Set up the test with kernel - let mut test = Test::new(&format!("test{}", line!()), program_source, true); - test.kernel_source = Some(test.source_manager.load( - SourceLanguage::Masm, - format!("kernel{}", line!()).into(), - kernel_source.to_string(), - )); + let test = build_debug_test!(program_source).with_kernel(kernel_source); // Compile to get the hash of `bar` let (program, _kernel) = test.compile().unwrap(); @@ -663,9 +627,9 @@ fn procref() -> Result<(), Report> { end"; let core_lib = CoreLibrary::default(); - let mut test = build_test!(source, &[]); - test.libraries.push(core_lib.library().clone()); - test.add_event_handlers(core_lib.handlers()); + let test = build_test!(source, &[]) + .with_library(core_lib.library().clone()) + .with_event_handlers(core_lib.handlers()); // procref pushes element[0] on top // Word from procedure_digests stores elements in BE order (word[0] = high) diff --git a/miden-vm/tests/integration/operations/crypto_ops.rs b/miden-vm/tests/integration/operations/crypto_ops.rs index 328c3fffac..ce58618516 100644 --- a/miden-vm/tests/integration/operations/crypto_ops.rs +++ b/miden-vm/tests/integration/operations/crypto_ops.rs @@ -77,10 +77,11 @@ fn hperm() { // --- test that the rest of the stack isn't affected ----------------------------------------- let stack_inputs: Vec = vec![1, 2, 3, 4]; - let expected_stack_slice = stack_inputs.iter().map(|&v| Felt::new(v)).collect::>(); + let expected_stack_slice = + stack_inputs.iter().map(|&v| Felt::new_unchecked(v)).collect::>(); let values_to_hash: Vec = vec![1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0]; - let mut full_inputs = values_to_hash.clone(); + let mut full_inputs = values_to_hash; full_inputs.extend_from_slice(&stack_inputs); let test = build_op_test!(asm_op, &full_inputs); @@ -104,10 +105,11 @@ fn hmerge() { // --- test that the rest of the stack isn't affected ----------------------------------------- let stack_inputs: Vec = vec![1, 2, 3, 4]; - let expected_stack_slice = stack_inputs.iter().map(|&v| Felt::new(v)).collect::>(); + let expected_stack_slice = + stack_inputs.iter().map(|&v| Felt::new_unchecked(v)).collect::>(); let values_to_hash: Vec = vec![1, 1, 0, 0, 0, 0, 0, 0]; - let mut full_inputs = values_to_hash.clone(); + let mut full_inputs = values_to_hash; full_inputs.extend_from_slice(&stack_inputs); let test = build_op_test!(asm_op, &full_inputs); @@ -244,7 +246,7 @@ fn mtree_update() { let tree = MerkleTree::new(leaves.clone()).unwrap(); let new_node = init_merkle_leaf(9); - let mut new_leaves = leaves.clone(); + let mut new_leaves = leaves; new_leaves[index] = new_node; let new_tree = MerkleTree::new(new_leaves).unwrap(); @@ -282,7 +284,7 @@ fn mtree_update() { new_tree.root()[3].as_canonical_u64(), ]; - let test = build_op_test!(asm_op, &stack_inputs, &[], store.clone()); + let test = build_op_test!(asm_op, &stack_inputs, &[], store); test.expect_stack(&final_stack); } @@ -321,8 +323,24 @@ fn crypto_stream_basic() { let c2 = [stack[3], stack[2], stack[1], stack[0]]; let c1 = [stack[7], stack[6], stack[5], stack[4]]; - assert_eq!(c2, [Felt::new(9), Felt::new(9), Felt::new(9), Felt::new(9)]); - assert_eq!(c1, [Felt::new(9), Felt::new(9), Felt::new(9), Felt::new(9)]); + assert_eq!( + c2, + [ + Felt::new_unchecked(9), + Felt::new_unchecked(9), + Felt::new_unchecked(9), + Felt::new_unchecked(9) + ] + ); + assert_eq!( + c1, + [ + Felt::new_unchecked(9), + Felt::new_unchecked(9), + Felt::new_unchecked(9), + Felt::new_unchecked(9) + ] + ); } #[test] @@ -633,13 +651,13 @@ proptest! { // Compute expected result using Horner's method // P(α) = c0*α^7 + c1*α^6 + c2*α^5 + c3*α^4 + c4*α^3 + c5*α^2 + c6*α + c7 // Horner form: (...((c0*α + c1)*α + c2)*α + ...)*α + c7 - let alpha = QuadFelt::new([Felt::new(alpha_0), Felt::new(alpha_1)]); - let acc_old = QuadFelt::new([Felt::new(acc_0), Felt::new(acc_1)]); + let alpha = QuadFelt::new([Felt::new_unchecked(alpha_0), Felt::new_unchecked(alpha_1)]); + let acc_old = QuadFelt::new([Felt::new_unchecked(acc_0), Felt::new_unchecked(acc_1)]); // Fold from c0 to c7: acc = acc_old, then acc = c0 + α*acc, acc = c1 + α*acc, etc. let acc_new = inputs[0..8] .iter() - .fold(acc_old, |acc, &coef| QuadFelt::from(Felt::new(coef)) + alpha * acc); + .fold(acc_old, |acc, &coef| QuadFelt::from(Felt::new_unchecked(coef)) + alpha * acc); // Prepare the advice stack with alpha values: [alpha_0, alpha_1, 0, 0] let adv_stack: Vec = vec![alpha_0, alpha_1, 0, 0]; @@ -718,15 +736,15 @@ proptest! { inputs[ACC_LOW_INDEX] = acc_0; // Compute expected result - let alpha = QuadFelt::new([Felt::new(alpha_0), Felt::new(alpha_1)]); - let acc_old = QuadFelt::new([Felt::new(acc_0), Felt::new(acc_1)]); + let alpha = QuadFelt::new([Felt::new_unchecked(alpha_0), Felt::new_unchecked(alpha_1)]); + let acc_old = QuadFelt::new([Felt::new_unchecked(acc_0), Felt::new_unchecked(acc_1)]); // Build extension field coefficients: chunks of 2 [low, high] // Horner: P(α) = c0*α^3 + c1*α^2 + c2*α + c3 let acc_new = inputs[0..8] .chunks(2) .map(|chunk| { - QuadFelt::new([Felt::new(chunk[0]), Felt::new(chunk[1])]) + QuadFelt::new([Felt::new_unchecked(chunk[0]), Felt::new_unchecked(chunk[1])]) }) .fold(acc_old, |acc, coef| coef + alpha * acc); diff --git a/miden-vm/tests/integration/operations/decorators/advice.rs b/miden-vm/tests/integration/operations/decorators/advice.rs index d02ac7fe4f..a16a63c307 100644 --- a/miden-vm/tests/integration/operations/decorators/advice.rs +++ b/miden-vm/tests/integration/operations/decorators/advice.rs @@ -81,7 +81,12 @@ fn advice_push_mapval() { let stack_key: [u64; 4] = [1, 2, 3, 4]; let adv_map = [( Word::try_from(stack_key).unwrap(), - vec![Felt::new(5), Felt::new(6), Felt::new(7), Felt::new(8)], + vec![ + Felt::new_unchecked(5), + Felt::new_unchecked(6), + Felt::new_unchecked(7), + Felt::new_unchecked(8), + ], )]; let test = build_test!(source, &stack_inputs, [], MerkleStore::default(), adv_map); @@ -97,7 +102,7 @@ fn advice_push_mapval() { dropw # move the number of values from the advice stack to the operand stack - adv_push.1 + adv_push swap drop end"; @@ -105,7 +110,13 @@ fn advice_push_mapval() { let stack_key: [u64; 4] = [1, 2, 3, 4]; let adv_map = [( Word::try_from(stack_key).unwrap(), - vec![Felt::new(9), Felt::new(8), Felt::new(7), Felt::new(6), Felt::new(5)], + vec![ + Felt::new_unchecked(9), + Felt::new_unchecked(8), + Felt::new_unchecked(7), + Felt::new_unchecked(6), + Felt::new_unchecked(5), + ], )]; let test = build_test!(source, &stack_inputs, [], MerkleStore::default(), adv_map); @@ -125,7 +136,7 @@ fn adv_push_mapvaln() { dropw # move the values from the advice stack to the operand stack - adv_push.6 + repeat.6 adv_push end swapdw dropw dropw end"; @@ -133,7 +144,13 @@ fn adv_push_mapvaln() { let stack_key: [u64; 4] = [1, 2, 3, 4]; let adv_map = [( Word::try_from(stack_key).unwrap(), - vec![Felt::new(11), Felt::new(12), Felt::new(13), Felt::new(14), Felt::new(15)], + vec![ + Felt::new_unchecked(11), + Felt::new_unchecked(12), + Felt::new_unchecked(13), + Felt::new_unchecked(14), + Felt::new_unchecked(15), + ], )]; let test = build_test!(source, &stack_inputs, [], MerkleStore::default(), adv_map); @@ -154,7 +171,7 @@ fn adv_push_mapvaln_padding() { dropw # move the values from the advice stack to the operand stack - adv_push.6 + repeat.6 adv_push end swapdw dropw dropw end"; @@ -162,7 +179,13 @@ fn adv_push_mapvaln_padding() { let stack_key: [u64; 4] = [1, 2, 3, 4]; let adv_map = [( Word::try_from(stack_key).unwrap(), - vec![Felt::new(11), Felt::new(12), Felt::new(13), Felt::new(14), Felt::new(15)], + vec![ + Felt::new_unchecked(11), + Felt::new_unchecked(12), + Felt::new_unchecked(13), + Felt::new_unchecked(14), + Felt::new_unchecked(15), + ], )]; let test = build_test!(source, &stack_inputs, [], MerkleStore::default(), adv_map); @@ -181,7 +204,7 @@ fn adv_push_mapvaln_padding() { dropw # move the values from the advice stack to the operand stack - adv_push.5 + repeat.5 adv_push end swapdw dropw dropw end"; @@ -189,7 +212,7 @@ fn adv_push_mapvaln_padding() { let stack_key: [u64; 4] = [1, 2, 3, 4]; let adv_map = [( Word::try_from(stack_key).unwrap(), - vec![Felt::new(11), Felt::new(12), Felt::new(13)], + vec![Felt::new_unchecked(11), Felt::new_unchecked(12), Felt::new_unchecked(13)], )]; let test = build_test!(source, &stack_inputs, [], MerkleStore::default(), adv_map); @@ -208,8 +231,8 @@ fn adv_push_mapvaln_padding() { dropw # move the values from the advice stack to the operand stack - adv_push.8 swapdw dropw dropw - adv_push.1 movup.9 drop + repeat.8 adv_push end swapdw dropw dropw + adv_push movup.9 drop end"; let stack_inputs = [1, 2, 3, 4]; @@ -217,12 +240,12 @@ fn adv_push_mapvaln_padding() { let adv_map = [( Word::try_from(stack_key).unwrap(), vec![ - Felt::new(11), - Felt::new(12), - Felt::new(13), - Felt::new(14), - Felt::new(15), - Felt::new(16), + Felt::new_unchecked(11), + Felt::new_unchecked(12), + Felt::new_unchecked(13), + Felt::new_unchecked(14), + Felt::new_unchecked(15), + Felt::new_unchecked(16), ], )]; @@ -241,7 +264,7 @@ fn advice_has_mapkey() { adv.has_mapkey # move the the flag from the advice stack to the operand stack - adv_push.1 + adv_push # check that the flag equals 1 -- the key is present in the map dup assert.err="presence flag should be equal 1" @@ -254,7 +277,12 @@ fn advice_has_mapkey() { let stack_key: [u64; 4] = [1, 2, 3, 4]; let adv_map = [( Word::try_from(stack_key).unwrap(), - vec![Felt::new(8), Felt::new(7), Felt::new(6), Felt::new(5)], + vec![ + Felt::new_unchecked(8), + Felt::new_unchecked(7), + Felt::new_unchecked(6), + Felt::new_unchecked(5), + ], )]; let test = build_test!(source, &stack_inputs, [], MerkleStore::default(), adv_map); @@ -269,7 +297,7 @@ fn advice_has_mapkey() { adv.has_mapkey # move the the flag from the advice stack to the operand stack - adv_push.1 + adv_push # check that the flag equals 0 -- the key is not present in the map dup assertz.err="presence flag should be equal 0" @@ -282,7 +310,12 @@ fn advice_has_mapkey() { let map_key = [5u64, 6, 7, 8]; let adv_map = [( Word::try_from(map_key).unwrap(), - vec![Felt::new(9), Felt::new(10), Felt::new(11), Felt::new(12)], + vec![ + Felt::new_unchecked(9), + Felt::new_unchecked(10), + Felt::new_unchecked(11), + Felt::new_unchecked(12), + ], )]; let test = build_test!(source, &stack_inputs, [], MerkleStore::default(), adv_map); diff --git a/miden-vm/tests/integration/operations/field_ops.rs b/miden-vm/tests/integration/operations/field_ops.rs index d30d9410b9..d90cdb323a 100644 --- a/miden-vm/tests/integration/operations/field_ops.rs +++ b/miden-vm/tests/integration/operations/field_ops.rs @@ -162,8 +162,8 @@ fn div() { // --- test remainder ------------------------------------------------------------------------- let test = build_op_test!(asm_op, &[2, 5]); - let expected = - (Felt::new(2).inverse().as_canonical_u64() as u128 * 5_u128) % Felt::ORDER_U64 as u128; + let expected = (Felt::new_unchecked(2).inverse().as_canonical_u64() as u128 * 5_u128) + % Felt::ORDER_U64 as u128; test.expect_stack(&[expected as u64]); // --- test that the rest of the stack isn't affected ----------------------------------------- @@ -200,8 +200,8 @@ fn div_b() { // --- test remainder ------------------------------------------------------------------------- let test = build_op_test!(build_asm_op(2), &[5]); - let expected = - (Felt::new(2).inverse().as_canonical_u64() as u128 * 5_u128) % Felt::ORDER_U64 as u128; + let expected = (Felt::new_unchecked(2).inverse().as_canonical_u64() as u128 * 5_u128) + % Felt::ORDER_U64 as u128; test.expect_stack(&[expected as u64]); // --- test that the rest of the stack isn't affected ----------------------------------------- @@ -271,12 +271,12 @@ fn inv() { test.expect_stack(&[ONE.inverse().as_canonical_u64()]); let test = build_op_test!(asm_op, &[64]); - test.expect_stack(&[Felt::new(64).inverse().as_canonical_u64()]); + test.expect_stack(&[Felt::new_unchecked(64).inverse().as_canonical_u64()]); // --- test that the rest of the stack isn't affected ----------------------------------------- let c = rand_value::(); let test = build_op_test!(asm_op, &[5, c]); - test.expect_stack(&[Felt::new(5).inverse().as_canonical_u64(), c]); + test.expect_stack(&[Felt::new_unchecked(5).inverse().as_canonical_u64(), c]); } #[test] @@ -339,7 +339,7 @@ fn exp_bits_length() { let base = 9; let pow = 1021; - let expected = Felt::new(base).exp_u64(pow); + let expected = Felt::new_unchecked(base).exp_u64(pow); let test = build_op_test!(build_asm_op(10), &[pow, base]); test.expect_stack(&[expected.as_canonical_u64()]); @@ -387,7 +387,7 @@ fn exp_small_pow() { let base = rand_value::(); let pow = 7; - let expected = Felt::new(base).exp_u64(pow); + let expected = Felt::new_unchecked(base).exp_u64(pow); let test = build_op_test!(build_asm_op(pow), &[base]); test.expect_stack(&[expected.as_canonical_u64()]); @@ -427,7 +427,7 @@ fn ilog2_ignores_prefilled_advice_in_real_opcode_path() { fn ilog2_bound_verification_source() -> &'static str { "begin # Pop claimed ilog2 from advice stack: [claimed_ilog2, n, ...] - adv_push.1 + adv_push # Compute pow2 = 2^claimed_ilog2. dup.0 @@ -536,7 +536,7 @@ fn not_fail() { expect_exec_error_matches!( test, - ExecutionError::OperationError { err: OperationError::NotBinaryValue { value }, .. } if value == Felt::new(2_u64) + ExecutionError::OperationError { err: OperationError::NotBinaryValue { value }, .. } if value == Felt::new_unchecked(2_u64) ); } @@ -564,19 +564,19 @@ fn and_fail() { let test = build_op_test!(asm_op, &[2, 3]); expect_exec_error_matches!( test, - ExecutionError::OperationError { err: OperationError::NotBinaryValue { value }, .. } if value == Felt::new(2_u64) + ExecutionError::OperationError { err: OperationError::NotBinaryValue { value }, .. } if value == Felt::new_unchecked(2_u64) ); let test = build_op_test!(asm_op, &[0, 2]); expect_exec_error_matches!( test, - ExecutionError::OperationError { err: OperationError::NotBinaryValue { value }, .. } if value == Felt::new(2_u64) + ExecutionError::OperationError { err: OperationError::NotBinaryValue { value }, .. } if value == Felt::new_unchecked(2_u64) ); let test = build_op_test!(asm_op, &[2, 0]); expect_exec_error_matches!( test, - ExecutionError::OperationError { err: OperationError::NotBinaryValue { value }, .. } if value == Felt::new(2_u64) + ExecutionError::OperationError { err: OperationError::NotBinaryValue { value }, .. } if value == Felt::new_unchecked(2_u64) ); } @@ -601,7 +601,7 @@ fn or() { fn or_fail() { let asm_op = "or"; - let expected_value = Felt::new(2); + let expected_value = Felt::new_unchecked(2); let test = build_op_test!(asm_op, &[2, 3]); expect_exec_error_matches!( test, @@ -642,7 +642,7 @@ fn xor() { fn xor_fail() { let asm_op = "xor"; - let expected_value = Felt::new(2); + let expected_value = Felt::new_unchecked(2); // --- test value > 1 -------------------------------------------------------------------- // Stack [3, 2] - VM checks position 1 first, so error for value 2 let test = build_op_test!(asm_op, &[3, 2]); @@ -742,6 +742,7 @@ fn gte() { // ================================================================================================ proptest! { + #![proptest_config(ProptestConfig::with_cases(100))] #[test] fn add_proptest(a in any::(), b in any::()) { let asm_op = "add"; @@ -813,7 +814,7 @@ proptest! { let asm_op = "div"; // allow a possible overflow then mod by the Felt Modulus - let expected = (Felt::new(b).inverse().as_canonical_u64() as u128 * a as u128) % Felt::ORDER_U64 as u128; + let expected = (Felt::new_unchecked(b).inverse().as_canonical_u64() as u128 * a as u128) % Felt::ORDER_U64 as u128; // b provided via the stack: stack [b, a] computes a / b let test = build_op_test!(asm_op, &[b, a]); @@ -843,7 +844,7 @@ proptest! { fn inv_proptest(a in 1..u64::MAX) { let asm_op = "inv"; - let expected = Felt::new(a).inverse().as_canonical_u64(); + let expected = Felt::new_unchecked(a).inverse().as_canonical_u64(); let test = build_op_test!(asm_op, &[a]); test.prop_expect_stack(&[expected])?; @@ -864,7 +865,7 @@ proptest! { let asm_op = "exp"; let base = a; let pow = b; - let expected = Felt::new(base).exp_u64(pow); + let expected = Felt::new_unchecked(base).exp_u64(pow); let test = build_op_test!(asm_op, &[pow, base]); test.prop_expect_stack(&[expected.as_canonical_u64()])?; @@ -873,7 +874,7 @@ proptest! { let build_asm_op = |param: u64| format!("exp.{param}"); let base = a; let pow = b; - let expected = Felt::new(base).exp_u64(pow); + let expected = Felt::new_unchecked(base).exp_u64(pow); let test = build_op_test!(build_asm_op(pow), &[base]); test.prop_expect_stack(&[expected.as_canonical_u64()])?; diff --git a/miden-vm/tests/integration/operations/fri_ops.rs b/miden-vm/tests/integration/operations/fri_ops.rs index 3b95380aa3..c92c28aaef 100644 --- a/miden-vm/tests/integration/operations/fri_ops.rs +++ b/miden-vm/tests/integration/operations/fri_ops.rs @@ -6,19 +6,22 @@ use miden_utils_testing::{Felt, TRUNCATE_STACK_PROC, build_test, push_inputs, ra #[test] fn fri_ext2fold4() { // create a set of random inputs - let mut inputs = rand_array::() - .iter() - .map(|v| v.as_canonical_u64()) - .collect::>(); - inputs[7] = 2; // domain segment must be < 4 - - // When domain segment is 2, query_values[2] = (v4, v5) must equal prev_value = (pe0, pe1). + let mut inputs = + rand_array::().iter().map(Felt::as_canonical_u64).collect::>(); + // inputs[7] -> stack[9] = p (bit-reversed tree index). + // The instruction computes d_seg = p & 3 and f_pos = p >> 2. + // We want d_seg=2, f_pos=inputs[8], so p = 4*f_pos + 2. + // f_pos must fit in u32 to avoid overflow when computing p. + inputs[8] %= (u32::MAX as u64) >> 2; + inputs[7] = 4 * inputs[8] + 2; + + // When d_seg=2, query_values[2] = (v4, v5) must equal prev_value = (pe0, pe1). // After pushing 17 inputs: - // Position 4 = inputs[12] (v4), Position 5 = inputs[11] (v5) - // Position 12 = inputs[4] (pe0), Position 11 = inputs[5] (pe1) - // So we need inputs[12] = inputs[4] and inputs[11] = inputs[5]. - inputs[12] = inputs[4]; - inputs[11] = inputs[5]; + // v4 = inputs[12] (stack[4]), v5 = inputs[11] (stack[5]) + // pe0 = inputs[5] (stack[11]), pe1 = inputs[4] (stack[12]) + // So we need inputs[12] = inputs[5] (v4 = pe0) and inputs[11] = inputs[4] (v5 = pe1). + inputs[12] = inputs[5]; + inputs[11] = inputs[4]; let end_ptr = inputs[0]; let layer_ptr = inputs[1]; @@ -44,11 +47,11 @@ fn fri_ext2fold4() { // check some items in the state transition; full state transition is checked in the // processor tests let stack_state = test.get_last_stack_state(); - assert_eq!(stack_state[8], Felt::new(poe).square()); - assert_eq!(stack_state[10], Felt::new(layer_ptr + 8)); - assert_eq!(stack_state[11], Felt::new(poe).exp_u64(4)); - assert_eq!(stack_state[12], Felt::new(f_pos)); - assert_eq!(stack_state[15], Felt::new(end_ptr)); + assert_eq!(stack_state[8], Felt::new_unchecked(poe).square()); + assert_eq!(stack_state[10], Felt::new_unchecked(layer_ptr + 8)); + assert_eq!(stack_state[11], Felt::new_unchecked(poe).exp_u64(4)); + assert_eq!(stack_state[12], Felt::new_unchecked(f_pos)); + assert_eq!(stack_state[15], Felt::new_unchecked(end_ptr)); // make sure STARK proof can be generated and verified test.check_constraints(); diff --git a/miden-vm/tests/integration/operations/io_ops/adv_ops.rs b/miden-vm/tests/integration/operations/io_ops/adv_ops.rs index d02e1a9ddf..ef9364f406 100644 --- a/miden-vm/tests/integration/operations/io_ops/adv_ops.rs +++ b/miden-vm/tests/integration/operations/io_ops/adv_ops.rs @@ -1,4 +1,6 @@ -use miden_core::{Felt, chiplets::hasher::apply_permutation, utils::ToElements}; +use miden_core::{ + Felt, advice::AdviceStackBuilder, chiplets::hasher::apply_permutation, utils::ToElements, +}; use miden_processor::{ExecutionError, advice::AdviceError}; use miden_utils_testing::expect_exec_error_matches; @@ -9,45 +11,54 @@ use super::{TRUNCATE_STACK_PROC, build_op_test, build_test}; #[test] fn adv_push() { - let asm_op = "adv_push"; - let advice_stack = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; - let test_n = |n: usize| { - let source = format!("{asm_op}.{n}"); - let mut final_stack = vec![0; n]; - final_stack.copy_from_slice(&advice_stack[..n]); - final_stack.reverse(); - - let test = build_op_test!(source, &[], &advice_stack); - test.expect_stack(&final_stack); - }; - - // --- push 1 --------------------------------------------------------------------------------- - test_n(1); - - // --- push max ------------------------------------------------------------------------------- - test_n(16); + let advice_stack = [42]; + let test = build_op_test!("adv_push", &[], &advice_stack); + test.expect_stack(&[42]); +} + +#[test] +fn adv_push_repeat() { + // AdviceStackBuilder handles the reversal required by sequential adv_push. + let mut builder = AdviceStackBuilder::new(); + builder.push_for_adv_push(&[ + Felt::new_unchecked(1), + Felt::new_unchecked(2), + Felt::new_unchecked(3), + Felt::new_unchecked(4), + ]); + let advice_stack = builder.build_vec_u64(); + let test = build_op_test!("repeat.4 adv_push end", &[], &advice_stack); + test.expect_stack(&[1, 2, 3, 4]); } #[test] fn adv_push_invalid() { // attempting to read from empty advice stack should throw an error - let test = build_op_test!("adv_push.1"); + let test = build_op_test!("adv_push"); expect_exec_error_matches!( test, ExecutionError::AdviceError { err: AdviceError::StackReadFailed, .. } ) } +// PUSHING WORDS ONTO THE STACK (PUSHW) +// ================================================================================================ + +#[test] +fn adv_pushw() { + let advice_stack = [1, 2, 3, 4]; + let test = build_op_test!("adv_pushw", &[], &advice_stack); + test.expect_stack(&[1, 2, 3, 4]); +} + // OVERWRITING VALUES ON THE STACK (LOAD) // ================================================================================================ #[test] fn adv_loadw() { - // adv_loadw loads the structural word directly (no built-in reversal). - // Use reversew afterward if canonical order is needed. let asm_op = "adv_loadw"; let advice_stack = [1, 2, 3, 4]; - let final_stack = advice_stack; // No reversal - structural order + let final_stack = advice_stack; let test = build_op_test!(asm_op, &[8, 7, 6, 5], &advice_stack); test.expect_stack(&final_stack); @@ -63,6 +74,15 @@ fn adv_loadw_invalid() { ); } +#[test] +fn adv_pushw_invalid() { + let test = build_op_test!("adv_pushw", &[], &[1, 2, 3]); + expect_exec_error_matches!( + test, + ExecutionError::AdviceError { err: AdviceError::StackReadFailed, .. } + ); +} + // MOVING ELEMENTS TO MEMORY VIA THE STACK (PIPE) // ================================================================================================ diff --git a/miden-vm/tests/integration/operations/io_ops/constant_ops.rs b/miden-vm/tests/integration/operations/io_ops/constant_ops.rs index 166a305061..e925b50263 100644 --- a/miden-vm/tests/integration/operations/io_ops/constant_ops.rs +++ b/miden-vm/tests/integration/operations/io_ops/constant_ops.rs @@ -104,7 +104,7 @@ proptest! { // Calculate expected value by padding with leading zero for odd lengths let padded_hex = if hex_str.len() % 2 == 1 { - format!("0{}", hex_str) + format!("0{hex_str}") } else { hex_str.clone() }; @@ -113,7 +113,7 @@ proptest! { let expected = u64::from_str_radix(&padded_hex, 16).unwrap(); // Build assembly operation - let asm_op = format!("push.0x{}", hex_str); + let asm_op = format!("push.0x{hex_str}"); // Test that it parses and executes correctly let test = build_op_test!(&asm_op); diff --git a/miden-vm/tests/integration/operations/io_ops/env_ops.rs b/miden-vm/tests/integration/operations/io_ops/env_ops.rs index 6a4ab29796..0cb581f679 100644 --- a/miden-vm/tests/integration/operations/io_ops/env_ops.rs +++ b/miden-vm/tests/integration/operations/io_ops/env_ops.rs @@ -6,8 +6,7 @@ use miden_core::{ }, operations::Operation, }; -use miden_debug_types::{SourceLanguage, SourceManager}; -use miden_utils_testing::{MIN_STACK_DEPTH, StackInputs, Test, Word, build_op_test, build_test}; +use miden_utils_testing::{MIN_STACK_DEPTH, Word, build_op_test, build_test}; use super::TRUNCATE_STACK_PROC; @@ -183,14 +182,7 @@ fn caller() { call.bar end"; - // TODO: update and use macro? - let mut test = Test::new(&format!("test{}", line!()), program_source, false); - test.stack_inputs = StackInputs::try_from_ints([1, 2, 3, 4, 5]).unwrap(); - test.kernel_source = Some(test.source_manager.load( - SourceLanguage::Masm, - format!("kernel{}", line!()).into(), - kernel_source.to_string(), - )); + let test = build_test!(program_source, &[1, 2, 3, 4, 5]).with_kernel(kernel_source); // top 4 elements should be overwritten with the hash of `bar` procedure, but the 5th // element should remain untouched (position 4 in input [1,2,3,4,5] is 5) diff --git a/miden-vm/tests/integration/operations/stack_ops.rs b/miden-vm/tests/integration/operations/stack_ops.rs index 47fa44aa6c..72d327b59e 100644 --- a/miden-vm/tests/integration/operations/stack_ops.rs +++ b/miden-vm/tests/integration/operations/stack_ops.rs @@ -433,6 +433,7 @@ fn cdropw() { } proptest! { + #![proptest_config(ProptestConfig::with_cases(100))] #[test] fn drop_proptest(test_values in prop::collection::vec(any::(), MIN_STACK_DEPTH)) { diff --git a/miden-vm/tests/integration/operations/sys_ops.rs b/miden-vm/tests/integration/operations/sys_ops.rs index 9b3df0f45b..ab9479565f 100644 --- a/miden-vm/tests/integration/operations/sys_ops.rs +++ b/miden-vm/tests/integration/operations/sys_ops.rs @@ -91,7 +91,7 @@ fn emit() { let event_id = event_name.to_event_id().as_felt(); let source = format!("push.{event_id} emit drop"); - let mut test = build_op_test!(&source, &[0, 0, 0, 0]); - test.add_event_handler(event_name, NoopEventHandler); + let test = + build_op_test!(&source, &[0, 0, 0, 0]).with_event_handler(event_name, NoopEventHandler); test.check_constraints(); } diff --git a/miden-vm/tests/integration/operations/u32_ops/arithmetic_ops.rs b/miden-vm/tests/integration/operations/u32_ops/arithmetic_ops.rs index 4c500b49e5..5749ce72bb 100644 --- a/miden-vm/tests/integration/operations/u32_ops/arithmetic_ops.rs +++ b/miden-vm/tests/integration/operations/u32_ops/arithmetic_ops.rs @@ -685,6 +685,7 @@ fn u32divmod_fail() { // U32 OPERATIONS TESTS - RANDOMIZED - ARITHMETIC OPERATIONS // ================================================================================================ proptest! { + #![proptest_config(ProptestConfig::with_cases(100))] #[test] fn u32unchecked_add_proptest(a in any::(), b in any::()) { let wrapping_asm_op = "u32wrapping_add"; diff --git a/miden-vm/tests/integration/operations/u32_ops/bitwise_ops.rs b/miden-vm/tests/integration/operations/u32_ops/bitwise_ops.rs index 60a10161e8..73fe025d4e 100644 --- a/miden-vm/tests/integration/operations/u32_ops/bitwise_ops.rs +++ b/miden-vm/tests/integration/operations/u32_ops/bitwise_ops.rs @@ -80,14 +80,14 @@ fn u32and_fail() { expect_exec_error_matches!( test, - ExecutionError::OperationError{ err: OperationError::NotU32Values{ values }, .. } if values == vec![Felt::new(U32_BOUND)] + ExecutionError::OperationError{ err: OperationError::NotU32Values{ values }, .. } if values == vec![Felt::new_unchecked(U32_BOUND)] ); let test = build_op_test!(asm_op, &[0, U32_BOUND]); expect_exec_error_matches!( test, - ExecutionError::OperationError{ err: OperationError::NotU32Values{ values }, .. } if values == vec![Felt::new(U32_BOUND)] + ExecutionError::OperationError{ err: OperationError::NotU32Values{ values }, .. } if values == vec![Felt::new_unchecked(U32_BOUND)] ); } @@ -163,14 +163,14 @@ fn u32or_fail() { expect_exec_error_matches!( test, - ExecutionError::OperationError{ err: OperationError::NotU32Values{ values }, .. } if values == vec![Felt::new(U32_BOUND)] + ExecutionError::OperationError{ err: OperationError::NotU32Values{ values }, .. } if values == vec![Felt::new_unchecked(U32_BOUND)] ); let test = build_op_test!(asm_op, &[0, U32_BOUND]); expect_exec_error_matches!( test, - ExecutionError::OperationError{ err: OperationError::NotU32Values{ values }, .. } if values == vec![Felt::new(U32_BOUND)] + ExecutionError::OperationError{ err: OperationError::NotU32Values{ values }, .. } if values == vec![Felt::new_unchecked(U32_BOUND)] ); } @@ -245,14 +245,14 @@ fn u32xor_fail() { expect_exec_error_matches!( test, - ExecutionError::OperationError{ err: OperationError::NotU32Values{ values }, .. } if values == vec![Felt::new(U32_BOUND)] + ExecutionError::OperationError{ err: OperationError::NotU32Values{ values }, .. } if values == vec![Felt::new_unchecked(U32_BOUND)] ); let test = build_op_test!(asm_op, &[0, U32_BOUND]); expect_exec_error_matches!( test, - ExecutionError::OperationError{ err: OperationError::NotU32Values{ values }, .. } if values == vec![Felt::new(U32_BOUND)] + ExecutionError::OperationError{ err: OperationError::NotU32Values{ values }, .. } if values == vec![Felt::new_unchecked(U32_BOUND)] ); } diff --git a/miden-vm/tests/integration/operations/u32_ops/conversion_ops.rs b/miden-vm/tests/integration/operations/u32_ops/conversion_ops.rs index ed704500d9..caacdec743 100644 --- a/miden-vm/tests/integration/operations/u32_ops/conversion_ops.rs +++ b/miden-vm/tests/integration/operations/u32_ops/conversion_ops.rs @@ -105,7 +105,7 @@ fn u32assert_fail() { test, ExecutionError::OperationError{ err: OperationError::NotU32Values{ values }, .. } if values.len() == 1 && - values[0] == Felt::new(equal) + values[0] == Felt::new_unchecked(equal) ); // --- test when a > 2^32 --------------------------------------------------------------------- @@ -115,7 +115,7 @@ fn u32assert_fail() { test, ExecutionError::OperationError{ err: OperationError::NotU32Values{ values }, .. } if values.len() == 1 && - values[0] == Felt::new(larger) + values[0] == Felt::new_unchecked(larger) ); } @@ -148,8 +148,8 @@ fn u32assert2_fail() { test, ExecutionError::OperationError{ err: OperationError::NotU32Values{ values }, .. } if values.len() == 2 && - values[0] == Felt::new(value_a) && - values[1] == Felt::new(value_b) + values[0] == Felt::new_unchecked(value_a) && + values[1] == Felt::new_unchecked(value_b) ); // -------- Case 2: a > 2^32 and b < 2^32 --------------------------------------------------- @@ -161,7 +161,7 @@ fn u32assert2_fail() { test, ExecutionError::OperationError{ err: OperationError::NotU32Values{ values }, .. } if values.len() == 1 && - values[0] == Felt::new(value_a) + values[0] == Felt::new_unchecked(value_a) ); // --------- Case 3: a < 2^32 and b > 2^32 -------------------------------------------------- @@ -173,7 +173,7 @@ fn u32assert2_fail() { test, ExecutionError::OperationError{ err: OperationError::NotU32Values{ values }, .. } if values.len() == 1 && - values[0] == Felt::new(value_b) + values[0] == Felt::new_unchecked(value_b) ); } @@ -203,7 +203,7 @@ fn u32assertw_fail() { test, ExecutionError::OperationError{ err: OperationError::NotU32Values{ values }, .. } if values.len() == 2 && - values.iter().all(|v| *v == Felt::new(U32_BOUND)) + values.iter().all(|v| *v == Felt::new_unchecked(U32_BOUND)) ); } diff --git a/miden-vm/tests/integration/operations/u32_ops/mod.rs b/miden-vm/tests/integration/operations/u32_ops/mod.rs index e0d52d81bb..c6c477396d 100644 --- a/miden-vm/tests/integration/operations/u32_ops/mod.rs +++ b/miden-vm/tests/integration/operations/u32_ops/mod.rs @@ -18,7 +18,7 @@ pub fn test_input_out_of_bounds(asm_op: &str) { test, ExecutionError::OperationError{ err: OperationError::NotU32Values{ values }, .. } if values.len() == 1 && - values[0] == Felt::new(U32_BOUND) + values[0] == Felt::new_unchecked(U32_BOUND) ); } @@ -38,7 +38,7 @@ pub fn test_inputs_out_of_bounds(asm_op: &str, input_count: usize) { test, ExecutionError::OperationError{ err: OperationError::NotU32Values{ values }, .. } if values.len() == 1 && - values[0] == Felt::new(U32_BOUND) + values[0] == Felt::new_unchecked(U32_BOUND) ); } } diff --git a/miden-vm/tests/integration/prove_verify.rs b/miden-vm/tests/integration/prove_verify.rs index 464aaa06aa..7d41f86a54 100644 --- a/miden-vm/tests/integration/prove_verify.rs +++ b/miden-vm/tests/integration/prove_verify.rs @@ -3,42 +3,106 @@ use alloc::sync::Arc; use miden_assembly::{Assembler, DefaultSourceManager}; -use miden_prover::{AdviceInputs, ProvingOptions, StackInputs, prove_sync}; +use miden_core::{precompile::PrecompileTranscriptState, proof::ExecutionProof}; +use miden_core_lib::CoreLibrary; +use miden_processor::ExecutionOptions; +use miden_prover::{ + AdviceInputs, ProgramInfo, ProvingOptions, PublicInputs, StackInputs, StackOutputs, prove_sync, +}; use miden_verifier::verify; use miden_vm::{DefaultHost, HashFunction}; -#[test] -fn test_blake3_256_prove_verify() { - // Compute many Fibonacci iterations to generate a trace >= 2048 rows - let source = " - begin - repeat.1000 - swap dup.1 add - end - end - "; - +fn assert_prove_verify( + source: &str, + hash_fn: HashFunction, + hash_name: &str, + print_stack_outputs: bool, + verify_recursively: bool, +) { let program = Assembler::default().assemble_program(source).unwrap(); let stack_inputs = StackInputs::try_from_ints([0, 1]).unwrap(); let advice_inputs = AdviceInputs::default(); let mut host = DefaultHost::default().with_source_manager(Arc::new(DefaultSourceManager::default())); + let options = ProvingOptions::with_96_bit_security(hash_fn); + + println!("Proving with {hash_name}..."); + let (stack_outputs, proof) = prove_sync( + &program, + stack_inputs, + advice_inputs, + &mut host, + ExecutionOptions::default(), + options, + ) + .expect("Proving failed"); - // Create proving options with Blake3_256 (96-bit security) - let options = ProvingOptions::with_96_bit_security(HashFunction::Blake3_256); + println!("Proof generated successfully!"); + if print_stack_outputs { + println!("Stack outputs: {stack_outputs:?}"); + } - println!("Proving with Blake3_256..."); - let (stack_outputs, proof) = - prove_sync(&program, stack_inputs, advice_inputs, &mut host, options) - .expect("Proving failed"); + if verify_recursively { + assert_recursive_verify( + program.to_info(), + stack_inputs, + stack_outputs, + PrecompileTranscriptState::default(), + &proof, + ); + } - println!("Proof generated successfully!"); println!("Verifying proof..."); - let security_level = verify(program.into(), stack_inputs, stack_outputs, proof).expect("Verification failed"); - println!("Verification successful! Security level: {}", security_level); + println!("Verification successful! Security level: {security_level}"); +} + +fn assert_recursive_verify( + program_info: ProgramInfo, + stack_inputs: StackInputs, + stack_outputs: StackOutputs, + pc_transcript_state: PrecompileTranscriptState, + proof: &ExecutionProof, +) { + assert_eq!(proof.hash_fn(), HashFunction::Poseidon2); + + let pub_inputs = + PublicInputs::new(program_info, stack_inputs, stack_outputs, pc_transcript_state); + let verifier_inputs = + recursive_verifier::generate_advice_inputs(proof.stark_proof(), pub_inputs); + + let source = " + use miden::core::sys::vm + begin + exec.vm::verify_proof + end + "; + + let mut test = crate::build_test!( + source, + &verifier_inputs.initial_stack, + &verifier_inputs.advice_stack, + verifier_inputs.store, + verifier_inputs.advice_map + ); + test.libraries.push(CoreLibrary::default().library().clone()); + test.execute().expect("recursive verifier execution failed"); +} + +#[test] +fn test_blake3_256_prove_verify() { + // Compute many Fibonacci iterations to generate a trace >= 2048 rows + let source = " + begin + repeat.1000 + swap dup.1 add + end + end + "; + + assert_prove_verify(source, HashFunction::Blake3_256, "Blake3_256", false, false); } #[test] @@ -52,33 +116,7 @@ fn test_keccak_prove_verify() { end "; - // Compile the program - let program = Assembler::default().assemble_program(source).unwrap(); - - // Prepare inputs - start with 0 and 1 on the stack for Fibonacci - let stack_inputs = StackInputs::try_from_ints([0, 1]).unwrap(); - let advice_inputs = AdviceInputs::default(); - let mut host = - DefaultHost::default().with_source_manager(Arc::new(DefaultSourceManager::default())); - - // Create proving options with Keccak (96-bit security) - let options = ProvingOptions::with_96_bit_security(HashFunction::Keccak); - - // Prove the program - println!("Proving with Keccak..."); - let (stack_outputs, proof) = - prove_sync(&program, stack_inputs, advice_inputs, &mut host, options) - .expect("Proving failed"); - - println!("Proof generated successfully!"); - println!("Stack outputs: {:?}", stack_outputs); - - // Verify the proof - println!("Verifying proof..."); - let security_level = - verify(program.into(), stack_inputs, stack_outputs, proof).expect("Verification failed"); - - println!("Verification successful! Security level: {}", security_level); + assert_prove_verify(source, HashFunction::Keccak, "Keccak", true, false); } #[test] @@ -92,33 +130,7 @@ fn test_rpo_prove_verify() { end "; - // Compile the program - let program = Assembler::default().assemble_program(source).unwrap(); - - // Prepare inputs - start with 0 and 1 on the stack for Fibonacci - let stack_inputs = StackInputs::try_from_ints([0, 1]).unwrap(); - let advice_inputs = AdviceInputs::default(); - let mut host = - DefaultHost::default().with_source_manager(Arc::new(DefaultSourceManager::default())); - - // Create proving options with RPO (96-bit security) - let options = ProvingOptions::with_96_bit_security(HashFunction::Rpo256); - - // Prove the program - println!("Proving with RPO..."); - let (stack_outputs, proof) = - prove_sync(&program, stack_inputs, advice_inputs, &mut host, options) - .expect("Proving failed"); - - println!("Proof generated successfully!"); - println!("Stack outputs: {:?}", stack_outputs); - - // Verify the proof - println!("Verifying proof..."); - let security_level = - verify(program.into(), stack_inputs, stack_outputs, proof).expect("Verification failed"); - - println!("Verification successful! Security level: {}", security_level); + assert_prove_verify(source, HashFunction::Rpo256, "RPO", true, false); } #[test] @@ -132,28 +144,7 @@ fn test_poseidon2_prove_verify() { end "; - let program = Assembler::default().assemble_program(source).unwrap(); - let stack_inputs = StackInputs::try_from_ints([0, 1]).unwrap(); - let advice_inputs = AdviceInputs::default(); - let mut host = - DefaultHost::default().with_source_manager(Arc::new(DefaultSourceManager::default())); - - // Create proving options with Poseidon2 (96-bit security) - let options = ProvingOptions::with_96_bit_security(HashFunction::Poseidon2); - - println!("Proving with Poseidon2..."); - let (stack_outputs, proof) = - prove_sync(&program, stack_inputs, advice_inputs, &mut host, options) - .expect("Proving failed"); - - println!("Proof generated successfully!"); - println!("Stack outputs: {:?}", stack_outputs); - - println!("Verifying proof..."); - let security_level = - verify(program.into(), stack_inputs, stack_outputs, proof).expect("Verification failed"); - - println!("Verification successful! Security level: {}", security_level); + assert_prove_verify(source, HashFunction::Poseidon2, "Poseidon2", true, true); } /// Test end-to-end proving and verification with RPX @@ -168,28 +159,256 @@ fn test_rpx_prove_verify() { end "; - let program = Assembler::default().assemble_program(source).unwrap(); - let stack_inputs = StackInputs::try_from_ints([0, 1]).unwrap(); - let advice_inputs = AdviceInputs::default(); - let mut host = - DefaultHost::default().with_source_manager(Arc::new(DefaultSourceManager::default())); + assert_prove_verify(source, HashFunction::Rpx256, "RPX", true, false); +} - // Create proving options with RPX (96-bit security) - let options = ProvingOptions::with_96_bit_security(HashFunction::Rpx256); +mod recursive_verifier { + use alloc::vec::Vec; - println!("Proving with RPX..."); - let (stack_outputs, proof) = - prove_sync(&program, stack_inputs, advice_inputs, &mut host, options) - .expect("Proving failed"); + use miden_core::{ + Felt, WORD_SIZE, Word, + field::{BasedVectorSpace, QuadFelt}, + }; + use miden_crypto::stark::{ + StarkConfig, + challenger::CanObserve, + fri::PcsTranscript, + lmcs::{Lmcs, proof::BatchProofView}, + proof::StarkTranscript, + }; + use miden_lifted_stark::AirInstance; + use miden_prover::{ProcessorAir, PublicInputs, config}; + use miden_utils_testing::crypto::{MerklePath, MerkleStore, PartialMerkleTree}; + + type Challenge = QuadFelt; + type P2Config = config::Poseidon2Config; + type P2Lmcs = >::Lmcs; + + pub struct VerifierInputs { + pub initial_stack: Vec, + pub advice_stack: Vec, + pub store: MerkleStore, + pub advice_map: Vec<(Word, Vec)>, + } - println!("Proof generated successfully!"); - println!("Stack outputs: {:?}", stack_outputs); + pub fn generate_advice_inputs(proof_bytes: &[u8], pub_inputs: PublicInputs) -> VerifierInputs { + let params = config::pcs_params(); + let config = config::poseidon2_config(params); + let transcript_data = + bincode::deserialize(proof_bytes).expect("failed to deserialize proof bytes"); - println!("Verifying proof..."); - let security_level = - verify(program.into(), stack_inputs, stack_outputs, proof).expect("Verification failed"); + let (public_values, kernel_felts) = pub_inputs.to_air_inputs(); + let mut challenger = config.challenger(); + config::observe_protocol_params(&mut challenger); + challenger.observe_slice(&public_values); + let var_len_public_inputs: &[&[Felt]] = &[&kernel_felts]; + config::observe_var_len_public_inputs(&mut challenger, var_len_public_inputs, &[WORD_SIZE]); + + let air = ProcessorAir; + let instance = AirInstance { + public_values: &public_values, + var_len_public_inputs, + }; + + let (stark, _digest) = + StarkTranscript::from_proof(&config, &[(&air, instance)], &transcript_data, challenger) + .expect("failed to replay verifier transcript"); + let log_trace_height = stark.instance_shapes.log_trace_heights()[0] as usize; + + let kernel_digests: Vec = kernel_felts + .chunks_exact(4) + .map(|chunk| Word::new([chunk[0], chunk[1], chunk[2], chunk[3]])) + .collect(); + + build_advice(&config, &stark, log_trace_height, pub_inputs, &kernel_digests) + } + + fn build_advice( + config: &P2Config, + stark: &StarkTranscript, + log_trace_height: usize, + pub_inputs: PublicInputs, + kernel_digests: &[Word], + ) -> VerifierInputs { + let pcs = &stark.pcs_transcript; + let mut advice_stack = Vec::new(); + + let params = config::pcs_params(); + advice_stack.push(params.num_queries() as u64); + advice_stack.push(params.query_pow_bits() as u64); + advice_stack.push(config::DEEP_POW_BITS as u64); + advice_stack.push(config::FOLDING_POW_BITS as u64); + + advice_stack.extend_from_slice(&build_fixed_len_inputs(&pub_inputs)); + advice_stack.push(kernel_digests.len() as u64); + advice_stack.extend_from_slice(&build_kernel_digest_advice(kernel_digests)); + + let alpha = stark.randomness[0]; + let beta = stark.randomness[1]; + let beta_coeffs: &[Felt] = beta.as_basis_coefficients_slice(); + let alpha_coeffs: &[Felt] = alpha.as_basis_coefficients_slice(); + advice_stack.extend_from_slice(&[ + beta_coeffs[0].as_canonical_u64(), + beta_coeffs[1].as_canonical_u64(), + alpha_coeffs[0].as_canonical_u64(), + alpha_coeffs[1].as_canonical_u64(), + ]); + + advice_stack.extend_from_slice(&commitment_to_u64s(stark.main_commit)); + advice_stack.extend_from_slice(&commitment_to_u64s(stark.aux_commit)); + + if let Some(aux_values) = stark.all_aux_values.first() { + advice_stack.extend_from_slice(&challenges_to_u64s(aux_values)); + } + + advice_stack.extend_from_slice(&commitment_to_u64s(stark.quotient_commit)); + + let deep_alpha = pcs.deep_transcript.challenge_columns; + let deep_coeffs: &[Felt] = deep_alpha.as_basis_coefficients_slice(); + advice_stack.extend_from_slice(&[ + deep_coeffs[1].as_canonical_u64(), + deep_coeffs[0].as_canonical_u64(), + ]); + + append_ood_evaluations(&mut advice_stack, pcs); + advice_stack.push(pcs.deep_transcript.pow_witness.as_canonical_u64()); + + for round in &pcs.fri_transcript.rounds { + advice_stack.extend_from_slice(&commitment_to_u64s(round.commitment)); + advice_stack.push(round.pow_witness.as_canonical_u64()); + } + + let final_poly = &pcs.fri_transcript.final_poly; + let remainder_base: Vec = QuadFelt::flatten_to_base(final_poly.to_vec()); + advice_stack.extend(remainder_base.iter().map(Felt::as_canonical_u64)); + advice_stack.push(pcs.query_pow_witness.as_canonical_u64()); + + let (store, advice_map) = build_merkle_data(config, stark); + VerifierInputs { + initial_stack: vec![log_trace_height as u64], + advice_stack, + store, + advice_map, + } + } + + fn append_ood_evaluations(advice_stack: &mut Vec, pcs: &PcsTranscript) + where + L: Lmcs, + { + let evals = &pcs.deep_transcript.evals; + let mut local_values = Vec::new(); + let mut next_values = Vec::new(); + + for group in evals { + for matrix in group { + let width = matrix.width; + let values = matrix.values.as_slice(); + local_values.extend_from_slice(&values[..width]); + if values.len() > width { + next_values.extend_from_slice(&values[width..2 * width]); + } + } + } + + advice_stack.extend_from_slice(&challenges_to_u64s(&local_values)); + advice_stack.extend_from_slice(&challenges_to_u64s(&next_values)); + } + + fn build_merkle_data( + config: &P2Config, + stark: &StarkTranscript, + ) -> (MerkleStore, Vec<(Word, Vec)>) { + let pcs = &stark.pcs_transcript; + let lmcs = config.lmcs(); + + let mut partial_trees = Vec::new(); + let mut advice_map = Vec::new(); + + for batch_proof in &pcs.deep_witnesses { + let (trees, entries) = batch_proof_to_merkle(lmcs, batch_proof); + partial_trees.extend(trees); + advice_map.extend(entries); + } + + for batch_proof in pcs.fri_witnesses.iter() { + let (trees, entries) = batch_proof_to_merkle(lmcs, batch_proof); + partial_trees.extend(trees); + advice_map.extend(entries); + } + + let mut store = MerkleStore::new(); + for tree in &partial_trees { + store.extend(tree.inner_nodes()); + } + + (store, advice_map) + } + + fn batch_proof_to_merkle( + lmcs: &L, + batch_proof: &L::BatchProof, + ) -> (Vec, Vec<(Word, Vec)>) + where + L: Lmcs, + L::Commitment: Copy + Into<[Felt; 4]> + PartialEq, + L::BatchProof: BatchProofView, + { + let mut paths = Vec::new(); + let mut advice_entries = Vec::new(); + + for index in batch_proof.indices() { + let rows = batch_proof.opening(index).expect("missing opening for query index"); + let siblings = batch_proof.path(index).expect("missing Merkle path for query index"); + let leaf_data = rows.as_slice().to_vec(); + let leaf_hash = lmcs.hash(rows.iter_rows()); + let leaf_word = Word::new(leaf_hash.into()); + let merkle_path = MerklePath::new( + siblings.into_iter().map(|commitment| Word::new(commitment.into())).collect(), + ); + + paths.push((index as u64, leaf_word, merkle_path)); + advice_entries.push((leaf_word, leaf_data)); + } + + let tree = + PartialMerkleTree::with_paths(paths).expect("failed to build partial Merkle tree"); + (vec![tree], advice_entries) + } + + fn build_kernel_digest_advice(kernel_digests: &[Word]) -> Vec { + let mut result = Vec::with_capacity(kernel_digests.len() * 8); + for digest in kernel_digests { + let mut padded: Vec = + digest.as_elements().iter().map(Felt::as_canonical_u64).collect(); + padded.resize(8, 0); + padded.reverse(); + result.extend_from_slice(&padded); + } + result + } + + fn build_fixed_len_inputs(pub_inputs: &PublicInputs) -> Vec { + let mut felts = Vec::::new(); + felts.extend_from_slice(pub_inputs.program_info().program_hash().as_elements()); + felts.extend_from_slice(pub_inputs.stack_inputs().as_ref()); + felts.extend_from_slice(pub_inputs.stack_outputs().as_ref()); + felts.extend_from_slice(pub_inputs.pc_transcript_state().as_ref()); + + let mut fixed_len: Vec = felts.iter().map(Felt::as_canonical_u64).collect(); + fixed_len.resize(fixed_len.len().next_multiple_of(8), 0); + fixed_len + } + + fn commitment_to_u64s>(commitment: C) -> Vec { + let felts: [Felt; 4] = commitment.into(); + felts.iter().map(Felt::as_canonical_u64).collect() + } - println!("Verification successful! Security level: {}", security_level); + fn challenges_to_u64s(challenges: &[Challenge]) -> Vec { + let base: Vec = QuadFelt::flatten_to_base(challenges.to_vec()); + base.iter().map(Felt::as_canonical_u64).collect() + } } // ================================================================================================ @@ -197,23 +416,56 @@ fn test_rpx_prove_verify() { // ================================================================================================ mod fast_parallel { - use alloc::sync::Arc; + use alloc::{sync::Arc, vec::Vec}; use miden_assembly::{Assembler, DefaultSourceManager}; use miden_core::{ - Felt, + Felt, Word, + events::{EventId, EventName}, + precompile::{ + PrecompileCommitment, PrecompileError, PrecompileRequest, PrecompileTranscript, + PrecompileVerifier, PrecompileVerifierRegistry, + }, proof::{ExecutionProof, HashFunction}, }; + use miden_core_lib::CoreLibrary; use miden_processor::{ - ExecutionOptions, FastProcessor, StackInputs, advice::AdviceInputs, trace::build_trace, + DefaultHost, ExecutionOptions, FastProcessor, ProcessorState, StackInputs, StackOutputs, + advice::{AdviceInputs, AdviceMutation}, + event::{EventError, EventHandler}, + trace::build_trace, + }; + use miden_prover::{ + ProvingOptions, TraceProvingInputs, config, prove_from_trace_sync, prove_stark, }; - use miden_prover::{config, prove_stark}; - use miden_verifier::verify; - use miden_vm::DefaultHost; + use miden_verifier::{verify, verify_with_precompiles}; + use miden_vm::{Program, TraceBuildInputs}; /// Default fragment size for parallel trace generation const FRAGMENT_SIZE: usize = 1024; + fn parallel_execution_options() -> ExecutionOptions { + ExecutionOptions::default() + .with_core_trace_fragment_size(FRAGMENT_SIZE) + .unwrap() + } + + fn execute_parallel_trace_inputs( + program: &Program, + stack_inputs: StackInputs, + advice_inputs: AdviceInputs, + host: &mut DefaultHost, + ) -> TraceBuildInputs { + FastProcessor::new_with_options(stack_inputs, advice_inputs, parallel_execution_options()) + .expect("processor advice inputs should fit advice map limits") + .execute_trace_inputs_sync(program, host) + .expect("Fast processor execution failed") + } + + fn default_source_manager_host() -> DefaultHost { + DefaultHost::default().with_source_manager(Arc::new(DefaultSourceManager::default())) + } + /// Test that proves and verifies using the fast processor + parallel trace generation path. /// This verifies the complete code path works end-to-end. /// @@ -234,22 +486,14 @@ mod fast_parallel { let program = Assembler::default().assemble_program(source).unwrap(); let stack_inputs = StackInputs::try_from_ints([0, 1]).unwrap(); let advice_inputs = AdviceInputs::default(); - let mut host = - DefaultHost::default().with_source_manager(Arc::new(DefaultSourceManager::default())); + let mut host = default_source_manager_host(); + let trace_inputs = + execute_parallel_trace_inputs(&program, stack_inputs, advice_inputs, &mut host); - let options = ExecutionOptions::default() - .with_core_trace_fragment_size(FRAGMENT_SIZE) - .unwrap(); - let fast_processor = - FastProcessor::new_with_options(stack_inputs, advice_inputs.clone(), options); - let (execution_output, trace_context) = fast_processor - .execute_for_trace_sync(&program, &mut host) - .expect("Fast processor execution failed"); - - let fast_stack_outputs = execution_output.stack; + let fast_stack_outputs = *trace_inputs.stack_outputs(); // Build trace using parallel trace generation - let trace = build_trace(execution_output, trace_context, program.to_info()).unwrap(); + let trace = build_trace(trace_inputs).unwrap(); // Convert trace to row-major format for proving let trace_matrix = trace.to_row_major_matrix(); @@ -258,18 +502,11 @@ mod fast_parallel { let (public_values, kernel_felts) = trace.public_inputs().to_air_inputs(); let var_len_public_inputs: &[&[Felt]] = &[&kernel_felts]; - let aux_builder = trace.aux_trace_builders(); - // Generate proof using Blake3_256 let blake3_config = config::blake3_256_config(config::pcs_params()); - let proof_bytes = prove_stark( - &blake3_config, - &trace_matrix, - &public_values, - var_len_public_inputs, - &aux_builder, - ) - .expect("Proving failed"); + let proof_bytes = + prove_stark(&blake3_config, &trace_matrix, &public_values, var_len_public_inputs) + .expect("Proving failed"); let precompile_requests = trace.precompile_requests().to_vec(); @@ -279,4 +516,288 @@ mod fast_parallel { verify(program.into(), stack_inputs, fast_stack_outputs, proof) .expect("Verification failed"); } + + #[test] + fn test_prove_from_trace_sync() { + let source = " + begin + repeat.128 + swap dup.1 add + end + end + "; + + let program = Assembler::default().assemble_program(source).unwrap(); + let stack_inputs = StackInputs::try_from_ints([0, 1]).unwrap(); + let advice_inputs = AdviceInputs::default(); + let mut host = default_source_manager_host(); + let trace_inputs = + execute_parallel_trace_inputs(&program, stack_inputs, advice_inputs, &mut host); + + let (stack_outputs, proof) = prove_from_trace_sync(TraceProvingInputs::new( + trace_inputs, + ProvingOptions::with_96_bit_security(HashFunction::Blake3_256), + )) + .expect("prove_from_trace_sync failed"); + + verify(program.into(), stack_inputs, stack_outputs, proof).expect("Verification failed"); + } + + #[test] + fn test_prove_from_trace_sync_preserves_precompile_requests() { + let LoggedPrecompileProofFixture { + program, + stack_inputs, + stack_outputs, + proof, + verifier_registry, + expected_transcript, + } = prove_logged_precompile_fixture(HashFunction::Blake3_256); + + let (_, pc_transcript_digest) = verify_with_precompiles( + program.into(), + stack_inputs, + stack_outputs, + proof, + &verifier_registry, + ) + .expect("proof verification with precompiles failed"); + assert_eq!(expected_transcript.finalize(), pc_transcript_digest); + } + + #[test] + fn test_poseidon2_recursive_verify_with_precompile_requests() { + let LoggedPrecompileProofFixture { + program, + stack_inputs, + stack_outputs, + proof, + verifier_registry, + expected_transcript, + } = prove_logged_precompile_fixture(HashFunction::Poseidon2); + + super::assert_recursive_verify( + program.to_info(), + stack_inputs, + stack_outputs, + expected_transcript.state(), + &proof, + ); + + verify_with_precompiles( + program.into(), + stack_inputs, + stack_outputs, + proof, + &verifier_registry, + ) + .expect("proof verification with precompiles failed"); + } + + fn prove_logged_precompile_fixture(hash_fn: HashFunction) -> LoggedPrecompileProofFixture { + const NUM_ITERATIONS: usize = 256; + let fixtures = logged_precompile_fixtures(NUM_ITERATIONS); + + let request_snippets = fixtures + .iter() + .map(LoggedPrecompileFixture::source_snippet) + .collect::>() + .join("\n"); + + let source = format!( + " + use miden::core::sys + + begin + {request_snippets} + end + " + ); + + let program = Assembler::default() + .with_dynamic_library(CoreLibrary::default()) + .expect("failed to load core library") + .assemble_program(source) + .expect("failed to assemble log_precompile fixture"); + let stack_inputs = StackInputs::default(); + let advice_inputs = AdviceInputs::default(); + let mut host = DefaultHost::default(); + let core_lib = CoreLibrary::default(); + host.load_library(&core_lib).expect("failed to load core library into host"); + for fixture in &fixtures { + host.register_handler( + fixture.event_name.clone(), + Arc::new(DummyLogPrecompileHandler::new(fixture)), + ) + .expect("failed to register dummy handler"); + } + + let trace_inputs = + execute_parallel_trace_inputs(&program, stack_inputs, advice_inputs, &mut host); + assert!( + trace_inputs.trace_generation_context().core_trace_contexts.len() > 1, + "expected precompile fixture to span multiple core-trace fragments" + ); + + let (stack_outputs, proof) = prove_from_trace_sync(TraceProvingInputs::new( + trace_inputs, + ProvingOptions::with_96_bit_security(hash_fn), + )) + .expect("prove_from_trace_sync failed"); + + let expected_requests = + fixtures.iter().map(LoggedPrecompileFixture::request).collect::>(); + + assert_eq!(proof.precompile_requests(), expected_requests.as_slice()); + + let verifier_registry = + fixtures.iter().fold(PrecompileVerifierRegistry::new(), |registry, fixture| { + registry.with_verifier( + &fixture.event_name, + Arc::new(DummyLogPrecompileVerifier::new(fixture)), + ) + }); + let transcript = verifier_registry + .requests_transcript(proof.precompile_requests()) + .expect("failed to recompute deferred commitment"); + let mut expected_transcript = PrecompileTranscript::new(); + for fixture in &fixtures { + expected_transcript.record(fixture.commitment); + } + assert_eq!(transcript.finalize(), expected_transcript.finalize()); + + LoggedPrecompileProofFixture { + program, + stack_inputs, + stack_outputs, + proof, + verifier_registry, + expected_transcript, + } + } + + struct LoggedPrecompileProofFixture { + program: Program, + stack_inputs: StackInputs, + stack_outputs: StackOutputs, + proof: ExecutionProof, + verifier_registry: PrecompileVerifierRegistry, + expected_transcript: PrecompileTranscript, + } + + fn logged_precompile_fixtures(num_iterations: usize) -> Vec { + (0..num_iterations) + .flat_map(|iteration| { + (0..3) + .map(move |slot| LoggedPrecompileFixture::for_iteration(iteration as u8, slot)) + }) + .collect() + } + + #[derive(Clone)] + struct LoggedPrecompileFixture { + event_name: EventName, + calldata: Vec, + commitment: PrecompileCommitment, + } + + impl LoggedPrecompileFixture { + fn new(event_name: EventName, calldata: [u8; 4], tag: Word, comm_calldata: Word) -> Self { + Self { + event_name, + calldata: calldata.into(), + commitment: PrecompileCommitment::new(tag, comm_calldata), + } + } + + fn for_iteration(iteration: u8, slot: u8) -> Self { + let event_name = + EventName::from_string(format!("test::sys::log_precompile_{iteration}_{slot}")); + let iteration = u64::from(iteration); + let slot = u64::from(slot); + let event_id = EventId::from_name(event_name.as_str()); + + Self::new( + event_name, + [ + iteration as u8, + slot as u8, + (iteration + slot) as u8, + ((iteration * 3) + slot + 1) as u8, + ], + Word::from([ + event_id.as_felt(), + Felt::new_unchecked(iteration + 1), + Felt::new_unchecked(slot + 1), + Felt::new_unchecked((iteration * 3) + slot + 7), + ]), + Word::from([ + Felt::new_unchecked((iteration * 5) + slot + 11), + Felt::new_unchecked((iteration * 7) + slot + 13), + Felt::new_unchecked((iteration * 11) + slot + 17), + Felt::new_unchecked((iteration * 13) + slot + 19), + ]), + ) + } + + fn event_id(&self) -> EventId { + self.commitment.event_id() + } + + fn request(&self) -> PrecompileRequest { + PrecompileRequest::new(self.event_id(), self.calldata.clone()) + } + + fn source_snippet(&self) -> String { + format!( + "emit.event(\"{event_name}\")\n\ + push.{tag} push.{comm}\n\ + exec.sys::log_precompile_request", + event_name = self.event_name, + tag = self.commitment.tag(), + comm = self.commitment.comm_calldata(), + ) + } + } + + #[derive(Clone)] + struct DummyLogPrecompileHandler { + event_id: EventId, + calldata: Vec, + } + + impl DummyLogPrecompileHandler { + fn new(fixture: &LoggedPrecompileFixture) -> Self { + Self { + event_id: fixture.event_id(), + calldata: fixture.calldata.clone(), + } + } + } + + impl EventHandler for DummyLogPrecompileHandler { + fn on_event(&self, _process: &ProcessorState) -> Result, EventError> { + Ok(vec![AdviceMutation::extend_precompile_requests([PrecompileRequest::new( + self.event_id, + self.calldata.clone(), + )])]) + } + } + + #[derive(Clone)] + struct DummyLogPrecompileVerifier { + commitment: PrecompileCommitment, + } + + impl DummyLogPrecompileVerifier { + fn new(fixture: &LoggedPrecompileFixture) -> Self { + Self { commitment: fixture.commitment } + } + } + + impl PrecompileVerifier for DummyLogPrecompileVerifier { + fn verify(&self, _calldata: &[u8]) -> Result { + Ok(self.commitment) + } + } } diff --git a/processor/Cargo.toml b/processor/Cargo.toml index 062874dfda..d3e54a753d 100644 --- a/processor/Cargo.toml +++ b/processor/Cargo.toml @@ -19,7 +19,7 @@ bench = false doctest = false [features] -concurrent = ["std"] +concurrent = ["std", "miden-air/concurrent"] default = ["std"] std = [ "miden-core/std", @@ -28,8 +28,10 @@ std = [ "thiserror/std", ] testing = ["miden-air/testing"] -# Like `testing`, but slows down the processor speed to make it easier to debug. -bus-debugger = ["testing", "miden-air/testing"] +# Pulls in the LogUp debug surface from miden-air (under `#[cfg(feature = "std")]`). +# NOTE: the real-trace bus debugger is not yet wired into the prover/processor paths, +# so today this feature only compiles in the LookupAir shape-validation walker. +bus-debugger = ["miden-air/std"] [dependencies] # Miden dependencies @@ -46,19 +48,11 @@ rayon = { version = "1.10", default-features = false } tracing.workspace = true thiserror.workspace = true -# Platform-specific tokio dependencies -# On non-wasm targets, enable rt-multi-thread for better performance -[target.'cfg(not(target_family = "wasm"))'.dependencies] -tokio = { workspace = true, features = ["rt", "rt-multi-thread"] } - -# On wasm32, only basic tokio features are supported -[target.'cfg(target_family = "wasm")'.dependencies] -tokio = { workspace = true, features = ["rt", "macros"] } - [dev-dependencies] miden-assembly = { workspace = true, features = ["testing"] } miden-utils-testing.workspace = true insta.workspace = true -pretty_assertions = { version = "1.4" } +pretty_assertions = { workspace = true, features = ["std"] } proptest.workspace = true -rstest = { version = "0.26" } +rstest = { workspace = true } +tokio = { workspace = true, features = ["macros", "rt"] } diff --git a/processor/README.md b/processor/README.md index 54ac8c979c..995eda806c 100644 --- a/processor/README.md +++ b/processor/README.md @@ -5,7 +5,8 @@ This crate contains an implementation of Miden VM processor. The purpose of the The processor provides multiple APIs depending on your use case: ### High-level API -The `execute()` function provides a convenient interface that executes a program and generates a complete execution trace: +The `execute()` function provides a convenient interface that executes a program and returns the +resulting `ExecutionOutput`: * `program: &Program` - a reference to a Miden program to be executed. * `stack_inputs: StackInputs` - a set of public inputs with which to execute the program. @@ -13,14 +14,20 @@ The `execute()` function provides a convenient interface that executes a program * `host: &mut impl Host` - an instance of a host which can be used to supply non-deterministic inputs to the VM and receive messages from the VM. * `options: ExecutionOptions` - a set of options for executing the specified program (e.g., max allowed number of cycles). -The (async) function returns a `Result` which will contain the execution trace of the program if the execution was successful, or an error if the execution failed. +The (async) function returns a `Result` which will contain the +final stack state, advice provider, memory, and precompile transcript if the execution was +successful, or an error if the execution failed. + +If you also need an `ExecutionTrace`, use `FastProcessor::execute_trace_inputs()` / +`FastProcessor::execute_trace_inputs_sync()` and then pass the returned `TraceBuildInputs` bundle +to `build_trace()`. ### Low-level API For more control over execution and trace generation, you can use `FastProcessor` directly: * `FastProcessor::execute()` - Executes a program without any trace generation overhead. Returns `ExecutionOutput` containing the final stack state and other execution results. -* `FastProcessor::execute_for_trace()` - Executes a program while collecting metadata for trace generation. Returns both `ExecutionOutput` and `TraceGenerationContext`. -* `build_trace()` - Takes the `ExecutionOutput` and `TraceGenerationContext` from `execute_for_trace()` and constructs the full execution trace. When the `concurrent` feature is enabled, trace building is parallelized. +* `FastProcessor::execute_trace_inputs()` / `FastProcessor::execute_trace_inputs_sync()` - Executes a program while collecting the execution metadata required for trace generation. Returns a `TraceBuildInputs` bundle. +* `build_trace()` - Takes the `TraceBuildInputs` bundle from `execute_trace_inputs*()` and constructs the full execution trace. When the `concurrent` feature is enabled, trace building is parallelized. ## Processor components The processor is separated into two main components: **execution** and **trace generation**. @@ -29,10 +36,10 @@ The processor is separated into two main components: **execution** and **trace g The `FastProcessor` is designed for fast program execution with minimal overhead. It can operate in two modes: * **Pure execution** via `FastProcessor::execute()`: Executes a program without generating any trace-related metadata. This mode is optimized for maximum performance when proof generation is not required. -* **Execution for trace generation** via `FastProcessor::execute_for_trace()`: Executes a program while collecting metadata required for subsequent trace generation. This metadata is encapsulated in a `TraceGenerationContext` that is passed to the `build_trace()` function. +* **Execution for trace generation** via `FastProcessor::execute_trace_inputs()` / `FastProcessor::execute_trace_inputs_sync()`: Executes a program while collecting the metadata required for subsequent trace generation. This metadata is bundled with the execution output into `TraceBuildInputs`, which is then passed to `build_trace()`. ### Trace generation with `build_trace()` -After execution with `FastProcessor::execute_for_trace()`, the `build_trace()` function uses the returned `TraceGenerationContext` to construct the full execution trace. When the `concurrent` feature is enabled, trace generation is parallelized for improved performance. +After execution with `FastProcessor::execute_trace_inputs*()`, the `build_trace()` function uses the returned `TraceBuildInputs` bundle to construct the full execution trace. When the `concurrent` feature is enabled, trace generation is parallelized for improved performance. The trace consists of several sections: * The decoder, which tracks instruction decoding and control flow. diff --git a/processor/src/continuation_stack.rs b/processor/src/continuation_stack.rs index 8b6994766d..95e2ac3145 100644 --- a/processor/src/continuation_stack.rs +++ b/processor/src/continuation_stack.rs @@ -239,8 +239,7 @@ mod tests { #[test] fn get_next_clock_cycle_increment_empty_stack() { let stack = ContinuationStack::default(); - let result: Vec<_> = stack.iter_continuations_for_next_clock().collect(); - assert!(result.is_empty()); + assert!(stack.iter_continuations_for_next_clock().next().is_none()); } #[test] diff --git a/processor/src/debug.rs b/processor/src/debug.rs deleted file mode 100644 index 8f4c399ee0..0000000000 --- a/processor/src/debug.rs +++ /dev/null @@ -1,120 +0,0 @@ -use alloc::{boxed::Box, string::String, vec::Vec}; -use core::fmt; - -use miden_air::trace::Challenges; -use miden_core::field::ExtensionField; - -use crate::Felt; - -/// A message that can be sent on a bus. -pub(crate) trait BusMessage>: fmt::Display { - /// The concrete value that this message evaluates to. - fn value(&self, challenges: &Challenges) -> E; - - /// The source of this message (e.g. "mload" or "memory chiplet"). - fn source(&self) -> &str; -} - -/// A debugger for a bus that can be used to track outstanding requests and responses. -/// -/// Note: we use `Vec` internally instead of a `BTreeMap`, since messages can have collisions (i.e. -/// 2 messages sent with the same key), which results in relatively complex insertion/deletion -/// logic. Since this is only used in debug/test code, the performance hit is acceptable. -pub(crate) struct BusDebugger> { - pub bus_name: String, - pub outstanding_requests: Vec<(E, Box>)>, - pub outstanding_responses: Vec<(E, Box>)>, -} - -impl BusDebugger -where - E: ExtensionField, -{ - pub fn new(bus_name: String) -> Self { - Self { - bus_name, - outstanding_requests: Vec::new(), - outstanding_responses: Vec::new(), - } - } -} - -impl BusDebugger -where - E: ExtensionField, -{ - /// Attempts to match the request with an existing response. If a match is found, the response - /// is removed from the list of outstanding responses. Otherwise, the request is added to the - /// list of outstanding requests. - #[cfg(any(test, feature = "bus-debugger"))] - pub fn add_request(&mut self, request_msg: Box>, challenges: &Challenges) { - let msg_value = request_msg.value(challenges); - - if let Some(pos) = - self.outstanding_responses.iter().position(|(value, _)| *value == msg_value) - { - self.outstanding_responses.swap_remove(pos); - } else { - self.outstanding_requests.push((msg_value, request_msg)); - } - } - - /// Attempts to match the response with an existing request. If a match is found, the request is - /// removed from the list of outstanding requests. Otherwise, the response is added to the list - /// of outstanding responses. - #[cfg(any(test, feature = "bus-debugger"))] - pub fn add_response( - &mut self, - response_msg: Box>, - challenges: &Challenges, - ) { - let msg_value = response_msg.value(challenges); - - if let Some(pos) = - self.outstanding_requests.iter().position(|(value, _)| *value == msg_value) - { - self.outstanding_requests.swap_remove(pos); - } else { - self.outstanding_responses.push((msg_value, response_msg)); - } - } - - /// Returns true if there are no outstanding requests or responses. - /// - /// This is meant to be called at the end of filling the bus. If there are any outstanding - /// requests or responses, it means that there is a mismatch between the requests and responses, - /// and the test should fail. The `Debug` implementation for `BusDebugger` will print out the - /// outstanding requests and responses. - pub fn is_empty(&self) -> bool { - self.outstanding_requests.is_empty() && self.outstanding_responses.is_empty() - } -} - -impl fmt::Display for BusDebugger -where - E: ExtensionField, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if self.is_empty() { - writeln!(f, "Bus '{}' is empty.", self.bus_name)?; - } else { - writeln!(f, "Bus '{}' construction failed.", self.bus_name)?; - - if !self.outstanding_requests.is_empty() { - writeln!(f, "The following requests are still outstanding:")?; - for (_value, msg) in &self.outstanding_requests { - writeln!(f, "- {}: {}", msg.source(), msg)?; - } - } - - if !self.outstanding_responses.is_empty() { - writeln!(f, "\nThe following responses are still outstanding:")?; - for (_value, msg) in &self.outstanding_responses { - writeln!(f, "- {}: {}", msg.source(), msg)?; - } - } - } - - Ok(()) - } -} diff --git a/processor/src/errors.rs b/processor/src/errors.rs index 37c5f6fa67..4c11b46cb6 100644 --- a/processor/src/errors.rs +++ b/processor/src/errors.rs @@ -8,7 +8,7 @@ use miden_debug_types::{SourceFile, SourceSpan}; use miden_utils_diagnostics::{Diagnostic, miette}; use crate::{ - ContextId, DebugError, Felt, Host, TraceError, Word, + BaseHost, ContextId, DebugError, Felt, TraceError, Word, advice::AdviceError, event::{EventError, EventId, EventName}, fast::SystemEventError, @@ -42,8 +42,8 @@ pub enum ExecutionError { #[error("exceeded the allowed number of max cycles {0}")] CycleLimitExceeded(u32), #[error("error during processing of event {}", match event_name { - Some(name) => format!("'{}' (ID: {})", name, event_id), - None => format!("with ID: {}", event_id), + Some(name) => format!("'{name}' (ID: {event_id})"), + None => format!("with ID: {event_id}"), })] #[diagnostic()] EventError { @@ -58,6 +58,8 @@ pub enum ExecutionError { }, #[error("failed to execute the program for internal reason: {0}")] Internal(&'static str), + #[error("operand stack depth {depth} exceeds the maximum of {max}")] + StackDepthLimitExceeded { depth: usize, max: usize }, /// This means trace generation would go over the configured row limit. /// /// In parallel trace building, this is used for core-row prechecks and chiplet overflow. @@ -108,6 +110,17 @@ pub enum ExecutionError { HostError(#[from] HostError), } +impl ExecutionError { + /// Wraps an advice error without source-location context. + pub fn advice_error_no_context(err: AdviceError) -> Self { + Self::AdviceError { + label: SourceSpan::UNKNOWN, + source_file: None, + err, + } + } +} + impl AsRef for ExecutionError { fn as_ref(&self) -> &(dyn Diagnostic + 'static) { self @@ -294,6 +307,21 @@ pub enum OperationError { err_code: Felt, err_msg: Option>, }, + #[error( + "u32 assertion failed with error {}: invalid values: {invalid_values:?}", + match err_msg { + Some(msg) => format!("message: {msg}"), + None => format!("code: {err_code}"), + } + )] + #[diagnostic(help( + "u32assert2 requires both stack values to be valid 32-bit unsigned integers" + ))] + U32AssertionFailed { + err_code: Felt, + err_msg: Option>, + invalid_values: Vec, + }, #[error("FRI operation failed: {0}")] FriError(String), #[error( @@ -347,7 +375,7 @@ impl OperationError { self, mast_forest: &MastForest, node_id: MastNodeId, - host: &impl Host, + host: &impl BaseHost, ) -> ExecutionError { let (label, source_file) = get_label_and_source_file(None, mast_forest, node_id, host); ExecutionError::OperationError { label, source_file, err: self } @@ -378,7 +406,7 @@ fn get_label_and_source_file( op_idx: Option, mast_forest: &MastForest, node_id: MastNodeId, - host: &impl Host, + host: &impl BaseHost, ) -> (SourceSpan, Option>) { mast_forest .get_assembly_op(node_id, op_idx) @@ -397,9 +425,10 @@ pub fn advice_error_with_context( err: AdviceError, mast_forest: &MastForest, node_id: MastNodeId, - host: &impl Host, + host: &impl BaseHost, + op_idx: Option, ) -> ExecutionError { - let (label, source_file) = get_label_and_source_file(None, mast_forest, node_id, host); + let (label, source_file) = get_label_and_source_file(op_idx, mast_forest, node_id, host); ExecutionError::AdviceError { label, source_file, err } } @@ -411,11 +440,12 @@ pub fn event_error_with_context( error: EventError, mast_forest: &MastForest, node_id: MastNodeId, - host: &impl Host, + host: &impl BaseHost, + op_idx: Option, event_id: EventId, event_name: Option, ) -> ExecutionError { - let (label, source_file) = get_label_and_source_file(None, mast_forest, node_id, host); + let (label, source_file) = get_label_and_source_file(op_idx, mast_forest, node_id, host); ExecutionError::EventError { label, source_file, @@ -430,7 +460,7 @@ pub fn procedure_not_found_with_context( root_digest: Word, mast_forest: &MastForest, node_id: MastNodeId, - host: &impl Host, + host: &impl BaseHost, ) -> ExecutionError { let (label, source_file) = get_label_and_source_file(None, mast_forest, node_id, host); ExecutionError::ProcedureNotFound { label, source_file, root_digest } @@ -453,7 +483,7 @@ pub trait MapExecErr { self, mast_forest: &MastForest, node_id: MastNodeId, - host: &impl Host, + host: &impl BaseHost, ) -> Result; } @@ -466,7 +496,7 @@ pub trait MapExecErrWithOpIdx { self, mast_forest: &MastForest, node_id: MastNodeId, - host: &impl Host, + host: &impl BaseHost, op_idx: usize, ) -> Result; } @@ -486,7 +516,7 @@ impl MapExecErr for Result { self, mast_forest: &MastForest, node_id: MastNodeId, - host: &impl Host, + host: &impl BaseHost, ) -> Result { match self { Ok(v) => Ok(v), @@ -505,7 +535,7 @@ impl MapExecErrWithOpIdx for Result { self, mast_forest: &MastForest, node_id: MastNodeId, - host: &impl Host, + host: &impl BaseHost, op_idx: usize, ) -> Result { match self { @@ -540,11 +570,11 @@ impl MapExecErr for Result { self, mast_forest: &MastForest, node_id: MastNodeId, - host: &impl Host, + host: &impl BaseHost, ) -> Result { match self { Ok(v) => Ok(v), - Err(err) => Err(advice_error_with_context(err, mast_forest, node_id, host)), + Err(err) => Err(advice_error_with_context(err, mast_forest, node_id, host, None)), } } } @@ -570,7 +600,7 @@ impl MapExecErr for Result { self, mast_forest: &MastForest, node_id: MastNodeId, - host: &impl Host, + host: &impl BaseHost, ) -> Result { match self { Ok(v) => Ok(v), @@ -589,7 +619,7 @@ impl MapExecErrWithOpIdx for Result { self, mast_forest: &MastForest, node_id: MastNodeId, - host: &impl Host, + host: &impl BaseHost, op_idx: usize, ) -> Result { match self { @@ -610,7 +640,7 @@ impl MapExecErr for Result { self, mast_forest: &MastForest, node_id: MastNodeId, - host: &impl Host, + host: &impl BaseHost, ) -> Result { match self { Ok(v) => Ok(v), @@ -639,7 +669,7 @@ impl MapExecErrWithOpIdx for Result { self, mast_forest: &MastForest, node_id: MastNodeId, - host: &impl Host, + host: &impl BaseHost, op_idx: usize, ) -> Result { match self { @@ -670,7 +700,7 @@ impl MapExecErrWithOpIdx for Result { self, mast_forest: &MastForest, node_id: MastNodeId, - host: &impl Host, + host: &impl BaseHost, op_idx: usize, ) -> Result { match self { @@ -699,7 +729,7 @@ impl MapExecErrWithOpIdx for Result { self, mast_forest: &MastForest, node_id: MastNodeId, - host: &impl Host, + host: &impl BaseHost, op_idx: usize, ) -> Result { match self { @@ -727,7 +757,7 @@ impl MapExecErrWithOpIdx for Result { self, mast_forest: &MastForest, node_id: MastNodeId, - host: &impl Host, + host: &impl BaseHost, op_idx: usize, ) -> Result { match self { diff --git a/processor/src/execution/basic_block.rs b/processor/src/execution/basic_block.rs index b432538003..e8e19c1fe8 100644 --- a/processor/src/execution/basic_block.rs +++ b/processor/src/execution/basic_block.rs @@ -2,7 +2,7 @@ use alloc::sync::Arc; use core::ops::ControlFlow; use crate::{ - BreakReason, Host, Stopper, + BaseHost, BreakReason, Stopper, continuation_stack::{Continuation, ContinuationStack}, execution::{ ExecutionState, InternalBreakReason, execute_op, finalize_clock_cycle_with_continuation, @@ -27,7 +27,7 @@ pub(super) fn execute_basic_block_node_from_start( ) -> ControlFlow where P: Processor, - H: Host, + H: BaseHost, S: Stopper, T: Tracer, { @@ -85,7 +85,7 @@ pub(super) fn execute_basic_block_node_from_op_idx( ) -> ControlFlow where P: Processor, - H: Host, + H: BaseHost, S: Stopper, T: Tracer, { @@ -127,7 +127,7 @@ pub(super) fn execute_basic_block_node_from_batch( ) -> ControlFlow where P: Processor, - H: Host, + H: BaseHost, S: Stopper, T: Tracer, { @@ -200,7 +200,7 @@ pub(super) fn finish_basic_block( ) -> ControlFlow where P: Processor, - H: Host, + H: BaseHost, S: Stopper, T: Tracer, { @@ -248,7 +248,7 @@ fn execute_op_batch( ) -> ControlFlow where P: Processor, - H: Host, + H: BaseHost, S: Stopper, T: Tracer, { diff --git a/processor/src/execution/call.rs b/processor/src/execution/call.rs index cce0f39f58..004f96fe0b 100644 --- a/processor/src/execution/call.rs +++ b/processor/src/execution/call.rs @@ -4,7 +4,7 @@ use core::ops::ControlFlow; use miden_core::{FMP_ADDR, FMP_INIT_VALUE}; use crate::{ - BreakReason, ContextId, Host, MapExecErr, Stopper, + BaseHost, BreakReason, ContextId, MapExecErr, Stopper, continuation_stack::Continuation, execution::{ ExecutionState, finalize_clock_cycle, finalize_clock_cycle_with_continuation, @@ -29,7 +29,7 @@ pub(super) fn start_call_node( ) -> ControlFlow where P: Processor, - H: Host, + H: BaseHost, S: Stopper, T: Tracer, { @@ -110,7 +110,7 @@ pub(super) fn finish_call_node( ) -> ControlFlow where P: Processor, - H: Host, + H: BaseHost, S: Stopper, T: Tracer, { diff --git a/processor/src/execution/dyn.rs b/processor/src/execution/dyn.rs index 1bf21daea3..85f2462b53 100644 --- a/processor/src/execution/dyn.rs +++ b/processor/src/execution/dyn.rs @@ -4,7 +4,7 @@ use core::ops::ControlFlow; use miden_core::{FMP_ADDR, FMP_INIT_VALUE}; use crate::{ - BreakReason, ContextId, Host, MapExecErr, Stopper, + BaseHost, BreakReason, ContextId, MapExecErr, Stopper, continuation_stack::{Continuation, ContinuationStack}, execution::{ ExecutionState, InternalBreakReason, finalize_clock_cycle, @@ -27,7 +27,7 @@ pub(super) fn start_dyn_node( ) -> ControlFlow where P: Processor, - H: Host, + H: BaseHost, S: Stopper, T: Tracer, { @@ -182,7 +182,7 @@ pub(super) fn finish_dyn_node( ) -> ControlFlow where P: Processor, - H: Host, + H: BaseHost, S: Stopper, T: Tracer, { diff --git a/processor/src/execution/external.rs b/processor/src/execution/external.rs index a41db94986..0935150e6a 100644 --- a/processor/src/execution/external.rs +++ b/processor/src/execution/external.rs @@ -2,7 +2,7 @@ use alloc::sync::Arc; use core::ops::ControlFlow; use crate::{ - BreakReason, Host, + BaseHost, BreakReason, continuation_stack::ContinuationStack, execution::InternalBreakReason, mast::{MastForest, MastNodeExt, MastNodeId}, @@ -20,7 +20,7 @@ pub(super) fn execute_external_node( processor: &mut impl Processor, external_node_id: MastNodeId, current_forest: &mut Arc, - host: &mut impl Host, + host: &mut impl BaseHost, ) -> ControlFlow { // Execute decorators that should be executed before entering the node processor @@ -46,7 +46,7 @@ pub fn finish_load_mast_forest_from_external( external_node_id: MastNodeId, current_forest: &mut Arc, continuation_stack: &mut ContinuationStack, - host: &mut impl Host, + host: &mut impl BaseHost, tracer: &mut impl Tracer, ) -> ControlFlow { let external_node = current_forest[external_node_id].unwrap_external(); diff --git a/processor/src/execution/join.rs b/processor/src/execution/join.rs index eb0783a696..46a5cd0934 100644 --- a/processor/src/execution/join.rs +++ b/processor/src/execution/join.rs @@ -2,7 +2,7 @@ use alloc::sync::Arc; use core::ops::ControlFlow; use crate::{ - BreakReason, Host, Stopper, + BaseHost, BreakReason, Stopper, continuation_stack::Continuation, execution::{ExecutionState, finalize_clock_cycle, finalize_clock_cycle_with_continuation}, mast::{JoinNode, MastForest, MastNodeId}, @@ -23,7 +23,7 @@ pub(super) fn start_join_node( ) -> ControlFlow where P: Processor, - H: Host, + H: BaseHost, S: Stopper, T: Tracer, { @@ -62,7 +62,7 @@ pub(super) fn finish_join_node( ) -> ControlFlow where P: Processor, - H: Host, + H: BaseHost, S: Stopper, T: Tracer, { diff --git a/processor/src/execution/loop.rs b/processor/src/execution/loop.rs index 77d3a49493..b4e5eba389 100644 --- a/processor/src/execution/loop.rs +++ b/processor/src/execution/loop.rs @@ -2,7 +2,7 @@ use alloc::sync::Arc; use core::ops::ControlFlow; use crate::{ - BreakReason, Host, MapExecErr, ONE, Stopper, ZERO, + BaseHost, BreakReason, MapExecErr, ONE, Stopper, ZERO, continuation_stack::Continuation, execution::{ExecutionState, finalize_clock_cycle, finalize_clock_cycle_with_continuation}, mast::{LoopNode, MastForest, MastNodeId}, @@ -24,7 +24,7 @@ pub(super) fn start_loop_node( ) -> ControlFlow where P: Processor, - H: Host, + H: BaseHost, S: Stopper, T: Tracer, { @@ -53,8 +53,12 @@ where // execute the loop body as long as the condition is true if condition == ONE { - // Push the loop to check condition again after body - // executes + // Push the loop to check condition again after body executes. + // + // WARNING: if we eventually push another continuation in between the `FinishLoop` and the + // `StartNode` continuations, then the logic in `ExecutionTracer::start_clock_cycle()` that + // computes the value for the `is_loop_body` flag will be incorrect and needs to be + // adjusted. state.continuation_stack.push_finish_loop_entered(current_node_id); state.continuation_stack.push_start_node(loop_node.body()); @@ -110,7 +114,7 @@ pub(super) fn finish_loop_node( ) -> ControlFlow where P: Processor, - H: Host, + H: BaseHost, S: Stopper, T: Tracer, { diff --git a/processor/src/execution/mod.rs b/processor/src/execution/mod.rs index 12c57d87d6..c998322110 100644 --- a/processor/src/execution/mod.rs +++ b/processor/src/execution/mod.rs @@ -2,7 +2,7 @@ use alloc::sync::Arc; use core::ops::ControlFlow; use crate::{ - BreakReason, ContextId, Host, Kernel, Stopper, Word, + BaseHost, BreakReason, ContextId, Kernel, Stopper, Word, continuation_stack::{Continuation, ContinuationStack}, mast::{MastForest, MastNode, MastNodeId}, processor::{Processor, SystemInterface}, @@ -58,9 +58,9 @@ pub(crate) struct ExecutionState<'a, P, H, S, T> { /// # Tracing /// /// Different processor implementations will need to record different pieces of information as the -/// the program is executed. For example, the [`crate::FastProcessor::execute_for_trace`] -/// execution mode needs to build a [`crate::fast::execution_tracer::TraceGenerationContext`] which -/// records information necessary to build the trace at each clock cycle, while the +/// the program is executed. For example, the [`crate::FastProcessor::execute_trace_inputs`] +/// execution mode needs to build a [`crate::TraceGenerationContext`] which records information +/// necessary to build the trace at each clock cycle, while the /// [`crate::parallel::core_trace_fragment::CoreTraceFragmentFiller`] needs to build the trace /// essentially by recording the processor state at each clock cycle. For this purpose, the /// [`Self::execute_impl`] method takes in [`Tracer`] argument that abstracts away the "information @@ -101,7 +101,7 @@ pub(crate) struct ExecutionState<'a, P, H, S, T> { /// // Handle user-initiated break (e.g., propagate break reason) /// }, /// InternalBreakReason::Emit { basic_block_node_id, op_idx, continuation } => { -/// // Handle Emit operation (e.g., call `Host::on_event`) +/// // Handle Emit operation (e.g., call `SyncHost::on_event`) /// self.op_emit(...); /// /// // As per `InternalBreakReason::Emit` documentation, we call `finish_emit_op_execution` @@ -132,7 +132,7 @@ pub(crate) fn execute_impl( continuation_stack: &mut ContinuationStack, current_forest: &mut Arc, kernel: &Kernel, - host: &mut impl Host, + host: &mut impl BaseHost, tracer: &mut T, stopper: &S, ) -> ControlFlow diff --git a/processor/src/execution/operations/crypto_ops/mod.rs b/processor/src/execution/operations/crypto_ops/mod.rs index 1beedc4ba0..f363317aa2 100644 --- a/processor/src/execution/operations/crypto_ops/mod.rs +++ b/processor/src/execution/operations/crypto_ops/mod.rs @@ -277,7 +277,7 @@ pub(super) fn op_mrupdate( pub(super) fn op_horner_eval_base( processor: &mut P, tracer: &mut T, -) -> Result { +) -> Result { // Stack positions: low coefficient closer to top (lower index) const ALPHA_ADDR_INDEX: usize = 13; const ACC_LOW_INDEX: usize = 14; @@ -387,7 +387,7 @@ pub(super) fn op_horner_eval_base( pub(super) fn op_horner_eval_ext( processor: &mut P, tracer: &mut T, -) -> Result { +) -> Result { // Stack positions: low coefficient closer to top (lower index) const ALPHA_ADDR_INDEX: usize = 13; const ACC_LOW_INDEX: usize = 14; @@ -527,7 +527,7 @@ pub(super) fn op_log_precompile( pub(super) fn op_crypto_stream( processor: &mut P, tracer: &mut T, -) -> Result { +) -> Result { // Stack layout: [rate(8), capacity(4), src_ptr, dst_ptr, ...] const SRC_PTR_IDX: usize = 12; const DST_PTR_IDX: usize = 13; diff --git a/processor/src/execution/operations/crypto_ops/tests.rs b/processor/src/execution/operations/crypto_ops/tests.rs index 6489d2101d..205d9501bf 100644 --- a/processor/src/execution/operations/crypto_ops/tests.rs +++ b/processor/src/execution/operations/crypto_ops/tests.rs @@ -6,7 +6,7 @@ use miden_core::{ crypto::merkle::{MerkleStore, MerkleTree, NodeIndex}, field::{BasedVectorSpace, QuadFelt}, mast::MastForest, - program::{MIN_STACK_DEPTH, StackInputs}, + program::StackInputs, }; use proptest::prelude::*; @@ -53,22 +53,22 @@ proptest! { // Build the initial stack state // Stack layout (top first): [s0, s1, s2, ..., s11, s12, s13, s14, s15] let stack_inputs = [ - Felt::new(s0), // position 0 (top) - Felt::new(s1), // position 1 - Felt::new(s2), // position 2 - Felt::new(s3), // position 3 - Felt::new(s4), // position 4 - Felt::new(s5), // position 5 - Felt::new(s6), // position 6 - Felt::new(s7), // position 7 - Felt::new(s8), // position 8 - Felt::new(s9), // position 9 - Felt::new(s10), // position 10 - Felt::new(s11), // position 11 - Felt::new(s12), // position 12 - Felt::new(s13), // position 13 - Felt::new(s14), // position 14 - Felt::new(s15), // position 15 (bottom) + Felt::new_unchecked(s0), // position 0 (top) + Felt::new_unchecked(s1), // position 1 + Felt::new_unchecked(s2), // position 2 + Felt::new_unchecked(s3), // position 3 + Felt::new_unchecked(s4), // position 4 + Felt::new_unchecked(s5), // position 5 + Felt::new_unchecked(s6), // position 6 + Felt::new_unchecked(s7), // position 7 + Felt::new_unchecked(s8), // position 8 + Felt::new_unchecked(s9), // position 9 + Felt::new_unchecked(s10), // position 10 + Felt::new_unchecked(s11), // position 11 + Felt::new_unchecked(s12), // position 12 + Felt::new_unchecked(s13), // position 13 + Felt::new_unchecked(s14), // position 14 + Felt::new_unchecked(s15), // position 15 (bottom) ]; let mut processor = FastProcessor::new(StackInputs::new(&stack_inputs).unwrap()); let mut tracer = NoopTracer; @@ -78,18 +78,18 @@ proptest! { // So input_state = [s0, s1, s2, ..., s11] let expected_state = { let mut expected_state = [ - Felt::new(s0), - Felt::new(s1), - Felt::new(s2), - Felt::new(s3), - Felt::new(s4), - Felt::new(s5), - Felt::new(s6), - Felt::new(s7), - Felt::new(s8), - Felt::new(s9), - Felt::new(s10), - Felt::new(s11), + Felt::new_unchecked(s0), + Felt::new_unchecked(s1), + Felt::new_unchecked(s2), + Felt::new_unchecked(s3), + Felt::new_unchecked(s4), + Felt::new_unchecked(s5), + Felt::new_unchecked(s6), + Felt::new_unchecked(s7), + Felt::new_unchecked(s8), + Felt::new_unchecked(s9), + Felt::new_unchecked(s10), + Felt::new_unchecked(s11), ]; apply_permutation(&mut expected_state); @@ -116,10 +116,10 @@ proptest! { } // Check that positions 12-15 are NOT affected - prop_assert_eq!(stack[3], Felt::new(s12), "s12 at position 12"); - prop_assert_eq!(stack[2], Felt::new(s13), "s13 at position 13"); - prop_assert_eq!(stack[1], Felt::new(s14), "s14 at position 14"); - prop_assert_eq!(stack[0], Felt::new(s15), "s15 at position 15"); + prop_assert_eq!(stack[3], Felt::new_unchecked(s12), "s12 at position 12"); + prop_assert_eq!(stack[2], Felt::new_unchecked(s13), "s13 at position 13"); + prop_assert_eq!(stack[1], Felt::new_unchecked(s14), "s14 at position 14"); + prop_assert_eq!(stack[0], Felt::new_unchecked(s15), "s15 at position 15"); } } @@ -160,20 +160,20 @@ proptest! { // Build the initial stack state // Stack layout (top first): [r0, r1, r2, r3, r4, r5, r6, r7, c0, c1, c2, c3, src_ptr, dst_ptr, 0, 0] let stack_inputs = [ - Felt::new(r0), // position 0 (top) - Felt::new(r1), // position 1 - Felt::new(r2), // position 2 - Felt::new(r3), // position 3 - Felt::new(r4), // position 4 - Felt::new(r5), // position 5 - Felt::new(r6), // position 6 - Felt::new(r7), // position 7 - Felt::new(c0), // position 8 - Felt::new(c1), // position 9 - Felt::new(c2), // position 10 - Felt::new(c3), // position 11 - Felt::new(src_addr), // position 12 (src_ptr) - Felt::new(dst_addr), // position 13 (dst_ptr) + Felt::new_unchecked(r0), // position 0 (top) + Felt::new_unchecked(r1), // position 1 + Felt::new_unchecked(r2), // position 2 + Felt::new_unchecked(r3), // position 3 + Felt::new_unchecked(r4), // position 4 + Felt::new_unchecked(r5), // position 5 + Felt::new_unchecked(r6), // position 6 + Felt::new_unchecked(r7), // position 7 + Felt::new_unchecked(c0), // position 8 + Felt::new_unchecked(c1), // position 9 + Felt::new_unchecked(c2), // position 10 + Felt::new_unchecked(c3), // position 11 + Felt::new_unchecked(src_addr), // position 12 (src_ptr) + Felt::new_unchecked(dst_addr), // position 13 (dst_ptr) ZERO, // position 14 ZERO, // position 15 (bottom) ]; @@ -181,13 +181,13 @@ proptest! { let mut tracer = NoopTracer; // Store plaintext in memory at src_addr - let plaintext_word1: Word = [Felt::new(p0), Felt::new(p1), Felt::new(p2), Felt::new(p3)].into(); - let plaintext_word2: Word = [Felt::new(p4), Felt::new(p5), Felt::new(p6), Felt::new(p7)].into(); + let plaintext_word1: Word = [Felt::new_unchecked(p0), Felt::new_unchecked(p1), Felt::new_unchecked(p2), Felt::new_unchecked(p3)].into(); + let plaintext_word2: Word = [Felt::new_unchecked(p4), Felt::new_unchecked(p5), Felt::new_unchecked(p6), Felt::new_unchecked(p7)].into(); let clk = processor.clock(); processor.memory_mut().write_word( ContextId::root(), - Felt::new(src_addr), + Felt::new_unchecked(src_addr), clk, plaintext_word1, ).unwrap(); @@ -196,7 +196,7 @@ proptest! { let clk = processor.clock(); processor.memory_mut().write_word( ContextId::root(), - Felt::new(src_addr + 4), + Felt::new_unchecked(src_addr + 4), clk, plaintext_word2, ).unwrap(); @@ -209,22 +209,22 @@ proptest! { // Compute expected ciphertext: ciphertext = plaintext + rate let expected_cipher1 = [ - Felt::new(p0) + Felt::new(r0), - Felt::new(p1) + Felt::new(r1), - Felt::new(p2) + Felt::new(r2), - Felt::new(p3) + Felt::new(r3), + Felt::new_unchecked(p0) + Felt::new_unchecked(r0), + Felt::new_unchecked(p1) + Felt::new_unchecked(r1), + Felt::new_unchecked(p2) + Felt::new_unchecked(r2), + Felt::new_unchecked(p3) + Felt::new_unchecked(r3), ]; let expected_cipher2 = [ - Felt::new(p4) + Felt::new(r4), - Felt::new(p5) + Felt::new(r5), - Felt::new(p6) + Felt::new(r6), - Felt::new(p7) + Felt::new(r7), + Felt::new_unchecked(p4) + Felt::new_unchecked(r4), + Felt::new_unchecked(p5) + Felt::new_unchecked(r5), + Felt::new_unchecked(p6) + Felt::new_unchecked(r6), + Felt::new_unchecked(p7) + Felt::new_unchecked(r7), ]; // Check that ciphertext was written to destination memory let clk = processor.clock(); - let cipher_word1 = processor.memory_mut().read_word(ContextId::root(), Felt::new(dst_addr), clk).unwrap(); - let cipher_word2 = processor.memory_mut().read_word(ContextId::root(), Felt::new(dst_addr + 4), clk).unwrap(); + let cipher_word1 = processor.memory_mut().read_word(ContextId::root(), Felt::new_unchecked(dst_addr), clk).unwrap(); + let cipher_word2 = processor.memory_mut().read_word(ContextId::root(), Felt::new_unchecked(dst_addr + 4), clk).unwrap(); prop_assert_eq!(cipher_word1[0], expected_cipher1[0], "cipher word1[0]"); prop_assert_eq!(cipher_word1[1], expected_cipher1[1], "cipher word1[1]"); @@ -249,14 +249,14 @@ proptest! { prop_assert_eq!(stack[8], expected_cipher2[3], "cipher2[3] at position 7"); // Capacity should be unchanged (c0 at position 8) - prop_assert_eq!(stack[7], Felt::new(c0), "c0 at position 8"); - prop_assert_eq!(stack[6], Felt::new(c1), "c1 at position 9"); - prop_assert_eq!(stack[5], Felt::new(c2), "c2 at position 10"); - prop_assert_eq!(stack[4], Felt::new(c3), "c3 at position 11"); + prop_assert_eq!(stack[7], Felt::new_unchecked(c0), "c0 at position 8"); + prop_assert_eq!(stack[6], Felt::new_unchecked(c1), "c1 at position 9"); + prop_assert_eq!(stack[5], Felt::new_unchecked(c2), "c2 at position 10"); + prop_assert_eq!(stack[4], Felt::new_unchecked(c3), "c3 at position 11"); // Pointers should be incremented by 8 - prop_assert_eq!(stack[3], Felt::new(src_addr + 8), "src_ptr incremented"); - prop_assert_eq!(stack[2], Felt::new(dst_addr + 8), "dst_ptr incremented"); + prop_assert_eq!(stack[3], Felt::new_unchecked(src_addr + 8), "src_ptr incremented"); + prop_assert_eq!(stack[2], Felt::new_unchecked(dst_addr + 8), "dst_ptr incremented"); } } @@ -292,33 +292,33 @@ proptest! { // Stack layout (top first): [c0, c1, c2, c3, c4, c5, c6, c7, s8, s9, s10, s11, s12, alpha_addr, acc0, acc1] // Position 0 (top) = c0, position 7 = c7, position 13 = alpha_addr, position 14 = acc0, position 15 = acc1 let stack_inputs = [ - Felt::new(c0), // position 0 (top) - Felt::new(c1), // position 1 - Felt::new(c2), // position 2 - Felt::new(c3), // position 3 - Felt::new(c4), // position 4 - Felt::new(c5), // position 5 - Felt::new(c6), // position 6 - Felt::new(c7), // position 7 - Felt::new(s8), // position 8 - Felt::new(s9), // position 9 - Felt::new(s10), // position 10 - Felt::new(s11), // position 11 - Felt::new(s12), // position 12 - Felt::new(ALPHA_ADDR), // position 13 - Felt::new(acc_0), // position 14 (acc low) - Felt::new(acc_1), // position 15 (bottom, acc high) + Felt::new_unchecked(c0), // position 0 (top) + Felt::new_unchecked(c1), // position 1 + Felt::new_unchecked(c2), // position 2 + Felt::new_unchecked(c3), // position 3 + Felt::new_unchecked(c4), // position 4 + Felt::new_unchecked(c5), // position 5 + Felt::new_unchecked(c6), // position 6 + Felt::new_unchecked(c7), // position 7 + Felt::new_unchecked(s8), // position 8 + Felt::new_unchecked(s9), // position 9 + Felt::new_unchecked(s10), // position 10 + Felt::new_unchecked(s11), // position 11 + Felt::new_unchecked(s12), // position 12 + Felt::new_unchecked(ALPHA_ADDR), // position 13 + Felt::new_unchecked(acc_0), // position 14 (acc low) + Felt::new_unchecked(acc_1), // position 15 (bottom, acc high) ]; let mut processor = FastProcessor::new(StackInputs::new(&stack_inputs).unwrap()); let mut tracer = NoopTracer; // Store alpha in memory at ALPHA_ADDR // Memory format requirement: [alpha_0, alpha_1, 0, 0] - let alpha_word: Word = [Felt::new(alpha_0), Felt::new(alpha_1), ZERO, ZERO].into(); + let alpha_word: Word = [Felt::new_unchecked(alpha_0), Felt::new_unchecked(alpha_1), ZERO, ZERO].into(); let clk = processor.clock(); processor.memory_mut().write_word( ContextId::root(), - Felt::new(ALPHA_ADDR), + Felt::new_unchecked(ALPHA_ADDR), clk, alpha_word, ).unwrap(); @@ -333,17 +333,17 @@ proptest! { processor.system_mut().increment_clock(); // Compute expected result - let alpha = QuadFelt::new([Felt::new(alpha_0), Felt::new(alpha_1)]); - let acc_old = QuadFelt::new([Felt::new(acc_0), Felt::new(acc_1)]); - - let c0_q = QuadFelt::from(Felt::new(c0)); - let c1_q = QuadFelt::from(Felt::new(c1)); - let c2_q = QuadFelt::from(Felt::new(c2)); - let c3_q = QuadFelt::from(Felt::new(c3)); - let c4_q = QuadFelt::from(Felt::new(c4)); - let c5_q = QuadFelt::from(Felt::new(c5)); - let c6_q = QuadFelt::from(Felt::new(c6)); - let c7_q = QuadFelt::from(Felt::new(c7)); + let alpha = QuadFelt::new([Felt::new_unchecked(alpha_0), Felt::new_unchecked(alpha_1)]); + let acc_old = QuadFelt::new([Felt::new_unchecked(acc_0), Felt::new_unchecked(acc_1)]); + + let c0_q = QuadFelt::from(Felt::new_unchecked(c0)); + let c1_q = QuadFelt::from(Felt::new_unchecked(c1)); + let c2_q = QuadFelt::from(Felt::new_unchecked(c2)); + let c3_q = QuadFelt::from(Felt::new_unchecked(c3)); + let c4_q = QuadFelt::from(Felt::new_unchecked(c4)); + let c5_q = QuadFelt::from(Felt::new_unchecked(c5)); + let c6_q = QuadFelt::from(Felt::new_unchecked(c6)); + let c7_q = QuadFelt::from(Felt::new_unchecked(c7)); // Horner evaluation: P(α) = c0*α⁷ + c1*α⁶ + c2*α⁵ + c3*α⁴ + c4*α³ + c5*α² + c6*α + c7 // c0 (at stack position 0) has highest degree, c7 (at stack position 7) is constant term @@ -361,24 +361,24 @@ proptest! { let stack = processor.stack_top(); // Check that the top 8 stack elements (coefficients) were NOT affected (LE: c0 at top) - prop_assert_eq!(stack[15], Felt::new(c0), "c0 at position 0 (top)"); - prop_assert_eq!(stack[14], Felt::new(c1), "c1 at position 1"); - prop_assert_eq!(stack[13], Felt::new(c2), "c2 at position 2"); - prop_assert_eq!(stack[12], Felt::new(c3), "c3 at position 3"); - prop_assert_eq!(stack[11], Felt::new(c4), "c4 at position 4"); - prop_assert_eq!(stack[10], Felt::new(c5), "c5 at position 5"); - prop_assert_eq!(stack[9], Felt::new(c6), "c6 at position 6"); - prop_assert_eq!(stack[8], Felt::new(c7), "c7 at position 7"); + prop_assert_eq!(stack[15], Felt::new_unchecked(c0), "c0 at position 0 (top)"); + prop_assert_eq!(stack[14], Felt::new_unchecked(c1), "c1 at position 1"); + prop_assert_eq!(stack[13], Felt::new_unchecked(c2), "c2 at position 2"); + prop_assert_eq!(stack[12], Felt::new_unchecked(c3), "c3 at position 3"); + prop_assert_eq!(stack[11], Felt::new_unchecked(c4), "c4 at position 4"); + prop_assert_eq!(stack[10], Felt::new_unchecked(c5), "c5 at position 5"); + prop_assert_eq!(stack[9], Felt::new_unchecked(c6), "c6 at position 6"); + prop_assert_eq!(stack[8], Felt::new_unchecked(c7), "c7 at position 7"); // Check that middle stack elements were NOT affected - prop_assert_eq!(stack[7], Felt::new(s8), "s8 at position 8"); - prop_assert_eq!(stack[6], Felt::new(s9), "s9 at position 9"); - prop_assert_eq!(stack[5], Felt::new(s10), "s10 at position 10"); - prop_assert_eq!(stack[4], Felt::new(s11), "s11 at position 11"); - prop_assert_eq!(stack[3], Felt::new(s12), "s12 at position 12"); + prop_assert_eq!(stack[7], Felt::new_unchecked(s8), "s8 at position 8"); + prop_assert_eq!(stack[6], Felt::new_unchecked(s9), "s9 at position 9"); + prop_assert_eq!(stack[5], Felt::new_unchecked(s10), "s10 at position 10"); + prop_assert_eq!(stack[4], Felt::new_unchecked(s11), "s11 at position 11"); + prop_assert_eq!(stack[3], Felt::new_unchecked(s12), "s12 at position 12"); // Check that alpha_addr was NOT affected - prop_assert_eq!(stack[2], Felt::new(ALPHA_ADDR), "alpha_addr at position 13"); + prop_assert_eq!(stack[2], Felt::new_unchecked(ALPHA_ADDR), "alpha_addr at position 13"); // Check that the accumulator was updated correctly (LE: low at lower position) let acc_new_base: &[Felt] = acc_new.as_basis_coefficients_slice(); @@ -418,33 +418,33 @@ proptest! { // Position 6 = c3_0 (low), position 7 = c3_1 (high) // Position 13 = alpha_addr, position 14 = acc0 (low), position 15 = acc1 (high) let stack_inputs = [ - Felt::new(c0_0), // position 0 (top, c0 low) - Felt::new(c0_1), // position 1 (c0 high) - Felt::new(c1_0), // position 2 (c1 low) - Felt::new(c1_1), // position 3 (c1 high) - Felt::new(c2_0), // position 4 (c2 low) - Felt::new(c2_1), // position 5 (c2 high) - Felt::new(c3_0), // position 6 (c3 low) - Felt::new(c3_1), // position 7 (c3 high) - Felt::new(s8), // position 8 - Felt::new(s9), // position 9 - Felt::new(s10), // position 10 - Felt::new(s11), // position 11 - Felt::new(s12), // position 12 - Felt::new(ALPHA_ADDR), // position 13 - Felt::new(acc_0), // position 14 (low) - Felt::new(acc_1), // position 15 (bottom, high) + Felt::new_unchecked(c0_0), // position 0 (top, c0 low) + Felt::new_unchecked(c0_1), // position 1 (c0 high) + Felt::new_unchecked(c1_0), // position 2 (c1 low) + Felt::new_unchecked(c1_1), // position 3 (c1 high) + Felt::new_unchecked(c2_0), // position 4 (c2 low) + Felt::new_unchecked(c2_1), // position 5 (c2 high) + Felt::new_unchecked(c3_0), // position 6 (c3 low) + Felt::new_unchecked(c3_1), // position 7 (c3 high) + Felt::new_unchecked(s8), // position 8 + Felt::new_unchecked(s9), // position 9 + Felt::new_unchecked(s10), // position 10 + Felt::new_unchecked(s11), // position 11 + Felt::new_unchecked(s12), // position 12 + Felt::new_unchecked(ALPHA_ADDR), // position 13 + Felt::new_unchecked(acc_0), // position 14 (low) + Felt::new_unchecked(acc_1), // position 15 (bottom, high) ]; let mut processor = FastProcessor::new(StackInputs::new(&stack_inputs).unwrap()); let mut tracer = NoopTracer; // Store alpha in memory at ALPHA_ADDR // Memory format requirement: [alpha_0, alpha_1, k0, k1] (k0, k1 are unused but read) - let alpha_word: Word = [Felt::new(alpha_0), Felt::new(alpha_1), ZERO, ZERO].into(); + let alpha_word: Word = [Felt::new_unchecked(alpha_0), Felt::new_unchecked(alpha_1), ZERO, ZERO].into(); let clk = processor.clock(); processor.memory_mut().write_word( ContextId::root(), - Felt::new(ALPHA_ADDR), + Felt::new_unchecked(ALPHA_ADDR), clk, alpha_word, ).unwrap(); @@ -456,13 +456,13 @@ proptest! { processor.system_mut().increment_clock(); // Compute expected result - let alpha = QuadFelt::new([Felt::new(alpha_0), Felt::new(alpha_1)]); - let acc_old = QuadFelt::new([Felt::new(acc_0), Felt::new(acc_1)]); + let alpha = QuadFelt::new([Felt::new_unchecked(alpha_0), Felt::new_unchecked(alpha_1)]); + let acc_old = QuadFelt::new([Felt::new_unchecked(acc_0), Felt::new_unchecked(acc_1)]); - let c0 = QuadFelt::new([Felt::new(c0_0), Felt::new(c0_1)]); - let c1 = QuadFelt::new([Felt::new(c1_0), Felt::new(c1_1)]); - let c2 = QuadFelt::new([Felt::new(c2_0), Felt::new(c2_1)]); - let c3 = QuadFelt::new([Felt::new(c3_0), Felt::new(c3_1)]); + let c0 = QuadFelt::new([Felt::new_unchecked(c0_0), Felt::new_unchecked(c0_1)]); + let c1 = QuadFelt::new([Felt::new_unchecked(c1_0), Felt::new_unchecked(c1_1)]); + let c2 = QuadFelt::new([Felt::new_unchecked(c2_0), Felt::new_unchecked(c2_1)]); + let c3 = QuadFelt::new([Felt::new_unchecked(c3_0), Felt::new_unchecked(c3_1)]); let coefficients = [c0, c1, c2, c3]; @@ -476,24 +476,24 @@ proptest! { let stack = processor.stack_top(); // Check that the top 8 stack elements (coefficients) were NOT affected (LE: low at lower position) - prop_assert_eq!(stack[15], Felt::new(c0_0), "c0_0 at position 0 (top, low)"); - prop_assert_eq!(stack[14], Felt::new(c0_1), "c0_1 at position 1 (high)"); - prop_assert_eq!(stack[13], Felt::new(c1_0), "c1_0 at position 2 (low)"); - prop_assert_eq!(stack[12], Felt::new(c1_1), "c1_1 at position 3 (high)"); - prop_assert_eq!(stack[11], Felt::new(c2_0), "c2_0 at position 4 (low)"); - prop_assert_eq!(stack[10], Felt::new(c2_1), "c2_1 at position 5 (high)"); - prop_assert_eq!(stack[9], Felt::new(c3_0), "c3_0 at position 6 (low)"); - prop_assert_eq!(stack[8], Felt::new(c3_1), "c3_1 at position 7 (high)"); + prop_assert_eq!(stack[15], Felt::new_unchecked(c0_0), "c0_0 at position 0 (top, low)"); + prop_assert_eq!(stack[14], Felt::new_unchecked(c0_1), "c0_1 at position 1 (high)"); + prop_assert_eq!(stack[13], Felt::new_unchecked(c1_0), "c1_0 at position 2 (low)"); + prop_assert_eq!(stack[12], Felt::new_unchecked(c1_1), "c1_1 at position 3 (high)"); + prop_assert_eq!(stack[11], Felt::new_unchecked(c2_0), "c2_0 at position 4 (low)"); + prop_assert_eq!(stack[10], Felt::new_unchecked(c2_1), "c2_1 at position 5 (high)"); + prop_assert_eq!(stack[9], Felt::new_unchecked(c3_0), "c3_0 at position 6 (low)"); + prop_assert_eq!(stack[8], Felt::new_unchecked(c3_1), "c3_1 at position 7 (high)"); // Check that middle stack elements were NOT affected - prop_assert_eq!(stack[7], Felt::new(s8), "s8 at position 8"); - prop_assert_eq!(stack[6], Felt::new(s9), "s9 at position 9"); - prop_assert_eq!(stack[5], Felt::new(s10), "s10 at position 10"); - prop_assert_eq!(stack[4], Felt::new(s11), "s11 at position 11"); - prop_assert_eq!(stack[3], Felt::new(s12), "s12 at position 12"); + prop_assert_eq!(stack[7], Felt::new_unchecked(s8), "s8 at position 8"); + prop_assert_eq!(stack[6], Felt::new_unchecked(s9), "s9 at position 9"); + prop_assert_eq!(stack[5], Felt::new_unchecked(s10), "s10 at position 10"); + prop_assert_eq!(stack[4], Felt::new_unchecked(s11), "s11 at position 11"); + prop_assert_eq!(stack[3], Felt::new_unchecked(s12), "s12 at position 12"); // Check that alpha_addr was NOT affected - prop_assert_eq!(stack[2], Felt::new(ALPHA_ADDR), "alpha_addr at position 13"); + prop_assert_eq!(stack[2], Felt::new_unchecked(ALPHA_ADDR), "alpha_addr at position 13"); // Check that the accumulator was updated correctly (LE: low at lower position) let acc_new_base: &[Felt] = acc_new.as_basis_coefficients_slice(); @@ -548,8 +548,8 @@ proptest! { node[1], // position 1 node[2], // position 2 node[3], // position 3 (node[3]) - Felt::new(depth), // position 4 - Felt::new(leaf_idx), // position 5 + Felt::new_unchecked(depth), // position 4 + Felt::new_unchecked(leaf_idx), // position 5 root[0], // position 6 (root[0]) root[1], // position 7 root[2], // position 8 @@ -562,7 +562,7 @@ proptest! { ZERO, // position 15 (bottom) ]; let mut processor = FastProcessor::new(StackInputs::new(&stack_inputs).unwrap()) - .with_advice(advice_inputs); + .with_advice(advice_inputs).expect("advice inputs should fit advice map limits"); let mut tracer = NoopTracer; let program = MastForest::default(); @@ -581,8 +581,8 @@ proptest! { prop_assert_eq!(stack[12], node[3], "node[3] at position 3"); // Check depth and index - prop_assert_eq!(stack[11], Felt::new(depth), "depth at position 4"); - prop_assert_eq!(stack[10], Felt::new(leaf_idx), "index at position 5"); + prop_assert_eq!(stack[11], Felt::new_unchecked(depth), "depth at position 4"); + prop_assert_eq!(stack[10], Felt::new_unchecked(leaf_idx), "index at position 5"); // Check root value - LE: root[0] at position 6 (stack[9]) prop_assert_eq!(stack[9], root[0], "root[0] at position 6"); @@ -644,8 +644,8 @@ proptest! { old_node[1], // position 1 old_node[2], // position 2 old_node[3], // position 3 (old_node[3]) - Felt::new(depth), // position 4 - Felt::new(leaf_idx), // position 5 + Felt::new_unchecked(depth), // position 4 + Felt::new_unchecked(leaf_idx), // position 5 old_root[0], // position 6 (old_root[0]) old_root[1], // position 7 old_root[2], // position 8 @@ -658,7 +658,7 @@ proptest! { ZERO, // position 15 (bottom) ]; let mut processor = FastProcessor::new(StackInputs::new(&stack_inputs).unwrap()) - .with_advice(advice_inputs); + .with_advice(advice_inputs).expect("advice inputs should fit advice map limits"); let mut tracer = NoopTracer; // Execute the operation @@ -676,8 +676,8 @@ proptest! { prop_assert_eq!(stack[12], expected_new_root[3], "new_root[3] at position 3"); // Check depth and index remain unchanged - prop_assert_eq!(stack[11], Felt::new(depth), "depth at position 4"); - prop_assert_eq!(stack[10], Felt::new(leaf_idx), "index at position 5"); + prop_assert_eq!(stack[11], Felt::new_unchecked(depth), "depth at position 4"); + prop_assert_eq!(stack[10], Felt::new_unchecked(leaf_idx), "index at position 5"); // Check old root remains unchanged (LE: [0] at position 6) prop_assert_eq!(stack[9], old_root[0], "old_root[0] at position 6"); @@ -745,25 +745,26 @@ fn test_op_mrupdate_merge_subtree() { // Stack layout (top first): // [old_node[0..3], depth, index, old_root[0..3], new_node[0..3], ...] let stack_inputs = [ - replaced_node[0], // position 0 (top, replaced_node[0]) - replaced_node[1], // position 1 - replaced_node[2], // position 2 - replaced_node[3], // position 3 (replaced_node[3]) - Felt::new(target_depth), // position 4 - Felt::new(target_index), // position 5 - replaced_root[0], // position 6 (replaced_root[0]) - replaced_root[1], // position 7 - replaced_root[2], // position 8 - replaced_root[3], // position 9 (replaced_root[3]) - target_node[0], // position 10 (target_node[0]) - target_node[1], // position 11 - target_node[2], // position 12 - target_node[3], // position 13 (target_node[3]) - ZERO, // position 14 - ZERO, // position 15 (bottom) + replaced_node[0], // position 0 (top, replaced_node[0]) + replaced_node[1], // position 1 + replaced_node[2], // position 2 + replaced_node[3], // position 3 (replaced_node[3]) + Felt::new_unchecked(target_depth), // position 4 + Felt::new_unchecked(target_index), // position 5 + replaced_root[0], // position 6 (replaced_root[0]) + replaced_root[1], // position 7 + replaced_root[2], // position 8 + replaced_root[3], // position 9 (replaced_root[3]) + target_node[0], // position 10 (target_node[0]) + target_node[1], // position 11 + target_node[2], // position 12 + target_node[3], // position 13 (target_node[3]) + ZERO, // position 14 + ZERO, // position 15 (bottom) ]; - let mut processor = - FastProcessor::new(StackInputs::new(&stack_inputs).unwrap()).with_advice(advice_inputs); + let mut processor = FastProcessor::new(StackInputs::new(&stack_inputs).unwrap()) + .with_advice(advice_inputs) + .expect("advice inputs should fit advice map limits"); let mut tracer = NoopTracer; // Execute the operation @@ -781,8 +782,8 @@ fn test_op_mrupdate_merge_subtree() { assert_eq!(stack[12], expected_root[3], "expected_root[3] at position 3"); // Check depth and index remain unchanged - assert_eq!(stack[11], Felt::new(target_depth), "depth at position 4"); - assert_eq!(stack[10], Felt::new(target_index), "index at position 5"); + assert_eq!(stack[11], Felt::new_unchecked(target_depth), "depth at position 4"); + assert_eq!(stack[10], Felt::new_unchecked(target_index), "index at position 5"); // Check old root remains unchanged (LE: [0] at position 6) assert_eq!(stack[9], replaced_root[0], "replaced_root[0] at position 6"); @@ -805,20 +806,5 @@ fn test_op_mrupdate_merge_subtree() { /// Creates a Word from a u64 value (used for Merkle tree leaves). fn init_node(value: u64) -> Word { - [Felt::new(value), ZERO, ZERO, ZERO].into() -} - -/// Builds an expected stack state from the given values. -/// -/// The values are provided in "stack order" (top of stack first), and the result is a Vec -/// that can be compared with `processor.stack_top()`, where the top of the stack is at the -/// **last** index. -#[allow(dead_code)] -fn build_expected(values: &[u64]) -> Vec { - let mut expected = vec![ZERO; MIN_STACK_DEPTH]; - for (i, &value) in values.iter().enumerate() { - // In the result, top of stack is at index 15, second at 14, etc. - expected[15 - i] = Felt::new(value); - } - expected + [Felt::new_unchecked(value), ZERO, ZERO, ZERO].into() } diff --git a/processor/src/execution/operations/field_ops/mod.rs b/processor/src/execution/operations/field_ops/mod.rs index e73fc2d779..70d5c61e98 100644 --- a/processor/src/execution/operations/field_ops/mod.rs +++ b/processor/src/execution/operations/field_ops/mod.rs @@ -195,7 +195,7 @@ pub(super) fn op_expacc(processor: &mut P) -> OperationHelperRegis let old_exp_int = processor.stack().get(3).as_canonical_u64(); // Compute new exponent. - let new_exp = Felt::new(old_exp_int >> 1); + let new_exp = Felt::new_unchecked(old_exp_int >> 1); // Compute new accumulator. We update the accumulator only when the least significant bit of // the exponent is 1. @@ -206,7 +206,7 @@ pub(super) fn op_expacc(processor: &mut P) -> OperationHelperRegis // Compute the new base. let new_base = old_base * old_base; - processor.stack_mut().set(0, Felt::new(exp_lsb)); + processor.stack_mut().set(0, Felt::new_unchecked(exp_lsb)); processor.stack_mut().set(1, new_base); processor.stack_mut().set(2, new_acc); processor.stack_mut().set(3, new_exp); @@ -222,7 +222,7 @@ pub(super) fn op_expacc(processor: &mut P) -> OperationHelperRegis /// to the third and fourth positions, and leaves the rest of the stack unchanged. #[inline(always)] pub(super) fn op_ext2mul(processor: &mut P) -> OperationHelperRegisters { - const SEVEN: Felt = Felt::new(7); + const SEVEN: Felt = Felt::new_unchecked(7); // get_word returns [s0, s1, s2, s3] where s0 is top of stack // Stack layout: s0=b0, s1=b1, s2=a0, s3=a1 let [b0, b1, a0, a1]: [Felt; 4] = processor.stack().get_word(0).into(); diff --git a/processor/src/execution/operations/field_ops/tests.rs b/processor/src/execution/operations/field_ops/tests.rs index 2dee74c096..5835631b22 100644 --- a/processor/src/execution/operations/field_ops/tests.rs +++ b/processor/src/execution/operations/field_ops/tests.rs @@ -105,7 +105,7 @@ fn test_op_incr() { #[test] fn test_op_and() { - let two = Felt::new(2); + let two = Felt::new_unchecked(2); // --- test 0 AND 0 --------------------------------------------------- let mut processor = FastProcessor::new(StackInputs::new(&[ZERO, ZERO, two]).unwrap()); @@ -146,7 +146,7 @@ fn test_op_and() { #[test] fn test_op_or() { - let two = Felt::new(2); + let two = Felt::new_unchecked(2); // --- test 0 OR 0 --------------------------------------------------- let mut processor = FastProcessor::new(StackInputs::new(&[ZERO, ZERO, two]).unwrap()); @@ -187,7 +187,7 @@ fn test_op_or() { #[test] fn test_op_not() { - let two = Felt::new(2); + let two = Felt::new_unchecked(2); // --- test NOT 0 ----------------------------------------------------- let mut processor = FastProcessor::new(StackInputs::new(&[ZERO, two]).unwrap()); @@ -211,9 +211,9 @@ fn test_op_not() { #[test] fn test_op_eq() { - let three = Felt::new(3); - let five = Felt::new(5); - let seven = Felt::new(7); + let three = Felt::new_unchecked(3); + let five = Felt::new_unchecked(5); + let seven = Felt::new_unchecked(7); // --- test when top two values are equal ----------------------------- let mut processor = FastProcessor::new(StackInputs::new(&[seven, seven, three]).unwrap()); @@ -234,8 +234,8 @@ fn test_op_eq() { #[test] fn test_op_eqz() { - let three = Felt::new(3); - let four = Felt::new(4); + let three = Felt::new_unchecked(3); + let four = Felt::new_unchecked(4); // --- test when top is zero ------------------------------------------ let mut processor = FastProcessor::new(StackInputs::new(&[ZERO, three]).unwrap()); @@ -256,13 +256,13 @@ fn test_op_eqz() { #[test] fn test_op_expacc() { // --- when base = 0 and exp is even, acc doesn't change -------------------------------- - let old_exp = Felt::new(8); - let old_acc = Felt::new(1); - let old_base = Felt::new(0); + let old_exp = Felt::new_unchecked(8); + let old_acc = Felt::new_unchecked(1); + let old_base = Felt::new_unchecked(0); - let new_exp = Felt::new(4); - let new_acc = Felt::new(1); - let new_base = Felt::new(0); + let new_exp = Felt::new_unchecked(4); + let new_acc = Felt::new_unchecked(1); + let new_base = Felt::new_unchecked(0); // Stack layout: [bit, base, acc, exp] with bit at position 0 (top) let mut processor = @@ -272,13 +272,13 @@ fn test_op_expacc() { assert_eq!(expected, processor.stack_top()); // --- when base = 0 and exp is odd, acc becomes 0 -------------------------------------- - let old_exp = Felt::new(9); - let old_acc = Felt::new(1); - let old_base = Felt::new(0); + let old_exp = Felt::new_unchecked(9); + let old_acc = Felt::new_unchecked(1); + let old_base = Felt::new_unchecked(0); - let new_exp = Felt::new(4); - let new_acc = Felt::new(0); - let new_base = Felt::new(0); + let new_exp = Felt::new_unchecked(4); + let new_acc = Felt::new_unchecked(0); + let new_base = Felt::new_unchecked(0); let mut processor = FastProcessor::new(StackInputs::new(&[ZERO, old_base, old_acc, old_exp]).unwrap()); @@ -287,13 +287,13 @@ fn test_op_expacc() { assert_eq!(expected, processor.stack_top()); // --- when exp = 0, acc doesn't change, and base doubles ------------------------------- - let old_exp = Felt::new(0); - let old_acc = Felt::new(32); - let old_base = Felt::new(4); + let old_exp = Felt::new_unchecked(0); + let old_acc = Felt::new_unchecked(32); + let old_base = Felt::new_unchecked(4); - let new_exp = Felt::new(0); - let new_acc = Felt::new(32); - let new_base = Felt::new(16); + let new_exp = Felt::new_unchecked(0); + let new_acc = Felt::new_unchecked(32); + let new_base = Felt::new_unchecked(16); let mut processor = FastProcessor::new(StackInputs::new(&[ZERO, old_base, old_acc, old_exp]).unwrap()); @@ -303,13 +303,13 @@ fn test_op_expacc() { // --- when lsb(exp) == 1, acc is updated // ---------------------------------------------------------- - let old_exp = Felt::new(3); - let old_acc = Felt::new(1); - let old_base = Felt::new(16); + let old_exp = Felt::new_unchecked(3); + let old_acc = Felt::new_unchecked(1); + let old_base = Felt::new_unchecked(16); - let new_exp = Felt::new(1); - let new_acc = Felt::new(16); - let new_base = Felt::new(16 * 16); + let new_exp = Felt::new_unchecked(1); + let new_acc = Felt::new_unchecked(16); + let new_base = Felt::new_unchecked(16 * 16); let mut processor = FastProcessor::new(StackInputs::new(&[ZERO, old_base, old_acc, old_exp]).unwrap()); @@ -323,16 +323,16 @@ fn test_op_expacc() { let old_acc_val = 5u64; let old_base_val = u32::MAX as u64 + 1; - let new_exp = Felt::new(8); - let new_acc = Felt::new(old_acc_val * old_base_val); - let new_base = Felt::new(old_base_val) * Felt::new(old_base_val); + let new_exp = Felt::new_unchecked(8); + let new_acc = Felt::new_unchecked(old_acc_val * old_base_val); + let new_base = Felt::new_unchecked(old_base_val) * Felt::new_unchecked(old_base_val); let mut processor = FastProcessor::new( StackInputs::new(&[ ZERO, - Felt::new(old_base_val), - Felt::new(old_acc_val), - Felt::new(old_exp_val), + Felt::new_unchecked(old_base_val), + Felt::new_unchecked(old_acc_val), + Felt::new_unchecked(old_exp_val), ]) .unwrap(), ); @@ -374,7 +374,7 @@ fn get_rand_values() -> (Felt, Felt, Felt) { let a: u64 = rand_value(); let b: u64 = rand_value(); let c: u64 = rand_value(); - (Felt::new(a), Felt::new(b), Felt::new(c)) + (Felt::new_unchecked(a), Felt::new_unchecked(b), Felt::new_unchecked(c)) } /// Builds an expected stack state from the given values. diff --git a/processor/src/execution/operations/fri_ops/mod.rs b/processor/src/execution/operations/fri_ops/mod.rs index acfdac46ca..26e8baab5d 100644 --- a/processor/src/execution/operations/fri_ops/mod.rs +++ b/processor/src/execution/operations/fri_ops/mod.rs @@ -23,14 +23,19 @@ mod tests; /// - Checks that the previous folding was done correctly. /// - Shifts the stack to the left to move an item from the overflow table to stack position 15. /// +/// Bit-reversal handling: +/// - Query values exist on the stack in bit-reversed order. +/// - p on the stack is a bit-reversed tree index. The instruction internally computes d_seg = p & 3 +/// (bit-reversed coset index) for the consistency check and tau factor. f_pos is provided +/// separately on the stack and the AIR constrains f_pos = p >> 2 via p = 4*f_pos + d_seg. +/// /// Stack transition for this operation looks as follows: /// /// Input: -/// [v0, v1, v2, v3, v4, v5, v6, v7, f_pos, d_seg, poe, pe1, pe0, a1, a0, cptr, ...] +/// [v0, v1, v2, v3, v4, v5, v6, v7, f_pos, p, poe, pe0, pe1, a0, a1, cptr, ...] /// /// Output: -/// [t1, t0, s1, s0, df3, df2, df1, df0, poe^2, f_tau, cptr+2, poe^4, f_pos, ne1, ne0, eptr, -/// ...] +/// [t0, t1, s0, s1, df3, df2, df1, df0, poe^2, f_tau, cptr+8, poe^4, f_pos, ne0, ne1, eptr, ...] /// /// In the above, eptr is moved from the stack overflow table and is expected to be the address /// of the final FRI layer. @@ -49,9 +54,12 @@ where { // --- read all relevant variables from the stack --------------------- let query_values = get_query_values(processor); - let folded_pos = processor.stack().get(8); - // the segment identifier of the position in the source domain - let domain_segment = processor.stack().get(9).as_canonical_u64(); + // Reorder from bit-reversed to natural for fold4. + let query_values_reordered = reorder_bitrev4(query_values); + // p is the bit-reversed tree index; compute f_pos and d_seg from it + let p = processor.stack().get(9).as_canonical_u64(); + let domain_segment = p & 3; + let folded_pos = Felt::new_unchecked(p >> 2); // the power of the domain generator which can be used to determine current domain value x let poe = processor.stack().get(10); if poe.is_zero() { @@ -59,14 +67,14 @@ where } // the result of the previous layer folding let prev_value = { - let pe1 = processor.stack().get(11); - let pe0 = processor.stack().get(12); + let pe0 = processor.stack().get(11); + let pe1 = processor.stack().get(12); QuadFelt::from_basis_coefficients_fn(|i: usize| [pe0, pe1][i]) }; // the verifier challenge for the current layer let alpha = { - let a1 = processor.stack().get(13); - let a0 = processor.stack().get(14); + let a0 = processor.stack().get(13); + let a1 = processor.stack().get(14); QuadFelt::from_basis_coefficients_fn(|i: usize| [a0, a1][i]) }; // the memory address of the current layer @@ -79,26 +87,37 @@ where ))); } + // Consistency check: query_values[d_seg] == prev_value. + // Both query_values and d_seg are bit-reversed, so indexing works out correctly. let d_seg = domain_segment as usize; if query_values[d_seg] != prev_value { return Err(OperationError::FriError(format!( - "degree-respecting projection is inconsistent: expected {} but was {}", - prev_value, query_values[d_seg] + "degree-respecting projection is inconsistent at d_seg={d_seg} poe={} fpos={}: expected {} but was {}; all values: [0]={} [1]={} [2]={} [3]={}", + poe.as_canonical_u64(), + folded_pos.as_canonical_u64(), + prev_value, + query_values[d_seg], + query_values[0], + query_values[1], + query_values[2], + query_values[3] ))); } // --- fold query values ---------------------------------------------- - let f_tau = get_tau_factor(d_seg); + // Bit-reverse d_seg to get natural coset index for tau factor and domain segment flags. + let d_seg_rev = bit_reverse_segment(d_seg); + let f_tau = get_tau_factor(d_seg_rev); let x = poe * f_tau; let x_inv = x.inverse(); let (ev, es) = compute_evaluation_points(alpha, x_inv); - let (folded_value, tmp0, tmp1) = fold4(query_values, ev, es); + let (folded_value, tmp0, tmp1) = fold4(query_values_reordered, ev, es); // --- write the relevant values into the next state of the stack ----- let tmp0 = tmp0.as_basis_coefficients_slice(); let tmp1 = tmp1.as_basis_coefficients_slice(); - let ds = get_domain_segment_flags(d_seg); + let ds = get_domain_segment_flags(d_seg_rev); let folded_value = folded_value.as_basis_coefficients_slice(); let poe2 = poe * poe; @@ -106,18 +125,18 @@ where processor.stack_mut().decrement_size()?; - processor.stack_mut().set(0, tmp0[1]); - processor.stack_mut().set(1, tmp0[0]); - processor.stack_mut().set(2, tmp1[1]); - processor.stack_mut().set(3, tmp1[0]); + processor.stack_mut().set(0, tmp0[0]); + processor.stack_mut().set(1, tmp0[1]); + processor.stack_mut().set(2, tmp1[0]); + processor.stack_mut().set(3, tmp1[1]); processor.stack_mut().set_word(4, &ds.into()); processor.stack_mut().set(8, poe2); processor.stack_mut().set(9, f_tau); processor.stack_mut().set(10, layer_ptr + EIGHT); processor.stack_mut().set(11, poe4); processor.stack_mut().set(12, folded_pos); - processor.stack_mut().set(13, folded_value[1]); - processor.stack_mut().set(14, folded_value[0]); + processor.stack_mut().set(13, folded_value[0]); + processor.stack_mut().set(14, folded_value[1]); Ok(OperationHelperRegisters::FriExt2Fold4 { ev, es, x, x_inv }) } @@ -145,18 +164,36 @@ fn get_query_values(processor: &mut P) -> [QuadFelt; 4] { ] } +/// Bit-reverses a 2-bit segment index: 0->0, 1->2, 2->1, 3->3. +#[inline(always)] +fn bit_reverse_segment(domain_segment: usize) -> usize { + match domain_segment { + 0 => 0, + 1 => 2, + 2 => 1, + 3 => 3, + _ => panic!("invalid domain segment {domain_segment}"), + } +} + +/// Reorders 4 evals from bit-reversed order to natural order. +#[inline(always)] +fn reorder_bitrev4(values: [QuadFelt; 4]) -> [QuadFelt; 4] { + [values[0], values[2], values[1], values[3]] +} + // HELPER FUNCTIONS // ================================================================================================ -const EIGHT: Felt = Felt::new(8); -const TWO_INV: Felt = Felt::new(9223372034707292161); +const EIGHT: Felt = Felt::new_unchecked(8); +const TWO_INV: Felt = Felt::new_unchecked(9223372034707292161); // Pre-computed powers of 1/tau, where tau is the generator of multiplicative subgroup of size 4 // (i.e., tau is the 4th root of unity). Correctness of these constants is checked in the test at // the end of this module. -const TAU_INV: Felt = Felt::new(18446462594437873665); // tau^{-1} -const TAU2_INV: Felt = Felt::new(18446744069414584320); // tau^{-2} -const TAU3_INV: Felt = Felt::new(281474976710656); // tau^{-3} +const TAU_INV: Felt = Felt::new_unchecked(18446462594437873665); // tau^{-1} +const TAU2_INV: Felt = Felt::new_unchecked(18446744069414584320); // tau^{-2} +const TAU3_INV: Felt = Felt::new_unchecked(281474976710656); // tau^{-3} /// Determines tau factor (needed to compute x value) for the specified domain segment. fn get_tau_factor(domain_segment: usize) -> Felt { diff --git a/processor/src/execution/operations/fri_ops/tests.rs b/processor/src/execution/operations/fri_ops/tests.rs index 0e37a921e0..17273e38eb 100644 --- a/processor/src/execution/operations/fri_ops/tests.rs +++ b/processor/src/execution/operations/fri_ops/tests.rs @@ -6,9 +6,9 @@ use miden_core::{ use proptest::prelude::*; use super::{ - super::stack_ops::op_push, EIGHT, TAU_INV, TAU2_INV, TAU3_INV, TWO_INV, + super::stack_ops::op_push, EIGHT, TAU_INV, TAU2_INV, TAU3_INV, TWO_INV, bit_reverse_segment, compute_evaluation_points, fold4 as fri_fold4, get_domain_segment_flags, get_tau_factor, - op_fri_ext2fold4, + op_fri_ext2fold4, reorder_bitrev4, }; use crate::{ fast::FastProcessor, @@ -18,10 +18,6 @@ use crate::{ // FRI FOLDING TESTS // -------------------------------------------------------------------------------------------- -// NOTE: The `test_fold4` proptest that compared our fold4 implementation against Winterfell's -// FRI folding has been removed as we've migrated from Winterfell to Plonky3. -// The test_op_fri_ext2fold4 proptest below still validates the fold4 implementation. - /// Tests that the pre-computed FRI constants are correct. #[test] fn test_constants() { @@ -31,7 +27,7 @@ fn test_constants() { assert_eq!(TAU2_INV, tau.square().inverse()); assert_eq!(TAU3_INV, tau.cube().inverse()); - assert_eq!(Felt::new(2).inverse(), TWO_INV); + assert_eq!(Felt::new_unchecked(2).inverse(), TWO_INV); } // FRI OPERATION TESTS @@ -53,8 +49,8 @@ proptest! { v2_1 in any::(), v3_0 in any::(), v3_1 in any::(), - // Folded position - f_pos in any::(), + // Tree position (f_pos, must fit in u32 to avoid overflow when computing p = f_pos*4+d_seg) + f_pos in 0u64..=(u32::MAX as u64 >> 2), // Domain segment (0-3) d_seg in 0u64..4, // Power of domain generator (must be non-zero to avoid InvalidFriDomainGenerator) @@ -69,27 +65,28 @@ proptest! { ) { // Query values let query_values = [ - QuadFelt::new([Felt::new(v0_0), Felt::new(v0_1)]), - QuadFelt::new([Felt::new(v1_0), Felt::new(v1_1)]), - QuadFelt::new([Felt::new(v2_0), Felt::new(v2_1)]), - QuadFelt::new([Felt::new(v3_0), Felt::new(v3_1)]), + QuadFelt::new([Felt::new_unchecked(v0_0), Felt::new_unchecked(v0_1)]), + QuadFelt::new([Felt::new_unchecked(v1_0), Felt::new_unchecked(v1_1)]), + QuadFelt::new([Felt::new_unchecked(v2_0), Felt::new_unchecked(v2_1)]), + QuadFelt::new([Felt::new_unchecked(v3_0), Felt::new_unchecked(v3_1)]), ]; // The previous value must match query_values[d_seg] for the operation to succeed let prev_value = query_values[d_seg as usize]; let prev_value_base = prev_value.as_basis_coefficients_slice(); - let alpha = QuadFelt::new([Felt::new(alpha_0), Felt::new(alpha_1)]); - let poe = Felt::new(poe); - let f_pos = Felt::new(f_pos); - let d_seg_felt = Felt::new(d_seg); - let layer_ptr = Felt::new(layer_ptr); - let end_ptr = Felt::new(end_ptr); + let alpha = QuadFelt::new([Felt::new_unchecked(alpha_0), Felt::new_unchecked(alpha_1)]); + let poe = Felt::new_unchecked(poe); + let f_pos_felt = Felt::new_unchecked(f_pos); + // p = f_pos * 4 + d_seg + let p = Felt::new_unchecked(f_pos * 4 + d_seg); + let layer_ptr = Felt::new_unchecked(layer_ptr); + let end_ptr = Felt::new_unchecked(end_ptr); // Build the stack inputs (only 16 elements for initial stack) // The operation expects the following layout after pushing v0 (17 elements): - // [v0, v1, v2, v3, v4, v5, v6, v7, f_pos, d_seg, poe, pe1, pe0, a1, a0, cptr, end_ptr] - // ^0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 overflow + // [v0, v1, v2, v3, v4, v5, v6, v7, f_pos, p, poe, pe0, pe1, a0, a1, cptr, end_ptr] + // ^0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 overflow let stack_inputs = [ query_values[0].as_basis_coefficients_slice()[1], // position 0 -> 1 (v1) after push query_values[1].as_basis_coefficients_slice()[0], // position 1 -> 2 (v2) @@ -98,13 +95,13 @@ proptest! { query_values[2].as_basis_coefficients_slice()[1], // position 4 -> 5 (v5) query_values[3].as_basis_coefficients_slice()[0], // position 5 -> 6 (v6) query_values[3].as_basis_coefficients_slice()[1], // position 6 -> 7 (v7) - f_pos, // position 7 -> 8 - d_seg_felt, // position 8 -> 9 + f_pos_felt, // position 7 -> 8 + p, // position 8 -> 9 poe, // position 9 -> 10 - prev_value_base[1], // position 10 -> 11 (pe1) - prev_value_base[0], // position 11 -> 12 (pe0) - Felt::new(alpha_1), // position 12 -> 13 (a1) - Felt::new(alpha_0), // position 13 -> 14 (a0) + prev_value_base[0], // position 10 -> 11 (pe0) + prev_value_base[1], // position 11 -> 12 (pe1) + Felt::new_unchecked(alpha_0), // position 12 -> 13 (a0) + Felt::new_unchecked(alpha_1), // position 13 -> 14 (a1) layer_ptr, // position 14 -> 15 after push (cptr) end_ptr, // position 15 (will be pushed to overflow) ]; @@ -112,7 +109,7 @@ proptest! { let mut processor = FastProcessor::new(StackInputs::new(&stack_inputs).unwrap()); // Push v0 to the top of the stack - // This shifts everything down by one position, moving end_ptr to overflow + // This shifts everything down by one position, moving end_ptr to overflow portion of the stack let v0 = query_values[0].as_basis_coefficients_slice()[0]; op_push(&mut processor, v0).unwrap(); processor.system_mut().increment_clock(); @@ -123,16 +120,18 @@ proptest! { processor.system_mut().increment_clock(); // Compute expected values - let f_tau = get_tau_factor(d_seg as usize); + let d_seg_rev = bit_reverse_segment(d_seg as usize); + let f_tau = get_tau_factor(d_seg_rev); let x = poe * f_tau; let x_inv = x.inverse(); let (ev, es) = compute_evaluation_points(alpha, x_inv); - let (folded_value, tmp0, tmp1) = fri_fold4(query_values, ev, es); + let query_values_reordered = reorder_bitrev4(query_values); + let (folded_value, tmp0, tmp1) = fri_fold4(query_values_reordered, ev, es); let tmp0_base: &[Felt] = tmp0.as_basis_coefficients_slice(); let tmp1_base: &[Felt] = tmp1.as_basis_coefficients_slice(); - let ds = get_domain_segment_flags(d_seg as usize); + let ds = get_domain_segment_flags(d_seg_rev); let folded_value_base: &[Felt] = folded_value.as_basis_coefficients_slice(); let poe2 = poe.square(); let poe4 = poe2.square(); @@ -141,10 +140,10 @@ proptest! { let stack = processor.stack_top(); // Check temp values (tmp0, tmp1) - prop_assert_eq!(stack[15], tmp0_base[1], "tmp0[1] at position 0"); - prop_assert_eq!(stack[14], tmp0_base[0], "tmp0[0] at position 1"); - prop_assert_eq!(stack[13], tmp1_base[1], "tmp1[1] at position 2"); - prop_assert_eq!(stack[12], tmp1_base[0], "tmp1[0] at position 3"); + prop_assert_eq!(stack[15], tmp0_base[0], "tmp0[0] at position 0"); + prop_assert_eq!(stack[14], tmp0_base[1], "tmp0[1] at position 1"); + prop_assert_eq!(stack[13], tmp1_base[0], "tmp1[0] at position 2"); + prop_assert_eq!(stack[12], tmp1_base[1], "tmp1[1] at position 3"); // Check domain segment flags: ds[0] at position 4, ds[3] at position 7 prop_assert_eq!(stack[11], ds[0], "ds[0] at position 4"); @@ -157,11 +156,11 @@ proptest! { prop_assert_eq!(stack[6], f_tau, "f_tau at position 9"); prop_assert_eq!(stack[5], layer_ptr + EIGHT, "layer_ptr+8 at position 10"); prop_assert_eq!(stack[4], poe4, "poe^4 at position 11"); - prop_assert_eq!(stack[3], f_pos, "f_pos at position 12"); + prop_assert_eq!(stack[3], f_pos_felt, "f_pos at position 12"); // Check folded value - prop_assert_eq!(stack[2], folded_value_base[1], "folded_value[1] at position 13"); - prop_assert_eq!(stack[1], folded_value_base[0], "folded_value[0] at position 14"); + prop_assert_eq!(stack[2], folded_value_base[0], "folded_value[0] at position 13"); + prop_assert_eq!(stack[1], folded_value_base[1], "folded_value[1] at position 14"); // Check end ptr (should be moved from overflow table) prop_assert_eq!(stack[0], end_ptr, "end_ptr at position 15"); diff --git a/processor/src/execution/operations/io_ops/mod.rs b/processor/src/execution/operations/io_ops/mod.rs index 2b8a1f3530..2b7a08f8f7 100644 --- a/processor/src/execution/operations/io_ops/mod.rs +++ b/processor/src/execution/operations/io_ops/mod.rs @@ -278,9 +278,9 @@ pub(super) fn op_pipe( tracer: &mut T, ) -> Result { /// WORD_SIZE, but as a `Felt`. - const WORD_SIZE_FELT: Felt = Felt::new(4); + const WORD_SIZE_FELT: Felt = Felt::new_unchecked(4); /// The size of a double-word. - const DOUBLE_WORD_SIZE: Felt = Felt::new(8); + const DOUBLE_WORD_SIZE: Felt = Felt::new_unchecked(8); // The stack index where the memory address to load the words from is stored. const MEM_ADDR_STACK_IDX: usize = 12; diff --git a/processor/src/execution/operations/io_ops/tests.rs b/processor/src/execution/operations/io_ops/tests.rs index bf1bdb5ff3..ed87b42526 100644 --- a/processor/src/execution/operations/io_ops/tests.rs +++ b/processor/src/execution/operations/io_ops/tests.rs @@ -23,10 +23,12 @@ fn test_op_advpop() { // popping from the advice stack should push the value onto the operand stack let advice_stack: Vec = vec![3]; let advice_inputs = AdviceInputs::default().with_stack_values(advice_stack).unwrap(); - let mut processor = FastProcessor::new(StackInputs::default()).with_advice(advice_inputs); + let mut processor = FastProcessor::new(StackInputs::default()) + .with_advice(advice_inputs) + .expect("advice inputs should fit advice map limits"); let mut tracer = NoopTracer; - op_push(&mut processor, Felt::new(1)).unwrap(); + op_push(&mut processor, Felt::new_unchecked(1)).unwrap(); processor.system_mut().increment_clock(); op_advpop(&mut processor, &mut tracer).unwrap(); processor.system_mut().increment_clock(); @@ -46,10 +48,12 @@ fn test_op_advpopw() { // word[0]=3 goes to stack position 0 (top), so result is [3, 4, 5, 6, 1]. let advice_stack: Vec = vec![3, 4, 5, 6]; let advice_inputs = AdviceInputs::default().with_stack_values(advice_stack).unwrap(); - let mut processor = FastProcessor::new(StackInputs::default()).with_advice(advice_inputs); + let mut processor = FastProcessor::new(StackInputs::default()) + .with_advice(advice_inputs) + .expect("advice inputs should fit advice map limits"); let mut tracer = NoopTracer; - op_push(&mut processor, Felt::new(1)).unwrap(); + op_push(&mut processor, Felt::new_unchecked(1)).unwrap(); processor.system_mut().increment_clock(); for _ in 0..4 { op_pad(&mut processor).unwrap(); @@ -74,7 +78,13 @@ fn test_op_mloadw() { assert_eq!(0, processor.memory().num_accessed_words()); // store a word at address 4 - let word: Word = [Felt::new(1), Felt::new(3), Felt::new(5), Felt::new(7)].into(); + let word: Word = [ + Felt::new_unchecked(1), + Felt::new_unchecked(3), + Felt::new_unchecked(5), + Felt::new_unchecked(7), + ] + .into(); store_word(&mut processor, 4, word, &mut tracer); // push four zeros onto the stack (padding) @@ -84,7 +94,7 @@ fn test_op_mloadw() { } // push the address onto the stack and load the word - op_push(&mut processor, Felt::new(4)).unwrap(); + op_push(&mut processor, Felt::new_unchecked(4)).unwrap(); processor.system_mut().increment_clock(); op_mloadw(&mut processor, &mut tracer).unwrap(); processor.system_mut().increment_clock(); @@ -98,12 +108,14 @@ fn test_op_mloadw() { // check memory state assert_eq!(1, processor.memory().num_accessed_words()); let clk = processor.clock(); - let stored_word = - processor.memory_mut().read_word(ContextId::root(), Felt::new(4), clk).unwrap(); + let stored_word = processor + .memory_mut() + .read_word(ContextId::root(), Felt::new_unchecked(4), clk) + .unwrap(); assert_eq!(word, stored_word); // --- calling MLOADW with address greater than u32::MAX leads to an error ---------------- - op_push(&mut processor, Felt::new(u64::MAX / 2)).unwrap(); + op_push(&mut processor, Felt::new_unchecked(u64::MAX / 2)).unwrap(); processor.system_mut().increment_clock(); assert!(op_mloadw(&mut processor, &mut tracer).is_err()); @@ -120,11 +132,17 @@ fn test_op_mload() { assert_eq!(0, processor.memory().num_accessed_words()); // store a word at address 4 - let word: Word = [Felt::new(1), Felt::new(3), Felt::new(5), Felt::new(7)].into(); + let word: Word = [ + Felt::new_unchecked(1), + Felt::new_unchecked(3), + Felt::new_unchecked(5), + Felt::new_unchecked(7), + ] + .into(); store_word(&mut processor, 4, word, &mut tracer); // push the address onto the stack and load the element - op_push(&mut processor, Felt::new(4)).unwrap(); + op_push(&mut processor, Felt::new_unchecked(4)).unwrap(); processor.system_mut().increment_clock(); op_mload(&mut processor, &mut tracer).unwrap(); processor.system_mut().increment_clock(); @@ -138,12 +156,14 @@ fn test_op_mload() { // check memory state assert_eq!(1, processor.memory().num_accessed_words()); let clk = processor.clock(); - let stored_word = - processor.memory_mut().read_word(ContextId::root(), Felt::new(4), clk).unwrap(); + let stored_word = processor + .memory_mut() + .read_word(ContextId::root(), Felt::new_unchecked(4), clk) + .unwrap(); assert_eq!(word, stored_word); // --- calling MLOAD with address greater than u32::MAX leads to an error ----------------- - op_push(&mut processor, Felt::new(u64::MAX / 2)).unwrap(); + op_push(&mut processor, Felt::new_unchecked(u64::MAX / 2)).unwrap(); processor.system_mut().increment_clock(); assert!(op_mload(&mut processor, &mut tracer).is_err()); @@ -158,19 +178,35 @@ fn test_op_mstream() { let mut tracer = NoopTracer; // save two words into memory addresses 4 and 8 - let word1: Word = [Felt::new(30), Felt::new(29), Felt::new(28), Felt::new(27)].into(); - let word2: Word = [Felt::new(26), Felt::new(25), Felt::new(24), Felt::new(23)].into(); + let word1: Word = [ + Felt::new_unchecked(30), + Felt::new_unchecked(29), + Felt::new_unchecked(28), + Felt::new_unchecked(27), + ] + .into(); + let word2: Word = [ + Felt::new_unchecked(26), + Felt::new_unchecked(25), + Felt::new_unchecked(24), + Felt::new_unchecked(23), + ] + .into(); store_word(&mut processor, 4, word1, &mut tracer); store_word(&mut processor, 8, word2, &mut tracer); // check memory state assert_eq!(2, processor.memory().num_accessed_words()); let clk = processor.clock(); - let stored_word1 = - processor.memory_mut().read_word(ContextId::root(), Felt::new(4), clk).unwrap(); + let stored_word1 = processor + .memory_mut() + .read_word(ContextId::root(), Felt::new_unchecked(4), clk) + .unwrap(); assert_eq!(word1, stored_word1); - let stored_word2 = - processor.memory_mut().read_word(ContextId::root(), Felt::new(8), clk).unwrap(); + let stored_word2 = processor + .memory_mut() + .read_word(ContextId::root(), Felt::new_unchecked(8), clk) + .unwrap(); assert_eq!(word2, stored_word2); // clear the stack (drop the 8 elements we pushed while storing) @@ -183,12 +219,12 @@ fn test_op_mstream() { // - 101 is at position 13 (to make sure it is not overwritten) // - 4 (the address) is at position 12 // - values 1 - 12 are at positions 0 - 11 - op_push(&mut processor, Felt::new(101)).unwrap(); + op_push(&mut processor, Felt::new_unchecked(101)).unwrap(); processor.system_mut().increment_clock(); - op_push(&mut processor, Felt::new(4)).unwrap(); + op_push(&mut processor, Felt::new_unchecked(4)).unwrap(); processor.system_mut().increment_clock(); for i in 1..13 { - op_push(&mut processor, Felt::new(i)).unwrap(); + op_push(&mut processor, Felt::new_unchecked(i)).unwrap(); processor.system_mut().increment_clock(); } @@ -225,7 +261,13 @@ fn test_op_mstorew() { assert_eq!(0, processor.memory().num_accessed_words()); // push the first word onto the stack and save it at address 0 - let word1: Word = [Felt::new(1), Felt::new(3), Felt::new(5), Felt::new(7)].into(); + let word1: Word = [ + Felt::new_unchecked(1), + Felt::new_unchecked(3), + Felt::new_unchecked(5), + Felt::new_unchecked(7), + ] + .into(); store_word(&mut processor, 0, word1, &mut tracer); // After store, word remains on stack with word[0] at top: [1, 3, 5, 7] @@ -235,12 +277,20 @@ fn test_op_mstorew() { // check memory state assert_eq!(1, processor.memory().num_accessed_words()); let clk = processor.clock(); - let stored_word = - processor.memory_mut().read_word(ContextId::root(), Felt::new(0), clk).unwrap(); + let stored_word = processor + .memory_mut() + .read_word(ContextId::root(), Felt::new_unchecked(0), clk) + .unwrap(); assert_eq!(word1, stored_word); // push the second word onto the stack and save it at address 4 - let word2: Word = [Felt::new(2), Felt::new(4), Felt::new(6), Felt::new(8)].into(); + let word2: Word = [ + Felt::new_unchecked(2), + Felt::new_unchecked(4), + Felt::new_unchecked(6), + Felt::new_unchecked(8), + ] + .into(); store_word(&mut processor, 4, word2, &mut tracer); // word2 on top of word1: [2, 4, 6, 8, 1, 3, 5, 7] @@ -250,15 +300,19 @@ fn test_op_mstorew() { // check memory state assert_eq!(2, processor.memory().num_accessed_words()); let clk = processor.clock(); - let stored_word1 = - processor.memory_mut().read_word(ContextId::root(), Felt::new(0), clk).unwrap(); + let stored_word1 = processor + .memory_mut() + .read_word(ContextId::root(), Felt::new_unchecked(0), clk) + .unwrap(); assert_eq!(word1, stored_word1); - let stored_word2 = - processor.memory_mut().read_word(ContextId::root(), Felt::new(4), clk).unwrap(); + let stored_word2 = processor + .memory_mut() + .read_word(ContextId::root(), Felt::new_unchecked(4), clk) + .unwrap(); assert_eq!(word2, stored_word2); // --- calling MSTOREW with address greater than u32::MAX leads to an error ---------------- - op_push(&mut processor, Felt::new(u64::MAX / 2)).unwrap(); + op_push(&mut processor, Felt::new_unchecked(u64::MAX / 2)).unwrap(); processor.system_mut().increment_clock(); assert!(op_mstorew(&mut processor, &mut tracer).is_err()); @@ -276,7 +330,7 @@ fn test_op_mstore() { // push new element onto the stack and save it as first element of the word on // uninitialized memory at address 0 - let element = Felt::new(10); + let element = Felt::new_unchecked(10); store_element(&mut processor, 0, element, &mut tracer); // check stack state @@ -287,16 +341,24 @@ fn test_op_mstore() { let expected_word: Word = [element, ZERO, ZERO, ZERO].into(); assert_eq!(1, processor.memory().num_accessed_words()); let clk = processor.clock(); - let stored_word = - processor.memory_mut().read_word(ContextId::root(), Felt::new(0), clk).unwrap(); + let stored_word = processor + .memory_mut() + .read_word(ContextId::root(), Felt::new_unchecked(0), clk) + .unwrap(); assert_eq!(expected_word, stored_word); // push a word onto the stack and save it at address 4 - let word2: Word = [Felt::new(1), Felt::new(3), Felt::new(5), Felt::new(7)].into(); + let word2: Word = [ + Felt::new_unchecked(1), + Felt::new_unchecked(3), + Felt::new_unchecked(5), + Felt::new_unchecked(7), + ] + .into(); store_word(&mut processor, 4, word2, &mut tracer); // push new element onto the stack and save it as first element of the word at address 4 - let element2 = Felt::new(12); + let element2 = Felt::new_unchecked(12); store_element(&mut processor, 4, element2, &mut tracer); // After store_word, stack is [1, 3, 5, 7, 10] @@ -305,15 +367,18 @@ fn test_op_mstore() { assert_eq!(expected, processor.stack_top()); // check memory state to make sure the other 3 elements were not affected - let expected_word2: Word = [element2, Felt::new(3), Felt::new(5), Felt::new(7)].into(); + let expected_word2: Word = + [element2, Felt::new_unchecked(3), Felt::new_unchecked(5), Felt::new_unchecked(7)].into(); assert_eq!(2, processor.memory().num_accessed_words()); let clk = processor.clock(); - let stored_word2 = - processor.memory_mut().read_word(ContextId::root(), Felt::new(4), clk).unwrap(); + let stored_word2 = processor + .memory_mut() + .read_word(ContextId::root(), Felt::new_unchecked(4), clk) + .unwrap(); assert_eq!(expected_word2, stored_word2); // --- calling MSTORE with address greater than u32::MAX leads to an error ---------------- - op_push(&mut processor, Felt::new(u64::MAX / 2)).unwrap(); + op_push(&mut processor, Felt::new_unchecked(u64::MAX / 2)).unwrap(); processor.system_mut().increment_clock(); assert!(op_mstore(&mut processor, &mut tracer).is_err()); @@ -329,19 +394,21 @@ fn test_op_pipe() { // pop_stack_dword pops: 30, 29, 28, 27 -> words[0], then 26, 25, 24, 23 -> words[1] let advice_stack: Vec = vec![30, 29, 28, 27, 26, 25, 24, 23]; let advice_inputs = AdviceInputs::default().with_stack_values(advice_stack).unwrap(); - let mut processor = FastProcessor::new(StackInputs::default()).with_advice(advice_inputs); + let mut processor = FastProcessor::new(StackInputs::default()) + .with_advice(advice_inputs) + .expect("advice inputs should fit advice map limits"); let mut tracer = NoopTracer; // arrange the stack such that: // - 101 is at position 13 (to make sure it is not overwritten) // - 4 (the address) is at position 12 // - values 1 - 12 are at positions 0 - 11 - op_push(&mut processor, Felt::new(101)).unwrap(); + op_push(&mut processor, Felt::new_unchecked(101)).unwrap(); processor.system_mut().increment_clock(); - op_push(&mut processor, Felt::new(4)).unwrap(); + op_push(&mut processor, Felt::new_unchecked(4)).unwrap(); processor.system_mut().increment_clock(); for i in 1..13 { - op_push(&mut processor, Felt::new(i)).unwrap(); + op_push(&mut processor, Felt::new_unchecked(i)).unwrap(); processor.system_mut().increment_clock(); } @@ -354,10 +421,14 @@ fn test_op_pipe() { // words[0] stored at addr 4, words[1] at addr 8 assert_eq!(2, processor.memory().num_accessed_words()); let clk = processor.clock(); - let stored_word1 = - processor.memory_mut().read_word(ContextId::root(), Felt::new(4), clk).unwrap(); - let stored_word2 = - processor.memory_mut().read_word(ContextId::root(), Felt::new(8), clk).unwrap(); + let stored_word1 = processor + .memory_mut() + .read_word(ContextId::root(), Felt::new_unchecked(4), clk) + .unwrap(); + let stored_word2 = processor + .memory_mut() + .read_word(ContextId::root(), Felt::new_unchecked(8), clk) + .unwrap(); let word1 = stored_word1; let word2 = stored_word2; @@ -395,7 +466,7 @@ fn store_word(processor: &mut FastProcessor, addr: u64, word: Word, tracer: &mut processor.system_mut().increment_clock(); } // Push address - op_push(processor, Felt::new(addr)).unwrap(); + op_push(processor, Felt::new_unchecked(addr)).unwrap(); processor.system_mut().increment_clock(); // Store the word (LE: stack pos 1-4 -> word[0-3]) op_mstorew(processor, tracer).unwrap(); @@ -407,7 +478,7 @@ fn store_element(processor: &mut FastProcessor, addr: u64, value: Felt, tracer: op_push(processor, value).unwrap(); processor.system_mut().increment_clock(); // Push address - op_push(processor, Felt::new(addr)).unwrap(); + op_push(processor, Felt::new_unchecked(addr)).unwrap(); processor.system_mut().increment_clock(); // Store the element op_mstore(processor, tracer).unwrap(); @@ -423,7 +494,7 @@ fn build_expected(values: &[u64]) -> Vec { let mut expected = vec![ZERO; MIN_STACK_DEPTH]; for (i, &value) in values.iter().enumerate() { // In the result, top of stack is at index 15, second at 14, etc. - expected[15 - i] = Felt::new(value); + expected[15 - i] = Felt::new_unchecked(value); } expected } diff --git a/processor/src/execution/operations/mod.rs b/processor/src/execution/operations/mod.rs index 48682f468a..53ff6f04a8 100644 --- a/processor/src/execution/operations/mod.rs +++ b/processor/src/execution/operations/mod.rs @@ -1,5 +1,5 @@ use crate::{ - ExecutionError, Felt, Host, + BaseHost, ExecutionError, Felt, errors::MapExecErrWithOpIdx, mast::{MastForest, MastNodeId}, operation::Operation, @@ -23,9 +23,9 @@ pub(crate) use eval_circuit::eval_circuit_impl; // ================================================================================================ /// WORD_SIZE, but as a `Felt`. -const WORD_SIZE_FELT: Felt = Felt::new(4); +const WORD_SIZE_FELT: Felt = Felt::new_unchecked(4); /// The size of a double-word. -const DOUBLE_WORD_SIZE: Felt = Felt::new(8); +const DOUBLE_WORD_SIZE: Felt = Felt::new_unchecked(8); // OPERATION HANDLER // ================================================================================================ @@ -45,7 +45,7 @@ pub(crate) fn execute_op( op_idx: usize, current_forest: &MastForest, node_id: MastNodeId, - host: &mut impl Host, + host: &mut impl BaseHost, tracer: &mut T, ) -> Result where @@ -165,8 +165,10 @@ where host, op_idx, )?, - Operation::U32assert2(err_code) => u32_ops::op_u32assert2(processor, *err_code, tracer) - .map_exec_err_with_op_idx(current_forest, node_id, host, op_idx)?, + Operation::U32assert2(err_code) => { + u32_ops::op_u32assert2(processor, *err_code, tracer, current_forest) + .map_exec_err_with_op_idx(current_forest, node_id, host, op_idx)? + }, // ----- stack manipulation ----------------------------------------------------------- Operation::Pad => stack_ops::op_pad(processor)?, diff --git a/processor/src/execution/operations/stack_ops/tests.rs b/processor/src/execution/operations/stack_ops/tests.rs index aadb0184c4..1a369e2432 100644 --- a/processor/src/execution/operations/stack_ops/tests.rs +++ b/processor/src/execution/operations/stack_ops/tests.rs @@ -30,7 +30,7 @@ fn test_op_push() { assert_eq!(expected, processor.stack_top()); // push another item onto the stack - op_push(&mut processor, Felt::new(3)).unwrap(); + op_push(&mut processor, Felt::new_unchecked(3)).unwrap(); let expected = build_expected(&[3, 1]); assert_eq!(MIN_STACK_DEPTH as u32 + 2, processor.stack_depth()); @@ -67,7 +67,7 @@ fn test_op_drop() { // push a few items onto the stack op_push(&mut processor, ONE).unwrap(); - op_push(&mut processor, Felt::new(2)).unwrap(); + op_push(&mut processor, Felt::new_unchecked(2)).unwrap(); // drop the first value Processor::stack_mut(&mut processor).decrement_size().unwrap(); @@ -107,8 +107,8 @@ fn test_op_dup() { // put 15 more items onto the stack let mut expected_arr = [ONE; 16]; for i in 2..17u64 { - op_push(&mut processor, Felt::new(i)).unwrap(); - expected_arr[16 - i as usize] = Felt::new(i); + op_push(&mut processor, Felt::new_unchecked(i)).unwrap(); + expected_arr[16 - i as usize] = Felt::new_unchecked(i); } // expected_arr now is [16, 15, 14, ..., 2, 1, 1] in "old test order" (top at index 0) // We need to reverse for comparison with stack_top() @@ -125,7 +125,7 @@ fn test_op_dup() { // duplicate 8th stack item (dup7 on the new stack state) dup_nth(&mut processor, 7).unwrap(); - assert_eq!(Felt::new(10), processor.stack_get(0)); + assert_eq!(Felt::new_unchecked(10), processor.stack_get(0)); assert_eq!(ONE, processor.stack_get(1)); // remove 4 items off the stack @@ -147,8 +147,10 @@ fn test_op_dup() { #[test] fn test_op_swap() { // Create processor with initial stack [3, 2, 1] (top=3) - let mut processor = - FastProcessor::new(StackInputs::new(&[Felt::new(3), Felt::new(2), Felt::new(1)]).unwrap()); + let mut processor = FastProcessor::new( + StackInputs::new(&[Felt::new_unchecked(3), Felt::new_unchecked(2), Felt::new_unchecked(1)]) + .unwrap(), + ); op_swap(&mut processor); let expected = build_expected(&[2, 3, 1]); @@ -164,15 +166,15 @@ fn test_op_swapw() { // Create processor with initial stack [9, 8, 7, 6, 5, 4, 3, 2, 1] (top=9) let mut processor = FastProcessor::new( StackInputs::new(&[ - Felt::new(9), - Felt::new(8), - Felt::new(7), - Felt::new(6), - Felt::new(5), - Felt::new(4), - Felt::new(3), - Felt::new(2), - Felt::new(1), + Felt::new_unchecked(9), + Felt::new_unchecked(8), + Felt::new_unchecked(7), + Felt::new_unchecked(6), + Felt::new_unchecked(5), + Felt::new_unchecked(4), + Felt::new_unchecked(3), + Felt::new_unchecked(2), + Felt::new_unchecked(1), ]) .unwrap(), ); @@ -191,19 +193,19 @@ fn test_op_swapw2() { // Create processor with initial stack [13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1] (top=13) let mut processor = FastProcessor::new( StackInputs::new(&[ - Felt::new(13), - Felt::new(12), - Felt::new(11), - Felt::new(10), - Felt::new(9), - Felt::new(8), - Felt::new(7), - Felt::new(6), - Felt::new(5), - Felt::new(4), - Felt::new(3), - Felt::new(2), - Felt::new(1), + Felt::new_unchecked(13), + Felt::new_unchecked(12), + Felt::new_unchecked(11), + Felt::new_unchecked(10), + Felt::new_unchecked(9), + Felt::new_unchecked(8), + Felt::new_unchecked(7), + Felt::new_unchecked(6), + Felt::new_unchecked(5), + Felt::new_unchecked(4), + Felt::new_unchecked(3), + Felt::new_unchecked(2), + Felt::new_unchecked(1), ]) .unwrap(), ); @@ -222,22 +224,22 @@ fn test_op_swapw3() { // Create processor with initial stack [16, 15, ..., 1] (top=16) let mut processor = FastProcessor::new( StackInputs::new(&[ - Felt::new(16), - Felt::new(15), - Felt::new(14), - Felt::new(13), - Felt::new(12), - Felt::new(11), - Felt::new(10), - Felt::new(9), - Felt::new(8), - Felt::new(7), - Felt::new(6), - Felt::new(5), - Felt::new(4), - Felt::new(3), - Felt::new(2), - Felt::new(1), + Felt::new_unchecked(16), + Felt::new_unchecked(15), + Felt::new_unchecked(14), + Felt::new_unchecked(13), + Felt::new_unchecked(12), + Felt::new_unchecked(11), + Felt::new_unchecked(10), + Felt::new_unchecked(9), + Felt::new_unchecked(8), + Felt::new_unchecked(7), + Felt::new_unchecked(6), + Felt::new_unchecked(5), + Felt::new_unchecked(4), + Felt::new_unchecked(3), + Felt::new_unchecked(2), + Felt::new_unchecked(1), ]) .unwrap(), ); @@ -256,22 +258,22 @@ fn test_op_swapdw() { // Create processor with initial stack [16, 15, ..., 1] (top=16) let mut processor = FastProcessor::new( StackInputs::new(&[ - Felt::new(16), - Felt::new(15), - Felt::new(14), - Felt::new(13), - Felt::new(12), - Felt::new(11), - Felt::new(10), - Felt::new(9), - Felt::new(8), - Felt::new(7), - Felt::new(6), - Felt::new(5), - Felt::new(4), - Felt::new(3), - Felt::new(2), - Felt::new(1), + Felt::new_unchecked(16), + Felt::new_unchecked(15), + Felt::new_unchecked(14), + Felt::new_unchecked(13), + Felt::new_unchecked(12), + Felt::new_unchecked(11), + Felt::new_unchecked(10), + Felt::new_unchecked(9), + Felt::new_unchecked(8), + Felt::new_unchecked(7), + Felt::new_unchecked(6), + Felt::new_unchecked(5), + Felt::new_unchecked(4), + Felt::new_unchecked(3), + Felt::new_unchecked(2), + Felt::new_unchecked(1), ]) .unwrap(), ); @@ -295,22 +297,22 @@ fn test_op_movup() { // Create processor with initial stack [1, 2, ..., 16] (top=1) let mut processor = FastProcessor::new( StackInputs::new(&[ - Felt::new(1), - Felt::new(2), - Felt::new(3), - Felt::new(4), - Felt::new(5), - Felt::new(6), - Felt::new(7), - Felt::new(8), - Felt::new(9), - Felt::new(10), - Felt::new(11), - Felt::new(12), - Felt::new(13), - Felt::new(14), - Felt::new(15), - Felt::new(16), + Felt::new_unchecked(1), + Felt::new_unchecked(2), + Felt::new_unchecked(3), + Felt::new_unchecked(4), + Felt::new_unchecked(5), + Felt::new_unchecked(6), + Felt::new_unchecked(7), + Felt::new_unchecked(8), + Felt::new_unchecked(9), + Felt::new_unchecked(10), + Felt::new_unchecked(11), + Felt::new_unchecked(12), + Felt::new_unchecked(13), + Felt::new_unchecked(14), + Felt::new_unchecked(15), + Felt::new_unchecked(16), ]) .unwrap(), ); @@ -345,22 +347,22 @@ fn test_op_movdn() { // Create processor with initial stack [1, 2, ..., 16] (top=1) let mut processor = FastProcessor::new( StackInputs::new(&[ - Felt::new(1), - Felt::new(2), - Felt::new(3), - Felt::new(4), - Felt::new(5), - Felt::new(6), - Felt::new(7), - Felt::new(8), - Felt::new(9), - Felt::new(10), - Felt::new(11), - Felt::new(12), - Felt::new(13), - Felt::new(14), - Felt::new(15), - Felt::new(16), + Felt::new_unchecked(1), + Felt::new_unchecked(2), + Felt::new_unchecked(3), + Felt::new_unchecked(4), + Felt::new_unchecked(5), + Felt::new_unchecked(6), + Felt::new_unchecked(7), + Felt::new_unchecked(8), + Felt::new_unchecked(9), + Felt::new_unchecked(10), + Felt::new_unchecked(11), + Felt::new_unchecked(12), + Felt::new_unchecked(13), + Felt::new_unchecked(14), + Felt::new_unchecked(15), + Felt::new_unchecked(16), ]) .unwrap(), ); @@ -394,8 +396,14 @@ fn test_op_movdn() { fn test_op_cswap() { // Create processor with initial stack [0, 1, 2, 3, 4] (top=0) let mut processor = FastProcessor::new( - StackInputs::new(&[Felt::new(0), Felt::new(1), Felt::new(2), Felt::new(3), Felt::new(4)]) - .unwrap(), + StackInputs::new(&[ + Felt::new_unchecked(0), + Felt::new_unchecked(1), + Felt::new_unchecked(2), + Felt::new_unchecked(3), + Felt::new_unchecked(4), + ]) + .unwrap(), ); // no swap (top of the stack is 0) op_cswap(&mut processor).unwrap(); @@ -420,18 +428,18 @@ fn test_op_cswapw() { // Create processor with initial stack [0, 1, 2, ..., 11] (top=0) let mut processor = FastProcessor::new( StackInputs::new(&[ - Felt::new(0), - Felt::new(1), - Felt::new(2), - Felt::new(3), - Felt::new(4), - Felt::new(5), - Felt::new(6), - Felt::new(7), - Felt::new(8), - Felt::new(9), - Felt::new(10), - Felt::new(11), + Felt::new_unchecked(0), + Felt::new_unchecked(1), + Felt::new_unchecked(2), + Felt::new_unchecked(3), + Felt::new_unchecked(4), + Felt::new_unchecked(5), + Felt::new_unchecked(6), + Felt::new_unchecked(7), + Felt::new_unchecked(8), + Felt::new_unchecked(9), + Felt::new_unchecked(10), + Felt::new_unchecked(11), ]) .unwrap(), ); @@ -465,7 +473,7 @@ fn build_expected(values: &[u64]) -> Vec { let mut expected = vec![ZERO; 16]; for (i, &value) in values.iter().enumerate() { // In the result, top of stack is at index 15, second at 14, etc. - expected[15 - i] = Felt::new(value); + expected[15 - i] = Felt::new_unchecked(value); } expected } diff --git a/processor/src/execution/operations/sys_ops/tests.rs b/processor/src/execution/operations/sys_ops/tests.rs index 58ca06fcca..de0ed39283 100644 --- a/processor/src/execution/operations/sys_ops/tests.rs +++ b/processor/src/execution/operations/sys_ops/tests.rs @@ -90,11 +90,11 @@ fn test_op_clk() { /// The values are provided in "stack order" (top of stack first), and the result is a Vec /// that can be compared with `processor.stack_top()`, where the top of the stack is at the /// **last** index. -fn build_expected(values: &[u64]) -> alloc::vec::Vec { +fn build_expected(values: &[u64]) -> vec::Vec { let mut expected = vec![ZERO; 16]; for (i, &value) in values.iter().enumerate() { // In the result, top of stack is at index 15, second at 14, etc. - expected[15 - i] = Felt::new(value); + expected[15 - i] = Felt::new_unchecked(value); } expected } diff --git a/processor/src/execution/operations/u32_ops/mod.rs b/processor/src/execution/operations/u32_ops/mod.rs index e1756eef47..da19e0bf8a 100644 --- a/processor/src/execution/operations/u32_ops/mod.rs +++ b/processor/src/execution/operations/u32_ops/mod.rs @@ -4,6 +4,7 @@ use paste::paste; use crate::{ ExecutionError, Felt, ZERO, + mast::MastForest, operation::OperationError, processor::{Processor, StackInterface, SystemInterface}, tracer::{OperationHelperRegisters, Tracer}, @@ -84,7 +85,7 @@ pub(super) fn op_u32add( let (carry, sum) = { let (a, b) = require_u32_operands!(processor, [0, 1]); - let result = Felt::new(a.as_canonical_u64() + b.as_canonical_u64()); + let result = Felt::new_unchecked(a.as_canonical_u64() + b.as_canonical_u64()); split_element(result) }; tracer.record_u32_range_checks(processor.system().clock(), sum, carry); @@ -114,7 +115,8 @@ where let (carry, sum) = { let (a, b, c) = require_u32_operands!(processor, [0, 1, 2]); - let result = Felt::new(a.as_canonical_u64() + b.as_canonical_u64() + c.as_canonical_u64()); + let result = + Felt::new_unchecked(a.as_canonical_u64() + b.as_canonical_u64() + c.as_canonical_u64()); split_element(result) }; tracer.record_u32_range_checks(processor.system().clock(), sum, carry); @@ -141,8 +143,8 @@ pub(super) fn op_u32sub( let (b, a) = require_u32_operands!(processor, [0, 1]); let result = a.as_canonical_u64().wrapping_sub(b.as_canonical_u64()); - let borrow = Felt::new(result >> 63); - let diff = Felt::new(result & u32::MAX as u64); + let borrow = Felt::new_unchecked(result >> 63); + let diff = Felt::new_unchecked(result & u32::MAX as u64); tracer.record_u32_range_checks(processor.system().clock(), diff, ZERO); @@ -164,7 +166,7 @@ pub(super) fn op_u32mul( ) -> Result { let (a, b) = require_u32_operands!(processor, [0, 1]); - let result = Felt::new(a.as_canonical_u64() * b.as_canonical_u64()); + let result = Felt::new_unchecked(a.as_canonical_u64() * b.as_canonical_u64()); let (hi, lo) = split_element(result); tracer.record_u32_range_checks(processor.system().clock(), lo, hi); @@ -191,7 +193,8 @@ where { let (a, b, c) = require_u32_operands!(processor, [0, 1, 2]); - let result = Felt::new(a.as_canonical_u64() * b.as_canonical_u64() + c.as_canonical_u64()); + let result = + Felt::new_unchecked(a.as_canonical_u64() * b.as_canonical_u64() + c.as_canonical_u64()); let (hi, lo) = split_element(result); tracer.record_u32_range_checks(processor.system().clock(), lo, hi); @@ -232,13 +235,13 @@ pub(super) fn op_u32div( let remainder = numerator - quotient * denominator; // remainder is placed on top of the stack, followed by quotient - processor.stack_mut().set(0, Felt::new(remainder)); - processor.stack_mut().set(1, Felt::new(quotient)); + processor.stack_mut().set(0, Felt::new_unchecked(remainder)); + processor.stack_mut().set(1, Felt::new_unchecked(quotient)); // These range checks help enforce that quotient <= numerator. - let lo = Felt::new(numerator - quotient); + let lo = Felt::new_unchecked(numerator - quotient); // These range checks help enforce that remainder < denominator. - let hi = Felt::new(denominator - remainder - 1); + let hi = Felt::new_unchecked(denominator - remainder - 1); tracer.record_u32_range_checks(processor.system().clock(), lo, hi); Ok(OperationHelperRegisters::U32Div { lo, hi }) @@ -265,7 +268,7 @@ where // Update stack processor.stack_mut().decrement_size()?; - processor.stack_mut().set(0, Felt::new(result)); + processor.stack_mut().set(0, Felt::new_unchecked(result)); Ok(OperationHelperRegisters::Empty) } @@ -290,7 +293,7 @@ where // Update stack processor.stack_mut().decrement_size()?; - processor.stack_mut().set(0, Felt::new(result)); + processor.stack_mut().set(0, Felt::new_unchecked(result)); Ok(OperationHelperRegisters::Empty) } @@ -300,10 +303,39 @@ where #[inline(always)] pub(super) fn op_u32assert2( processor: &mut P, - _err_code: Felt, + err_code: Felt, tracer: &mut T, + program: &MastForest, ) -> Result { - let (first, second) = require_u32_operands!(processor, [0, 1]); + let first = processor.stack().get(0); + let second = processor.stack().get(1); + + let first_invalid = first.as_canonical_u64() > U32_MAX; + let second_invalid = second.as_canonical_u64() > U32_MAX; + + if first_invalid || second_invalid { + let mut invalid_values = Vec::with_capacity(2); + if first_invalid { + invalid_values.push(first); + } + if second_invalid { + invalid_values.push(second); + } + + if err_code != ZERO { + // A custom error code was provided: surface it as a U32AssertionFailed so + // callers get both the error context *and* the offending values for + // richer diagnostics (addresses bobbinth's review suggestion). + let err_msg = program.resolve_error_message(err_code); + return Err(OperationError::U32AssertionFailed { err_code, err_msg, invalid_values }); + } + + // No custom error code: report the specific out-of-range values so + // the diagnostic layer can name them (matches historical behaviour and + // what u32assert / u32not / u32assertw expect when they internally + // lower to U32assert2(ZERO)). + return Err(OperationError::NotU32Values { values: invalid_values }); + } tracer.record_u32_range_checks(processor.system().clock(), first, second); @@ -321,5 +353,5 @@ fn split_element(value: Felt) -> (Felt, Felt) { let value = value.as_canonical_u64(); let lo = (value as u32) as u64; let hi = value >> 32; - (Felt::new(hi), Felt::new(lo)) + (Felt::new_unchecked(hi), Felt::new_unchecked(lo)) } diff --git a/processor/src/execution/operations/u32_ops/tests.rs b/processor/src/execution/operations/u32_ops/tests.rs index c365b7b16c..86b98b7832 100644 --- a/processor/src/execution/operations/u32_ops/tests.rs +++ b/processor/src/execution/operations/u32_ops/tests.rs @@ -1,8 +1,9 @@ -use alloc::vec::Vec; +use alloc::{sync::Arc, vec::Vec}; +use miden_assembly::{Assembler, DefaultSourceManager}; use miden_core::{ Felt, ZERO, - mast::{MastForest, MastNodeId}, + mast::{BasicBlockNodeBuilder, MastForest, MastForestContributor}, program::{MIN_STACK_DEPTH, StackInputs}, }; use proptest::prelude::*; @@ -15,7 +16,7 @@ use crate::{ DefaultHost, ExecutionError, execution::operations::execute_op, fast::{FastProcessor, NoopTracer}, - operation::Operation, + operation::{Operation, OperationError}, }; // CASTING OPERATIONS @@ -25,7 +26,7 @@ proptest! { #[test] fn test_op_u32split(a in any::()) { // Stack: [a] with a at top - let mut processor = FastProcessor::new(StackInputs::new(&[Felt::new(a)]).unwrap()); + let mut processor = FastProcessor::new(StackInputs::new(&[Felt::new_unchecked(a)]).unwrap()); let mut tracer = NoopTracer; let hi = a >> 32; @@ -40,7 +41,7 @@ proptest! { #[test] fn test_op_u32split_preserves_rest_of_stack(a in any::(), b in any::()) { // Stack: [a, b] with a at top - operation acts on top element (a) - let mut processor = FastProcessor::new(StackInputs::new(&[Felt::new(a), Felt::new(b)]).unwrap()); + let mut processor = FastProcessor::new(StackInputs::new(&[Felt::new_unchecked(a), Felt::new_unchecked(b)]).unwrap()); let mut tracer = NoopTracer; let hi = a >> 32; @@ -61,53 +62,248 @@ proptest! { fn test_op_u32assert2(a in any::(), b in any::(), c in any::(), d in any::()) { // Stack: [a, b, c, d] with a at top - assert checks a and b are u32 let mut processor = FastProcessor::new(StackInputs::new(&[ - Felt::new(a as u64), - Felt::new(b as u64), - Felt::new(c as u64), - Felt::new(d as u64), + Felt::new_unchecked(a as u64), + Felt::new_unchecked(b as u64), + Felt::new_unchecked(c as u64), + Felt::new_unchecked(d as u64), ]).unwrap()); let mut tracer = NoopTracer; - let _ = op_u32assert2(&mut processor, ZERO, &mut tracer).unwrap(); + let _ = op_u32assert2(&mut processor, ZERO, &mut tracer, &MastForest::default()).unwrap(); let expected = build_expected(&[a as u64, b as u64, c as u64, d as u64]); prop_assert_eq!(expected, processor.stack_top()); } } #[test] -fn test_op_u32assert2_both_invalid() { - // Stack: [invalid1, invalid2] with invalid1 at top - both > u32::MAX +fn test_op_u32assert2_both_invalid_with_err_code() { + // Both values > u32::MAX with a custom err_code: must return U32AssertionFailed + // carrying the err_code AND the offending values (per bobbinth's review). let mut processor = FastProcessor::new( - StackInputs::new(&[Felt::new(4294967296u64), Felt::new(4294967297u64)]).unwrap(), + StackInputs::new(&[Felt::new_unchecked(4294967296u64), Felt::new_unchecked(4294967297u64)]) + .unwrap(), ); let mut tracer = NoopTracer; + let err_code = Felt::from_u32(123u32); + + let err = + op_u32assert2(&mut processor, err_code, &mut tracer, &MastForest::default()).unwrap_err(); + assert!( + matches!( + err, + OperationError::U32AssertionFailed { + err_code: c, + ref invalid_values, + .. + } if c == err_code && invalid_values.len() == 2 + ), + "expected U32AssertionFailed with err_code 123 and 2 invalid values, got: {err:?}" + ); +} - let result = op_u32assert2(&mut processor, Felt::from_u32(123u32), &mut tracer); - assert!(result.is_err()); +#[test] +fn test_op_u32assert2_both_invalid_no_err_code() { + // Both values > u32::MAX with err_code=0: must return NotU32Values with both values + let invalid1 = 4294967296u64; // 2^32 + let invalid2 = 4294967297u64; // 2^32 + 1 + let mut processor = FastProcessor::new( + StackInputs::new(&[Felt::new_unchecked(invalid1), Felt::new_unchecked(invalid2)]).unwrap(), + ); + let mut tracer = NoopTracer; + + let err = op_u32assert2(&mut processor, ZERO, &mut tracer, &MastForest::default()).unwrap_err(); + assert!( + matches!(err, OperationError::NotU32Values { ref values } if values.len() == 2), + "expected NotU32Values with 2 invalid values" + ); } #[test] fn test_op_u32assert2_second_invalid() { - // Stack: [valid, invalid] with valid at top - second value > u32::MAX + // Stack: [valid, invalid] with valid at top - second value > u32::MAX, no err_code let mut processor = FastProcessor::new( - StackInputs::new(&[Felt::new(1000u64), Felt::new(4294967297u64)]).unwrap(), + StackInputs::new(&[Felt::new_unchecked(1000u64), Felt::new_unchecked(4294967297u64)]) + .unwrap(), ); let mut tracer = NoopTracer; - let result = op_u32assert2(&mut processor, Felt::from_u32(456u32), &mut tracer); - assert!(result.is_err()); + let err = op_u32assert2(&mut processor, ZERO, &mut tracer, &MastForest::default()).unwrap_err(); + assert!( + matches!(err, OperationError::NotU32Values { .. }), + "expected NotU32Values when err_code is zero" + ); } #[test] fn test_op_u32assert2_first_invalid() { - // Stack: [invalid, valid] with invalid at top - first value > u32::MAX + // Stack: [invalid, valid] with invalid at top - first value > u32::MAX, no err_code let mut processor = FastProcessor::new( - StackInputs::new(&[Felt::new(4294967296u64), Felt::new(2000u64)]).unwrap(), + StackInputs::new(&[Felt::new_unchecked(4294967296u64), Felt::new_unchecked(2000u64)]) + .unwrap(), ); let mut tracer = NoopTracer; - let result = op_u32assert2(&mut processor, Felt::from_u32(789), &mut tracer); - assert!(result.is_err()); + let err = op_u32assert2(&mut processor, ZERO, &mut tracer, &MastForest::default()).unwrap_err(); + assert!( + matches!(err, OperationError::NotU32Values { .. }), + "expected NotU32Values when err_code is zero" + ); +} + +#[test] +fn test_op_u32assert2_err_code_propagates_on_invalid() { + // err_code and the offending value must appear in U32AssertionFailed + let mut processor = FastProcessor::new( + StackInputs::new(&[Felt::new_unchecked(4294967296u64), Felt::new_unchecked(1u64)]).unwrap(), + ); + let mut tracer = NoopTracer; + let err_code = Felt::from_u32(42); + + let err = + op_u32assert2(&mut processor, err_code, &mut tracer, &MastForest::default()).unwrap_err(); + assert!( + matches!( + err, + OperationError::U32AssertionFailed { + err_code: c, + ref invalid_values, + .. + } if c == err_code && invalid_values.len() == 1 + ), + "expected U32AssertionFailed with err_code 42 and 1 invalid value, got: {err:?}" + ); +} + +#[test] +fn test_op_u32assert2_valid_inputs_succeed_with_nonzero_err_code() { + // A non-zero err_code must NOT cause an error when both values are valid u32s + let mut processor = FastProcessor::new( + StackInputs::new(&[ + Felt::new_unchecked(1u64), + Felt::new_unchecked(2u64), + Felt::new_unchecked(3u64), + Felt::new_unchecked(4u64), + ]) + .unwrap(), + ); + let mut tracer = NoopTracer; + + let result = + op_u32assert2(&mut processor, Felt::from_u32(99), &mut tracer, &MastForest::default()); + assert!(result.is_ok(), "valid u32 inputs must succeed regardless of err_code"); +} + +// ASSEMBLED PROGRAM TESTS +// -------------------------------------------------------------------------------------------- +// +// These tests use the full assembler + FastProcessor::execute_sync pipeline to verify that +// error messages stored in the MastForest are correctly resolved and surfaced through the +// execute_op dispatch layer (addresses huitseeker's review request). + +#[test] +fn test_op_u32assert2_assembled_err_msg_lookup() { + // Compile a program whose MastForest stores "value exceeded u32 range" as an error + // string keyed to the err_code emitted by `u32assert2.err=...`. + // Push 2^32 (invalid) and 1 (valid) so the assertion fails on the first element. + let source_manager = Arc::new(DefaultSourceManager::default()); + let program = Assembler::new(source_manager) + .assemble_program( + r#"begin push.4294967296 push.1 u32assert2.err="value exceeded u32 range" end"#, + ) + .expect("program should assemble"); + + let mut host = DefaultHost::default(); + let processor = FastProcessor::new(StackInputs::default()); + let exec_err = processor + .execute_sync(&program, &mut host) + .expect_err("expected u32 assertion failure"); + + // Unwrap the OperationError from the ExecutionError wrapper. + let op_err = match exec_err { + ExecutionError::OperationError { err, .. } => err, + other => panic!("expected OperationError, got {other:?}"), + }; + + // The resolved message must be present, confirming that resolve_error_message + // correctly looks up the string from the assembled MastForest. + match op_err { + OperationError::U32AssertionFailed { err_msg, ref invalid_values, .. } => { + assert_eq!( + err_msg.as_deref(), + Some("value exceeded u32 range"), + "err_msg should be resolved from the MastForest, got {err_msg:?}" + ); + assert!(!invalid_values.is_empty(), "at least one invalid value should be reported"); + }, + other => panic!("expected U32AssertionFailed, got {other:?}"), + } +} + +#[test] +fn test_u32assert_err_wrapper_assembled() { + // `u32assert.err=...` lowers to [Pad, U32assert2(err_code), Drop]. + // Push a value > u32::MAX so the assertion fires; verify the resolved + // error message makes it through the full execute_sync pipeline. + let source_manager = Arc::new(DefaultSourceManager::default()); + let program = Assembler::new(source_manager) + .assemble_program(r#"begin push.4294967296 u32assert.err="value must fit in u32" end"#) + .expect("program should assemble"); + + let mut host = DefaultHost::default(); + let exec_err = FastProcessor::new(StackInputs::default()) + .execute_sync(&program, &mut host) + .expect_err("expected u32 assertion failure"); + + let op_err = match exec_err { + ExecutionError::OperationError { err, .. } => err, + other => panic!("expected OperationError, got {other:?}"), + }; + match op_err { + OperationError::U32AssertionFailed { err_msg, ref invalid_values, .. } => { + assert_eq!( + err_msg.as_deref(), + Some("value must fit in u32"), + "err_msg should be resolved from MastForest, got {err_msg:?}" + ); + assert!(!invalid_values.is_empty(), "at least one invalid value expected"); + }, + other => panic!("expected U32AssertionFailed, got {other:?}"), + } +} + +#[test] +fn test_u32assertw_err_wrapper_assembled() { + // `u32assertw.err=...` lowers to two U32assert2(err_code) ops via `u32assertw`. + // Push a word where the third element exceeds u32::MAX; verify the error message + // is resolved end-to-end through execute_sync. + let source_manager = Arc::new(DefaultSourceManager::default()); + // Stack (top->bottom): 1 2 2^32 4 — element at position 2 is out of range + let program = Assembler::new(source_manager) + .assemble_program( + r#"begin push.4 push.4294967296 push.2 push.1 u32assertw.err="word contains non-u32 element" end"#, + ) + .expect("program should assemble"); + + let mut host = DefaultHost::default(); + let exec_err = FastProcessor::new(StackInputs::default()) + .execute_sync(&program, &mut host) + .expect_err("expected u32 assertion failure"); + + let op_err = match exec_err { + ExecutionError::OperationError { err, .. } => err, + other => panic!("expected OperationError, got {other:?}"), + }; + match op_err { + OperationError::U32AssertionFailed { err_msg, ref invalid_values, .. } => { + assert_eq!( + err_msg.as_deref(), + Some("word contains non-u32 element"), + "err_msg should be resolved from MastForest, got {err_msg:?}" + ); + assert!(!invalid_values.is_empty(), "at least one invalid value expected"); + }, + other => panic!("expected U32AssertionFailed, got {other:?}"), + } } // ARITHMETIC OPERATIONS @@ -118,10 +314,10 @@ proptest! { fn test_op_u32add(a in any::(), b in any::(), c in any::(), d in any::()) { // Stack: [a, b, c, d] with a at top - computes a + b let mut processor = FastProcessor::new(StackInputs::new(&[ - Felt::new(a as u64), - Felt::new(b as u64), - Felt::new(c as u64), - Felt::new(d as u64), + Felt::new_unchecked(a as u64), + Felt::new_unchecked(b as u64), + Felt::new_unchecked(c as u64), + Felt::new_unchecked(d as u64), ]).unwrap()); let mut tracer = NoopTracer; @@ -137,10 +333,10 @@ proptest! { fn test_op_u32add3(a in any::(), b in any::(), c in any::(), d in any::()) { // Stack: [a, b, c, d] with a at top - computes a + b + c let mut processor = FastProcessor::new(StackInputs::new(&[ - Felt::new(a as u64), - Felt::new(b as u64), - Felt::new(c as u64), - Felt::new(d as u64), + Felt::new_unchecked(a as u64), + Felt::new_unchecked(b as u64), + Felt::new_unchecked(c as u64), + Felt::new_unchecked(d as u64), ]).unwrap()); let mut tracer = NoopTracer; @@ -158,10 +354,10 @@ proptest! { fn test_op_u32sub(a in any::(), b in any::(), c in any::(), d in any::()) { // Stack: [a, b, c, d] with a at top - computes b - a let mut processor = FastProcessor::new(StackInputs::new(&[ - Felt::new(a as u64), - Felt::new(b as u64), - Felt::new(c as u64), - Felt::new(d as u64), + Felt::new_unchecked(a as u64), + Felt::new_unchecked(b as u64), + Felt::new_unchecked(c as u64), + Felt::new_unchecked(d as u64), ]).unwrap()); let mut tracer = NoopTracer; @@ -176,10 +372,10 @@ proptest! { fn test_op_u32mul(a in any::(), b in any::(), c in any::(), d in any::()) { // Stack: [a, b, c, d] with a at top - computes a * b let mut processor = FastProcessor::new(StackInputs::new(&[ - Felt::new(a as u64), - Felt::new(b as u64), - Felt::new(c as u64), - Felt::new(d as u64), + Felt::new_unchecked(a as u64), + Felt::new_unchecked(b as u64), + Felt::new_unchecked(c as u64), + Felt::new_unchecked(d as u64), ]).unwrap()); let mut tracer = NoopTracer; @@ -197,10 +393,10 @@ proptest! { fn test_op_u32madd(a in any::(), b in any::(), c in any::(), d in any::()) { // Stack: [a, b, c, d] with a at top - computes a * b + c let mut processor = FastProcessor::new(StackInputs::new(&[ - Felt::new(a as u64), - Felt::new(b as u64), - Felt::new(c as u64), - Felt::new(d as u64), + Felt::new_unchecked(a as u64), + Felt::new_unchecked(b as u64), + Felt::new_unchecked(c as u64), + Felt::new_unchecked(d as u64), ]).unwrap()); let mut tracer = NoopTracer; @@ -219,10 +415,10 @@ proptest! { // Stack: [a, b, c, d] with a at top - computes b / a // a must be non-zero to avoid division by zero let mut processor = FastProcessor::new(StackInputs::new(&[ - Felt::new(a as u64), - Felt::new(b as u64), - Felt::new(c as u64), - Felt::new(d as u64), + Felt::new_unchecked(a as u64), + Felt::new_unchecked(b as u64), + Felt::new_unchecked(c as u64), + Felt::new_unchecked(d as u64), ]).unwrap()); let mut tracer = NoopTracer; @@ -239,8 +435,9 @@ proptest! { #[test] fn test_op_u32div_by_zero() { // Stack: [0, 10] with 0 at top - divides 10 by 0 - let mut processor = - FastProcessor::new(StackInputs::new(&[Felt::new(0), Felt::new(10)]).unwrap()); + let mut processor = FastProcessor::new( + StackInputs::new(&[Felt::new_unchecked(0), Felt::new_unchecked(10)]).unwrap(), + ); let mut tracer = NoopTracer; let result = op_u32div(&mut processor, &mut tracer); @@ -255,10 +452,10 @@ proptest! { fn test_op_u32and(a in any::(), b in any::(), c in any::(), d in any::()) { // Stack: [a, b, c, d] with a at top - computes a & b let mut processor = FastProcessor::new(StackInputs::new(&[ - Felt::new(a as u64), - Felt::new(b as u64), - Felt::new(c as u64), - Felt::new(d as u64), + Felt::new_unchecked(a as u64), + Felt::new_unchecked(b as u64), + Felt::new_unchecked(c as u64), + Felt::new_unchecked(d as u64), ]).unwrap()); let mut tracer = NoopTracer; @@ -271,10 +468,10 @@ proptest! { fn test_op_u32xor(a in any::(), b in any::(), c in any::(), d in any::()) { // Stack: [a, b, c, d] with a at top - computes a ^ b let mut processor = FastProcessor::new(StackInputs::new(&[ - Felt::new(a as u64), - Felt::new(b as u64), - Felt::new(c as u64), - Felt::new(d as u64), + Felt::new_unchecked(a as u64), + Felt::new_unchecked(b as u64), + Felt::new_unchecked(c as u64), + Felt::new_unchecked(d as u64), ]).unwrap()); let mut tracer = NoopTracer; @@ -320,15 +517,13 @@ fn run_verify_clz_gadget(n: u32, clz: u32) -> Result Result Vec { let mut expected = vec![ZERO; MIN_STACK_DEPTH]; for (i, &value) in values.iter().enumerate() { // In the result, top of stack is at index 15, second at 14, etc. - expected[15 - i] = Felt::new(value); + expected[15 - i] = Felt::new_unchecked(value); } expected } diff --git a/processor/src/execution/split.rs b/processor/src/execution/split.rs index e65afa977a..dde86a06ff 100644 --- a/processor/src/execution/split.rs +++ b/processor/src/execution/split.rs @@ -2,7 +2,7 @@ use alloc::sync::Arc; use core::ops::ControlFlow; use crate::{ - BreakReason, Host, MapExecErr, ONE, Stopper, ZERO, + BaseHost, BreakReason, MapExecErr, ONE, Stopper, ZERO, continuation_stack::Continuation, execution::{ExecutionState, finalize_clock_cycle, finalize_clock_cycle_with_continuation}, mast::{MastForest, MastNodeId, SplitNode}, @@ -24,7 +24,7 @@ pub(super) fn start_split_node( ) -> ControlFlow where P: Processor, - H: Host, + H: BaseHost, S: Stopper, T: Tracer, { @@ -85,7 +85,7 @@ pub(super) fn finish_split_node( ) -> ControlFlow where P: Processor, - H: Host, + H: BaseHost, S: Stopper, T: Tracer, { diff --git a/processor/src/execution_options.rs b/processor/src/execution_options.rs index 1eda043e48..cc3c165cf8 100644 --- a/processor/src/execution_options.rs +++ b/processor/src/execution_options.rs @@ -1,4 +1,5 @@ use miden_air::trace::MIN_TRACE_LEN; +use miden_core::program::MIN_STACK_DEPTH; // EXECUTION OPTIONS // ================================================================================================ @@ -17,11 +18,16 @@ pub struct ExecutionOptions { /// Maximum number of field elements that can be inserted into the advice map in a single /// `adv.insert_mem` operation. max_adv_map_value_size: usize, + /// Maximum total number of field elements allowed in live advice map keys and values. + max_adv_map_elements: usize, /// Maximum number of input bytes allowed for a single hash precompile invocation. max_hash_len_bytes: usize, /// Maximum number of continuations allowed on the continuation stack at any point during /// execution. max_num_continuations: usize, + /// Maximum number of field elements allowed on the operand stack in the active execution + /// context. + max_stack_depth: usize, } impl Default for ExecutionOptions { @@ -33,8 +39,10 @@ impl Default for ExecutionOptions { enable_tracing: false, enable_debugging: false, max_adv_map_value_size: Self::DEFAULT_MAX_ADV_MAP_VALUE_SIZE, + max_adv_map_elements: Self::DEFAULT_MAX_ADV_MAP_ELEMENTS, max_hash_len_bytes: Self::DEFAULT_MAX_HASH_LEN_BYTES, max_num_continuations: Self::DEFAULT_MAX_NUM_CONTINUATIONS, + max_stack_depth: Self::DEFAULT_MAX_STACK_DEPTH, } } } @@ -50,9 +58,15 @@ impl ExecutionOptions { pub const DEFAULT_CORE_TRACE_FRAGMENT_SIZE: usize = 4096; // 2^12 /// Default maximum number of field elements in a single advice map value inserted via - /// `adv.insert_mem`. Set to 2^17 (~1 MB given 8-byte field elements). + /// execution-time advice map mutations. Set to 2^17 (~1 MB given 8-byte field elements). pub const DEFAULT_MAX_ADV_MAP_VALUE_SIZE: usize = 1 << 17; + /// Default maximum total number of field elements in live advice map keys and values. + /// + /// Set to 2^20 so the default allows multiple maximum-sized entries while still providing a + /// finite host-memory backstop. Each entry contributes 4 key elements plus its value length. + pub const DEFAULT_MAX_ADV_MAP_ELEMENTS: usize = 1 << 20; + /// Default maximum number of input bytes for a single hash precompile invocation (e.g. /// keccak256, sha512, etc.). Set to 2^20 (1 MB). pub const DEFAULT_MAX_HASH_LEN_BYTES: usize = 1 << 20; @@ -61,6 +75,12 @@ impl ExecutionOptions { /// Set to 2^16 (65536). pub const DEFAULT_MAX_NUM_CONTINUATIONS: usize = 1 << 16; + /// Default maximum number of field elements allowed on the operand stack. + /// + /// This preserves the effective stack depth ceiling imposed by the previous fixed + /// `FastProcessor` stack buffer. + pub const DEFAULT_MAX_STACK_DEPTH: usize = 6615; + // CONSTRUCTOR // -------------------------------------------------------------------------------------------- @@ -121,8 +141,10 @@ impl ExecutionOptions { enable_tracing, enable_debugging, max_adv_map_value_size: Self::DEFAULT_MAX_ADV_MAP_VALUE_SIZE, + max_adv_map_elements: Self::DEFAULT_MAX_ADV_MAP_ELEMENTS, max_hash_len_bytes: Self::DEFAULT_MAX_HASH_LEN_BYTES, max_num_continuations: Self::DEFAULT_MAX_NUM_CONTINUATIONS, + max_stack_depth: Self::DEFAULT_MAX_STACK_DEPTH, }) } @@ -193,26 +215,37 @@ impl ExecutionOptions { self.enable_debugging } - /// Returns the maximum number of field elements allowed in a single advice map value - /// inserted via `adv.insert_mem`. + /// Returns the maximum number of field elements allowed in a single live advice map value. #[inline] pub fn max_adv_map_value_size(&self) -> usize { self.max_adv_map_value_size } + /// Returns the maximum total number of field elements allowed in live advice map keys and + /// values. + #[inline] + pub fn max_adv_map_elements(&self) -> usize { + self.max_adv_map_elements + } + /// Returns the maximum number of input bytes allowed for a single hash precompile invocation. #[inline] pub fn max_hash_len_bytes(&self) -> usize { self.max_hash_len_bytes } - /// Sets the maximum number of field elements allowed in a single advice map value - /// inserted via `adv.insert_mem`. + /// Sets the maximum number of field elements allowed in a single live advice map value. pub fn with_max_adv_map_value_size(mut self, size: usize) -> Self { self.max_adv_map_value_size = size; self } + /// Sets the maximum total number of field elements allowed in live advice map keys and values. + pub fn with_max_adv_map_elements(mut self, size: usize) -> Self { + self.max_adv_map_elements = size; + self + } + /// Sets the maximum number of input bytes allowed for a single hash precompile invocation. pub fn with_max_hash_len_bytes(mut self, size: usize) -> Self { self.max_hash_len_bytes = size; @@ -225,11 +258,34 @@ impl ExecutionOptions { self.max_num_continuations } + /// Returns the maximum number of field elements allowed on the operand stack in the active + /// execution context. + #[inline] + pub fn max_stack_depth(&self) -> usize { + self.max_stack_depth + } + /// Sets the maximum number of continuations allowed on the continuation stack. pub fn with_max_num_continuations(mut self, max_num_continuations: usize) -> Self { self.max_num_continuations = max_num_continuations; self } + + /// Sets the maximum number of field elements allowed on the operand stack in the active + /// execution context. + pub fn with_max_stack_depth( + mut self, + max_stack_depth: usize, + ) -> Result { + if max_stack_depth < MIN_STACK_DEPTH { + return Err(ExecutionOptionsError::MaxStackDepthTooSmall { + max_stack_depth, + min_stack_depth: MIN_STACK_DEPTH, + }); + } + self.max_stack_depth = max_stack_depth; + Ok(self) + } } // EXECUTION OPTIONS ERROR @@ -247,6 +303,11 @@ pub enum ExecutionOptionsError { MaxCycleNumTooBig { max_cycles: u32, max_cycles_limit: u32 }, #[error("core trace fragment size must be greater than 0")] CoreTraceFragmentSizeTooSmall, + #[error("maximum stack depth {max_stack_depth} must be at least {min_stack_depth}")] + MaxStackDepthTooSmall { + max_stack_depth: usize, + min_stack_depth: usize, + }, } // TESTS @@ -305,4 +366,20 @@ mod tests { assert!(opts.is_ok()); assert_eq!(opts.unwrap().expected_cycles(), 64); } + + #[test] + fn max_stack_depth_validates_minimum_depth() { + let result = ExecutionOptions::default().with_max_stack_depth(MIN_STACK_DEPTH - 1); + assert!(matches!( + result, + Err(ExecutionOptionsError::MaxStackDepthTooSmall { + max_stack_depth, + min_stack_depth: MIN_STACK_DEPTH, + }) if max_stack_depth == MIN_STACK_DEPTH - 1 + )); + + let result = ExecutionOptions::default().with_max_stack_depth(MIN_STACK_DEPTH); + assert!(result.is_ok()); + assert_eq!(result.unwrap().max_stack_depth(), MIN_STACK_DEPTH); + } } diff --git a/processor/src/fast/basic_block/mod.rs b/processor/src/fast/basic_block/mod.rs index 3f334501f9..1e8c50f601 100644 --- a/processor/src/fast/basic_block/mod.rs +++ b/processor/src/fast/basic_block/mod.rs @@ -1,4 +1,4 @@ -use alloc::sync::Arc; +use alloc::{sync::Arc, vec::Vec}; use core::ops::ControlFlow; use miden_core::{ @@ -7,8 +7,10 @@ use miden_core::{ }; use crate::{ - Host, + BaseHost, Host, SyncHost, + advice::AdviceMutation, errors::{MapExecErrWithOpIdx, advice_error_with_context, event_error_with_context}, + event::EventError, fast::{BreakReason, FastProcessor}, }; @@ -17,6 +19,64 @@ pub use sys_event_handlers::SystemEventError; use sys_event_handlers::handle_system_event; impl FastProcessor { + #[inline(always)] + fn handle_system_event( + &mut self, + system_event: SystemEvent, + current_forest: &MastForest, + node_id: MastNodeId, + host: &impl BaseHost, + op_idx: usize, + ) -> ControlFlow { + match handle_system_event(self, system_event).map_exec_err_with_op_idx( + current_forest, + node_id, + host, + op_idx, + ) { + Ok(()) => ControlFlow::Continue(()), + Err(err) => ControlFlow::Break(BreakReason::Err(err)), + } + } + + #[inline(always)] + fn apply_host_event_mutations( + &mut self, + current_forest: &MastForest, + node_id: MastNodeId, + host: &impl BaseHost, + op_idx: usize, + event_id: EventId, + mutations: Result, EventError>, + ) -> ControlFlow { + let mutations = match mutations { + Ok(mutations) => mutations, + Err(err) => { + let event_name = host.resolve_event(event_id).cloned(); + return ControlFlow::Break(BreakReason::Err(event_error_with_context( + err, + current_forest, + node_id, + host, + Some(op_idx), + event_id, + event_name, + ))); + }, + }; + + match self.advice.apply_mutations(mutations) { + Ok(()) => ControlFlow::Continue(()), + Err(err) => ControlFlow::Break(BreakReason::Err(advice_error_with_context( + err, + current_forest, + node_id, + host, + Some(op_idx), + ))), + } + } + /// Executes any decorator in a basic block that is to be executed after all operations in the /// block. This only differs from [`Self::execute_after_exit_decorators`] in that these /// decorators are stored in the basic block node itself. @@ -26,7 +86,7 @@ impl FastProcessor { basic_block_node: &BasicBlockNode, node_id: MastNodeId, current_forest: &Arc, - host: &mut impl Host, + host: &mut impl BaseHost, ) -> ControlFlow { if self.should_execute_decorators() { #[cfg(test)] @@ -41,6 +101,26 @@ impl FastProcessor { ControlFlow::Continue(()) } + #[inline(always)] + pub(super) fn op_emit_sync( + &mut self, + host: &mut impl SyncHost, + current_forest: &MastForest, + node_id: MastNodeId, + op_idx: usize, + ) -> ControlFlow { + let event_id = EventId::from_felt(self.stack_get(0)); + + // If it's a system event, handle it directly. Otherwise, forward it to the host. + if let Some(system_event) = SystemEvent::from_event_id(event_id) { + return self.handle_system_event(system_event, current_forest, node_id, host, op_idx); + } + + let processor_state = self.state(); + let mutations = host.on_event(&processor_state); + self.apply_host_event_mutations(current_forest, node_id, host, op_idx, event_id, mutations) + } + #[inline(always)] pub(super) async fn op_emit( &mut self, @@ -51,41 +131,12 @@ impl FastProcessor { ) -> ControlFlow { let event_id = EventId::from_felt(self.stack_get(0)); - // If it's a system event, handle it directly. Otherwise, forward it to the host. if let Some(system_event) = SystemEvent::from_event_id(event_id) { - if let Err(err) = handle_system_event(self, system_event).map_exec_err_with_op_idx( - current_forest, - node_id, - host, - op_idx, - ) { - return ControlFlow::Break(BreakReason::Err(err)); - } - } else { - let processor_state = self.state(); - let mutations = match host.on_event(&processor_state).await { - Ok(m) => m, - Err(err) => { - let event_name = host.resolve_event(event_id).cloned(); - return ControlFlow::Break(BreakReason::Err(event_error_with_context( - err, - current_forest, - node_id, - host, - event_id, - event_name, - ))); - }, - }; - if let Err(err) = self.advice.apply_mutations(mutations) { - return ControlFlow::Break(BreakReason::Err(advice_error_with_context( - err, - current_forest, - node_id, - host, - ))); - } + return self.handle_system_event(system_event, current_forest, node_id, host, op_idx); } - ControlFlow::Continue(()) + + let processor_state = self.state(); + let mutations = host.on_event(&processor_state).await; + self.apply_host_event_mutations(current_forest, node_id, host, op_idx, event_id, mutations) } } diff --git a/processor/src/fast/basic_block/sys_event_handlers.rs b/processor/src/fast/basic_block/sys_event_handlers.rs index e4bf281b13..e0d905002c 100644 --- a/processor/src/fast/basic_block/sys_event_handlers.rs +++ b/processor/src/fast/basic_block/sys_event_handlers.rs @@ -368,7 +368,7 @@ fn copy_map_value_length_to_adv_stack( // Note: we assume values_len fits within the field modulus. This is always true // in practice since the field modulus (2^64 - 2^32 + 1) is much larger than any // practical vector length that could fit in memory. - processor.advice.push_stack(Felt::new(values_len as u64))?; + processor.advice.push_stack(Felt::new_unchecked(values_len as u64))?; Ok(()) } @@ -540,7 +540,7 @@ mod tests { use miden_core::{Felt, ZERO, crypto::hash::Poseidon2}; use super::*; - use crate::{StackInputs, fast::FastProcessor}; + use crate::{ExecutionOptions, StackInputs, fast::FastProcessor}; /// Tests that `insert_hperm_into_adv_map` produces the same key as applying /// `Poseidon2::apply_permutation` directly to the same state, and stores the rate portion @@ -548,7 +548,7 @@ mod tests { #[test] fn insert_hperm_into_adv_map_consistent_with_permutation() { // Build a 12-element state with distinct values. - let state_felts: [Felt; 12] = core::array::from_fn(|i| Felt::new((i + 1) as u64)); + let state_felts: [Felt; 12] = core::array::from_fn(|i| Felt::new_unchecked((i + 1) as u64)); // The stack for the system event has event_id at position 0, then state[0..12] at // positions 1..13. StackInputs takes elements top-first, so position 0 is the first @@ -564,9 +564,8 @@ mod tests { // Compute expected key by applying the permutation to the same state. let mut expected_state_after_perm = state_felts; Poseidon2::apply_permutation(&mut expected_state_after_perm); - let expected_key = miden_core::Word::new( - expected_state_after_perm[Poseidon2::DIGEST_RANGE].try_into().unwrap(), - ); + let expected_key = + Word::new(expected_state_after_perm[Poseidon2::DIGEST_RANGE].try_into().unwrap()); // The expected values are the rate portion (first 8 elements) of the *input* state. let expected_values = state_felts[Poseidon2::RATE_RANGE].to_vec(); @@ -578,4 +577,72 @@ mod tests { .expect("key should be present in advice map"); assert_eq!(stored_values, expected_values.as_slice()); } + + #[test] + fn insert_hdword_into_adv_map_respects_max_adv_map_value_size() { + let stack_values = stack_with_values(8, 1); + let options = ExecutionOptions::default().with_max_adv_map_value_size(7); + let mut processor = FastProcessor::new(StackInputs::new(&stack_values).unwrap()) + .with_options(options) + .expect("test advice inputs should fit advice map limits"); + + let err = insert_hdword_into_adv_map(&mut processor, ZERO).unwrap_err(); + assert!(matches!( + err, + SystemEventError::Advice(AdviceError::AdvMapValueSizeExceeded { size: 8, max: 7 }) + )); + } + + #[test] + fn insert_hqword_into_adv_map_respects_max_adv_map_value_size() { + let stack_values = stack_with_values(15, 1); + let options = ExecutionOptions::default().with_max_adv_map_value_size(15); + let mut processor = FastProcessor::new(StackInputs::new(&stack_values).unwrap()) + .with_options(options) + .expect("test advice inputs should fit advice map limits"); + + let err = insert_hqword_into_adv_map(&mut processor).unwrap_err(); + assert!(matches!( + err, + SystemEventError::Advice(AdviceError::AdvMapValueSizeExceeded { size: 16, max: 15 }) + )); + } + + #[test] + fn repeated_hdword_insertions_respect_adv_map_element_budget() { + let stack_values = stack_with_values(8, 1); + let options = ExecutionOptions::default().with_max_adv_map_elements(24); + let mut processor = FastProcessor::new(StackInputs::new(&stack_values).unwrap()) + .with_options(options) + .expect("test advice inputs should fit advice map limits"); + + for i in 0..2 { + write_stack_values(&mut processor, 8, i * 8 + 1); + insert_hdword_into_adv_map(&mut processor, ZERO).unwrap(); + } + + write_stack_values(&mut processor, 8, 17); + let err = insert_hdword_into_adv_map(&mut processor, ZERO).unwrap_err(); + let SystemEventError::Advice(AdviceError::AdvMapElementBudgetExceeded { + current, + added: 12, + max: 24, + }) = err + else { + panic!("expected advice map element budget error, got {err:?}"); + }; + assert_eq!(current, 2 * (WORD_SIZE + 2 * WORD_SIZE)); + } + + fn stack_with_values(count: usize, start: u64) -> Vec { + let mut stack_values = vec![ZERO]; + stack_values.extend((0..count).map(|idx| Felt::new_unchecked(start + idx as u64))); + stack_values + } + + fn write_stack_values(processor: &mut FastProcessor, count: usize, start: u64) { + for idx in 0..count { + processor.stack_write(idx + 1, Felt::new_unchecked(start + idx as u64)); + } + } } diff --git a/processor/src/fast/call_and_dyn.rs b/processor/src/fast/call_and_dyn.rs index 9abacc6a5f..2fe24cc2b4 100644 --- a/processor/src/fast/call_and_dyn.rs +++ b/processor/src/fast/call_and_dyn.rs @@ -4,7 +4,7 @@ use miden_core::{ZERO, program::MIN_STACK_DEPTH, utils::range}; use crate::{ errors::OperationError, - fast::{ExecutionContextInfo, FastProcessor, INITIAL_STACK_TOP_IDX, STACK_BUFFER_SIZE}, + fast::{ExecutionContextInfo, FastProcessor, INITIAL_STACK_TOP_IDX}, }; impl FastProcessor { @@ -73,6 +73,10 @@ impl FastProcessor { #[inline(always)] fn restore_overflow_stack(&mut self, ctx_info: &ExecutionContextInfo) { let target_overflow_len = ctx_info.overflow_stack.len(); + debug_assert!( + MIN_STACK_DEPTH.saturating_add(target_overflow_len) <= self.options.max_stack_depth(), + "suspended caller stacks are checked against the operand stack depth limit before being saved" + ); // Check if there's enough room to restore the overflow stack in the current stack buffer. if target_overflow_len > self.stack_bot_idx { @@ -80,8 +84,8 @@ impl FastProcessor { // location of the stack in the buffer. We reset it so that after restoring the overflow // stack, the stack_bot_idx is at its original position (i.e. INITIAL_STACK_TOP_IDX - // 16). - let new_stack_top_idx = - core::cmp::min(INITIAL_STACK_TOP_IDX + target_overflow_len, STACK_BUFFER_SIZE - 1); + let new_stack_top_idx = INITIAL_STACK_TOP_IDX + target_overflow_len; + self.ensure_stack_capacity_for_top_idx(new_stack_top_idx); self.reset_stack_in_buffer(new_stack_top_idx); } diff --git a/processor/src/fast/execution_api.rs b/processor/src/fast/execution_api.rs new file mode 100644 index 0000000000..7a589fda66 --- /dev/null +++ b/processor/src/fast/execution_api.rs @@ -0,0 +1,620 @@ +use alloc::{sync::Arc, vec::Vec}; +use core::ops::ControlFlow; + +use miden_core::{ + Word, + mast::{MastForest, MastNodeId}, + program::{Kernel, MIN_STACK_DEPTH, Program, StackOutputs}, +}; +use tracing::instrument; + +use super::{ + FastProcessor, NoopTracer, + external::maybe_use_caller_error_context, + step::{BreakReason, NeverStopper, ResumeContext, StepStopper}, +}; +use crate::{ + ExecutionError, ExecutionOutput, Host, Stopper, SyncHost, TraceBuildInputs, + continuation_stack::ContinuationStack, + errors::{MapExecErr, MapExecErrNoCtx, OperationError}, + execution::{ + InternalBreakReason, execute_impl, finish_emit_op_execution, + finish_load_mast_forest_from_dyn_start, finish_load_mast_forest_from_external, + }, + trace::execution_tracer::ExecutionTracer, + tracer::Tracer, +}; + +impl FastProcessor { + // EXECUTE + // ------------------------------------------------------------------------------------------- + + /// Executes the given program synchronously and returns the execution output. + pub fn execute_sync( + self, + program: &Program, + host: &mut impl SyncHost, + ) -> Result { + self.execute_with_tracer_sync(program, host, &mut NoopTracer) + } + + /// Async variant of [`Self::execute_sync`] for hosts that need async callbacks. + #[inline(always)] + pub async fn execute( + self, + program: &Program, + host: &mut impl Host, + ) -> Result { + self.execute_with_tracer(program, host, &mut NoopTracer).await + } + + /// Executes the given program synchronously and returns the bundled trace inputs required by + /// [`crate::trace::build_trace`]. + /// + /// # Example + /// ``` + /// use miden_assembly::Assembler; + /// use miden_processor::{DefaultHost, FastProcessor, StackInputs}; + /// + /// let program = Assembler::default().assemble_program("begin push.1 drop end").unwrap(); + /// let mut host = DefaultHost::default(); + /// + /// let trace_inputs = FastProcessor::new(StackInputs::default()) + /// .execute_trace_inputs_sync(&program, &mut host) + /// .unwrap(); + /// let trace = miden_processor::trace::build_trace(trace_inputs).unwrap(); + /// + /// assert_eq!(*trace.program_hash(), program.hash()); + /// ``` + #[instrument(name = "execute_trace_inputs_sync", skip_all)] + pub fn execute_trace_inputs_sync( + self, + program: &Program, + host: &mut impl SyncHost, + ) -> Result { + let mut tracer = ExecutionTracer::new( + self.options.core_trace_fragment_size(), + self.options.max_stack_depth(), + ); + let execution_output = self.execute_with_tracer_sync(program, host, &mut tracer)?; + Ok(Self::trace_build_inputs_from_parts(program, execution_output, tracer)) + } + + /// Async variant of [`Self::execute_trace_inputs_sync`] for async hosts. + #[inline(always)] + #[instrument(name = "execute_trace_inputs", skip_all)] + pub async fn execute_trace_inputs( + self, + program: &Program, + host: &mut impl Host, + ) -> Result { + let mut tracer = ExecutionTracer::new( + self.options.core_trace_fragment_size(), + self.options.max_stack_depth(), + ); + let execution_output = self.execute_with_tracer(program, host, &mut tracer).await?; + Ok(Self::trace_build_inputs_from_parts(program, execution_output, tracer)) + } + + /// Executes the given program with the provided tracer using an async host. + pub async fn execute_with_tracer( + mut self, + program: &Program, + host: &mut impl Host, + tracer: &mut T, + ) -> Result + where + T: Tracer, + { + let mut continuation_stack = ContinuationStack::new(program); + let mut current_forest = program.mast_forest().clone(); + + self.advice.extend_map(current_forest.advice_map()).map_exec_err_no_ctx()?; + let flow = self + .execute_impl_async( + &mut continuation_stack, + &mut current_forest, + program.kernel(), + host, + tracer, + &NeverStopper, + ) + .await; + Self::execution_result_from_flow(flow, self) + } + + /// Executes the given program with the provided tracer using a sync host. + pub fn execute_with_tracer_sync( + mut self, + program: &Program, + host: &mut impl SyncHost, + tracer: &mut T, + ) -> Result + where + T: Tracer, + { + let mut continuation_stack = ContinuationStack::new(program); + let mut current_forest = program.mast_forest().clone(); + + self.advice.extend_map(current_forest.advice_map()).map_exec_err_no_ctx()?; + let flow = self.execute_impl( + &mut continuation_stack, + &mut current_forest, + program.kernel(), + host, + tracer, + &NeverStopper, + ); + Self::execution_result_from_flow(flow, self) + } + + /// Executes a single clock cycle synchronously. + pub fn step_sync( + &mut self, + host: &mut impl SyncHost, + resume_ctx: ResumeContext, + ) -> Result, ExecutionError> { + let ResumeContext { + mut current_forest, + mut continuation_stack, + kernel, + } = resume_ctx; + + let flow = self.execute_impl( + &mut continuation_stack, + &mut current_forest, + &kernel, + host, + &mut NoopTracer, + &StepStopper, + ); + Self::resume_context_from_flow(flow, continuation_stack, current_forest, kernel) + } + + /// Async variant of [`Self::step_sync`]. + #[inline(always)] + pub async fn step( + &mut self, + host: &mut impl Host, + resume_ctx: ResumeContext, + ) -> Result, ExecutionError> { + let ResumeContext { + mut current_forest, + mut continuation_stack, + kernel, + } = resume_ctx; + + let flow = self + .execute_impl_async( + &mut continuation_stack, + &mut current_forest, + &kernel, + host, + &mut NoopTracer, + &StepStopper, + ) + .await; + Self::resume_context_from_flow(flow, continuation_stack, current_forest, kernel) + } + + /// Pairs execution output with the trace inputs captured by the tracer. + #[inline(always)] + fn trace_build_inputs_from_parts( + program: &Program, + execution_output: ExecutionOutput, + tracer: ExecutionTracer, + ) -> TraceBuildInputs { + TraceBuildInputs::from_execution( + program, + execution_output, + tracer.into_trace_generation_context(), + ) + } + + /// Converts a step-wise execution result into the next resume context, if execution stopped. + #[inline(always)] + fn resume_context_from_flow( + flow: ControlFlow, + mut continuation_stack: ContinuationStack, + current_forest: Arc, + kernel: Kernel, + ) -> Result, ExecutionError> { + match flow { + ControlFlow::Continue(_) => Ok(None), + ControlFlow::Break(break_reason) => match break_reason { + BreakReason::Err(err) => Err(err), + BreakReason::Stopped(maybe_continuation) => { + if let Some(continuation) = maybe_continuation { + continuation_stack.push_continuation(continuation); + } + + Ok(Some(ResumeContext { + current_forest, + continuation_stack, + kernel, + })) + }, + }, + } + } + + /// Materializes the current stack as public outputs without consuming the processor. + #[inline(always)] + fn current_stack_outputs(&self) -> StackOutputs { + StackOutputs::new( + &self.stack[self.stack_bot_idx..self.stack_top_idx] + .iter() + .rev() + .copied() + .collect::>(), + ) + .unwrap() + } + + /// Executes the given program with the provided tracer and returns the stack outputs. + /// + /// This function takes a `&mut self` (compared to `self` for the public sync execution + /// methods) so that the processor state may be accessed after execution. Reusing the same + /// processor for a second program is incorrect. This is mainly meant to be used in tests. + fn execute_impl( + &mut self, + continuation_stack: &mut ContinuationStack, + current_forest: &mut Arc, + kernel: &Kernel, + host: &mut impl SyncHost, + tracer: &mut T, + stopper: &S, + ) -> ControlFlow + where + S: Stopper, + T: Tracer, + { + while let ControlFlow::Break(internal_break_reason) = + execute_impl(self, continuation_stack, current_forest, kernel, host, tracer, stopper) + { + match internal_break_reason { + InternalBreakReason::User(break_reason) => return ControlFlow::Break(break_reason), + InternalBreakReason::Emit { + basic_block_node_id, + op_idx, + continuation, + } => { + self.op_emit_sync(host, current_forest, basic_block_node_id, op_idx)?; + + finish_emit_op_execution( + continuation, + self, + continuation_stack, + current_forest, + tracer, + stopper, + )?; + }, + InternalBreakReason::LoadMastForestFromDyn { dyn_node_id, callee_hash } => { + let (root_id, new_forest) = match self.load_mast_forest_sync( + callee_hash, + host, + current_forest, + dyn_node_id, + ) { + Ok(result) => result, + Err(err) => return ControlFlow::Break(BreakReason::Err(err)), + }; + + finish_load_mast_forest_from_dyn_start( + root_id, + new_forest, + self, + current_forest, + continuation_stack, + tracer, + stopper, + )?; + }, + InternalBreakReason::LoadMastForestFromExternal { + external_node_id, + procedure_hash, + } => { + let (root_id, new_forest) = match self.load_mast_forest_sync( + procedure_hash, + host, + current_forest, + external_node_id, + ) { + Ok(result) => result, + Err(err) => { + let maybe_enriched_err = maybe_use_caller_error_context( + err, + current_forest, + continuation_stack, + host, + ); + + return ControlFlow::Break(BreakReason::Err(maybe_enriched_err)); + }, + }; + + finish_load_mast_forest_from_external( + root_id, + new_forest, + external_node_id, + current_forest, + continuation_stack, + host, + tracer, + )?; + }, + } + } + + match StackOutputs::new( + &self.stack[self.stack_bot_idx..self.stack_top_idx] + .iter() + .rev() + .copied() + .collect::>(), + ) { + Ok(stack_outputs) => ControlFlow::Continue(stack_outputs), + Err(_) => ControlFlow::Break(BreakReason::Err(ExecutionError::OutputStackOverflow( + self.stack_top_idx - self.stack_bot_idx - MIN_STACK_DEPTH, + ))), + } + } + + async fn execute_impl_async( + &mut self, + continuation_stack: &mut ContinuationStack, + current_forest: &mut Arc, + kernel: &Kernel, + host: &mut impl Host, + tracer: &mut T, + stopper: &S, + ) -> ControlFlow + where + S: Stopper, + T: Tracer, + { + while let ControlFlow::Break(internal_break_reason) = + execute_impl(self, continuation_stack, current_forest, kernel, host, tracer, stopper) + { + match internal_break_reason { + InternalBreakReason::User(break_reason) => return ControlFlow::Break(break_reason), + InternalBreakReason::Emit { + basic_block_node_id, + op_idx, + continuation, + } => { + self.op_emit(host, current_forest, basic_block_node_id, op_idx).await?; + + finish_emit_op_execution( + continuation, + self, + continuation_stack, + current_forest, + tracer, + stopper, + )?; + }, + InternalBreakReason::LoadMastForestFromDyn { dyn_node_id, callee_hash } => { + let (root_id, new_forest) = match self + .load_mast_forest(callee_hash, host, current_forest, dyn_node_id) + .await + { + Ok(result) => result, + Err(err) => return ControlFlow::Break(BreakReason::Err(err)), + }; + + finish_load_mast_forest_from_dyn_start( + root_id, + new_forest, + self, + current_forest, + continuation_stack, + tracer, + stopper, + )?; + }, + InternalBreakReason::LoadMastForestFromExternal { + external_node_id, + procedure_hash, + } => { + let (root_id, new_forest) = match self + .load_mast_forest(procedure_hash, host, current_forest, external_node_id) + .await + { + Ok(result) => result, + Err(err) => { + let maybe_enriched_err = maybe_use_caller_error_context( + err, + current_forest, + continuation_stack, + host, + ); + + return ControlFlow::Break(BreakReason::Err(maybe_enriched_err)); + }, + }; + + finish_load_mast_forest_from_external( + root_id, + new_forest, + external_node_id, + current_forest, + continuation_stack, + host, + tracer, + )?; + }, + } + } + + match StackOutputs::new( + &self.stack[self.stack_bot_idx..self.stack_top_idx] + .iter() + .rev() + .copied() + .collect::>(), + ) { + Ok(stack_outputs) => ControlFlow::Continue(stack_outputs), + Err(_) => ControlFlow::Break(BreakReason::Err(ExecutionError::OutputStackOverflow( + self.stack_top_idx - self.stack_bot_idx - MIN_STACK_DEPTH, + ))), + } + } + + // HELPERS + // ------------------------------------------------------------------------------------------ + + fn load_mast_forest_sync( + &mut self, + node_digest: Word, + host: &mut impl SyncHost, + current_forest: &MastForest, + node_id: MastNodeId, + ) -> Result<(MastNodeId, Arc), ExecutionError> { + let mast_forest = host.get_mast_forest(&node_digest).ok_or_else(|| { + crate::errors::procedure_not_found_with_context( + node_digest, + current_forest, + node_id, + host, + ) + })?; + + let root_id = mast_forest.find_procedure_root(node_digest).ok_or_else(|| { + Err::<(), _>(OperationError::MalformedMastForestInHost { root_digest: node_digest }) + .map_exec_err(current_forest, node_id, host) + .unwrap_err() + })?; + + self.advice.extend_map(mast_forest.advice_map()).map_exec_err( + current_forest, + node_id, + host, + )?; + + Ok((root_id, mast_forest)) + } + + async fn load_mast_forest( + &mut self, + node_digest: Word, + host: &mut impl Host, + current_forest: &MastForest, + node_id: MastNodeId, + ) -> Result<(MastNodeId, Arc), ExecutionError> { + let mast_forest = if let Some(mast_forest) = host.get_mast_forest(&node_digest).await { + mast_forest + } else { + return Err(crate::errors::procedure_not_found_with_context( + node_digest, + current_forest, + node_id, + host, + )); + }; + + let root_id = mast_forest.find_procedure_root(node_digest).ok_or_else(|| { + Err::<(), _>(OperationError::MalformedMastForestInHost { root_digest: node_digest }) + .map_exec_err(current_forest, node_id, host) + .unwrap_err() + })?; + + self.advice.extend_map(mast_forest.advice_map()).map_exec_err( + current_forest, + node_id, + host, + )?; + + Ok((root_id, mast_forest)) + } + + /// Executes the given program synchronously one step at a time. + pub fn execute_by_step_sync( + mut self, + program: &Program, + host: &mut impl SyncHost, + ) -> Result { + let mut current_resume_ctx = self.get_initial_resume_context(program)?; + + loop { + match self.step_sync(host, current_resume_ctx)? { + Some(next_resume_ctx) => { + current_resume_ctx = next_resume_ctx; + }, + None => break Ok(self.current_stack_outputs()), + } + } + } + + /// Async variant of [`Self::execute_by_step_sync`]. + #[inline(always)] + pub async fn execute_by_step( + mut self, + program: &Program, + host: &mut impl Host, + ) -> Result { + let mut current_resume_ctx = self.get_initial_resume_context(program)?; + let mut processor = self; + + loop { + match processor.step(host, current_resume_ctx).await? { + Some(next_resume_ctx) => { + current_resume_ctx = next_resume_ctx; + }, + None => break Ok(processor.current_stack_outputs()), + } + } + } + + /// Similar to [`Self::execute_sync`], but allows mutable access to the processor. + /// + /// This is mainly meant to be used in tests. + #[cfg(any(test, feature = "testing"))] + pub fn execute_mut_sync( + &mut self, + program: &Program, + host: &mut impl SyncHost, + ) -> Result { + let mut continuation_stack = ContinuationStack::new(program); + let mut current_forest = program.mast_forest().clone(); + + self.advice.extend_map(current_forest.advice_map()).map_exec_err_no_ctx()?; + + let flow = self.execute_impl( + &mut continuation_stack, + &mut current_forest, + program.kernel(), + host, + &mut NoopTracer, + &NeverStopper, + ); + Self::stack_result_from_flow(flow) + } + + /// Async variant of [`Self::execute_mut_sync`]. + #[cfg(any(test, feature = "testing"))] + #[inline(always)] + pub async fn execute_mut( + &mut self, + program: &Program, + host: &mut impl Host, + ) -> Result { + let mut continuation_stack = ContinuationStack::new(program); + let mut current_forest = program.mast_forest().clone(); + + self.advice.extend_map(current_forest.advice_map()).map_exec_err_no_ctx()?; + + let flow = self + .execute_impl_async( + &mut continuation_stack, + &mut current_forest, + program.kernel(), + host, + &mut NoopTracer, + &NeverStopper, + ) + .await; + Self::stack_result_from_flow(flow) + } +} diff --git a/processor/src/fast/external.rs b/processor/src/fast/external.rs index 7324a71f4c..5f07482c8f 100644 --- a/processor/src/fast/external.rs +++ b/processor/src/fast/external.rs @@ -1,7 +1,7 @@ use miden_core::mast::MastForest; use crate::{ - ExecutionError, Host, + BaseHost, ExecutionError, continuation_stack::{Continuation, ContinuationStack}, errors::{OperationError, procedure_not_found_with_context}, }; @@ -35,7 +35,7 @@ pub(super) fn maybe_use_caller_error_context( original_err: ExecutionError, current_forest: &MastForest, continuation_stack: &ContinuationStack, - host: &mut impl Host, + host: &mut impl BaseHost, ) -> ExecutionError { // We only care about procedure-not-found errors or malformed MAST forest errors. let root_digest = match &original_err { diff --git a/processor/src/fast/mod.rs b/processor/src/fast/mod.rs index e86db5584c..3ba61e02b1 100644 --- a/processor/src/fast/mod.rs +++ b/processor/src/fast/mod.rs @@ -1,6 +1,6 @@ #[cfg(test)] use alloc::rc::Rc; -use alloc::{boxed::Box, sync::Arc, vec::Vec}; +use alloc::{boxed::Box, sync::Arc, vec, vec::Vec}; #[cfg(test)] use core::cell::Cell; use core::{cmp::min, ops::ControlFlow}; @@ -11,36 +11,30 @@ use miden_core::{ mast::{MastForest, MastNodeExt, MastNodeId}, operations::Decorator, precompile::PrecompileTranscript, - program::{Kernel, MIN_STACK_DEPTH, Program, StackInputs, StackOutputs}, + program::{MIN_STACK_DEPTH, Program, StackInputs, StackOutputs}, utils::range, }; -use tracing::instrument; use crate::{ - AdviceInputs, AdviceProvider, ContextId, ExecutionError, ExecutionOptions, Host, - ProcessorState, Stopper, + AdviceInputs, AdviceProvider, BaseHost, ContextId, ExecutionError, ExecutionOptions, + ProcessorState, + advice::AdviceError, continuation_stack::{Continuation, ContinuationStack}, - errors::{MapExecErr, MapExecErrNoCtx, OperationError}, - execution::{ - InternalBreakReason, execute_impl, finish_emit_op_execution, - finish_load_mast_forest_from_dyn_start, finish_load_mast_forest_from_external, - }, - trace::execution_tracer::{ExecutionTracer, TraceGenerationContext}, + errors::MapExecErrNoCtx, tracer::{OperationHelperRegisters, Tracer}, }; mod basic_block; mod call_and_dyn; +mod execution_api; mod external; mod memory; mod operation; mod step; pub use basic_block::SystemEventError; -use external::maybe_use_caller_error_context; pub use memory::Memory; pub use step::{BreakReason, ResumeContext}; -use step::{NeverStopper, StepStopper}; #[cfg(test)] mod tests; @@ -48,7 +42,7 @@ mod tests; // CONSTANTS // ================================================================================================ -/// The size of the stack buffer. +/// The initial size of the stack buffer. /// /// Note: This value is much larger than it needs to be for the majority of programs. However, some /// existing programs need it, so we're forced to push it up (though this should be double-checked). @@ -56,7 +50,7 @@ mod tests; /// example, the blake3 benchmark went from 285 MHz to 250 MHz (~10% degradation). Perhaps a better /// solution would be to make this value much smaller (~1000), and then fallback to a `Vec` if the /// stack overflows. -const STACK_BUFFER_SIZE: usize = 6850; +const INITIAL_STACK_BUFFER_SIZE: usize = 6850; /// The initial position of the top of the stack in the stack buffer. /// @@ -66,6 +60,16 @@ const STACK_BUFFER_SIZE: usize = 6850; /// occurs, it is most likely a bug. const INITIAL_STACK_TOP_IDX: usize = 250; +/// Default maximum operand stack depth preserving the previous fixed-buffer ceiling. +const DEFAULT_MAX_STACK_DEPTH: usize = + INITIAL_STACK_BUFFER_SIZE - INITIAL_STACK_TOP_IDX - 1 + MIN_STACK_DEPTH; + +const _: [(); 1] = + [(); (ExecutionOptions::DEFAULT_MAX_STACK_DEPTH == DEFAULT_MAX_STACK_DEPTH) as usize]; + +/// The stack buffer index where the logical operand stack starts after reset/recenter. +const STACK_BUFFER_BASE_IDX: usize = INITIAL_STACK_TOP_IDX - MIN_STACK_DEPTH; + // FAST PROCESSOR // ================================================================================================ @@ -78,7 +82,7 @@ const INITIAL_STACK_TOP_IDX: usize = 250; /// # Stack Management /// A few key points about how the stack was designed for maximum performance: /// -/// - The stack has a fixed buffer size defined by `STACK_BUFFER_SIZE`. +/// - The stack starts with a fixed buffer size defined by `INITIAL_STACK_BUFFER_SIZE`. /// - This was observed to increase performance by at least 2x compared to using a `Vec` with /// `push()` & `pop()`. /// - We track the stack top and bottom using indices `stack_top_idx` and `stack_bot_idx`, @@ -103,7 +107,7 @@ const INITIAL_STACK_TOP_IDX: usize = 250; #[derive(Debug)] pub struct FastProcessor { /// The stack is stored in reverse order, so that the last element is at the top of the stack. - stack: Box<[Felt; STACK_BUFFER_SIZE]>, + stack: Box<[Felt]>, /// The index of the top of the stack. stack_top_idx: usize, /// The index of the bottom of the stack. @@ -144,6 +148,53 @@ pub struct FastProcessor { } impl FastProcessor { + /// Packages the processor state after successful execution into a public result type. + #[inline(always)] + fn into_execution_output(self, stack: StackOutputs) -> ExecutionOutput { + ExecutionOutput { + stack, + advice: self.advice, + memory: self.memory, + final_precompile_transcript: self.pc_transcript, + } + } + + /// Converts the terminal result of a full execution run into [`ExecutionOutput`]. + #[inline(always)] + fn execution_result_from_flow( + flow: ControlFlow, + processor: Self, + ) -> Result { + match flow { + ControlFlow::Continue(stack_outputs) => { + Ok(processor.into_execution_output(stack_outputs)) + }, + ControlFlow::Break(break_reason) => match break_reason { + BreakReason::Err(err) => Err(err), + BreakReason::Stopped(_) => { + unreachable!("Execution never stops prematurely with NeverStopper") + }, + }, + } + } + + /// Converts a testing-only execution result into stack outputs. + #[cfg(any(test, feature = "testing"))] + #[inline(always)] + fn stack_result_from_flow( + flow: ControlFlow, + ) -> Result { + match flow { + ControlFlow::Continue(stack_outputs) => Ok(stack_outputs), + ControlFlow::Break(break_reason) => match break_reason { + BreakReason::Err(err) => Err(err), + BreakReason::Stopped(_) => { + unreachable!("Execution never stops prematurely with NeverStopper") + }, + }, + } + } + // CONSTRUCTORS // ---------------------------------------------------------------------------------------------- @@ -158,25 +209,40 @@ impl FastProcessor { /// /// let processor = FastProcessor::new(stack_inputs) /// .with_advice(advice_inputs) + /// .expect("advice inputs should fit advice map limits") /// .with_debugging(true) /// .with_tracing(true); /// ``` + /// + /// When using non-default advice map limits, prefer [`Self::new_with_options`] so the advice + /// inputs are validated against the intended execution options. pub fn new(stack_inputs: StackInputs) -> Self { Self::new_with_options(stack_inputs, AdviceInputs::default(), ExecutionOptions::default()) + .expect("empty advice inputs should fit default advice map limits") } /// Sets the advice inputs for the processor. - pub fn with_advice(mut self, advice_inputs: AdviceInputs) -> Self { - self.advice = advice_inputs.into(); - self + /// + /// Advice inputs are loaded into the live advice provider immediately and are validated against + /// the processor's current [`ExecutionOptions`]. If the advice map needs non-default limits, + /// construct the processor with [`Self::new_with_options`] or call [`Self::with_options`] + /// before calling this method. + pub fn with_advice(mut self, advice_inputs: AdviceInputs) -> Result { + self.advice = AdviceProvider::new(advice_inputs, &self.options)?; + Ok(self) } /// Sets the execution options for the processor. /// /// This will override any previously set debugging or tracing settings. - pub fn with_options(mut self, options: ExecutionOptions) -> Self { + /// + /// Existing advice inputs are revalidated against the new options before they are applied. To + /// load advice inputs that require non-default advice map limits, call this before + /// [`Self::with_advice`] or use [`Self::new_with_options`]. + pub fn with_options(mut self, options: ExecutionOptions) -> Result { + self.advice.set_options(&options)?; self.options = options; - self + Ok(self) } /// Enables or disables debugging mode. @@ -202,14 +268,13 @@ impl FastProcessor { stack_inputs: StackInputs, advice_inputs: AdviceInputs, options: ExecutionOptions, - ) -> Self { + ) -> Result { let stack_top_idx = INITIAL_STACK_TOP_IDX; let stack = { // Note: we use `Vec::into_boxed_slice()` here, since `Box::new([T; N])` first allocates // the array on the stack, and then moves it to the heap. This might cause a // stack overflow on some systems. - let mut stack: Box<[Felt; STACK_BUFFER_SIZE]> = - vec![ZERO; STACK_BUFFER_SIZE].into_boxed_slice().try_into().unwrap(); + let mut stack = vec![ZERO; INITIAL_STACK_BUFFER_SIZE].into_boxed_slice(); // Copy inputs in reverse order so first element ends up at top of stack for (i, &input) in stack_inputs.iter().enumerate() { @@ -218,8 +283,8 @@ impl FastProcessor { stack }; - Self { - advice: advice_inputs.into(), + Ok(Self { + advice: AdviceProvider::new(advice_inputs, &options)?, stack, stack_top_idx, stack_bot_idx: stack_top_idx - MIN_STACK_DEPTH, @@ -232,10 +297,10 @@ impl FastProcessor { pc_transcript: PrecompileTranscript::new(), #[cfg(test)] decorator_retrieval_count: Rc::new(Cell::new(0)), - } + }) } - /// Returns the resume context to be used with the first call to `step()`. + /// Returns the resume context to be used with the first call to `step_sync()`. pub fn get_initial_resume_context( &mut self, program: &Program, @@ -454,231 +519,6 @@ impl FastProcessor { self.stack_write(idx2, a); } - // EXECUTE - // ------------------------------------------------------------------------------------------- - - /// Executes the given program and returns the stack outputs as well as the advice provider. - pub async fn execute( - self, - program: &Program, - host: &mut impl Host, - ) -> Result { - self.execute_with_tracer(program, host, &mut NoopTracer).await - } - - /// Executes the given program and returns the stack outputs, the advice provider, and - /// context necessary to build the trace. - #[instrument(name = "execute_for_trace", skip_all)] - pub async fn execute_for_trace( - self, - program: &Program, - host: &mut impl Host, - ) -> Result<(ExecutionOutput, TraceGenerationContext), ExecutionError> { - let mut tracer = ExecutionTracer::new(self.options.core_trace_fragment_size()); - let execution_output = self.execute_with_tracer(program, host, &mut tracer).await?; - - let context = tracer.into_trace_generation_context(); - - Ok((execution_output, context)) - } - - /// Executes the given program with the provided tracer and returns the stack outputs, and the - /// advice provider. - pub async fn execute_with_tracer( - mut self, - program: &Program, - host: &mut impl Host, - tracer: &mut T, - ) -> Result - where - T: Tracer, - { - let mut continuation_stack = ContinuationStack::new(program); - let mut current_forest = program.mast_forest().clone(); - - // Merge the program's advice map into the advice provider - self.advice.extend_map(current_forest.advice_map()).map_exec_err_no_ctx()?; - - match self - .execute_impl( - &mut continuation_stack, - &mut current_forest, - program.kernel(), - host, - tracer, - &NeverStopper, - ) - .await - { - ControlFlow::Continue(stack_outputs) => Ok(ExecutionOutput { - stack: stack_outputs, - advice: self.advice, - memory: self.memory, - final_pc_transcript: self.pc_transcript, - }), - ControlFlow::Break(break_reason) => match break_reason { - BreakReason::Err(err) => Err(err), - BreakReason::Stopped(_) => { - unreachable!("Execution never stops prematurely with NeverStopper") - }, - }, - } - } - - /// Executes a single clock cycle - pub async fn step( - &mut self, - host: &mut impl Host, - resume_ctx: ResumeContext, - ) -> Result, ExecutionError> { - let ResumeContext { - mut current_forest, - mut continuation_stack, - kernel, - } = resume_ctx; - - match self - .execute_impl( - &mut continuation_stack, - &mut current_forest, - &kernel, - host, - &mut NoopTracer, - &StepStopper, - ) - .await - { - ControlFlow::Continue(_) => Ok(None), - ControlFlow::Break(break_reason) => match break_reason { - BreakReason::Err(err) => Err(err), - BreakReason::Stopped(maybe_continuation) => { - if let Some(continuation) = maybe_continuation { - continuation_stack.push_continuation(continuation); - } - - Ok(Some(ResumeContext { - current_forest, - continuation_stack, - kernel, - })) - }, - }, - } - } - - /// Executes the given program with the provided tracer and returns the stack outputs. - /// - /// This function takes a `&mut self` (compared to `self` for the public execute functions) so - /// that the processor state may be accessed after execution. It is incorrect to execute a - /// second program using the same processor. This is mainly meant to be used in tests. - async fn execute_impl( - &mut self, - continuation_stack: &mut ContinuationStack, - current_forest: &mut Arc, - kernel: &Kernel, - host: &mut impl Host, - tracer: &mut T, - stopper: &S, - ) -> ControlFlow - where - S: Stopper, - T: Tracer, - { - while let ControlFlow::Break(internal_break_reason) = - execute_impl(self, continuation_stack, current_forest, kernel, host, tracer, stopper) - { - match internal_break_reason { - InternalBreakReason::User(break_reason) => return ControlFlow::Break(break_reason), - InternalBreakReason::Emit { - basic_block_node_id, - op_idx, - continuation, - } => { - self.op_emit(host, current_forest, basic_block_node_id, op_idx).await?; - - // Call `finish_emit_op_execution()`, as per the sans-IO contract. - finish_emit_op_execution( - continuation, - self, - continuation_stack, - current_forest, - tracer, - stopper, - )?; - }, - InternalBreakReason::LoadMastForestFromDyn { dyn_node_id, callee_hash } => { - // load mast forest asynchronously - let (root_id, new_forest) = match self - .load_mast_forest(callee_hash, host, current_forest, dyn_node_id) - .await - { - Ok(result) => result, - Err(err) => return ControlFlow::Break(BreakReason::Err(err)), - }; - - // Finish loading the MAST forest from the Dyn node, as per the sans-IO - // contract. - finish_load_mast_forest_from_dyn_start( - root_id, - new_forest, - self, - current_forest, - continuation_stack, - tracer, - stopper, - )?; - }, - InternalBreakReason::LoadMastForestFromExternal { - external_node_id, - procedure_hash, - } => { - // load mast forest asynchronously - let (root_id, new_forest) = match self - .load_mast_forest(procedure_hash, host, current_forest, external_node_id) - .await - { - Ok(result) => result, - Err(err) => { - let maybe_enriched_err = maybe_use_caller_error_context( - err, - current_forest, - continuation_stack, - host, - ); - - return ControlFlow::Break(BreakReason::Err(maybe_enriched_err)); - }, - }; - - // Finish loading the MAST forest from the External node, as per the sans-IO - // contract. - finish_load_mast_forest_from_external( - root_id, - new_forest, - external_node_id, - current_forest, - continuation_stack, - host, - tracer, - )?; - }, - } - } - - match StackOutputs::new( - &self.stack[self.stack_bot_idx..self.stack_top_idx] - .iter() - .rev() - .copied() - .collect::>(), - ) { - Ok(stack_outputs) => ControlFlow::Continue(stack_outputs), - Err(_) => ControlFlow::Break(BreakReason::Err(ExecutionError::OutputStackOverflow( - self.stack_top_idx - self.stack_bot_idx - MIN_STACK_DEPTH, - ))), - } - } - // DECORATOR EXECUTORS // -------------------------------------------------------------------------------------------- @@ -687,7 +527,7 @@ impl FastProcessor { &self, node_id: MastNodeId, current_forest: &MastForest, - host: &mut impl Host, + host: &mut impl BaseHost, ) -> ControlFlow { if !self.should_execute_decorators() { return ControlFlow::Continue(()); @@ -712,9 +552,9 @@ impl FastProcessor { &self, node_id: MastNodeId, current_forest: &MastForest, - host: &mut impl Host, + host: &mut impl BaseHost, ) -> ControlFlow { - if !self.in_debug_mode() { + if !self.should_execute_decorators() { return ControlFlow::Continue(()); } @@ -736,7 +576,7 @@ impl FastProcessor { fn execute_decorator( &self, decorator: &Decorator, - host: &mut impl Host, + host: &mut impl BaseHost, ) -> ControlFlow { match decorator { Decorator::Debug(options) => { @@ -764,47 +604,6 @@ impl FastProcessor { ControlFlow::Continue(()) } - // HELPERS - // ---------------------------------------------------------------------------------------------- - - async fn load_mast_forest( - &mut self, - node_digest: Word, - host: &mut impl Host, - current_forest: &MastForest, - node_id: MastNodeId, - ) -> Result<(MastNodeId, Arc), ExecutionError> { - let mast_forest = host.get_mast_forest(&node_digest).await.ok_or_else(|| { - crate::errors::procedure_not_found_with_context( - node_digest, - current_forest, - node_id, - host, - ) - })?; - - // We limit the parts of the program that can be called externally to procedure - // roots, even though MAST doesn't have that restriction. - let root_id = mast_forest.find_procedure_root(node_digest).ok_or_else(|| { - Err::<(), _>(OperationError::MalformedMastForestInHost { root_digest: node_digest }) - .map_exec_err(current_forest, node_id, host) - .unwrap_err() - })?; - - // Merge the advice map of this forest into the advice provider. - // Note that the map may be merged multiple times if a different procedure from the same - // forest is called. - // For now, only compiled libraries contain non-empty advice maps, so for most cases, - // this call will be cheap. - self.advice.extend_map(mast_forest.advice_map()).map_exec_err( - current_forest, - node_id, - host, - )?; - - Ok((root_id, mast_forest)) - } - /// Increments the stack top pointer by 1. /// /// The bottom of the stack is never affected by this operation. @@ -813,6 +612,80 @@ impl FastProcessor { self.stack_top_idx += 1; } + /// Ensures the internal stack storage can accommodate one additional logical stack element. + /// + /// The operand stack depth limit is the semantic resource bound; the buffer is only an + /// implementation detail. We therefore check the logical depth before allocating so a program + /// cannot force memory growth beyond `ExecutionOptions::max_stack_depth()`. When storage does + /// need to grow, it grows geometrically and remains heap-allocated as a boxed slice. A + /// `SmallVec` would put a useful inline buffer inside `FastProcessor`, and preallocating the + /// full limit would penalize ordinary programs. This policy is performance-sensitive and should + /// be benchmarked against the fixed-buffer baseline. + #[inline(always)] + fn ensure_stack_capacity_for_push(&mut self) -> Result<(), ExecutionError> { + let depth = self.stack_size() + 1; + let max = self.options.max_stack_depth(); + if depth > max { + return Err(ExecutionError::StackDepthLimitExceeded { depth, max }); + } + + if self.stack_top_idx >= self.stack.len() - 1 { + self.grow_stack_buffer(self.stack_top_idx + 2); + } + + Ok(()) + } + + fn ensure_stack_capacity_for_top_idx(&mut self, top_idx: usize) { + if top_idx >= self.stack.len() { + self.grow_stack_buffer(top_idx + 1); + } + } + + fn grow_stack_buffer(&mut self, requested_min_len: usize) { + // The maximum allocation is tied to the logical operand stack depth, not to the current + // buffer position. Using `stack_bot_idx` here would make the allocation ceiling drift when + // the live stack has moved away from the initial base. + let max_len = STACK_BUFFER_BASE_IDX + .saturating_add(self.options.max_stack_depth()) + .saturating_add(1); + let live_len = self.stack_size(); + + // Growth also recenters the live stack at the normal base. This keeps future push/drop + // behavior close to the fixed-buffer layout and avoids carrying unused prefix cells into + // the new allocation. The extra slot is for the next checked push that triggered growth. + let recentered_min_len = STACK_BUFFER_BASE_IDX.saturating_add(live_len).saturating_add(2); + debug_assert!(recentered_min_len <= max_len); + + // Allocation growth is based on the stack's post-recentered live range, not the previous + // buffer length. The `requested_min_len` may be beyond the allocation cap when a shallow + // context is still positioned near the end of the old buffer; recentering the live stack is + // what makes that valid. The VM-visible requirements are that the live stack is restored at + // `STACK_BUFFER_BASE_IDX`, the post-recentered push slot is available, and allocation stays + // capped by the configured stack depth. The allocation size can differ from the previous + // doubling policy: normal push growth may allocate a couple of extra cells because of the + // spare push slot, while restoring a deep caller from a shallow callee may allocate only + // the requested restored range instead of doubling the old buffer. That smaller + // restore allocation is intentional, but it means future pushes can grow again + // sooner and should stay covered by benchmarks. + let new_len = recentered_min_len.saturating_mul(2).max(requested_min_len).min(max_len); + debug_assert!(new_len <= max_len); + + let mut new_stack = vec![ZERO; new_len].into_boxed_slice(); + let new_stack_bot_idx = STACK_BUFFER_BASE_IDX; + let new_stack_top_idx = new_stack_bot_idx + live_len; + + // Only the active stack range carries VM state. Prefix/suffix cells are scratch storage and + // stay zeroed, which keeps growth proportional to the live depth instead of the old buffer + // length. + new_stack[new_stack_bot_idx..new_stack_top_idx] + .copy_from_slice(&self.stack[self.stack_bot_idx..self.stack_top_idx]); + + self.stack = new_stack; + self.stack_bot_idx = new_stack_bot_idx; + self.stack_top_idx = new_stack_top_idx; + } + /// Decrements the stack top pointer by 1. /// /// The bottom of the stack is only decremented in cases where the stack depth would become less @@ -854,186 +727,6 @@ impl FastProcessor { self.stack_bot_idx = new_stack_bot_idx; self.stack_top_idx = new_stack_top_idx; } - - // SYNC WRAPPERS - // ---------------------------------------------------------------------------------------------- - - /// Convenience sync wrapper to [Self::step]. - pub fn step_sync( - &mut self, - host: &mut impl Host, - resume_ctx: ResumeContext, - ) -> Result, ExecutionError> { - // Create a new Tokio runtime and block on the async execution - let rt = tokio::runtime::Builder::new_current_thread().build().unwrap(); - - let execution_output = rt.block_on(self.step(host, resume_ctx))?; - - Ok(execution_output) - } - - /// Executes the given program step by step (calling [`Self::step`] repeatedly) and returns the - /// stack outputs. - pub fn execute_by_step_sync( - mut self, - program: &Program, - host: &mut impl Host, - ) -> Result { - // Create a new Tokio runtime and block on the async execution - let rt = tokio::runtime::Builder::new_current_thread().build().unwrap(); - let mut current_resume_ctx = self.get_initial_resume_context(program).unwrap(); - - rt.block_on(async { - loop { - match self.step(host, current_resume_ctx).await { - Ok(maybe_resume_ctx) => match maybe_resume_ctx { - Some(next_resume_ctx) => { - current_resume_ctx = next_resume_ctx; - }, - None => { - // End of program was reached - break Ok(StackOutputs::new( - &self.stack[self.stack_bot_idx..self.stack_top_idx] - .iter() - .rev() - .copied() - .collect::>(), - ) - .unwrap()); - }, - }, - Err(err) => { - break Err(err); - }, - } - } - }) - } - - /// Convenience sync wrapper to [Self::execute]. - /// - /// This method is only available on non-wasm32 targets. On wasm32, use the - /// async `execute()` method directly since wasm32 runs in the browser's event loop. - /// - /// # Panics - /// Panics if called from within an existing Tokio runtime. Use the async `execute()` - /// method instead in async contexts. - #[cfg(not(target_family = "wasm"))] - pub fn execute_sync( - self, - program: &Program, - host: &mut impl Host, - ) -> Result { - match tokio::runtime::Handle::try_current() { - Ok(_handle) => { - // We're already inside a Tokio runtime - this is not supported - // because we cannot safely create a nested runtime or move the - // non-Send host reference to another thread - panic!( - "Cannot call execute_sync from within a Tokio runtime. \ - Use the async execute() method instead." - ) - }, - Err(_) => { - // No runtime exists - create one and use it - let rt = tokio::runtime::Builder::new_current_thread().build().unwrap(); - rt.block_on(self.execute(program, host)) - }, - } - } - - /// Convenience sync wrapper to [Self::execute_for_trace]. - /// - /// This method is only available on non-wasm32 targets. On wasm32, use the - /// async `execute_for_trace()` method directly since wasm32 runs in the browser's event loop. - /// - /// # Panics - /// Panics if called from within an existing Tokio runtime. Use the async `execute_for_trace()` - /// method instead in async contexts. - #[cfg(not(target_family = "wasm"))] - #[instrument(name = "execute_for_trace_sync", skip_all)] - pub fn execute_for_trace_sync( - self, - program: &Program, - host: &mut impl Host, - ) -> Result<(ExecutionOutput, TraceGenerationContext), ExecutionError> { - match tokio::runtime::Handle::try_current() { - Ok(_handle) => { - // We're already inside a Tokio runtime - this is not supported - // because we cannot safely create a nested runtime or move the - // non-Send host reference to another thread - panic!( - "Cannot call execute_for_trace_sync from within a Tokio runtime. \ - Use the async execute_for_trace() method instead." - ) - }, - Err(_) => { - // No runtime exists - create one and use it - let rt = tokio::runtime::Builder::new_current_thread().build().unwrap(); - rt.block_on(self.execute_for_trace(program, host)) - }, - } - } - - /// Similar to [Self::execute_sync], but allows mutable access to the processor. - /// - /// This method is only available on non-wasm32 targets for testing. On wasm32, use - /// async execution methods directly since wasm32 runs in the browser's event loop. - /// - /// # Panics - /// Panics if called from within an existing Tokio runtime. Use async execution - /// methods instead in async contexts. - #[cfg(all(any(test, feature = "testing"), not(target_family = "wasm")))] - pub fn execute_sync_mut( - &mut self, - program: &Program, - host: &mut impl Host, - ) -> Result { - let mut continuation_stack = ContinuationStack::new(program); - let mut current_forest = program.mast_forest().clone(); - - // Merge the program's advice map into the advice provider - self.advice.extend_map(current_forest.advice_map()).map_exec_err_no_ctx()?; - - let execute_fut = async { - match self - .execute_impl( - &mut continuation_stack, - &mut current_forest, - program.kernel(), - host, - &mut NoopTracer, - &NeverStopper, - ) - .await - { - ControlFlow::Continue(stack_outputs) => Ok(stack_outputs), - ControlFlow::Break(break_reason) => match break_reason { - BreakReason::Err(err) => Err(err), - BreakReason::Stopped(_) => { - unreachable!("Execution never stops prematurely with NeverStopper") - }, - }, - } - }; - - match tokio::runtime::Handle::try_current() { - Ok(_handle) => { - // We're already inside a Tokio runtime - this is not supported - // because we cannot safely create a nested runtime or move the - // non-Send host reference to another thread - panic!( - "Cannot call execute_sync_mut from within a Tokio runtime. \ - Use async execution methods instead." - ) - }, - Err(_) => { - // No runtime exists - create one and use it - let rt = tokio::runtime::Builder::new_current_thread().build().unwrap(); - rt.block_on(execute_fut) - }, - } - } } // EXECUTION OUTPUT @@ -1046,7 +739,7 @@ pub struct ExecutionOutput { pub stack: StackOutputs, pub advice: AdviceProvider, pub memory: Memory, - pub final_pc_transcript: PrecompileTranscript, + pub final_precompile_transcript: PrecompileTranscript, } // EXECUTION CONTEXT INFO diff --git a/processor/src/fast/operation.rs b/processor/src/fast/operation.rs index c2d9ba0f9f..8700cf55c4 100644 --- a/processor/src/fast/operation.rs +++ b/processor/src/fast/operation.rs @@ -14,9 +14,9 @@ use miden_core::{ use super::step::BreakReason; use crate::{ - AdviceProvider, ContextId, ExecutionError, Host, + AdviceProvider, BaseHost, ContextId, ExecutionError, errors::OperationError, - fast::{FastProcessor, STACK_BUFFER_SIZE, memory::Memory}, + fast::{FastProcessor, memory::Memory}, processor::{HasherInterface, Processor, StackInterface, SystemInterface}, }; @@ -92,7 +92,7 @@ impl Processor for FastProcessor { &self, node_id: MastNodeId, current_forest: &MastForest, - host: &mut impl Host, + host: &mut impl BaseHost, ) -> ControlFlow { self.execute_before_enter_decorators(node_id, current_forest, host) } @@ -102,7 +102,7 @@ impl Processor for FastProcessor { &self, node_id: MastNodeId, current_forest: &MastForest, - host: &mut impl Host, + host: &mut impl BaseHost, ) -> ControlFlow { self.execute_after_exit_decorators(node_id, current_forest, host) } @@ -113,7 +113,7 @@ impl Processor for FastProcessor { node_id: MastNodeId, op_idx_in_block: usize, current_forest: &MastForest, - host: &mut impl Host, + host: &mut impl BaseHost, ) -> ControlFlow { if self.should_execute_decorators() { #[cfg(test)] @@ -133,7 +133,7 @@ impl Processor for FastProcessor { basic_block_node: &BasicBlockNode, node_id: MastNodeId, current_forest: &Arc, - host: &mut impl Host, + host: &mut impl BaseHost, ) -> ControlFlow { self.execute_end_of_block_decorators(basic_block_node, node_id, current_forest, host) } @@ -309,12 +309,9 @@ impl StackInterface for FastProcessor { #[inline(always)] fn increment_size(&mut self) -> Result<(), ExecutionError> { - if self.stack_top_idx < STACK_BUFFER_SIZE - 1 { - self.increment_stack_size(); - Ok(()) - } else { - Err(ExecutionError::Internal("stack overflow")) - } + self.ensure_stack_capacity_for_push()?; + self.increment_stack_size(); + Ok(()) } #[inline(always)] diff --git a/processor/src/fast/tests/advice_provider.rs b/processor/src/fast/tests/advice_provider.rs index 25a2f840d4..530253dab2 100644 --- a/processor/src/fast/tests/advice_provider.rs +++ b/processor/src/fast/tests/advice_provider.rs @@ -148,6 +148,7 @@ fn test_advice_provider() { let mut fast_host = TestHost::with_kernel_forest(kernel_lib.mast_forest().clone()); let processor = FastProcessor::new(StackInputs::default()) .with_advice(AdviceInputs::default()) + .expect("advice inputs should fit advice map limits") .with_debugging(true) .with_tracing(true); let fast_stack_outputs = processor.execute_sync(&program, &mut fast_host).unwrap().stack; diff --git a/processor/src/fast/tests/fast_decorator_execution_tests.rs b/processor/src/fast/tests/fast_decorator_execution_tests.rs index c5e4b7bff4..8687c998ea 100644 --- a/processor/src/fast/tests/fast_decorator_execution_tests.rs +++ b/processor/src/fast/tests/fast_decorator_execution_tests.rs @@ -51,12 +51,13 @@ fn test_before_enter_decorator_executed_once_fast() { let mut host = TestHost::new(); let processor = FastProcessor::new(StackInputs::default()) .with_advice(AdviceInputs::default()) + .expect("advice inputs should fit advice map limits") .with_debugging(true) .with_tracing(true); // Execute the program let result = processor.execute_sync(&program, &mut host); - assert!(result.is_ok(), "Execution failed: {:?}", result); + assert!(result.is_ok(), "Execution failed: {result:?}"); // Verify decorator execution counts assert_eq!(host.get_trace_count(1), 1, "before_enter decorator should execute exactly once"); @@ -69,6 +70,29 @@ fn test_before_enter_decorator_executed_once_fast() { assert_eq!(order[1].0, 2, "Second trace should be after_exit"); } +#[test] +fn test_after_exit_trace_executes_with_tracing_only_fast() { + let after_exit_decorator = Decorator::Trace(2); + let operations = [Operation::Noop]; + + let program = create_test_program(&[], &[after_exit_decorator], &operations); + + let mut host = TestHost::new(); + let processor = FastProcessor::new(StackInputs::default()) + .with_advice(AdviceInputs::default()) + .expect("advice inputs should fit advice map limits") + .with_tracing(true); + + let result = processor.execute_sync(&program, &mut host); + assert!(result.is_ok(), "Execution failed: {result:?}"); + + assert_eq!( + host.get_trace_count(2), + 1, + "after_exit trace decorator should execute when tracing is enabled without debug mode" + ); +} + #[test] fn test_multiple_before_enter_decorators_each_once_fast() { let before_enter_decorators = [Decorator::Trace(1), Decorator::Trace(2), Decorator::Trace(3)]; @@ -81,12 +105,13 @@ fn test_multiple_before_enter_decorators_each_once_fast() { let mut host = TestHost::new(); let processor = FastProcessor::new(StackInputs::default()) .with_advice(AdviceInputs::default()) + .expect("advice inputs should fit advice map limits") .with_debugging(true) .with_tracing(true); // Execute the program let result = processor.execute_sync(&program, &mut host); - assert!(result.is_ok(), "Execution failed: {:?}", result); + assert!(result.is_ok(), "Execution failed: {result:?}"); // Verify decorator execution counts assert_eq!( @@ -127,12 +152,13 @@ fn test_multiple_after_exit_decorators_each_once_fast() { let mut host = TestHost::new(); let processor = FastProcessor::new(StackInputs::default()) .with_advice(AdviceInputs::default()) + .expect("advice inputs should fit advice map limits") .with_debugging(true) .with_tracing(true); // Execute the program let result = processor.execute_sync(&program, &mut host); - assert!(result.is_ok(), "Execution failed: {:?}", result); + assert!(result.is_ok(), "Execution failed: {result:?}"); // Verify decorator execution counts assert_eq!(host.get_trace_count(1), 1, "before_enter decorator should execute exactly once"); @@ -179,12 +205,13 @@ fn test_decorator_execution_order_fast() { let mut host = TestHost::new(); let processor = FastProcessor::new(StackInputs::default()) .with_advice(AdviceInputs::default()) + .expect("advice inputs should fit advice map limits") .with_debugging(true) .with_tracing(true); // Execute the program let result = processor.execute_sync(&program, &mut host); - assert!(result.is_ok(), "Execution failed: {:?}", result); + assert!(result.is_ok(), "Execution failed: {result:?}"); // Verify decorator execution counts assert_eq!( @@ -229,11 +256,12 @@ fn test_processor_decorator_execution() { let mut host = TestHost::new(); let processor = FastProcessor::new(StackInputs::default()) .with_advice(AdviceInputs::default()) + .expect("advice inputs should fit advice map limits") .with_debugging(true) .with_tracing(true); let execution_result = processor.execute_sync(&program, &mut host); - assert!(execution_result.is_ok(), "Execution failed: {:?}", execution_result); + assert!(execution_result.is_ok(), "Execution failed: {execution_result:?}"); // Check decorator execution insta::assert_debug_snapshot!( @@ -272,12 +300,13 @@ fn test_no_duplication_between_inner_and_before_exit_decorators_fast() { let mut host = TestHost::new(); let processor = FastProcessor::new(StackInputs::default()) .with_advice(AdviceInputs::default()) + .expect("advice inputs should fit advice map limits") .with_debugging(true) .with_tracing(true); // Execute the program let result = processor.execute_sync(&program, &mut host); - assert!(result.is_ok(), "Execution failed: {:?}", result); + assert!(result.is_ok(), "Execution failed: {result:?}"); // Verify each decorator executes exactly once (no duplication) assert_eq!(host.get_trace_count(1), 1, "before_enter decorator should execute exactly once"); @@ -352,6 +381,7 @@ fn test_decorator_bypass_in_debug_mode() { create_test_program(&[Decorator::Trace(1)], &[Decorator::Trace(2)], &[Operation::Noop]); let processor = FastProcessor::new(StackInputs::default()) .with_advice(AdviceInputs::default()) + .expect("advice inputs should fit advice map limits") .with_debugging(true) .with_tracing(true); let counter = processor.decorator_retrieval_count.clone(); diff --git a/processor/src/fast/tests/masm_consistency.rs b/processor/src/fast/tests/masm_consistency.rs index 1fa7258bbb..1e6928d2d6 100644 --- a/processor/src/fast/tests/masm_consistency.rs +++ b/processor/src/fast/tests/masm_consistency.rs @@ -363,9 +363,9 @@ fn test_log_precompile_correctness() { // Stack inputs: [1,2,3,4,5,6,7,8] with 1 at top // The stack represents [COMM, TAG] where COMM=[1,2,3,4] and TAG=[5,6,7,8] - let stack_inputs = [1, 2, 3, 4, 5, 6, 7, 8].map(Felt::new); - let comm_calldata: Word = [1, 2, 3, 4].map(Felt::new).into(); - let tag: Word = [5, 6, 7, 8].map(Felt::new).into(); + let stack_inputs = [1, 2, 3, 4, 5, 6, 7, 8].map(Felt::new_unchecked); + let comm_calldata: Word = [1, 2, 3, 4].map(Felt::new_unchecked).into(); + let tag: Word = [5, 6, 7, 8].map(Felt::new_unchecked).into(); let cap_prev = Word::empty(); // Compute expected output using Poseidon2 permutation diff --git a/processor/src/fast/tests/memory.rs b/processor/src/fast/tests/memory.rs index 707d623e3b..b34f44f156 100644 --- a/processor/src/fast/tests/memory.rs +++ b/processor/src/fast/tests/memory.rs @@ -51,7 +51,7 @@ fn test_mloadw_success() { processor.memory.write_word(ctx, addr, dummy_clk, word_at_addr.into()).unwrap(); let program = simple_program_with_ops(vec![Operation::MLoadW]); - let stack_outputs = processor.execute_sync_mut(&program, &mut host).unwrap(); + let stack_outputs = processor.execute_mut_sync(&program, &mut host).unwrap(); // Memory word[i] maps to stack position i (word[0] at top) assert_eq!( @@ -66,7 +66,7 @@ fn test_mloadw_success() { processor.memory.write_word(ctx, addr, dummy_clk, word_at_addr.into()).unwrap(); let program = simple_program_with_ops(vec![Operation::MLoadW]); - let stack_outputs = processor.execute_sync_mut(&program, &mut host).unwrap(); + let stack_outputs = processor.execute_mut_sync(&program, &mut host).unwrap(); assert_eq!(stack_outputs.get_num_elements(16), &vec![ZERO; 16]); } @@ -94,7 +94,7 @@ fn test_mstorew_success() { .unwrap(), ); let program = simple_program_with_ops(vec![Operation::MStoreW]); - processor.execute_sync_mut(&program, &mut host).unwrap(); + processor.execute_mut_sync(&program, &mut host).unwrap(); // Ensure that the memory was correctly modified assert_eq!(processor.memory.read_word(ctx, addr, clk).unwrap(), word_to_store); @@ -115,7 +115,7 @@ fn test_mstore_success(#[case] addr: u32, #[case] value_to_store: u32) { let mut processor = FastProcessor::new(StackInputs::new(&[Felt::from_u32(addr), value_to_store]).unwrap()); let program = simple_program_with_ops(vec![Operation::MStore]); - processor.execute_sync_mut(&program, &mut host).unwrap(); + processor.execute_mut_sync(&program, &mut host).unwrap(); // Ensure that the memory was correctly modified let word_addr = addr - (addr % WORD_SIZE as u32); @@ -144,7 +144,7 @@ fn test_mload_success(#[case] addr_to_access: u32) { .unwrap(); let program = simple_program_with_ops(vec![Operation::MLoad]); - let stack_outputs = processor.execute_sync_mut(&program, &mut host).unwrap(); + let stack_outputs = processor.execute_mut_sync(&program, &mut host).unwrap(); // Ensure that Operation::MLoad correctly reads the value on the stack assert_eq!( @@ -180,7 +180,7 @@ fn test_mstream() { .unwrap(); let program = simple_program_with_ops(vec![Operation::MStream]); - let stack_outputs = processor.execute_sync_mut(&program, &mut host).unwrap(); + let stack_outputs = processor.execute_mut_sync(&program, &mut host).unwrap(); // Word at addr 40 goes to positions 0-3, word at addr 44 goes to positions 4-7 // word[0] at lowest position (top of stack) diff --git a/processor/src/fast/tests/mod.rs b/processor/src/fast/tests/mod.rs index b3bd3e8ec2..89f7457010 100644 --- a/processor/src/fast/tests/mod.rs +++ b/processor/src/fast/tests/mod.rs @@ -84,7 +84,7 @@ fn stack_get_word_safe_partial_read() { // elements at indices 15, 16, 17, 18. Only index 15 is valid; the rest should be ZERO. let word = processor.stack_get_word_safe(15); // Index 15 is the bottom of the stack (value 16, since inputs are in stack order: top first). - assert_eq!(word, [Felt::new(16), ZERO, ZERO, ZERO].into()); + assert_eq!(word, [Felt::new_unchecked(16), ZERO, ZERO, ZERO].into()); } #[test] @@ -232,7 +232,8 @@ fn test_cycle_limit_exceeded() { let program = simple_program_with_ops(vec![Operation::Swap; MIN_TRACE_LEN]); let processor = - FastProcessor::new_with_options(StackInputs::default(), AdviceInputs::default(), options); + FastProcessor::new_with_options(StackInputs::default(), AdviceInputs::default(), options) + .expect("processor advice inputs should fit advice map limits"); let err = processor.execute_sync(&program, &mut host).unwrap_err(); assert_matches!(err, ExecutionError::CycleLimitExceeded(max_cycles) if max_cycles == MIN_TRACE_LEN as u32); @@ -265,7 +266,8 @@ fn test_cycle_limit_exactly_max_cycles_succeeds() { .unwrap(); let processor = - FastProcessor::new_with_options(StackInputs::default(), AdviceInputs::default(), options); + FastProcessor::new_with_options(StackInputs::default(), AdviceInputs::default(), options) + .expect("processor advice inputs should fit advice map limits"); let result = processor.execute_sync(&program, &mut host); // The program should succeed since it uses exactly max_cycles cycles. @@ -357,10 +359,11 @@ fn test_frie2f4() { // --- build stack inputs --------------------------------------------- // FastProcessor::new expects inputs in natural order: first element goes to top. // After Push(42), the stack layout becomes: - // [v0, v1, v2, v3, v4, v5, v6, v7, f_pos, d_seg, poe, pe1, pe0, a1, a0, cptr, ...] - // ^0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + // [v0, v1, v2, v3, v4, v5, v6, v7, f_pos, p, poe, pe0, pe1, a0, a1, cptr, ...] + // ^0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 // - // With d_seg=2, query_values[2] = (v4, v5) must equal prev_value = (pe0, pe1). + // p is the bit-reversed tree index; the instruction computes d_seg = p & 3. + // With p=38 (d_seg=2, f_pos=9), query_values[2] = (v4, v5) must equal prev_value = (pe0, pe1). let previous_value: [Felt; 2] = [Felt::from_u32(10), Felt::from_u32(11)]; let stack_inputs = StackInputs::new(&[ Felt::from_u32(16), // pos 0 -> pos 1 (v1) after push @@ -371,19 +374,21 @@ fn test_frie2f4() { Felt::from_u32(11), // pos 5 -> pos 6 (v6) after push Felt::from_u32(10), // pos 6 -> pos 7 (v7) after push Felt::from_u32(9), // pos 7 -> pos 8 (f_pos) after push - Felt::from_u32(2), // pos 8 -> pos 9 (d_seg=2) after push + Felt::from_u32(38), // pos 8 -> pos 9 (p=4*9+2=38, d_seg=2) after push Felt::from_u32(7), // pos 9 -> pos 10 (poe) after push - previous_value[1], // pos 10 -> pos 11 (pe1) after push - previous_value[0], // pos 11 -> pos 12 (pe0) after push - Felt::from_u32(3), // pos 12 -> pos 13 (a1) after push - Felt::from_u32(2), // pos 13 -> pos 14 (a0) after push + previous_value[0], // pos 10 -> pos 11 (pe0) after push + previous_value[1], // pos 11 -> pos 12 (pe1) after push + Felt::from_u32(2), // pos 12 -> pos 13 (a0) after push + Felt::from_u32(3), // pos 13 -> pos 14 (a1) after push Felt::from_u32(1), // pos 14 -> pos 15 (cptr) after push Felt::from_u32(0), // pos 15 -> overflow after push ]) .unwrap(); - let program = - simple_program_with_ops(vec![Operation::Push(Felt::new(42_u64)), Operation::FriE2F4]); + let program = simple_program_with_ops(vec![ + Operation::Push(Felt::new_unchecked(42_u64)), + Operation::FriE2F4, + ]); // fast processor let fast_processor = FastProcessor::new(stack_inputs); @@ -472,7 +477,7 @@ fn test_call_node_preserves_stack_overflow_table() { ); // Execute the program - let result = processor.execute_sync_mut(&program, &mut host).unwrap(); + let result = processor.execute_mut_sync(&program, &mut host).unwrap(); assert_eq!( result.get_num_elements(16), @@ -510,7 +515,7 @@ fn test_external_node_decorator_sequencing() { // Add a decorator to the lib forest to track execution inside the external node let lib_decorator = Decorator::Trace(2); - let lib_decorator_id = lib_forest.add_decorator(lib_decorator.clone()).unwrap(); + let lib_decorator_id = lib_forest.add_decorator(lib_decorator).unwrap(); let lib_operations = [Operation::Push(Felt::from_u32(1)), Operation::Add]; // Attach the decorator to the first operation (index 0) @@ -523,8 +528,8 @@ fn test_external_node_decorator_sequencing() { let mut main_forest = MastForest::new(); let before_decorator = Decorator::Trace(1); let after_decorator = Decorator::Trace(3); - let before_id = main_forest.add_decorator(before_decorator.clone()).unwrap(); - let after_id = main_forest.add_decorator(after_decorator.clone()).unwrap(); + let before_id = main_forest.add_decorator(before_decorator).unwrap(); + let after_id = main_forest.add_decorator(after_decorator).unwrap(); let external_id = ExternalNodeBuilder::new(lib_forest[lib_block_id].digest()) .with_before_enter([before_id]) @@ -537,11 +542,12 @@ fn test_external_node_decorator_sequencing() { let mut host = crate::test_utils::TestHost::with_kernel_forest(Arc::new(lib_forest)); let processor = FastProcessor::new(StackInputs::default()) .with_advice(AdviceInputs::default()) + .expect("advice inputs should fit advice map limits") .with_debugging(true) .with_tracing(true); let result = processor.execute_sync(&program, &mut host); - assert!(result.is_ok(), "Execution failed: {:?}", result); + assert!(result.is_ok(), "Execution failed: {result:?}"); // Verify all decorators executed assert_eq!(host.get_trace_count(1), 1, "before_enter decorator should execute exactly once"); @@ -570,6 +576,396 @@ fn test_external_node_decorator_sequencing() { ); } +#[test] +fn stack_depth_default_limit_exact_boundary_succeeds() { + let mut host = DefaultHost::default(); + + let pushes_to_default_limit = DEFAULT_MAX_STACK_DEPTH - MIN_STACK_DEPTH; + let program = simple_program_with_ops(pad_then_drop_ops(pushes_to_default_limit)); + + FastProcessor::new(StackInputs::default()) + .execute_sync(&program, &mut host) + .expect("using the full default stack depth limit should succeed"); +} + +#[test] +fn stack_depth_default_limit_exceeded_returns_typed_error() { + let mut host = DefaultHost::default(); + + let pushes_past_default_limit = DEFAULT_MAX_STACK_DEPTH - MIN_STACK_DEPTH + 1; + let program = simple_program_with_ops(vec![Operation::Pad; pushes_past_default_limit]); + + let err = FastProcessor::new(StackInputs::default()) + .execute_sync(&program, &mut host) + .expect_err("pushing past the default stack depth limit should fail"); + + assert_matches!( + err, + ExecutionError::StackDepthLimitExceeded { + depth, + max: DEFAULT_MAX_STACK_DEPTH, + } if depth == DEFAULT_MAX_STACK_DEPTH + 1 + ); +} + +#[test] +fn stack_depth_small_custom_limit_fails_before_buffer_growth() { + let mut host = DefaultHost::default(); + let max_stack_depth = MIN_STACK_DEPTH + 1; + let program = simple_program_with_ops(vec![Operation::Pad; 2]); + let options = ExecutionOptions::default().with_max_stack_depth(max_stack_depth).unwrap(); + + let err = + FastProcessor::new_with_options(StackInputs::default(), AdviceInputs::default(), options) + .expect("processor advice inputs should fit advice map limits") + .execute_sync(&program, &mut host) + .expect_err("small configured stack depth limit should fail before buffer growth"); + + assert_matches!( + err, + ExecutionError::StackDepthLimitExceeded { + depth, + max, + } if depth == max_stack_depth + 1 && max == max_stack_depth + ); +} + +#[test] +fn issue_2818_fast_processor_stack_grows_past_initial_buffer_by_multiple_elements() { + const GROWTH_MARGIN: usize = 4; + + let mut host = DefaultHost::default(); + + let pushes_past_initial_buffer = DEFAULT_MAX_STACK_DEPTH - MIN_STACK_DEPTH + GROWTH_MARGIN; + let program = simple_program_with_ops(pad_then_drop_ops(pushes_past_initial_buffer)); + let options = ExecutionOptions::default() + .with_max_stack_depth(DEFAULT_MAX_STACK_DEPTH + GROWTH_MARGIN) + .unwrap(); + + FastProcessor::new_with_options(StackInputs::default(), AdviceInputs::default(), options) + .expect("processor advice inputs should fit advice map limits") + .execute_sync(&program, &mut host) + .expect("stack growth multiple elements past the initial buffer should succeed"); +} + +#[test] +fn issue_2818_traced_execution_stack_grows_past_initial_buffer() { + const GROWTH_MARGIN: usize = 2; + + let mut host = DefaultHost::default(); + + let pushes_past_initial_buffer = DEFAULT_MAX_STACK_DEPTH - MIN_STACK_DEPTH + GROWTH_MARGIN; + let program = simple_program_with_ops(pad_then_drop_ops(pushes_past_initial_buffer)); + let options = ExecutionOptions::default() + .with_max_stack_depth(DEFAULT_MAX_STACK_DEPTH + GROWTH_MARGIN) + .unwrap(); + + let trace_inputs = + FastProcessor::new_with_options(StackInputs::default(), AdviceInputs::default(), options) + .expect("processor advice inputs should fit advice map limits") + .execute_trace_inputs_sync(&program, &mut host) + .expect("traced execution should grow the stack buffer past the initial buffer"); + + crate::trace::build_trace(trace_inputs) + .expect("trace replay should accept the same operand stack depth limit"); +} + +#[test] +fn issue_2818_step_execution_stack_grows_past_initial_buffer() { + const GROWTH_MARGIN: usize = 2; + + let mut host = DefaultHost::default(); + + let pushes_past_initial_buffer = DEFAULT_MAX_STACK_DEPTH - MIN_STACK_DEPTH + GROWTH_MARGIN; + let program = simple_program_with_ops(pad_then_drop_ops(pushes_past_initial_buffer)); + let options = ExecutionOptions::default() + .with_max_stack_depth(DEFAULT_MAX_STACK_DEPTH + GROWTH_MARGIN) + .unwrap(); + + FastProcessor::new_with_options(StackInputs::default(), AdviceInputs::default(), options) + .expect("processor advice inputs should fit advice map limits") + .execute_by_step_sync(&program, &mut host) + .expect("step execution should grow the stack buffer past the initial buffer"); +} + +#[test] +fn issue_2818_restore_context_grows_stack_buffer_for_suspended_caller() { + let caller_overflow_len = DEFAULT_MAX_STACK_DEPTH - MIN_STACK_DEPTH + 1; + let options = ExecutionOptions::default() + .with_max_stack_depth(DEFAULT_MAX_STACK_DEPTH + 1) + .unwrap(); + let mut processor = + FastProcessor::new_with_options(StackInputs::default(), AdviceInputs::default(), options) + .expect("processor advice inputs should fit advice map limits"); + + assert_eq!(processor.stack.len(), INITIAL_STACK_BUFFER_SIZE); + processor.call_stack.push(ExecutionContextInfo { + overflow_stack: vec![Felt::from_u32(42); caller_overflow_len], + ctx: processor.ctx, + fn_hash: processor.caller_hash, + }); + + // The active callee context is still at the minimum stack depth and the storage has not grown. + // Restoring this suspended caller is what requires moving the active stack and growing storage. + processor + .restore_context() + .expect("restoring a suspended caller should grow the stack buffer when needed"); + assert!( + processor.stack.len() > INITIAL_STACK_BUFFER_SIZE, + "context restore should have grown the stack buffer" + ); + assert_eq!(processor.stack_size(), MIN_STACK_DEPTH + caller_overflow_len); +} + +#[test] +fn stack_buffer_is_not_preallocated_to_operand_stack_depth_limit() { + const GROWTH_MARGIN: usize = 2; + + let options = ExecutionOptions::default() + .with_max_stack_depth(DEFAULT_MAX_STACK_DEPTH + GROWTH_MARGIN) + .unwrap(); + let mut processor = + FastProcessor::new_with_options(StackInputs::default(), AdviceInputs::default(), options) + .expect("processor advice inputs should fit advice map limits"); + + assert_eq!( + processor.stack.len(), + INITIAL_STACK_BUFFER_SIZE, + "processor should start with the initial stack buffer, not the full depth limit" + ); + + let mut host = DefaultHost::default(); + processor + .execute_mut_sync( + &simple_program_with_ops(vec![Operation::Pad, Operation::Drop]), + &mut host, + ) + .expect("ordinary shallow stack use should succeed"); + assert_eq!( + processor.stack.len(), + INITIAL_STACK_BUFFER_SIZE, + "ordinary shallow stack use should not grow the buffer" + ); + + let pushes_past_initial_buffer = DEFAULT_MAX_STACK_DEPTH - MIN_STACK_DEPTH + GROWTH_MARGIN; + let program = simple_program_with_ops(pad_then_drop_ops(pushes_past_initial_buffer)); + let mut processor = + FastProcessor::new_with_options(StackInputs::default(), AdviceInputs::default(), options) + .expect("processor advice inputs should fit advice map limits"); + let mut host = DefaultHost::default(); + + processor + .execute_mut_sync(&program, &mut host) + .expect("deep stack use should grow the buffer on demand"); + assert!( + processor.stack.len() > INITIAL_STACK_BUFFER_SIZE, + "deep stack use should grow the buffer only when needed" + ); +} + +#[test] +fn stack_growth_recenters_shallow_context_when_requested_len_exceeds_allocation_cap() { + let options = ExecutionOptions::default() + .with_max_stack_depth(DEFAULT_MAX_STACK_DEPTH) + .unwrap(); + let mut processor = + FastProcessor::new_with_options(StackInputs::default(), AdviceInputs::default(), options) + .expect("processor advice inputs should fit advice map limits"); + + // This models a callee that has only the minimum live stack depth, but is still positioned at + // the end of the current stack buffer after the caller filled the buffer and entered a new + // context. The next push requests one slot past the allocation cap using the old position, but + // growth can still succeed because it recenters the live stack before the push. + processor.stack_top_idx = INITIAL_STACK_BUFFER_SIZE - 1; + processor.stack_bot_idx = processor.stack_top_idx - MIN_STACK_DEPTH; + + processor + .ensure_stack_capacity_for_push() + .expect("recentered shallow context push should fit within the stack depth limit"); + + assert_eq!(processor.stack_bot_idx, STACK_BUFFER_BASE_IDX); + assert_eq!(processor.stack_top_idx, STACK_BUFFER_BASE_IDX + MIN_STACK_DEPTH); + assert_eq!(processor.stack.len(), INITIAL_STACK_BUFFER_SIZE); +} + +fn previous_growth_len( + stack_len: usize, + live_len: usize, + requested_min_len: usize, + max_len: usize, +) -> usize { + let recentered_min_len = STACK_BUFFER_BASE_IDX.saturating_add(live_len).saturating_add(2); + let required_len = requested_min_len.min(max_len).max(recentered_min_len); + + let mut new_len = stack_len; + while new_len < required_len { + let next_len = new_len.saturating_mul(2); + if next_len <= new_len { + return required_len; + } + new_len = next_len.min(max_len); + } + + new_len +} + +fn new_growth_len(live_len: usize, requested_min_len: usize, max_len: usize) -> usize { + let target_len = STACK_BUFFER_BASE_IDX + .saturating_add(live_len) + .saturating_add(2) + .saturating_mul(2); + + target_len.max(requested_min_len).min(max_len) +} + +#[derive(Debug, PartialEq, Eq)] +struct GrowthSemantics { + new_stack_bot_idx: usize, + new_stack_top_idx: usize, + covers_requested_len: bool, + covers_recentered_len: bool, + within_max_len: bool, +} + +fn growth_semantics( + new_len: usize, + live_len: usize, + requested_min_len: usize, + max_len: usize, +) -> GrowthSemantics { + let recentered_min_len = STACK_BUFFER_BASE_IDX.saturating_add(live_len).saturating_add(2); + + GrowthSemantics { + new_stack_bot_idx: STACK_BUFFER_BASE_IDX, + new_stack_top_idx: STACK_BUFFER_BASE_IDX + live_len, + covers_requested_len: new_len >= requested_min_len, + covers_recentered_len: new_len >= recentered_min_len, + within_max_len: new_len <= max_len, + } +} + +#[test] +fn new_stack_growth_algorithm_is_vm_equivalent_to_previous_algorithm() { + let max_depth = DEFAULT_MAX_STACK_DEPTH * 4; + let max_len = STACK_BUFFER_BASE_IDX.saturating_add(max_depth).saturating_add(1); + + for stack_len in [INITIAL_STACK_BUFFER_SIZE, INITIAL_STACK_BUFFER_SIZE * 2] { + // Push growth is called when the next push would need one slot past the current buffer. + let live_len = stack_len - STACK_BUFFER_BASE_IDX - 1; + let requested_min_len = stack_len + 1; + + let previous_len = previous_growth_len(stack_len, live_len, requested_min_len, max_len); + let new_len = new_growth_len(live_len, requested_min_len, max_len); + + assert_eq!( + growth_semantics(previous_len, live_len, requested_min_len, max_len), + growth_semantics(new_len, live_len, requested_min_len, max_len) + ); + } + + for overflow_len in 0..=(max_depth - MIN_STACK_DEPTH) { + // Restore growth is called from a callee with only the minimum live stack, but the + // requested length must cover the caller overflow stack being restored. + let requested_min_len = + INITIAL_STACK_TOP_IDX.saturating_add(overflow_len).saturating_add(1); + let previous_len = previous_growth_len( + INITIAL_STACK_BUFFER_SIZE, + MIN_STACK_DEPTH, + requested_min_len, + max_len, + ); + let new_len = new_growth_len(MIN_STACK_DEPTH, requested_min_len, max_len); + + assert_eq!( + growth_semantics(previous_len, MIN_STACK_DEPTH, requested_min_len, max_len), + growth_semantics(new_len, MIN_STACK_DEPTH, requested_min_len, max_len) + ); + } +} + +#[test] +fn new_stack_growth_algorithm_allocation_differences_are_intentional() { + let max_depth = DEFAULT_MAX_STACK_DEPTH * 4; + let max_len = STACK_BUFFER_BASE_IDX.saturating_add(max_depth).saturating_add(1); + + let push_live_len = INITIAL_STACK_BUFFER_SIZE - STACK_BUFFER_BASE_IDX - 1; + let push_requested_min_len = INITIAL_STACK_BUFFER_SIZE + 1; + assert_eq!( + previous_growth_len( + INITIAL_STACK_BUFFER_SIZE, + push_live_len, + push_requested_min_len, + max_len, + ), + INITIAL_STACK_BUFFER_SIZE * 2 + ); + assert_eq!( + new_growth_len(push_live_len, push_requested_min_len, max_len), + INITIAL_STACK_BUFFER_SIZE * 2 + 2 + ); + + let restore_requested_min_len = INITIAL_STACK_BUFFER_SIZE + 1; + assert_eq!( + previous_growth_len( + INITIAL_STACK_BUFFER_SIZE, + MIN_STACK_DEPTH, + restore_requested_min_len, + max_len, + ), + INITIAL_STACK_BUFFER_SIZE * 2 + ); + assert_eq!( + new_growth_len(MIN_STACK_DEPTH, restore_requested_min_len, max_len), + restore_requested_min_len + ); +} + +#[test] +fn new_stack_growth_algorithm_preserves_required_bounds() { + let max_depth = DEFAULT_MAX_STACK_DEPTH * 4; + let max_len = STACK_BUFFER_BASE_IDX.saturating_add(max_depth).saturating_add(1); + + for live_len in MIN_STACK_DEPTH..max_depth { + let recentered_min_len = STACK_BUFFER_BASE_IDX.saturating_add(live_len).saturating_add(2); + let requested_min_len = recentered_min_len.max(INITIAL_STACK_BUFFER_SIZE + 1); + let new_len = new_growth_len(live_len, requested_min_len, max_len); + + assert!(new_len >= requested_min_len); + assert!(new_len >= recentered_min_len); + assert!(new_len <= max_len); + } + + for overflow_len in 0..=(max_depth - MIN_STACK_DEPTH) { + let requested_min_len = + INITIAL_STACK_TOP_IDX.saturating_add(overflow_len).saturating_add(1); + let new_len = new_growth_len(MIN_STACK_DEPTH, requested_min_len, max_len); + + assert!(new_len >= requested_min_len); + assert!(new_len <= max_len); + } +} + +#[test] +fn stack_depth_limit_exceeded() { + let mut host = DefaultHost::default(); + let program = simple_program_with_ops(vec![Operation::Pad]); + let options = ExecutionOptions::default().with_max_stack_depth(MIN_STACK_DEPTH).unwrap(); + + let err = + FastProcessor::new_with_options(StackInputs::default(), AdviceInputs::default(), options) + .expect("processor advice inputs should fit advice map limits") + .execute_sync(&program, &mut host) + .expect_err("pushing past the configured stack depth should fail"); + + assert_matches!( + err, + ExecutionError::StackDepthLimitExceeded { + depth, + max: MIN_STACK_DEPTH, + } if depth == MIN_STACK_DEPTH + 1 + ); +} + /// Tests that `ExecutionError::Internal` is correctly emitted when the continuation stack grows /// past the maximum allowed size. #[test] @@ -604,12 +1000,41 @@ fn test_continuation_stack_limit_exceeded() { let options = ExecutionOptions::default().with_max_num_continuations(3); let processor = - FastProcessor::new_with_options(StackInputs::default(), AdviceInputs::default(), options); + FastProcessor::new_with_options(StackInputs::default(), AdviceInputs::default(), options) + .expect("processor advice inputs should fit advice map limits"); let err = processor.execute_sync(&program, &mut host).unwrap_err(); assert_matches!(err, ExecutionError::Internal(msg) if msg.contains("continuation stack")); } +/// Tests that a continuation stack size exactly equal to `max_num_continuations` succeeds. +#[test] +fn test_continuation_stack_limit_exactly_max_continuations_succeeds() { + let mut host = DefaultHost::default(); + + let program = { + let mut forest = MastForest::new(); + + let leaf_id = BasicBlockNodeBuilder::new(vec![Operation::Noop], Vec::new()) + .add_to_forest(&mut forest) + .unwrap(); + + let root = JoinNodeBuilder::new([leaf_id, leaf_id]).add_to_forest(&mut forest).unwrap(); + forest.make_root(root); + Program::new(forest.into(), root) + }; + + // A single join peaks at three continuations after the join start step: + // FinishJoin(root), StartNode(second), StartNode(first). + let options = ExecutionOptions::default().with_max_num_continuations(3); + + let processor = + FastProcessor::new_with_options(StackInputs::default(), AdviceInputs::default(), options) + .expect("processor advice inputs should fit advice map limits"); + + processor.execute_sync(&program, &mut host).unwrap(); +} + // TEST HELPERS // ----------------------------------------------------------------------------------------------- @@ -625,3 +1050,9 @@ fn simple_program_with_ops(ops: Vec) -> Program { program } + +fn pad_then_drop_ops(num_pads: usize) -> Vec { + let mut ops = vec![Operation::Pad; num_pads]; + ops.extend(vec![Operation::Drop; num_pads]); + ops +} diff --git a/processor/src/fast/tests/snapshots/miden_processor__fast__tests__advice_provider__trace_events.snap b/processor/src/fast/tests/snapshots/miden_processor__fast__tests__advice_provider__trace_events.snap index d7f5b72af9..e7719f3b54 100644 --- a/processor/src/fast/tests/snapshots/miden_processor__fast__tests__advice_provider__trace_events.snap +++ b/processor/src/fast/tests/snapshots/miden_processor__fast__tests__advice_provider__trace_events.snap @@ -1,6 +1,6 @@ --- source: processor/src/fast/tests/advice_provider.rs -assertion_line: 158 +assertion_line: 159 expression: fast_host.snapshots() --- { @@ -1344,49 +1344,49 @@ expression: fast_host.snapshots() MemoryAddress( 4, ), - 14528205893058374966, + 5184299127584737771, ), ( MemoryAddress( 5, ), - 10002243075344689708, + 17451682756172818109, ), ( MemoryAddress( 6, ), - 15326677089220390934, + 15042230557705027576, ), ( MemoryAddress( 7, ), - 11326013503063617228, + 14158574167506544015, ), ( MemoryAddress( 8, ), - 10259164447876083181, + 2496820811072890604, ), ( MemoryAddress( 9, ), - 3748228606777477704, + 4754492454862636102, ), ( MemoryAddress( 10, ), - 16172479349089150495, + 2102086890144081042, ), ( MemoryAddress( 11, ), - 13679129518036048304, + 10554372059076939352, ), ( MemoryAddress( @@ -1668,25 +1668,25 @@ expression: fast_host.snapshots() MemoryAddress( 4, ), - 14528205893058374966, + 5184299127584737771, ), ( MemoryAddress( 5, ), - 10002243075344689708, + 17451682756172818109, ), ( MemoryAddress( 6, ), - 15326677089220390934, + 15042230557705027576, ), ( MemoryAddress( 7, ), - 11326013503063617228, + 14158574167506544015, ), ( MemoryAddress( @@ -1830,49 +1830,49 @@ expression: fast_host.snapshots() MemoryAddress( 4, ), - 14528205893058374966, + 5184299127584737771, ), ( MemoryAddress( 5, ), - 10002243075344689708, + 17451682756172818109, ), ( MemoryAddress( 6, ), - 15326677089220390934, + 15042230557705027576, ), ( MemoryAddress( 7, ), - 11326013503063617228, + 14158574167506544015, ), ( MemoryAddress( 8, ), - 10259164447876083181, + 2496820811072890604, ), ( MemoryAddress( 9, ), - 3748228606777477704, + 4754492454862636102, ), ( MemoryAddress( 10, ), - 16172479349089150495, + 2102086890144081042, ), ( MemoryAddress( 11, ), - 13679129518036048304, + 10554372059076939352, ), ( MemoryAddress( @@ -2016,49 +2016,49 @@ expression: fast_host.snapshots() MemoryAddress( 4, ), - 4491847012518304166, + 163376667295860622, ), ( MemoryAddress( 5, ), - 4238546555679339688, + 3645880226357970599, ), ( MemoryAddress( 6, ), - 9254174781851869056, + 17530920680071307298, ), ( MemoryAddress( 7, ), - 7138823908759644402, + 14248036087791459349, ), ( MemoryAddress( 8, ), - 10259164447876083181, + 2496820811072890604, ), ( MemoryAddress( 9, ), - 3748228606777477704, + 4754492454862636102, ), ( MemoryAddress( 10, ), - 16172479349089150495, + 2102086890144081042, ), ( MemoryAddress( 11, ), - 13679129518036048304, + 10554372059076939352, ), ( MemoryAddress( @@ -2203,49 +2203,49 @@ expression: fast_host.snapshots() MemoryAddress( 4, ), - 4491847012518304166, + 163376667295860622, ), ( MemoryAddress( 5, ), - 4238546555679339688, + 3645880226357970599, ), ( MemoryAddress( 6, ), - 9254174781851869056, + 17530920680071307298, ), ( MemoryAddress( 7, ), - 7138823908759644402, + 14248036087791459349, ), ( MemoryAddress( 8, ), - 10259164447876083181, + 2496820811072890604, ), ( MemoryAddress( 9, ), - 3748228606777477704, + 4754492454862636102, ), ( MemoryAddress( 10, ), - 16172479349089150495, + 2102086890144081042, ), ( MemoryAddress( 11, ), - 13679129518036048304, + 10554372059076939352, ), ( MemoryAddress( @@ -2389,49 +2389,49 @@ expression: fast_host.snapshots() MemoryAddress( 4, ), - 4491847012518304166, + 163376667295860622, ), ( MemoryAddress( 5, ), - 4238546555679339688, + 3645880226357970599, ), ( MemoryAddress( 6, ), - 9254174781851869056, + 17530920680071307298, ), ( MemoryAddress( 7, ), - 7138823908759644402, + 14248036087791459349, ), ( MemoryAddress( 8, ), - 10259164447876083181, + 2496820811072890604, ), ( MemoryAddress( 9, ), - 3748228606777477704, + 4754492454862636102, ), ( MemoryAddress( 10, ), - 16172479349089150495, + 2102086890144081042, ), ( MemoryAddress( 11, ), - 13679129518036048304, + 10554372059076939352, ), ( MemoryAddress( @@ -2576,49 +2576,49 @@ expression: fast_host.snapshots() MemoryAddress( 4, ), - 4491847012518304166, + 163376667295860622, ), ( MemoryAddress( 5, ), - 4238546555679339688, + 3645880226357970599, ), ( MemoryAddress( 6, ), - 9254174781851869056, + 17530920680071307298, ), ( MemoryAddress( 7, ), - 7138823908759644402, + 14248036087791459349, ), ( MemoryAddress( 8, ), - 10259164447876083181, + 2496820811072890604, ), ( MemoryAddress( 9, ), - 3748228606777477704, + 4754492454862636102, ), ( MemoryAddress( 10, ), - 16172479349089150495, + 2102086890144081042, ), ( MemoryAddress( 11, ), - 13679129518036048304, + 10554372059076939352, ), ( MemoryAddress( @@ -2762,49 +2762,49 @@ expression: fast_host.snapshots() MemoryAddress( 4, ), - 4491847012518304166, + 163376667295860622, ), ( MemoryAddress( 5, ), - 4238546555679339688, + 3645880226357970599, ), ( MemoryAddress( 6, ), - 9254174781851869056, + 17530920680071307298, ), ( MemoryAddress( 7, ), - 7138823908759644402, + 14248036087791459349, ), ( MemoryAddress( 8, ), - 10259164447876083181, + 2496820811072890604, ), ( MemoryAddress( 9, ), - 3748228606777477704, + 4754492454862636102, ), ( MemoryAddress( 10, ), - 16172479349089150495, + 2102086890144081042, ), ( MemoryAddress( 11, ), - 13679129518036048304, + 10554372059076939352, ), ( MemoryAddress( @@ -2949,49 +2949,49 @@ expression: fast_host.snapshots() MemoryAddress( 4, ), - 4491847012518304166, + 163376667295860622, ), ( MemoryAddress( 5, ), - 4238546555679339688, + 3645880226357970599, ), ( MemoryAddress( 6, ), - 9254174781851869056, + 17530920680071307298, ), ( MemoryAddress( 7, ), - 7138823908759644402, + 14248036087791459349, ), ( MemoryAddress( 8, ), - 10259164447876083181, + 2496820811072890604, ), ( MemoryAddress( 9, ), - 3748228606777477704, + 4754492454862636102, ), ( MemoryAddress( 10, ), - 16172479349089150495, + 2102086890144081042, ), ( MemoryAddress( 11, ), - 13679129518036048304, + 10554372059076939352, ), ( MemoryAddress( @@ -3134,49 +3134,49 @@ expression: fast_host.snapshots() MemoryAddress( 4, ), - 4491847012518304166, + 163376667295860622, ), ( MemoryAddress( 5, ), - 4238546555679339688, + 3645880226357970599, ), ( MemoryAddress( 6, ), - 9254174781851869056, + 17530920680071307298, ), ( MemoryAddress( 7, ), - 7138823908759644402, + 14248036087791459349, ), ( MemoryAddress( 8, ), - 10259164447876083181, + 2496820811072890604, ), ( MemoryAddress( 9, ), - 3748228606777477704, + 4754492454862636102, ), ( MemoryAddress( 10, ), - 16172479349089150495, + 2102086890144081042, ), ( MemoryAddress( 11, ), - 13679129518036048304, + 10554372059076939352, ), ( MemoryAddress( @@ -3319,49 +3319,49 @@ expression: fast_host.snapshots() MemoryAddress( 4, ), - 4491847012518304166, + 163376667295860622, ), ( MemoryAddress( 5, ), - 4238546555679339688, + 3645880226357970599, ), ( MemoryAddress( 6, ), - 9254174781851869056, + 17530920680071307298, ), ( MemoryAddress( 7, ), - 7138823908759644402, + 14248036087791459349, ), ( MemoryAddress( 8, ), - 10259164447876083181, + 2496820811072890604, ), ( MemoryAddress( 9, ), - 3748228606777477704, + 4754492454862636102, ), ( MemoryAddress( 10, ), - 16172479349089150495, + 2102086890144081042, ), ( MemoryAddress( 11, ), - 13679129518036048304, + 10554372059076939352, ), ( MemoryAddress( @@ -3506,49 +3506,49 @@ expression: fast_host.snapshots() MemoryAddress( 4, ), - 4491847012518304166, + 163376667295860622, ), ( MemoryAddress( 5, ), - 4238546555679339688, + 3645880226357970599, ), ( MemoryAddress( 6, ), - 9254174781851869056, + 17530920680071307298, ), ( MemoryAddress( 7, ), - 7138823908759644402, + 14248036087791459349, ), ( MemoryAddress( 8, ), - 10259164447876083181, + 2496820811072890604, ), ( MemoryAddress( 9, ), - 3748228606777477704, + 4754492454862636102, ), ( MemoryAddress( 10, ), - 16172479349089150495, + 2102086890144081042, ), ( MemoryAddress( 11, ), - 13679129518036048304, + 10554372059076939352, ), ( MemoryAddress( @@ -3686,49 +3686,49 @@ expression: fast_host.snapshots() MemoryAddress( 4, ), - 4491847012518304166, + 163376667295860622, ), ( MemoryAddress( 5, ), - 4238546555679339688, + 3645880226357970599, ), ( MemoryAddress( 6, ), - 9254174781851869056, + 17530920680071307298, ), ( MemoryAddress( 7, ), - 7138823908759644402, + 14248036087791459349, ), ( MemoryAddress( 8, ), - 10259164447876083181, + 2496820811072890604, ), ( MemoryAddress( 9, ), - 3748228606777477704, + 4754492454862636102, ), ( MemoryAddress( 10, ), - 16172479349089150495, + 2102086890144081042, ), ( MemoryAddress( 11, ), - 13679129518036048304, + 10554372059076939352, ), ( MemoryAddress( @@ -4004,49 +4004,49 @@ expression: fast_host.snapshots() MemoryAddress( 4, ), - 4491847012518304166, + 163376667295860622, ), ( MemoryAddress( 5, ), - 4238546555679339688, + 3645880226357970599, ), ( MemoryAddress( 6, ), - 9254174781851869056, + 17530920680071307298, ), ( MemoryAddress( 7, ), - 7138823908759644402, + 14248036087791459349, ), ( MemoryAddress( 8, ), - 10259164447876083181, + 2496820811072890604, ), ( MemoryAddress( 9, ), - 3748228606777477704, + 4754492454862636102, ), ( MemoryAddress( 10, ), - 16172479349089150495, + 2102086890144081042, ), ( MemoryAddress( 11, ), - 13679129518036048304, + 10554372059076939352, ), ( MemoryAddress( diff --git a/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_01_vec_____operations_65_vec__Operation__HPerm_.snap b/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_01_vec_____operations_65_vec__Operation__HPerm_.snap index 8dc467a30a..d1358b9206 100644 --- a/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_01_vec_____operations_65_vec__Operation__HPerm_.snap +++ b/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_01_vec_____operations_65_vec__Operation__HPerm_.snap @@ -1,23 +1,23 @@ --- source: processor/src/fast/tests/all_ops.rs -assertion_line: 135 +assertion_line: 134 expression: fast_stack_outputs --- Ok( StackOutputs { elements: [ - 17235583951376661684, - 10083644464194131865, - 11409601709860874655, - 7577240030531334829, - 8506493735658085856, - 12669187451356861684, - 13514318840231451373, - 2992947611006288428, - 2342476110334384843, - 10439913347998057443, - 3445474787195226157, - 11568396492239269829, + 6571218845873207350, + 16394535650441775880, + 16729865362321995388, + 2844291130404209122, + 16063200788640006260, + 8977422641387935540, + 1100773186654011623, + 5296950920151051251, + 15508716854571599505, + 12365938385714563620, + 8500300421301734173, + 10881775167266999286, 0, 0, 0, diff --git a/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_02_vec__Felt__from_u32_1____operations_65_vec__Operation__HPerm_.snap b/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_02_vec__Felt__from_u32_1____operations_65_vec__Operation__HPerm_.snap index 3ed1be3791..38e7b01d4b 100644 --- a/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_02_vec__Felt__from_u32_1____operations_65_vec__Operation__HPerm_.snap +++ b/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_02_vec__Felt__from_u32_1____operations_65_vec__Operation__HPerm_.snap @@ -1,23 +1,22 @@ --- source: processor/src/fast/tests/all_ops.rs -assertion_line: 135 expression: fast_stack_outputs --- Ok( StackOutputs { elements: [ - 4479824471004609695, - 11911085689150556739, - 2866682401071334279, - 13063556788386096209, - 17973098356744174896, - 1074830276170501442, - 10925786739316964483, - 3901719002714985040, - 4546451181352198448, - 4489344781647936794, - 15204266792288945607, - 12234066309901722317, + 17455910245365348380, + 6832553410781580521, + 4005197613511741707, + 10253541772680548244, + 8364852239425393617, + 17505386921064310246, + 10706662992792322920, + 9654525249999507946, + 1047299952767701672, + 17539877794252713651, + 8114730363010872233, + 2122171766251887242, 0, 0, 0, diff --git a/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_03_vec__Felt__from_u32_1__Felt__from_u32_2____operations_65_vec__Operation__HPerm_.snap b/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_03_vec__Felt__from_u32_1__Felt__from_u32_2____operations_65_vec__Operation__HPerm_.snap index a19593a460..31c2154528 100644 --- a/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_03_vec__Felt__from_u32_1__Felt__from_u32_2____operations_65_vec__Operation__HPerm_.snap +++ b/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_03_vec__Felt__from_u32_1__Felt__from_u32_2____operations_65_vec__Operation__HPerm_.snap @@ -1,23 +1,22 @@ --- source: processor/src/fast/tests/all_ops.rs -assertion_line: 135 expression: fast_stack_outputs --- Ok( StackOutputs { elements: [ - 9164423616874635022, - 5941761159324491805, - 1501772137076846051, - 15752539538529161801, - 14208820683379630599, - 16484765646526118485, - 2396462519807773405, - 12703712861061551486, - 9499735573051879451, - 1455415507426042485, - 6594988977303351788, - 17002655751260034903, + 5791514288802007582, + 11370873416709992192, + 16398175753252366112, + 17632797390744920413, + 17881867204644557255, + 5661514241988971844, + 5048976572975064301, + 11074934715412329393, + 9159878505163050089, + 9499582931776386687, + 6221384515027069110, + 13000986385983645199, 0, 0, 0, diff --git a/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_04_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3____operations_65_vec__Operation__HPerm_.snap b/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_04_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3____operations_65_vec__Operation__HPerm_.snap index b4bbe3dfe5..952d9bb8f4 100644 --- a/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_04_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3____operations_65_vec__Operation__HPerm_.snap +++ b/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_04_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3____operations_65_vec__Operation__HPerm_.snap @@ -1,23 +1,22 @@ --- source: processor/src/fast/tests/all_ops.rs -assertion_line: 135 expression: fast_stack_outputs --- Ok( StackOutputs { elements: [ - 11274073450356067976, - 15815722435374099274, - 17820970150334694408, - 15630110688805608105, - 8966280661394520081, - 2936541456440881777, - 13662205957903548341, - 5552323316829092811, - 16007296129608446829, - 12684637471700515893, - 3593043717092405704, - 7526218217857528175, + 6599509807631651682, + 3658595305965272078, + 11154392636487252063, + 16345594221965239300, + 12375027178591107970, + 844741852058579016, + 14968027197433915838, + 3773477144943551340, + 1802317346910135014, + 7902574739790854118, + 13274653586351989421, + 3873845901700663669, 0, 0, 0, diff --git a/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_05_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_65_vec__Operation__HPerm_.snap b/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_05_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_65_vec__Operation__HPerm_.snap index 03eaad4924..020890149d 100644 --- a/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_05_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_65_vec__Operation__HPerm_.snap +++ b/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_05_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_65_vec__Operation__HPerm_.snap @@ -1,23 +1,22 @@ --- source: processor/src/fast/tests/all_ops.rs -assertion_line: 135 expression: fast_stack_outputs --- Ok( StackOutputs { elements: [ - 3268190814961491436, - 1488680730895588193, - 2286185831284995639, - 8644526748136604730, - 8452048350027914148, - 15993120682537482033, - 9923321615730191340, - 13593862298035447804, - 17768924324271485746, - 12547607158593337792, - 12680742430385726821, - 6196646796297290071, + 2353468074576525019, + 11515885715665303456, + 16861259375362574542, + 13083346552201796764, + 14620457192644002984, + 11043029007095970993, + 9718957964093791308, + 16012941698970619541, + 2405091240790409555, + 15009746800011104877, + 3267753577816193092, + 14938279376941628125, 0, 0, 0, diff --git a/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_06_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_65_vec__Operation__HPerm_.snap b/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_06_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_65_vec__Operation__HPerm_.snap index ca57bb0692..f10595900e 100644 --- a/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_06_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_65_vec__Operation__HPerm_.snap +++ b/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_06_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_65_vec__Operation__HPerm_.snap @@ -1,23 +1,22 @@ --- source: processor/src/fast/tests/all_ops.rs -assertion_line: 135 expression: fast_stack_outputs --- Ok( StackOutputs { elements: [ - 7990607168939163795, - 9498983967354495525, - 8002718409520801727, - 1492571359694440300, - 18425757046949514735, - 11215491611975966450, - 4666436629716968449, - 673894918047172708, - 314515619064233224, - 8811122795494577882, - 15806744581261270778, - 14327912189600712010, + 13363521242936483155, + 206696360459131660, + 10192065751917015241, + 8847072300198232031, + 15887831930496356326, + 14317595769594204925, + 10369947195256127299, + 2284563656427448679, + 2565139298116607198, + 15392631554294074198, + 16294234802149031576, + 8370500975236844806, 0, 0, 0, diff --git a/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_07_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_65_vec__Operation__HPerm_.snap b/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_07_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_65_vec__Operation__HPerm_.snap index 7795d59581..20207cb5a2 100644 --- a/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_07_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_65_vec__Operation__HPerm_.snap +++ b/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_07_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_65_vec__Operation__HPerm_.snap @@ -1,23 +1,22 @@ --- source: processor/src/fast/tests/all_ops.rs -assertion_line: 135 expression: fast_stack_outputs --- Ok( StackOutputs { elements: [ - 671991757919180502, - 12466007527255172286, - 4466077373719406959, - 16551433650283727430, - 5318845950311173892, - 6815018521920641786, - 9368097095824314056, - 17735685170104324865, - 15006790259484023058, - 1857099212867630968, - 16412552972317651415, - 1496105740998126279, + 4667339602351854292, + 18159046276642031647, + 4510728384430376441, + 3802486729163867609, + 7828132104839559123, + 3241147342483020453, + 9615124367822181878, + 8430736170527717926, + 15880659927416966887, + 6315202759208895045, + 10093602094366555615, + 13730260884363791433, 0, 0, 0, diff --git a/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_08_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_65_vec__Operation__HPerm_.snap b/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_08_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_65_vec__Operation__HPerm_.snap index 75b034764f..60c6a6f4a0 100644 --- a/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_08_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_65_vec__Operation__HPerm_.snap +++ b/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_08_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_65_vec__Operation__HPerm_.snap @@ -1,23 +1,22 @@ --- source: processor/src/fast/tests/all_ops.rs -assertion_line: 135 expression: fast_stack_outputs --- Ok( StackOutputs { elements: [ - 6263680378774352277, - 9279771031059472698, - 13546434408043569558, - 7687412803303528446, - 12713896232409823588, - 2893532390780102989, - 11535410126291011009, - 8349464623600469207, - 14296079793316461816, - 5020442677979956824, - 10561749224916480247, - 7897590573115575364, + 14580400598076117747, + 12862870230236996768, + 13251835182682981414, + 15628141822255708082, + 9628690596649727345, + 12324934267245352874, + 1483956613176918570, + 3883706149861120285, + 6213881485243866120, + 2827751809845328397, + 9932437693152254451, + 3144283263496216171, 0, 0, 0, diff --git a/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_09_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_65_vec__Operation__HPerm_.snap b/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_09_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_65_vec__Operation__HPerm_.snap index 174d9bdf1d..0433f52183 100644 --- a/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_09_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_65_vec__Operation__HPerm_.snap +++ b/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_09_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_65_vec__Operation__HPerm_.snap @@ -1,23 +1,22 @@ --- source: processor/src/fast/tests/all_ops.rs -assertion_line: 135 expression: fast_stack_outputs --- Ok( StackOutputs { elements: [ - 14169459326663239568, - 11007621527201139918, - 14501677898772564345, - 7338250321276309337, - 12493530127940321746, - 4247975686057378059, - 2211474754412158822, - 14628179861099512048, - 17855737964673825435, - 18228642351235930419, - 12894130174218584556, - 9020642757710095097, + 12175850710574191021, + 13800397389470483709, + 10717919348058185020, + 5151936205780666844, + 10291964643087183853, + 14779717229392016912, + 14290514441950687491, + 13791650757144473752, + 15845077848276659080, + 16000617562050663817, + 13055526489431477437, + 6605640152688323436, 0, 0, 0, diff --git a/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_10_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_65_vec__Operation__HPerm_.snap b/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_10_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_65_vec__Operation__HPerm_.snap index 934555f5d3..3f292dfb66 100644 --- a/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_10_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_65_vec__Operation__HPerm_.snap +++ b/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_10_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_65_vec__Operation__HPerm_.snap @@ -1,23 +1,22 @@ --- source: processor/src/fast/tests/all_ops.rs -assertion_line: 135 expression: fast_stack_outputs --- Ok( StackOutputs { elements: [ - 10775936814798533358, - 717837267233237073, - 6483381374078582797, - 51209481100416195, - 11339414429114857210, - 15738267391211900405, - 6069766725807781859, - 14238728327240552339, - 5019069159821100045, - 2424991439256656916, - 15608469037412457919, - 5433644271130838389, + 17060849736193631575, + 9437431550433740330, + 4790787753101722654, + 13928475910023407549, + 5681572831771938305, + 17441327217307150836, + 380938787849249752, + 9250343451371816604, + 8085017466841934730, + 12335558491746498352, + 7364384275669594926, + 10438406874817038491, 0, 0, 0, diff --git a/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_11_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_65_vec__Operation__HPerm_.snap b/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_11_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_65_vec__Operation__HPerm_.snap index 1e9a2017b6..69bf0ab5d4 100644 --- a/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_11_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_65_vec__Operation__HPerm_.snap +++ b/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_11_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_65_vec__Operation__HPerm_.snap @@ -1,23 +1,22 @@ --- source: processor/src/fast/tests/all_ops.rs -assertion_line: 135 expression: fast_stack_outputs --- Ok( StackOutputs { elements: [ - 6513841105929115274, - 8452859522714636211, - 12785460359391503614, - 16075074459222436687, - 1386110757868123007, - 10829091722528621837, - 11388383770755416995, - 2739804518057946324, - 12619774244900105618, - 5155751796348001624, - 8345179732046761616, - 6143280867542628106, + 5586993864370339724, + 1868361575743815124, + 8963108921496263854, + 16436362863946497702, + 11846713062559823253, + 16178497959751826781, + 12669434307665867770, + 1348613851626606283, + 9634176741319834489, + 17634317287326092044, + 407916618999768508, + 13138468015286270637, 0, 0, 0, diff --git a/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_12_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_65_vec__Operation__HPerm_.snap b/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_12_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_65_vec__Operation__HPerm_.snap index 6faf5600d2..74144d6769 100644 --- a/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_12_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_65_vec__Operation__HPerm_.snap +++ b/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_12_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_65_vec__Operation__HPerm_.snap @@ -1,23 +1,22 @@ --- source: processor/src/fast/tests/all_ops.rs -assertion_line: 135 expression: fast_stack_outputs --- Ok( StackOutputs { elements: [ - 17966300967277909844, - 2061493019207963774, - 2380049000948598281, - 14382057426864304835, - 6533668052888309526, - 8872475309913852926, - 18015717762819057015, - 16490550559779846365, - 8062829296065603817, - 8942423709565274232, - 14148376995225537024, - 4593484252994392826, + 13109608066154500912, + 17884936513248079792, + 16585897853219181604, + 11373944235420141268, + 16714917479629630886, + 17788758792634084805, + 474869837271505314, + 15651443784496617038, + 17867373004810114811, + 6266341860788427359, + 5436129488805537434, + 2449971071261804935, 0, 0, 0, diff --git a/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_12_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_66_vec__Operation__FriE2F4_.snap b/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_12_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_66_vec__Operation__FriE2F4_.snap index 3f0e973429..cf5c234054 100644 --- a/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_12_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_66_vec__Operation__FriE2F4_.snap +++ b/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_12_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_66_vec__Operation__FriE2F4_.snap @@ -17,7 +17,7 @@ Err( }, source_file: None, err: FriError( - "domain segment value cannot exceed 3, but was 10", + "degree-respecting projection is inconsistent at d_seg=2 poe=11 fpos=2: expected 0 but was 5 + 6 X; all values: [0]=1 + 2 X [1]=3 + 4 X [2]=5 + 6 X [3]=7 + 8 X", ), }, ) diff --git a/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_13_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_65_vec__Operation__HPerm_.snap b/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_13_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_65_vec__Operation__HPerm_.snap index 3a1a05e18e..b2b2b01a07 100644 --- a/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_13_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_65_vec__Operation__HPerm_.snap +++ b/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_13_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_65_vec__Operation__HPerm_.snap @@ -1,23 +1,22 @@ --- source: processor/src/fast/tests/all_ops.rs -assertion_line: 135 expression: fast_stack_outputs --- Ok( StackOutputs { elements: [ - 2503707170632265954, - 15180655835972913581, - 6548692545207744731, - 7938385606554554595, - 14763055227748061529, - 5556446269561107255, - 15735462690091524251, - 14917303742821939652, - 8669843507636010842, - 17572366888672974210, - 13099123354528731374, - 260611570515428088, + 907345902243359370, + 7828947614562846950, + 11457993704067699945, + 3892495100168374213, + 13851442350130782381, + 11237433120130255027, + 8208890525312016619, + 12497592728156559685, + 5679820591634267396, + 11619687737260192666, + 15600433222549891385, + 3047245305681446692, 0, 0, 0, diff --git a/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_13_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_66_vec__Operation__FriE2F4_.snap b/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_13_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_66_vec__Operation__FriE2F4_.snap index 3f0e973429..198ad8de80 100644 --- a/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_13_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_66_vec__Operation__FriE2F4_.snap +++ b/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_13_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_66_vec__Operation__FriE2F4_.snap @@ -17,7 +17,7 @@ Err( }, source_file: None, err: FriError( - "domain segment value cannot exceed 3, but was 10", + "degree-respecting projection is inconsistent at d_seg=2 poe=11 fpos=2: expected 12 but was 5 + 6 X; all values: [0]=1 + 2 X [1]=3 + 4 X [2]=5 + 6 X [3]=7 + 8 X", ), }, ) diff --git a/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_14_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_65_vec__Operation__HPerm_.snap b/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_14_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_65_vec__Operation__HPerm_.snap index 2283fca5e5..63786242dc 100644 --- a/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_14_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_65_vec__Operation__HPerm_.snap +++ b/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_14_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_65_vec__Operation__HPerm_.snap @@ -1,23 +1,22 @@ --- source: processor/src/fast/tests/all_ops.rs -assertion_line: 135 expression: fast_stack_outputs --- Ok( StackOutputs { elements: [ - 2503707170632265954, - 15180655835972913581, - 6548692545207744731, - 7938385606554554595, - 14763055227748061529, - 5556446269561107255, - 15735462690091524251, - 14917303742821939652, - 8669843507636010842, - 17572366888672974210, - 13099123354528731374, - 260611570515428088, + 907345902243359370, + 7828947614562846950, + 11457993704067699945, + 3892495100168374213, + 13851442350130782381, + 11237433120130255027, + 8208890525312016619, + 12497592728156559685, + 5679820591634267396, + 11619687737260192666, + 15600433222549891385, + 3047245305681446692, 13, 0, 0, diff --git a/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_14_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_66_vec__Operation__FriE2F4_.snap b/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_14_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_66_vec__Operation__FriE2F4_.snap index 3f0e973429..59cc8fbb58 100644 --- a/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_14_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_66_vec__Operation__FriE2F4_.snap +++ b/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_14_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_66_vec__Operation__FriE2F4_.snap @@ -17,7 +17,7 @@ Err( }, source_file: None, err: FriError( - "domain segment value cannot exceed 3, but was 10", + "degree-respecting projection is inconsistent at d_seg=2 poe=11 fpos=2: expected 12 + 13 X but was 5 + 6 X; all values: [0]=1 + 2 X [1]=3 + 4 X [2]=5 + 6 X [3]=7 + 8 X", ), }, ) diff --git a/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_15_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_65_vec__Operation__HPerm_.snap b/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_15_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_65_vec__Operation__HPerm_.snap index 37a15cf936..054fc1c505 100644 --- a/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_15_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_65_vec__Operation__HPerm_.snap +++ b/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_15_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_65_vec__Operation__HPerm_.snap @@ -1,23 +1,22 @@ --- source: processor/src/fast/tests/all_ops.rs -assertion_line: 135 expression: fast_stack_outputs --- Ok( StackOutputs { elements: [ - 2503707170632265954, - 15180655835972913581, - 6548692545207744731, - 7938385606554554595, - 14763055227748061529, - 5556446269561107255, - 15735462690091524251, - 14917303742821939652, - 8669843507636010842, - 17572366888672974210, - 13099123354528731374, - 260611570515428088, + 907345902243359370, + 7828947614562846950, + 11457993704067699945, + 3892495100168374213, + 13851442350130782381, + 11237433120130255027, + 8208890525312016619, + 12497592728156559685, + 5679820591634267396, + 11619687737260192666, + 15600433222549891385, + 3047245305681446692, 13, 14, 0, diff --git a/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_15_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_66_vec__Operation__FriE2F4_.snap b/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_15_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_66_vec__Operation__FriE2F4_.snap index 3f0e973429..59cc8fbb58 100644 --- a/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_15_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_66_vec__Operation__FriE2F4_.snap +++ b/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_15_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_66_vec__Operation__FriE2F4_.snap @@ -17,7 +17,7 @@ Err( }, source_file: None, err: FriError( - "domain segment value cannot exceed 3, but was 10", + "degree-respecting projection is inconsistent at d_seg=2 poe=11 fpos=2: expected 12 + 13 X but was 5 + 6 X; all values: [0]=1 + 2 X [1]=3 + 4 X [2]=5 + 6 X [3]=7 + 8 X", ), }, ) diff --git a/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_16_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_65_vec__Operation__HPerm_.snap b/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_16_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_65_vec__Operation__HPerm_.snap index 5c7866b554..54fd9c7265 100644 --- a/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_16_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_65_vec__Operation__HPerm_.snap +++ b/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_16_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_65_vec__Operation__HPerm_.snap @@ -1,23 +1,22 @@ --- source: processor/src/fast/tests/all_ops.rs -assertion_line: 135 expression: fast_stack_outputs --- Ok( StackOutputs { elements: [ - 2503707170632265954, - 15180655835972913581, - 6548692545207744731, - 7938385606554554595, - 14763055227748061529, - 5556446269561107255, - 15735462690091524251, - 14917303742821939652, - 8669843507636010842, - 17572366888672974210, - 13099123354528731374, - 260611570515428088, + 907345902243359370, + 7828947614562846950, + 11457993704067699945, + 3892495100168374213, + 13851442350130782381, + 11237433120130255027, + 8208890525312016619, + 12497592728156559685, + 5679820591634267396, + 11619687737260192666, + 15600433222549891385, + 3047245305681446692, 13, 14, 15, diff --git a/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_16_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_66_vec__Operation__FriE2F4_.snap b/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_16_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_66_vec__Operation__FriE2F4_.snap index 3f0e973429..59cc8fbb58 100644 --- a/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_16_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_66_vec__Operation__FriE2F4_.snap +++ b/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_16_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_66_vec__Operation__FriE2F4_.snap @@ -17,7 +17,7 @@ Err( }, source_file: None, err: FriError( - "domain segment value cannot exceed 3, but was 10", + "degree-respecting projection is inconsistent at d_seg=2 poe=11 fpos=2: expected 12 + 13 X but was 5 + 6 X; all values: [0]=1 + 2 X [1]=3 + 4 X [2]=5 + 6 X [3]=7 + 8 X", ), }, ) diff --git a/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_17_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_65_vec__Operation__HPerm_.snap b/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_17_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_65_vec__Operation__HPerm_.snap index b6a63b1557..b88b6aec28 100644 --- a/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_17_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_65_vec__Operation__HPerm_.snap +++ b/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_17_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_65_vec__Operation__HPerm_.snap @@ -1,23 +1,22 @@ --- source: processor/src/fast/tests/all_ops.rs -assertion_line: 135 expression: fast_stack_outputs --- Ok( StackOutputs { elements: [ - 2503707170632265954, - 15180655835972913581, - 6548692545207744731, - 7938385606554554595, - 14763055227748061529, - 5556446269561107255, - 15735462690091524251, - 14917303742821939652, - 8669843507636010842, - 17572366888672974210, - 13099123354528731374, - 260611570515428088, + 907345902243359370, + 7828947614562846950, + 11457993704067699945, + 3892495100168374213, + 13851442350130782381, + 11237433120130255027, + 8208890525312016619, + 12497592728156559685, + 5679820591634267396, + 11619687737260192666, + 15600433222549891385, + 3047245305681446692, 13, 14, 15, diff --git a/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_17_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_66_vec__Operation__FriE2F4_.snap b/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_17_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_66_vec__Operation__FriE2F4_.snap index 3f0e973429..59cc8fbb58 100644 --- a/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_17_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_66_vec__Operation__FriE2F4_.snap +++ b/processor/src/fast/tests/snapshots/miden_processor__fast__tests__all_ops__fast__tests__all_ops__test_basic_block__stack_inputs_17_vec__Felt__from_u32_1__Felt__from_u32_2__Felt__from_u32_3__Felt___operations_66_vec__Operation__FriE2F4_.snap @@ -17,7 +17,7 @@ Err( }, source_file: None, err: FriError( - "domain segment value cannot exceed 3, but was 10", + "degree-respecting projection is inconsistent at d_seg=2 poe=11 fpos=2: expected 12 + 13 X but was 5 + 6 X; all values: [0]=1 + 2 X [1]=3 + 4 X [2]=5 + 6 X [3]=7 + 8 X", ), }, ) diff --git a/processor/src/fast/tests/snapshots/miden_processor__fast__tests__frie2f4.snap b/processor/src/fast/tests/snapshots/miden_processor__fast__tests__frie2f4.snap index 6cfb2abbb5..d08d2c19a5 100644 --- a/processor/src/fast/tests/snapshots/miden_processor__fast__tests__frie2f4.snap +++ b/processor/src/fast/tests/snapshots/miden_processor__fast__tests__frie2f4.snap @@ -1,24 +1,25 @@ --- source: processor/src/fast/tests/mod.rs +assertion_line: 393 expression: stack_outputs --- StackOutputs { elements: [ - 17129119493027828304, - 17129119493027828312, - 7906149565430122801, - 10542846303798146793, - 0, + 6590052996059796070, + 10542705566309791467, + 15811494916641072287, + 7905747458320536148, 0, 1, 0, + 0, 49, - 18446744069414584320, + 18446462594437873665, 9, 2401, 9, - 15112046832839714565, - 3656396054197128425, + 14492051010740125224, + 6668243544126892022, 0, ], } diff --git a/processor/src/fast/tests/snapshots/miden_processor__fast__tests__masm_consistency__fast__tests__masm_consistency__test_masm_consistency__case_03.snap b/processor/src/fast/tests/snapshots/miden_processor__fast__tests__masm_consistency__fast__tests__masm_consistency__test_masm_consistency__case_03.snap index 0db589ecab..959576a5d7 100644 --- a/processor/src/fast/tests/snapshots/miden_processor__fast__tests__masm_consistency__fast__tests__masm_consistency__test_masm_consistency__case_03.snap +++ b/processor/src/fast/tests/snapshots/miden_processor__fast__tests__masm_consistency__fast__tests__masm_consistency__test_masm_consistency__case_03.snap @@ -1,14 +1,13 @@ --- source: processor/src/fast/tests/masm_consistency.rs -assertion_line: 273 expression: fast_stack_outputs --- StackOutputs { elements: [ - 2229435470361087275, - 7423332830524758578, - 15027361523733553720, - 18289623750613555234, + 801716320522881597, + 1003970481894184430, + 825403729357249437, + 12056788342160990837, 16, 16, 16, diff --git a/processor/src/fast/tests/snapshots/miden_processor__fast__tests__masm_consistency__fast__tests__masm_consistency__test_masm_consistency__case_26.snap b/processor/src/fast/tests/snapshots/miden_processor__fast__tests__masm_consistency__fast__tests__masm_consistency__test_masm_consistency__case_26.snap index b784250b67..892e4612e4 100644 --- a/processor/src/fast/tests/snapshots/miden_processor__fast__tests__masm_consistency__fast__tests__masm_consistency__test_masm_consistency__case_26.snap +++ b/processor/src/fast/tests/snapshots/miden_processor__fast__tests__masm_consistency__fast__tests__masm_consistency__test_masm_consistency__case_26.snap @@ -1,22 +1,21 @@ --- source: processor/src/fast/tests/masm_consistency.rs -assertion_line: 273 expression: fast_stack_outputs --- StackOutputs { elements: [ - 14169459326663239568, - 11007621527201139918, - 14501677898772564345, - 7338250321276309337, - 12493530127940321746, - 4247975686057378059, - 2211474754412158822, - 14628179861099512048, - 17855737964673825435, - 18228642351235930419, - 12894130174218584556, - 9020642757710095097, + 12175850710574191021, + 13800397389470483709, + 10717919348058185020, + 5151936205780666844, + 10291964643087183853, + 14779717229392016912, + 14290514441950687491, + 13791650757144473752, + 15845077848276659080, + 16000617562050663817, + 13055526489431477437, + 6605640152688323436, 0, 0, 0, diff --git a/processor/src/host/advice/errors.rs b/processor/src/host/advice/errors.rs index ce9250550d..9d8a3534a8 100644 --- a/processor/src/host/advice/errors.rs +++ b/processor/src/host/advice/errors.rs @@ -28,6 +28,10 @@ pub enum AdviceError { StackSizeExceeded { push_count: usize, max: usize }, #[error("advice map value size of {size} exceeds the maximum of {max}")] AdvMapValueSizeExceeded { size: usize, max: usize }, + #[error( + "advice map element budget exceeded: adding {added} elements to the current {current} would exceed the maximum of {max}" + )] + AdvMapElementBudgetExceeded { current: usize, added: usize, max: usize }, #[error( "provided merkle tree {depth} is out of bounds and cannot be represented as an unsigned 8-bit integer" )] diff --git a/processor/src/host/advice/mod.rs b/processor/src/host/advice/mod.rs index 217039a063..8bfdb4e5e6 100644 --- a/processor/src/host/advice/mod.rs +++ b/processor/src/host/advice/mod.rs @@ -1,19 +1,18 @@ -use alloc::{ - collections::{VecDeque, btree_map::Entry}, - vec::Vec, -}; +use alloc::{collections::VecDeque, vec::Vec}; use miden_core::{ - Felt, Word, + Felt, WORD_SIZE, Word, advice::{AdviceInputs, AdviceMap}, crypto::merkle::{InnerNodeInfo, MerklePath, MerkleStore, NodeIndex}, precompile::PrecompileRequest, }; +#[cfg(test)] +use miden_core::{crypto::hash::Blake3_256, serde::Serializable}; mod errors; pub use errors::AdviceError; -use crate::{host::AdviceMutation, processor::AdviceProviderInterface}; +use crate::{ExecutionOptions, host::AdviceMutation, processor::AdviceProviderInterface}; // CONSTANTS // ================================================================================================ @@ -28,6 +27,10 @@ const MAX_ADVICE_STACK_SIZE: usize = 1 << 17; /// the host (i.e., result of a computation performed outside of the VM), as well as insert new data /// into the advice provider to be recovered by the host after the program has finished executing. /// +/// Advice map size limits are enforced here, rather than by `AdviceMap`, because they are part of +/// execution policy. The provider owns the active `ExecutionOptions` and tracks the live advice map +/// budget across initial advice, host mutations, and system-event inserts. +/// /// An advice provider consists of the following components: /// 1. Advice stack, which is a LIFO data structure. The processor can move the elements from the /// advice stack onto the operand stack, as well as push new elements onto the advice stack. The @@ -46,16 +49,72 @@ const MAX_ADVICE_STACK_SIZE: usize = 1 << 17; /// or, /// - used to produce a STARK proof using a precompile VM, which can be verified in the epilog of /// the program. -#[derive(Debug, Clone, Default)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct AdviceProvider { stack: VecDeque, map: AdviceMap, + map_element_count: usize, + max_map_value_size: usize, + max_map_elements: usize, store: MerkleStore, pc_requests: Vec, } +impl Default for AdviceProvider { + fn default() -> Self { + Self::empty(&ExecutionOptions::default()) + } +} + impl AdviceProvider { + /// Creates a new advice provider from the provided inputs and execution options. + /// + /// The advice map limits in `options` are enforced while loading the initial advice inputs. + pub fn new(inputs: AdviceInputs, options: &ExecutionOptions) -> Result { + let AdviceInputs { stack, map, store } = inputs; + let mut provider = Self::empty(options); + provider.extend_stack(stack)?; + provider.extend_merkle_store(store.inner_nodes()); + provider.extend_map(&map)?; + Ok(provider) + } + + fn empty(options: &ExecutionOptions) -> Self { + Self { + stack: VecDeque::new(), + map: AdviceMap::default(), + map_element_count: 0, + max_map_value_size: options.max_adv_map_value_size(), + max_map_elements: options.max_adv_map_elements(), + store: MerkleStore::default(), + pc_requests: Vec::new(), + } + } + + pub(crate) fn set_options(&mut self, options: &ExecutionOptions) -> Result<(), AdviceError> { + Self::validate_map_values(&self.map, options.max_adv_map_value_size())?; + let map_element_count = + self.map.total_element_count().ok_or(AdviceError::AdvMapElementBudgetExceeded { + current: self.map_element_count, + added: usize::MAX, + max: options.max_adv_map_elements(), + })?; + if map_element_count > options.max_adv_map_elements() { + return Err(AdviceError::AdvMapElementBudgetExceeded { + current: 0, + added: map_element_count, + max: options.max_adv_map_elements(), + }); + } + + self.map_element_count = map_element_count; + self.max_map_value_size = options.max_adv_map_value_size(); + self.max_map_elements = options.max_adv_map_elements(); + Ok(()) + } + #[cfg(test)] + #[expect(dead_code)] pub(crate) fn merkle_store(&self) -> &MerkleStore { &self.store } @@ -86,6 +145,44 @@ impl AdviceProvider { Ok(()) } + /// Returns a stable fingerprint of the advice state. + /// + /// The fingerprint is insensitive to advice-map insertion order and Merkle-store insertion + /// order, but it still reflects advice-stack order and precompile-request order. + #[cfg(test)] + #[must_use] + pub(crate) fn fingerprint(&self) -> [u8; 32] { + let stack = self.stack.iter().copied().collect::>().to_bytes(); + let map = self.map.to_bytes(); + let mut store_nodes = self + .store + .inner_nodes() + .map(|info| (info.value, info.left, info.right)) + .collect::>(); + store_nodes.sort_unstable_by(|lhs, rhs| { + lhs.0 + .cmp(&rhs.0) + .then_with(|| lhs.1.cmp(&rhs.1)) + .then_with(|| lhs.2.cmp(&rhs.2)) + }); + let store = store_nodes + .into_iter() + .flat_map(|(value, left, right)| [value, left, right]) + .collect::>() + .to_bytes(); + let precompile_requests = self.pc_requests.to_bytes(); + Blake3_256::hash_iter( + [ + stack.as_slice(), + map.as_slice(), + store.as_slice(), + precompile_requests.as_slice(), + ] + .into_iter(), + ) + .into() + } + // ADVICE STACK // -------------------------------------------------------------------------------------------- @@ -222,12 +319,12 @@ impl AdviceProvider { // Treat map values as already canonical sequences of FELTs. // The advice stack is LIFO; extend in reverse so that the first element of `values` - // becomes the first element returned by a subsequent `adv_push.*`. + // becomes the first element returned by a subsequent `adv_push`. for &value in values.iter().rev() { self.stack.push_front(value); } if include_len { - self.stack.push_front(Felt::new(values.len() as u64)); + self.stack.push_front(Felt::new_unchecked(values.len() as u64)); } Ok(()) } @@ -260,7 +357,52 @@ impl AdviceProvider { /// Returns a reference to the value(s) associated with the specified key in the advice map. pub fn get_mapped_values(&self, key: &Word) -> Option<&[Felt]> { - self.map.get(key).map(|value| value.as_ref()) + self.map.get(key).map(AsRef::as_ref) + } + + fn validate_map_values(map: &AdviceMap, max_value_size: usize) -> Result<(), AdviceError> { + for (_, values) in map.iter() { + if values.len() > max_value_size { + return Err(AdviceError::AdvMapValueSizeExceeded { + size: values.len(), + max: max_value_size, + }); + } + } + Ok(()) + } + + fn entry_element_count(value_len: usize) -> Option { + WORD_SIZE.checked_add(value_len) + } + + fn check_map_value_size(&self, size: usize) -> Result<(), AdviceError> { + if size > self.max_map_value_size { + return Err(AdviceError::AdvMapValueSizeExceeded { + size, + max: self.max_map_value_size, + }); + } + Ok(()) + } + + fn check_map_element_budget(&self, added: usize) -> Result<(), AdviceError> { + let Some(new_total) = self.map_element_count.checked_add(added) else { + return Err(AdviceError::AdvMapElementBudgetExceeded { + current: self.map_element_count, + added, + max: self.max_map_elements, + }); + }; + + if new_total > self.max_map_elements { + return Err(AdviceError::AdvMapElementBudgetExceeded { + current: self.map_element_count, + added, + max: self.max_map_elements, + }); + } + Ok(()) } /// Inserts the provided value into the advice map under the specified key. @@ -270,12 +412,9 @@ impl AdviceProvider { /// /// Returns an error if the specified key is already present in the advice map. pub fn insert_into_map(&mut self, key: Word, values: Vec) -> Result<(), AdviceError> { - match self.map.entry(key) { - Entry::Vacant(entry) => { - entry.insert(values.into()); - }, - Entry::Occupied(entry) => { - let existing_values = entry.get().as_ref(); + match self.map.get(&key) { + Some(existing_values) => { + let existing_values = existing_values.as_ref(); if existing_values != values { return Err(AdviceError::MapKeyAlreadyPresent { key, @@ -284,6 +423,19 @@ impl AdviceProvider { }); } }, + None => { + self.check_map_value_size(values.len())?; + let added = Self::entry_element_count(values.len()).ok_or( + AdviceError::AdvMapElementBudgetExceeded { + current: self.map_element_count, + added: usize::MAX, + max: self.max_map_elements, + }, + )?; + self.check_map_element_budget(added)?; + self.map.insert(key, values); + self.map_element_count += added; + }, } Ok(()) } @@ -293,13 +445,46 @@ impl AdviceProvider { /// Returns an error if any new entry already exists with the same key but a different value /// than the one currently stored. The current map remains unchanged. pub fn extend_map(&mut self, other: &AdviceMap) -> Result<(), AdviceError> { + let mut added = 0usize; + for (key, values) in other.iter() { + if let Some(existing_values) = self.map.get(key) { + if existing_values.as_ref() != values.as_ref() { + return Err(AdviceError::MapKeyAlreadyPresent { + key: *key, + prev_values: existing_values.to_vec(), + new_values: values.to_vec(), + }); + } + continue; + } + + self.check_map_value_size(values.len())?; + let entry_elements = Self::entry_element_count(values.len()).ok_or( + AdviceError::AdvMapElementBudgetExceeded { + current: self.map_element_count, + added: usize::MAX, + max: self.max_map_elements, + }, + )?; + added = added.checked_add(entry_elements).ok_or( + AdviceError::AdvMapElementBudgetExceeded { + current: self.map_element_count, + added: usize::MAX, + max: self.max_map_elements, + }, + )?; + } + self.check_map_element_budget(added)?; + self.map.merge(other).map_err(|((key, prev_values), new_values)| { AdviceError::MapKeyAlreadyPresent { key, prev_values: prev_values.to_vec(), new_values: new_values.to_vec(), } - }) + })?; + self.map_element_count += added; + Ok(()) } // MERKLE STORE @@ -457,18 +642,6 @@ impl AdviceProvider { } } -impl From for AdviceProvider { - fn from(inputs: AdviceInputs) -> Self { - let AdviceInputs { stack, map, store } = inputs; - Self { - stack: VecDeque::from(stack), - map, - store, - pc_requests: Vec::new(), - } - } -} - // ADVICE PROVIDER INTERFACE IMPLEMENTATION // ================================================================================================ @@ -509,3 +682,143 @@ impl AdviceProviderInterface for AdviceProvider { self.update_merkle_node(root, depth, index, value).map(|(path, _)| Some(path)) } } + +#[cfg(test)] +mod tests { + use alloc::{collections::BTreeMap, vec, vec::Vec}; + + use miden_core::WORD_SIZE; + + use super::AdviceProvider; + use crate::{ + AdviceInputs, ExecutionOptions, Felt, Word, + advice::{AdviceError, AdviceMap}, + crypto::merkle::{MerkleStore, MerkleTree}, + }; + + fn make_leaf(seed: u64) -> Word { + [ + Felt::new_unchecked(seed), + Felt::new_unchecked(seed + 1), + Felt::new_unchecked(seed + 2), + Felt::new_unchecked(seed + 3), + ] + .into() + } + + #[test] + fn fingerprint_is_stable_across_merkle_store_insertion_order() { + let tree_a = + MerkleTree::new([make_leaf(1), make_leaf(5), make_leaf(9), make_leaf(13)]).unwrap(); + let tree_b = + MerkleTree::new([make_leaf(17), make_leaf(21), make_leaf(25), make_leaf(29)]).unwrap(); + + let mut store_a = MerkleStore::default(); + store_a.extend(tree_a.inner_nodes()); + store_a.extend(tree_b.inner_nodes()); + + let mut store_b = MerkleStore::default(); + store_b.extend(tree_b.inner_nodes()); + store_b.extend(tree_a.inner_nodes()); + + assert_eq!(store_a, store_b); + + let provider_a = AdviceProvider::new( + AdviceInputs::default().with_merkle_store(store_a), + &Default::default(), + ) + .unwrap(); + let provider_b = AdviceProvider::new( + AdviceInputs::default().with_merkle_store(store_b), + &Default::default(), + ) + .unwrap(); + + assert_eq!(provider_a, provider_b); + assert_eq!(provider_a.fingerprint(), provider_b.fingerprint()); + } + + #[test] + fn advice_map_insert_respects_element_budget() { + let options = ExecutionOptions::default().with_max_adv_map_elements(WORD_SIZE + 1); + let mut provider = AdviceProvider::new(AdviceInputs::default(), &options).unwrap(); + + provider.insert_into_map(make_leaf(0), vec![Felt::ONE]).unwrap(); + + let err = provider.insert_into_map(make_leaf(1), vec![Felt::ONE]).unwrap_err(); + assert!(matches!( + err, + AdviceError::AdvMapElementBudgetExceeded { current: 5, added: 5, max: 5 } + )); + + assert_eq!(provider.map.len(), 1); + assert!(provider.contains_map_key(&make_leaf(0))); + assert!(!provider.contains_map_key(&make_leaf(1))); + } + + #[test] + fn advice_map_insert_respects_value_limit() { + let options = ExecutionOptions::default().with_max_adv_map_value_size(1); + let mut provider = AdviceProvider::new(AdviceInputs::default(), &options).unwrap(); + let values = vec![Felt::ONE, Felt::new_unchecked(2)]; + + let err = provider.insert_into_map(make_leaf(0), values).unwrap_err(); + assert!(matches!(err, AdviceError::AdvMapValueSizeExceeded { size: 2, max: 1 })); + + assert_eq!(provider.map.len(), 0); + } + + #[test] + fn advice_map_extend_respects_element_budget_atomically() { + let options = ExecutionOptions::default().with_max_adv_map_elements(2 * (WORD_SIZE + 1)); + let mut provider = AdviceProvider::new(AdviceInputs::default(), &options).unwrap(); + provider.insert_into_map(make_leaf(0), vec![Felt::ONE]).unwrap(); + let other = advice_map_from_entries(1..3, 1); + + let err = provider.extend_map(&other).unwrap_err(); + assert!(matches!( + err, + AdviceError::AdvMapElementBudgetExceeded { current: 5, added: 10, max: 10 } + )); + + assert_eq!(provider.map.len(), 1); + assert!(provider.contains_map_key(&make_leaf(0))); + assert!(!provider.contains_map_key(&make_leaf(1))); + assert!(!provider.contains_map_key(&make_leaf(2))); + } + + #[test] + fn advice_map_extend_respects_value_limit_atomically() { + let options = ExecutionOptions::default().with_max_adv_map_value_size(1); + let mut provider = AdviceProvider::new(AdviceInputs::default(), &options).unwrap(); + let other = advice_map_from_entries(0..2, 2); + + let err = provider.extend_map(&other).unwrap_err(); + assert!(matches!(err, AdviceError::AdvMapValueSizeExceeded { size: 2, max: 1 })); + + assert_eq!(provider.map.len(), 0); + } + + #[test] + fn initial_advice_map_respects_element_budget() { + let options = ExecutionOptions::default().with_max_adv_map_elements(WORD_SIZE); + let inputs = AdviceInputs::default().with_map([(make_leaf(0), vec![Felt::ONE])]); + + let err = AdviceProvider::new(inputs, &options).unwrap_err(); + assert!(matches!( + err, + AdviceError::AdvMapElementBudgetExceeded { current: 0, added: 5, max: 4 } + )); + } + + fn advice_map_from_entries(keys: impl Iterator, value_len: usize) -> AdviceMap { + keys.map(|key| { + let values = (0..value_len) + .map(|offset| Felt::new_unchecked(key + offset as u64)) + .collect::>(); + (make_leaf(key), values) + }) + .collect::>() + .into() + } +} diff --git a/processor/src/host/debug.rs b/processor/src/host/debug.rs index 4b0ae64771..c35b55e65f 100644 --- a/processor/src/host/debug.rs +++ b/processor/src/host/debug.rs @@ -18,7 +18,7 @@ pub struct StdoutWriter; impl fmt::Write for StdoutWriter { fn write_str(&mut self, _s: &str) -> fmt::Result { #[cfg(feature = "std")] - std::print!("{}", _s); + std::print!("{_s}"); Ok(()) } } @@ -262,7 +262,7 @@ impl DefaultDebugHandler { .into_iter() .map(|(addr, value_opt)| { let value_string = format_value(value_opt); - format!("{addr:>width$}: {value_string}", width = max_addr_width) + format!("{addr:>max_addr_width$}: {value_string}") }) .collect(); diff --git a/processor/src/host/default.rs b/processor/src/host/default.rs index e0f9b919d8..5ff9103922 100644 --- a/processor/src/host/default.rs +++ b/processor/src/host/default.rs @@ -9,19 +9,18 @@ use miden_core::{ use miden_debug_types::{DefaultSourceManager, Location, SourceFile, SourceManager, SourceSpan}; use super::{ - FutureMaybeSend, debug::DefaultDebugHandler, handlers::{EventError, EventHandler, EventHandlerRegistry}, }; use crate::{ - DebugError, DebugHandler, ExecutionError, Host, MastForestStore, MemMastForestStore, - ProcessorState, TraceError, advice::AdviceMutation, + BaseHost, DebugError, DebugHandler, ExecutionError, MastForestStore, MemMastForestStore, + ProcessorState, SyncHost, TraceError, advice::AdviceMutation, }; // DEFAULT HOST IMPLEMENTATION // ================================================================================================ -/// A default Host implementation that provides the essential functionality required by the VM. +/// A default SyncHost implementation that provides the essential functionality required by the VM. #[derive(Debug)] pub struct DefaultHost< D: DebugHandler = DefaultDebugHandler, @@ -125,7 +124,7 @@ where } } -impl Host for DefaultHost +impl BaseHost for DefaultHost where D: DebugHandler, S: SourceManager, @@ -139,34 +138,6 @@ where (span, maybe_file) } - fn get_mast_forest(&self, node_digest: &Word) -> impl FutureMaybeSend>> { - let result = self.store.get(node_digest); - async move { result } - } - - fn on_event( - &mut self, - process: &ProcessorState<'_>, - ) -> impl FutureMaybeSend, EventError>> { - let event_id = EventId::from_felt(process.get_stack_item(0)); - let result = match self.event_handlers.handle_event(event_id, process) { - Ok(Some(mutations)) => { - // the event was handled by the registered event handlers; just return - Ok(mutations) - }, - Ok(None) => { - // EventError is a `Box` so we can define the error anonymously. - #[derive(Debug, thiserror::Error)] - #[error("no event handler registered")] - struct UnhandledEvent; - - Err(UnhandledEvent.into()) - }, - Err(e) => Err(e), - }; - async move { result } - } - fn on_debug( &mut self, process: &ProcessorState, @@ -184,13 +155,41 @@ where } } +impl SyncHost for DefaultHost +where + D: DebugHandler, + S: SourceManager, +{ + fn get_mast_forest(&self, node_digest: &Word) -> Option> { + self.store.get(node_digest) + } + + fn on_event( + &mut self, + process: &ProcessorState<'_>, + ) -> Result, EventError> { + let event_id = EventId::from_felt(process.get_stack_item(0)); + match self.event_handlers.handle_event(event_id, process) { + Ok(Some(mutations)) => Ok(mutations), + Ok(None) => { + #[derive(Debug, thiserror::Error)] + #[error("no event handler registered")] + struct UnhandledEvent; + + Err(UnhandledEvent.into()) + }, + Err(e) => Err(e), + } + } +} + // NOOPHOST // ================================================================================================ -/// A Host which does nothing. +/// A SyncHost which does nothing. pub struct NoopHost; -impl Host for NoopHost { +impl BaseHost for NoopHost { #[inline(always)] fn get_label_and_source_file( &self, @@ -198,21 +197,20 @@ impl Host for NoopHost { ) -> (SourceSpan, Option>) { (SourceSpan::UNKNOWN, None) } +} +impl SyncHost for NoopHost { #[inline(always)] - fn get_mast_forest( - &self, - _node_digest: &Word, - ) -> impl FutureMaybeSend>> { - async { None } + fn get_mast_forest(&self, _node_digest: &Word) -> Option> { + None } #[inline(always)] fn on_event( &mut self, _process: &ProcessorState<'_>, - ) -> impl FutureMaybeSend, EventError>> { - async { Ok(Vec::new()) } + ) -> Result, EventError> { + Ok(Vec::new()) } } diff --git a/processor/src/host/mod.rs b/processor/src/host/mod.rs index ec5b952213..53a1590b72 100644 --- a/processor/src/host/mod.rs +++ b/processor/src/host/mod.rs @@ -58,13 +58,13 @@ impl AdviceMutation { // HOST TRAIT // ================================================================================================ -/// Defines an interface by which the VM can interact with the host. +/// Defines the host functionality shared by both sync and async execution. /// /// There are three main categories of interactions between the VM and the host: /// 1. getting a library's MAST forest, /// 2. handling VM events (which can mutate the process' advice provider), and /// 3. handling debug and trace events. -pub trait Host { +pub trait BaseHost { // REQUIRED METHODS // -------------------------------------------------------------------------------------------- @@ -74,30 +74,6 @@ pub trait Host { location: &Location, ) -> (SourceSpan, Option>); - // Note: we don't use the `async` keyword in get_mast_forest and on_event, since we need to - // specify the `+ Send` bound to the returned Future, and `async` doesn't allow us to do that. - - /// Returns MAST forest corresponding to the specified digest, or None if the MAST forest for - /// this digest could not be found in this host. - fn get_mast_forest(&self, node_digest: &Word) -> impl FutureMaybeSend>>; - - /// Handles the event emitted from the VM and provides advice mutations to be applied to - /// the advice provider. - /// - /// The event ID is available at the top of the stack (position 0) when this handler is called. - /// This allows the handler to access both the event ID and any additional context data that - /// may have been pushed onto the stack prior to the emit operation. - /// - /// ## Implementation notes - /// - Extract the event ID via `EventId::from_felt(process.get_stack_item(0))` - /// - Return errors without event names or IDs - the caller will enrich them via - /// [`Host::resolve_event()`] - /// - System events (IDs 0-255) are handled by the VM before calling this method - fn on_event( - &mut self, - process: &ProcessorState<'_>, - ) -> impl FutureMaybeSend, EventError>>; - // PROVIDED METHODS // -------------------------------------------------------------------------------------------- @@ -126,12 +102,80 @@ pub trait Host { } } +/// Defines a synchronous interface by which the VM can interact with the host during execution. +pub trait SyncHost: BaseHost { + /// Returns MAST forest corresponding to the specified digest, or None if the MAST forest for + /// this digest could not be found in this host. + fn get_mast_forest(&self, node_digest: &Word) -> Option>; + + /// Handles the event emitted from the VM and provides advice mutations to be applied to + /// the advice provider. + /// + /// The event ID is available at the top of the stack (position 0) when this handler is called. + /// This allows the handler to access both the event ID and any additional context data that + /// may have been pushed onto the stack prior to the emit operation. + /// + /// ## Implementation notes + /// - Extract the event ID via `EventId::from_felt(process.get_stack_item(0))` + /// - Return errors without event names or IDs - the caller will enrich them via + /// [`BaseHost::resolve_event()`] + /// - System events (IDs 0-255) are handled by the VM before calling this method + fn on_event(&mut self, process: &ProcessorState<'_>) + -> Result, EventError>; +} + +/// Defines an async interface by which the VM can interact with the host during execution. +/// +/// This mirrors the historic async host surface while allowing the sync-first core to depend on +/// [`BaseHost`]. +pub trait Host: BaseHost { + // REQUIRED METHODS + // -------------------------------------------------------------------------------------------- + + /// Returns MAST forest corresponding to the specified digest, or None if the MAST forest for + /// this digest could not be found in this host. + fn get_mast_forest(&self, node_digest: &Word) -> impl FutureMaybeSend>>; + + /// Handles the event emitted from the VM and provides advice mutations to be applied to + /// the advice provider. + /// + /// The event ID is available at the top of the stack (position 0) when this handler is called. + /// This allows the handler to access both the event ID and any additional context data that + /// may have been pushed onto the stack prior to the emit operation. + /// + /// ## Implementation notes + /// - Extract the event ID via `EventId::from_felt(process.get_stack_item(0))` + /// - Return errors without event names or IDs - the caller will enrich them via + /// [`BaseHost::resolve_event()`] + /// - System events (IDs 0-255) are handled by the VM before calling this method + fn on_event( + &mut self, + process: &ProcessorState<'_>, + ) -> impl FutureMaybeSend, EventError>>; +} + +impl Host for T +where + T: SyncHost, +{ + fn get_mast_forest(&self, node_digest: &Word) -> impl FutureMaybeSend>> { + let result = SyncHost::get_mast_forest(self, node_digest); + async move { result } + } + + fn on_event( + &mut self, + process: &ProcessorState<'_>, + ) -> impl FutureMaybeSend, EventError>> { + let result = SyncHost::on_event(self, process); + async move { result } + } +} + /// Alias for a `Future` /// /// Unless the compilation target family is `wasm`, we add `Send` to the required bounds. For /// `wasm` compilation targets there is no `Send` bound. -/// -/// We also provide a blank implementation of this trait for all features. #[cfg(target_family = "wasm")] pub trait FutureMaybeSend: Future {} @@ -142,8 +186,6 @@ impl FutureMaybeSend for T where T: Future {} /// /// Unless the compilation target family is `wasm`, we add `Send` to the required bounds. For /// `wasm` compilation targets there is no `Send` bound. -/// -/// We also provide a blank implementation of this trait for all features. #[cfg(not(target_family = "wasm"))] pub trait FutureMaybeSend: Future + Send {} diff --git a/processor/src/lib.rs b/processor/src/lib.rs index dc4b8ecfa8..218b899b23 100644 --- a/processor/src/lib.rs +++ b/processor/src/lib.rs @@ -1,4 +1,7 @@ #![no_std] +// Trace tests intentionally use index-based `for i in a..b` over column slices; clippy's iterator +// suggestion is noisier than helpful there. +#![cfg_attr(test, allow(clippy::needless_range_loop))] #[macro_use] extern crate alloc; @@ -13,7 +16,6 @@ use core::{ }; mod continuation_stack; -mod debug; mod errors; mod execution; mod execution_options; @@ -25,9 +27,9 @@ mod tracer; use crate::{ advice::{AdviceInputs, AdviceProvider}, continuation_stack::ContinuationStack, - errors::MapExecErr, + errors::{MapExecErr, MapExecErrNoCtx}, processor::{Processor, SystemInterface}, - trace::{ExecutionTrace, RowIndex}, + trace::RowIndex, }; #[cfg(any(test, feature = "testing"))] @@ -46,7 +48,7 @@ pub use errors::{AceError, ExecutionError, HostError, MemoryError}; pub use execution_options::{ExecutionOptions, ExecutionOptionsError}; pub use fast::{BreakReason, ExecutionOutput, FastProcessor, ResumeContext}; pub use host::{ - FutureMaybeSend, Host, MastForestStore, MemMastForestStore, + BaseHost, FutureMaybeSend, Host, MastForestStore, MemMastForestStore, SyncHost, debug::DefaultDebugHandler, default::{DefaultHost, HostLibrary}, handlers::{DebugError, DebugHandler, TraceError}, @@ -58,6 +60,7 @@ pub use miden_core::{ }, serde, utils, }; +pub use trace::{TraceBuildInputs, TraceGenerationContext}; pub mod advice { pub use miden_core::advice::{AdviceInputs, AdviceMap, AdviceStackBuilder}; @@ -87,10 +90,8 @@ pub mod trace; // EXECUTORS // ================================================================================================ -/// Returns an execution trace resulting from executing the provided program against the provided -/// inputs. -/// -/// This is an async function that works on all platforms including wasm32. +/// Executes the provided program against the provided inputs and returns the resulting execution +/// output. /// /// The `host` parameter is used to provide the external environment to the program being executed, /// such as access to the advice provider and libraries that the program depends on. @@ -104,15 +105,10 @@ pub async fn execute( advice_inputs: AdviceInputs, host: &mut impl Host, options: ExecutionOptions, -) -> Result { - let processor = FastProcessor::new_with_options(stack_inputs, advice_inputs, options); - let (execution_output, trace_generation_context) = - processor.execute_for_trace(program, host).await?; - - let trace = trace::build_trace(execution_output, trace_generation_context, program.to_info())?; - - assert_eq!(&program.hash(), trace.program_hash(), "inconsistent program hash"); - Ok(trace) +) -> Result { + let processor = FastProcessor::new_with_options(stack_inputs, advice_inputs, options) + .map_exec_err_no_ctx()?; + processor.execute(program, host).await } /// Synchronous wrapper for the async `execute()` function. @@ -129,24 +125,12 @@ pub fn execute_sync( program: &Program, stack_inputs: StackInputs, advice_inputs: AdviceInputs, - host: &mut impl Host, + host: &mut impl SyncHost, options: ExecutionOptions, -) -> Result { - match tokio::runtime::Handle::try_current() { - Ok(_handle) => { - // We're already inside a Tokio runtime - this is not supported because we cannot - // safely create a nested runtime or move the non-Send host reference to another thread - panic!( - "Cannot call execute_sync from within a Tokio runtime. \ - Use the async execute() method instead." - ) - }, - Err(_) => { - // No runtime exists - create one and use it - let rt = tokio::runtime::Builder::new_current_thread().build().unwrap(); - rt.block_on(execute(program, stack_inputs, advice_inputs, host, options)) - }, - } +) -> Result { + let processor = FastProcessor::new_with_options(stack_inputs, advice_inputs, options) + .map_exec_err_no_ctx()?; + processor.execute_sync(program, host) } // PROCESSOR STATE @@ -298,7 +282,7 @@ pub trait Stopper { &self, processor: &Self::Processor, continuation_stack: &ContinuationStack, - continuation_after_stop: impl FnOnce() -> Option, + continuation_after_stop: impl FnOnce() -> Option, ) -> ControlFlow; } @@ -376,13 +360,13 @@ impl From for u32 { } impl Display for MemoryAddress { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Display::fmt(&self.0, f) } } impl LowerHex for MemoryAddress { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { LowerHex::fmt(&self.0, f) } } diff --git a/processor/src/processor.rs b/processor/src/processor.rs index 7000575687..9202eeaad5 100644 --- a/processor/src/processor.rs +++ b/processor/src/processor.rs @@ -4,7 +4,7 @@ use core::ops::ControlFlow; use miden_air::trace::{RowIndex, chiplets::hasher::HasherState}; use crate::{ - BreakReason, ContextId, ExecutionError, Felt, Host, MemoryError, Word, + BaseHost, BreakReason, ContextId, ExecutionError, Felt, MemoryError, Word, advice::AdviceError, crypto::merkle::MerklePath, errors::OperationError, @@ -71,7 +71,7 @@ pub(crate) trait Processor: Sized { &self, node_id: MastNodeId, current_forest: &MastForest, - host: &mut impl Host, + host: &mut impl BaseHost, ) -> ControlFlow; /// Executes the decorators that should be executed after exiting a node. @@ -79,7 +79,7 @@ pub(crate) trait Processor: Sized { &self, node_id: MastNodeId, current_forest: &MastForest, - host: &mut impl Host, + host: &mut impl BaseHost, ) -> ControlFlow; /// Executes any decorator in a basic block that is to be executed before the operation at the @@ -89,7 +89,7 @@ pub(crate) trait Processor: Sized { node_id: MastNodeId, op_idx_in_block: usize, current_forest: &MastForest, - host: &mut impl Host, + host: &mut impl BaseHost, ) -> ControlFlow; /// Executes any decorator in a basic block that is to be executed after all operations in the @@ -100,7 +100,7 @@ pub(crate) trait Processor: Sized { basic_block_node: &BasicBlockNode, node_id: MastNodeId, current_forest: &Arc, - host: &mut impl Host, + host: &mut impl BaseHost, ) -> ControlFlow; } diff --git a/processor/src/test_utils/test_host.rs b/processor/src/test_utils/test_host.rs index adab8586af..0a354e5eee 100644 --- a/processor/src/test_utils/test_host.rs +++ b/processor/src/test_utils/test_host.rs @@ -11,8 +11,8 @@ use miden_debug_types::{ }; use crate::{ - DebugError, DebugHandler, FutureMaybeSend, Host, MastForestStore, MemMastForestStore, - ProcessorState, TraceError, Word, advice::AdviceMutation, event::EventError, mast::MastForest, + BaseHost, DebugError, DebugHandler, MastForestStore, MemMastForestStore, ProcessorState, + SyncHost, TraceError, Word, advice::AdviceMutation, event::EventError, mast::MastForest, }; /// A snapshot of the processor state for consistency checking between processors. @@ -119,7 +119,7 @@ impl TestHost { /// Creates a new TestHost with a kernel forest for full consistency testing. pub fn with_kernel_forest(kernel_forest: Arc) -> Self { let mut store = MemMastForestStore::default(); - store.insert(kernel_forest.clone()); + store.insert(kernel_forest); Self { trace_collector: TraceCollector::new(), event_handler: Vec::new(), @@ -152,7 +152,7 @@ impl Default for TestHost { } } -impl Host for TestHost +impl BaseHost for TestHost where S: SourceManagerSync, { @@ -165,20 +165,6 @@ where (span, maybe_file) } - fn get_mast_forest(&self, node_digest: &Word) -> impl FutureMaybeSend>> { - let result = self.store.get(node_digest); - async move { result } - } - - fn on_event( - &mut self, - process: &ProcessorState, - ) -> impl FutureMaybeSend, EventError>> { - let event_id: u32 = process.get_stack_item(0).as_canonical_u64().try_into().unwrap(); - self.event_handler.push(event_id); - async move { Ok(Vec::new()) } - } - fn on_debug( &mut self, _process: &ProcessorState, @@ -199,3 +185,18 @@ where Ok(()) } } + +impl SyncHost for TestHost +where + S: SourceManagerSync, +{ + fn get_mast_forest(&self, node_digest: &Word) -> Option> { + self.store.get(node_digest) + } + + fn on_event(&mut self, process: &ProcessorState) -> Result, EventError> { + let event_id: u32 = process.get_stack_item(0).as_canonical_u64().try_into().unwrap(); + self.event_handler.push(event_id); + Ok(Vec::new()) + } +} diff --git a/processor/src/tests/debug.rs b/processor/src/tests/debug.rs index 52092a4990..d801a987cc 100644 --- a/processor/src/tests/debug.rs +++ b/processor/src/tests/debug.rs @@ -324,7 +324,7 @@ fn test_debug_adv_stack() { push.[8, 7, 6, 5] assert_eqw # => [4, 3, 2, 1, 0] - adv_push.1 + adv_push # => [4, 4, 3, 2, 1, 0] debug.stack.6 debug.adv_stack # => [3, 2, 1] @@ -334,7 +334,7 @@ fn test_debug_adv_stack() { # => [3, 2, 1, 0] # Pops the remaining elements one-by-one - adv_push.3 + adv_push adv_push adv_push # => [1, 2, 3, 3, 2, 1, 0] debug.stack.7 diff --git a/processor/src/tests/debug_mode_decorator_tests.rs b/processor/src/tests/debug_mode_decorator_tests.rs index ddf53f60df..b208e22853 100644 --- a/processor/src/tests/debug_mode_decorator_tests.rs +++ b/processor/src/tests/debug_mode_decorator_tests.rs @@ -49,7 +49,7 @@ fn test_decorators_only_execute_in_debug_mode() { let process_debug_off = FastProcessor::new(StackInputs::default()); let result = process_debug_off.execute_sync(&program, &mut host_debug_off); - assert!(result.is_ok(), "Execution failed: {:?}", result); + assert!(result.is_ok(), "Execution failed: {result:?}"); assert!( host_debug_off.get_trace_count(999) == 0, "Decorator should NOT execute when debug mode is OFF" @@ -59,11 +59,12 @@ fn test_decorators_only_execute_in_debug_mode() { let mut host_debug_on = TestHost::new(); let process_debug_on = FastProcessor::new(StackInputs::default()) .with_advice(AdviceInputs::default()) + .expect("advice inputs should fit advice map limits") .with_debugging(true) .with_tracing(true); let result = process_debug_on.execute_sync(&program, &mut host_debug_on); - assert!(result.is_ok(), "Execution failed: {:?}", result); + assert!(result.is_ok(), "Execution failed: {result:?}"); assert!( host_debug_on.get_trace_count(999) == 1, "Decorator SHOULD execute when debug mode is ON" @@ -84,7 +85,7 @@ fn test_decorators_only_execute_in_debug_mode_off() { // Execute the program let result = processor.execute_sync(&program, &mut host); - assert!(result.is_ok(), "Execution failed: {:?}", result); + assert!(result.is_ok(), "Execution failed: {result:?}"); // Verify that the decorator was NOT executed (trace count should be 0) assert_eq!( @@ -110,12 +111,13 @@ fn test_decorators_only_execute_in_debug_mode_on() { // Create processor with debug mode ON (tracing enabled) let processor = FastProcessor::new(StackInputs::default()) .with_advice(AdviceInputs::default()) + .expect("advice inputs should fit advice map limits") .with_debugging(true) .with_tracing(true); // Execute the program let result = processor.execute_sync(&program, &mut host); - assert!(result.is_ok(), "Execution failed: {:?}", result); + assert!(result.is_ok(), "Execution failed: {result:?}"); // Verify that the decorator WAS executed (trace count should be 1) assert_eq!( @@ -174,6 +176,7 @@ fn test_zero_overhead_when_debug_off() { let mut host_on = TestHost::new(); let processor_on = FastProcessor::new(StackInputs::default()) .with_advice(AdviceInputs::default()) + .expect("advice inputs should fit advice map limits") .with_debugging(true) .with_tracing(true); diff --git a/processor/src/tests/mod.rs b/processor/src/tests/mod.rs index 97479b0398..82c91b4bdd 100644 --- a/processor/src/tests/mod.rs +++ b/processor/src/tests/mod.rs @@ -17,14 +17,38 @@ use miden_utils_testing::{ /// Tests in this file make sure that diagnostics presented to the user are as expected. use crate::{ - DefaultHost, FastProcessor, Kernel, ONE, Program, StackInputs, Word, ZERO, - advice::{AdviceInputs, AdviceMap}, + DefaultHost, FastProcessor, Kernel, ONE, ProcessorState, Program, StackInputs, Word, ZERO, + advice::{AdviceInputs, AdviceMap, AdviceMutation}, + event::{EventError, EventHandler, EventName}, operation::Operation, }; mod debug; mod debug_mode_decorator_tests; +#[derive(Debug, thiserror::Error)] +#[error("dummy host event failure")] +struct DummyHostEventError; + +struct AlwaysFailEventHandler; + +impl EventHandler for AlwaysFailEventHandler { + fn on_event(&self, _process: &ProcessorState) -> Result, EventError> { + Err(DummyHostEventError.into()) + } +} + +struct DuplicateMapMutationHandler; + +impl EventHandler for DuplicateMapMutationHandler { + fn on_event(&self, _process: &ProcessorState) -> Result, EventError> { + Ok(vec![AdviceMutation::extend_map(AdviceMap::from_iter([( + Word::default(), + vec![ONE], + )]))]) + } +} + // AdviceMap inlined in the script // ------------------------------------------------------------------------------------------------ @@ -37,7 +61,7 @@ begin push.A adv.push_mapval dropw - adv_push.1 + adv_push push.1 assert_eq end"; @@ -140,6 +164,77 @@ fn test_diagnostic_advice_map_key_not_found_2() { ); } +// Host event diagnostics +// ------------------------------------------------------------------------------------------------ + +#[test] +fn test_diagnostic_host_event_error_uses_emit_location() { + let event = EventName::new("test::host_event_error"); + let source_manager = Arc::new(DefaultSourceManager::default()); + let source = format!( + " + begin + push.1 emit.event(\"{event}\") + end" + ); + let program = Assembler::new(source_manager.clone()).assemble_program(source).unwrap(); + let mut host = DefaultHost::default().with_source_manager(source_manager); + host.register_handler(event.clone(), Arc::new(AlwaysFailEventHandler)).unwrap(); + + let processor = FastProcessor::new(StackInputs::default()) + .with_advice(AdviceInputs::default()) + .expect("advice inputs should fit advice map limits") + .with_debugging(true) + .with_tracing(true); + let err = processor.execute_sync(&program, &mut host).expect_err("expected error"); + #[rustfmt::skip] + assert_diagnostic_lines!( + err, + format!(" x error during processing of event '{event}' (ID: {})", event.to_event_id()), + " `-> dummy host event failure", + regex!(r#",-\[::\$exec:3:20\]"#), + " 2 | begin", + r#" 3 | push.1 emit.event("test::host_event_error")"#, + " : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^", + " 4 | end", + " `----" + ); +} + +#[test] +fn test_diagnostic_host_event_advice_error_uses_emit_location() { + let event = EventName::new("test::host_event_advice_error"); + let source_manager = Arc::new(DefaultSourceManager::default()); + let source = format!( + " + begin + push.1 emit.event(\"{event}\") + end" + ); + let program = Assembler::new(source_manager.clone()).assemble_program(source).unwrap(); + let mut host = DefaultHost::default().with_source_manager(source_manager); + host.register_handler(event, Arc::new(DuplicateMapMutationHandler)).unwrap(); + + let processor = FastProcessor::new(StackInputs::default()) + .with_advice(AdviceInputs::default().with_map([(Word::default(), vec![ZERO])])) + .expect("advice inputs should fit advice map limits") + .with_debugging(true) + .with_tracing(true); + let err = processor.execute_sync(&program, &mut host).expect_err("expected error"); + #[rustfmt::skip] + assert_diagnostic_lines!( + err, + " x value for key 0x0000000000000000000000000000000000000000000000000000000000000000 already present in the advice map", + regex!(r#",-\[::\$exec:3:20\]"#), + " 2 | begin", + r#" 3 | push.1 emit.event("test::host_event_advice_error")"#, + " : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^", + " 4 | end", + " `----", + "help: previous values at key were '[0]'. Operation would have replaced them with '[1]'" + ); +} + // AdviceStackReadFailed // ------------------------------------------------------------------------------------------------ @@ -147,7 +242,7 @@ fn test_diagnostic_advice_map_key_not_found_2() { fn test_diagnostic_advice_stack_read_failed() { let source = " begin - swap adv_push.1 trace.2 + swap adv_push trace.2 end"; let build_test = build_test_by_mode!(true, source, &[1, 2]); @@ -157,8 +252,8 @@ fn test_diagnostic_advice_stack_read_failed() { " x advice stack read failed", regex!(r#",-\[test[\d]+:3:18\]"#), " 2 | begin", - " 3 | swap adv_push.1 trace.2", - " : ^^^^^^^^^^", + " 3 | swap adv_push trace.2", + " : ^^^^^^^^", " 4 | end", " `----" ); @@ -716,7 +811,7 @@ fn test_diagnostic_procedure_not_found_call() { "; let uri = Uri::from("src.masm"); let content = SourceContent::new(SourceLanguage::Masm, uri.clone(), src); - let source_file = source_manager.load_from_raw_parts(uri.clone(), content); + let source_file = source_manager.load_from_raw_parts(uri, content); Module::parse( PathBuf::new(module_name).unwrap(), miden_assembly::ast::ModuleKind::Library, @@ -746,12 +841,13 @@ fn test_diagnostic_procedure_not_found_call() { let processor = FastProcessor::new(StackInputs::default()) .with_advice(AdviceInputs::default()) + .expect("advice inputs should fit advice map limits") .with_debugging(true) .with_tracing(true); let err = processor.execute_sync(&program, &mut host).unwrap_err(); assert_diagnostic_lines!( err, - "procedure with root digest 0x21458fd12b211505c36fe477314b3149bd4b2214f3304cbafa04ea80579d4328 could not be found", + "procedure with root digest 0x6c0c95a9f04e21fe073801b42748ef0639eebd0467afd64c3d317b537451454d could not be found", regex!(r#",-\[::\$exec:5:13\]"#), " 4 | begin", " 5 | call.bar::dummy_proc", @@ -774,7 +870,7 @@ fn test_diagnostic_procedure_not_found_join() { "; let uri = Uri::from("src.masm"); let content = SourceContent::new(SourceLanguage::Masm, uri.clone(), src); - let source_file = source_manager.load_from_raw_parts(uri.clone(), content); + let source_file = source_manager.load_from_raw_parts(uri, content); Module::parse( PathBuf::new(module_name).unwrap(), miden_assembly::ast::ModuleKind::Library, @@ -805,12 +901,13 @@ fn test_diagnostic_procedure_not_found_join() { let processor = FastProcessor::new(StackInputs::default()) .with_advice(AdviceInputs::default()) + .expect("advice inputs should fit advice map limits") .with_debugging(true) .with_tracing(true); let err = processor.execute_sync(&program, &mut host).unwrap_err(); assert_diagnostic_lines!( err, - "procedure with root digest 0x21458fd12b211505c36fe477314b3149bd4b2214f3304cbafa04ea80579d4328 could not be found", + "procedure with root digest 0x6c0c95a9f04e21fe073801b42748ef0639eebd0467afd64c3d317b537451454d could not be found", regex!(r#",-\[::\$exec:4:9\]"#), " 3 |", " 4 | ,-> begin", @@ -835,7 +932,7 @@ fn test_diagnostic_procedure_not_found_loop() { "; let uri = Uri::from("src.masm"); let content = SourceContent::new(SourceLanguage::Masm, uri.clone(), src); - let source_file = source_manager.load_from_raw_parts(uri.clone(), content); + let source_file = source_manager.load_from_raw_parts(uri, content); Module::parse( PathBuf::new(module_name).unwrap(), miden_assembly::ast::ModuleKind::Library, @@ -868,12 +965,13 @@ fn test_diagnostic_procedure_not_found_loop() { let processor = FastProcessor::new(StackInputs::default()) .with_advice(AdviceInputs::default()) + .expect("advice inputs should fit advice map limits") .with_debugging(true) .with_tracing(true); let err = processor.execute_sync(&program, &mut host).unwrap_err(); assert_diagnostic_lines!( err, - "procedure with root digest 0x21458fd12b211505c36fe477314b3149bd4b2214f3304cbafa04ea80579d4328 could not be found", + "procedure with root digest 0x6c0c95a9f04e21fe073801b42748ef0639eebd0467afd64c3d317b537451454d could not be found", regex!(r#",-\[::\$exec:6:13\]"#), " 5 | push.1", " 6 | ,-> while.true", @@ -897,7 +995,7 @@ fn test_diagnostic_procedure_not_found_split() { "; let uri = Uri::from("src.masm"); let content = SourceContent::new(SourceLanguage::Masm, uri.clone(), src); - let source_file = source_manager.load_from_raw_parts(uri.clone(), content); + let source_file = source_manager.load_from_raw_parts(uri, content); Module::parse( PathBuf::new(module_name).unwrap(), miden_assembly::ast::ModuleKind::Library, @@ -932,12 +1030,13 @@ fn test_diagnostic_procedure_not_found_split() { let processor = FastProcessor::new(StackInputs::default()) .with_advice(AdviceInputs::default()) + .expect("advice inputs should fit advice map limits") .with_debugging(true) .with_tracing(true); let err = processor.execute_sync(&program, &mut host).unwrap_err(); assert_diagnostic_lines!( err, - "procedure with root digest 0x21458fd12b211505c36fe477314b3149bd4b2214f3304cbafa04ea80579d4328 could not be found", + "procedure with root digest 0x6c0c95a9f04e21fe073801b42748ef0639eebd0467afd64c3d317b537451454d could not be found", regex!(r#",-\[::\$exec:6:13\]"#), " 5 | push.1", " 6 | ,-> if.true", @@ -1159,12 +1258,13 @@ fn test_diagnostic_syscall_target_not_in_kernel() { let processor = FastProcessor::new(StackInputs::default()) .with_advice(AdviceInputs::default()) + .expect("advice inputs should fit advice map limits") .with_debugging(true) .with_tracing(true); let err = processor.execute_sync(&program, &mut host).unwrap_err(); assert_diagnostic_lines!( err, - "syscall failed: procedure with root 0x3b7651d5f57f0d3eb4eb69c7491cf16ca9f2f0010e32ed41cffadf9c8e18e61b was not found in the kernel", + "syscall failed: procedure with root 0xcf69b6e65f586c6957de45a4a4188a9582251aca77a7d441cd040bfbcdfb192a was not found in the kernel", regex!(r#",-\[::\$exec:3:13\]"#), " 2 | begin", " 3 | syscall.dummy_proc", diff --git a/processor/src/trace/block_stack.rs b/processor/src/trace/block_stack.rs new file mode 100644 index 0000000000..d5c2e18101 --- /dev/null +++ b/processor/src/trace/block_stack.rs @@ -0,0 +1,102 @@ +use alloc::vec::Vec; + +use miden_air::Felt; +use miden_core::{Word, ZERO}; + +use crate::ContextId; + +// BLOCK STACK +// ================================================================================================ + +/// Tracks per-block data needed for trace generation that the [`ContinuationStack`] does not +/// carry. Specifically, it stores the hasher chiplet addresses (`addr`, `parent_addr`) assigned +/// during execution, and for CALL/SYSCALL/DYNCALL blocks, the caller's execution context so it +/// can be restored on END. +/// +/// [`ContinuationStack`]: crate::continuation_stack::ContinuationStack +#[derive(Debug, Default, Clone)] +pub struct BlockStack { + blocks: Vec, +} + +impl BlockStack { + // STATE ACCESSORS AND MUTATORS + // -------------------------------------------------------------------------------------------- + + /// Pushes a new code block onto the block stack and returns the address of the block's parent. + /// + /// The block is identified by its address. For CALL, SYSCALL and DYNCALL blocks, execution + /// context info must be provided so that the caller's context can be restored on END. + /// + /// When the block is later popped (on END), the flags for the trace row are fully reconstructed + /// from the continuation stack, and hence do not need to be stored in this data structure. + pub fn push(&mut self, addr: Felt, ctx_info: Option) -> Felt { + let parent_addr = match self.blocks.last() { + Some(parent) => parent.addr, + None => ZERO, + }; + + self.blocks.push(BlockInfo { addr, parent_addr, ctx_info }); + parent_addr + } + + pub fn pop(&mut self) -> BlockInfo { + self.blocks.pop().expect("block stack is empty") + } + + pub fn is_empty(&self) -> bool { + self.blocks.is_empty() + } + + pub fn peek(&self) -> &BlockInfo { + self.blocks.last().expect("block stack is empty") + } + + pub fn peek_mut(&mut self) -> &mut BlockInfo { + self.blocks.last_mut().expect("block stack is empty") + } +} + +// BLOCK INFO +// ================================================================================================ + +#[derive(Debug, Clone)] +pub struct BlockInfo { + pub addr: Felt, + pub parent_addr: Felt, + pub ctx_info: Option, +} + +// EXECUTION CONTEXT INFO +// ================================================================================================ + +/// Contains information about an execution context. Execution contexts are relevant only for CALL +/// and SYSCALL blocks. +#[derive(Debug, Default, Clone, Copy)] +pub struct ExecutionContextInfo { + /// Context ID of the block's parent. + pub parent_ctx: ContextId, + /// Hash of the function which initiated execution of the block's parent. If the parent is a + /// root context, this will be set to [ZERO; 4]. + pub parent_fn_hash: Word, + /// Depth of the operand stack right before a CALL operation is executed. + pub parent_stack_depth: u32, + /// Address of the top row in the overflow table right before a CALL operations is executed. + pub parent_next_overflow_addr: Felt, +} + +impl ExecutionContextInfo { + pub fn new( + parent_ctx: ContextId, + parent_fn_hash: Word, + parent_stack_depth: u32, + parent_next_overflow_addr: Felt, + ) -> Self { + Self { + parent_fn_hash, + parent_ctx, + parent_stack_depth, + parent_next_overflow_addr, + } + } +} diff --git a/processor/src/trace/chiplets/ace/mod.rs b/processor/src/trace/chiplets/ace/mod.rs index a41cf12237..d73fe96a65 100644 --- a/processor/src/trace/chiplets/ace/mod.rs +++ b/processor/src/trace/chiplets/ace/mod.rs @@ -1,19 +1,19 @@ use alloc::{collections::BTreeMap, vec::Vec}; -use miden_air::trace::{Challenges, MainTrace, RowIndex, chiplets::ace::ACE_CHIPLET_NUM_COLS}; -use miden_core::{Felt, ZERO, field::ExtensionField}; +use miden_air::trace::{RowIndex, chiplets::ace::ACE_CHIPLET_NUM_COLS}; +use miden_core::{Felt, ZERO}; use crate::trace::TraceFragment; mod trace; -pub use trace::{CircuitEvaluation, NUM_ACE_LOGUP_FRACTIONS_EVAL, NUM_ACE_LOGUP_FRACTIONS_READ}; +pub use trace::CircuitEvaluation; mod instruction; #[cfg(test)] mod tests; pub const PTR_OFFSET_ELEM: Felt = Felt::ONE; -pub const PTR_OFFSET_WORD: Felt = Felt::new(4); +pub const PTR_OFFSET_WORD: Felt = Felt::new_unchecked(4); pub const MAX_NUM_ACE_WIRES: u32 = instruction::MAX_ID; /// Arithmetic circuit evaluation (ACE) chiplet. @@ -31,14 +31,11 @@ pub struct Ace { impl Ace { /// Gets the total trace length of the ACE chiplet. pub(crate) fn trace_len(&self) -> usize { - self.circuit_evaluations.values().map(|eval_ctx| eval_ctx.num_rows()).sum() + self.circuit_evaluations.values().map(CircuitEvaluation::num_rows).sum() } /// Fills the portion of the main trace allocated to the ACE chiplet. - /// - /// This also returns helper data needed for generating the part of the auxiliary trace - /// associated with the ACE chiplet. - pub(crate) fn fill_trace(self, trace: &mut TraceFragment) -> Vec { + pub(crate) fn fill_trace(self, trace: &mut TraceFragment) { // make sure fragment dimensions are consistent with the dimensions of this trace debug_assert_eq!(self.trace_len(), trace.len(), "inconsistent trace lengths"); debug_assert_eq!(ACE_CHIPLET_NUM_COLS, trace.width(), "inconsistent trace widths"); @@ -49,21 +46,15 @@ impl Ace { .try_into() .expect("failed to convert vector to array"); - let mut sections_info = Vec::with_capacity(self.circuit_evaluations.keys().count()); - let mut offset = 0; for eval_ctx in self.circuit_evaluations.into_values() { eval_ctx.fill(offset, &mut gen_trace); offset += eval_ctx.num_rows(); - let section = EvaluatedCircuitsMetadata::from_evaluation_context(&eval_ctx); - sections_info.push(section); } for (out_column, column) in trace.columns().zip(gen_trace) { out_column.copy_from_slice(&column); } - - sections_info } /// Adds an entry resulting from a call to the ACE chiplet. @@ -75,180 +66,3 @@ impl Ace { self.circuit_evaluations.insert(clk, circuit_eval); } } - -/// Stores metadata associated to an evaluated circuit needed for building the portion of the -/// auxiliary trace segment relevant for the ACE chiplet. -#[derive(Debug, Default, Clone)] -pub struct EvaluatedCircuitsMetadata { - ctx: u32, - clk: u32, - num_vars: u32, - num_evals: u32, -} - -impl EvaluatedCircuitsMetadata { - pub fn clk(&self) -> u32 { - self.clk - } - - pub fn ctx(&self) -> u32 { - self.ctx - } - - pub fn num_vars(&self) -> u32 { - self.num_vars - } - - pub fn num_evals(&self) -> u32 { - self.num_evals - } - - fn from_evaluation_context(eval_ctx: &CircuitEvaluation) -> EvaluatedCircuitsMetadata { - EvaluatedCircuitsMetadata { - ctx: eval_ctx.ctx(), - clk: eval_ctx.clk(), - num_vars: eval_ctx.num_read_rows(), - num_evals: eval_ctx.num_eval_rows(), - } - } -} - -/// Stores metadata for the ACE chiplet useful when building the portion of the auxiliary -/// trace segment relevant for the ACE chiplet. -/// -/// This data is already present in the main trace but collecting it here allows us to simplify -/// the logic for building the auxiliary segment portion for the ACE chiplet. -/// For example, we know that `clk` and `ctx` are constant throughout each circuit evaluation -/// and we also know the exact number of ACE chiplet rows per circuit evaluation and the exact -/// number of rows per `READ` and `EVAL` portions, which allows us to avoid the need to compute -/// selectors as part of the logic of auxiliary trace generation. -#[derive(Clone, Debug, Default)] -pub struct AceHints { - offset_chiplet_trace: usize, - pub sections: Vec, -} - -impl AceHints { - pub fn new(offset_chiplet_trace: usize, sections: Vec) -> Self { - Self { offset_chiplet_trace, sections } - } - - pub(crate) fn offset(&self) -> usize { - self.offset_chiplet_trace - } - - /// Encodes an ACE wire value into a bus message. - /// - /// Layout: `alpha + beta^0*clk + beta^1*ctx + beta^2*wire[0] + beta^3*wire[1] + beta^4*wire[2]` - #[inline(always)] - fn encode_ace_wire_value>( - challenges: &Challenges, - clk: u32, - ctx: u32, - wire: [Felt; 3], - ) -> E { - challenges.encode([Felt::from_u32(clk), Felt::from_u32(ctx), wire[0], wire[1], wire[2]]) - } - - pub(crate) fn build_divisors>( - &self, - main_trace: &MainTrace, - challenges: &Challenges, - ) -> Vec { - let num_fractions = self.num_fractions(); - let mut total_values = vec![E::ZERO; num_fractions]; - let mut total_inv_values = vec![E::ZERO; num_fractions]; - - let mut chiplet_offset = self.offset_chiplet_trace; - let mut values_offset = 0; - let mut acc = E::ONE; - for section in self.sections.iter() { - let clk = section.clk(); - let ctx = section.ctx(); - - let values = &mut total_values[values_offset - ..values_offset + NUM_ACE_LOGUP_FRACTIONS_READ * section.num_vars() as usize]; - let inv_values = &mut total_inv_values[values_offset - ..values_offset + NUM_ACE_LOGUP_FRACTIONS_READ * section.num_vars() as usize]; - - // read section - for (i, (value, inv_value)) in values - .chunks_mut(NUM_ACE_LOGUP_FRACTIONS_READ) - .zip(inv_values.chunks_mut(NUM_ACE_LOGUP_FRACTIONS_READ)) - .enumerate() - { - let trace_row = i + chiplet_offset; - - let wire_0 = main_trace.chiplet_ace_wire_0(trace_row.into()); - let wire_1 = main_trace.chiplet_ace_wire_1(trace_row.into()); - - let value_0 = Self::encode_ace_wire_value(challenges, clk, ctx, wire_0); - let value_1 = Self::encode_ace_wire_value(challenges, clk, ctx, wire_1); - - value[0] = value_0; - value[1] = value_1; - inv_value[0] = acc; - acc *= value_0; - inv_value[1] = acc; - acc *= value_1; - } - - chiplet_offset += section.num_vars() as usize; - values_offset += NUM_ACE_LOGUP_FRACTIONS_READ * section.num_vars() as usize; - - // eval section - let values = &mut total_values[values_offset - ..values_offset + NUM_ACE_LOGUP_FRACTIONS_EVAL * section.num_evals() as usize]; - let inv_values = &mut total_inv_values[values_offset - ..values_offset + NUM_ACE_LOGUP_FRACTIONS_EVAL * section.num_evals() as usize]; - for (i, (value, inv_value)) in values - .chunks_mut(NUM_ACE_LOGUP_FRACTIONS_EVAL) - .zip(inv_values.chunks_mut(NUM_ACE_LOGUP_FRACTIONS_EVAL)) - .enumerate() - { - let trace_row = i + chiplet_offset; - - let wire_0 = main_trace.chiplet_ace_wire_0(trace_row.into()); - let wire_1 = main_trace.chiplet_ace_wire_1(trace_row.into()); - let wire_2 = main_trace.chiplet_ace_wire_2(trace_row.into()); - - let value_0 = Self::encode_ace_wire_value(challenges, clk, ctx, wire_0); - let value_1 = Self::encode_ace_wire_value(challenges, clk, ctx, wire_1); - let value_2 = Self::encode_ace_wire_value(challenges, clk, ctx, wire_2); - - value[0] = value_0; - value[1] = value_1; - value[2] = value_2; - inv_value[0] = acc; - acc *= value_0; - inv_value[1] = acc; - acc *= value_1; - inv_value[2] = acc; - acc *= value_2; - } - - chiplet_offset += section.num_evals() as usize; - values_offset += NUM_ACE_LOGUP_FRACTIONS_EVAL * section.num_evals() as usize; - } - - // invert the accumulated product - acc = acc.inverse(); - - for i in (0..total_values.len()).rev() { - total_inv_values[i] *= acc; - acc *= total_values[i]; - } - - total_inv_values - } - - fn num_fractions(&self) -> usize { - self.sections - .iter() - .map(|section| { - NUM_ACE_LOGUP_FRACTIONS_READ * (section.num_vars as usize) - + NUM_ACE_LOGUP_FRACTIONS_EVAL * (section.num_evals as usize) - }) - .sum() - } -} diff --git a/processor/src/trace/chiplets/ace/tests/encoder.rs b/processor/src/trace/chiplets/ace/tests/encoder.rs index 0d4a876868..f17632d1b6 100644 --- a/processor/src/trace/chiplets/ace/tests/encoder.rs +++ b/processor/src/trace/chiplets/ace/tests/encoder.rs @@ -141,7 +141,7 @@ impl EncodedCircuit { }; let encoded = id_l as u64 + ((id_r as u64) << ID_BITS) + (op << (2 * ID_BITS)); - Some(Felt::new(encoded)) + Some(Felt::new_unchecked(encoded)) } } diff --git a/processor/src/trace/chiplets/ace/tests/mod.rs b/processor/src/trace/chiplets/ace/tests/mod.rs index b3353bbf55..453a4a47ca 100644 --- a/processor/src/trace/chiplets/ace/tests/mod.rs +++ b/processor/src/trace/chiplets/ace/tests/mod.rs @@ -12,7 +12,7 @@ use miden_air::trace::{ }; use miden_core::{ Felt, WORD_SIZE, Word, ZERO, - field::{BasedVectorSpace, PrimeCharacteristicRing, QuadFelt}, + field::{PrimeCharacteristicRing, QuadFelt}, }; use crate::{ @@ -30,7 +30,7 @@ mod circuit; mod encoder; const PTR_OFFSET_ELEM: Felt = Felt::ONE; -const PTR_OFFSET_WORD: Felt = Felt::new(4); +const PTR_OFFSET_WORD: Felt = Felt::new_unchecked(4); #[test] fn test_var_plus_one() { @@ -164,10 +164,10 @@ fn test_circuit_encoding() { ZERO, ZERO, ZERO, - Felt::new(7 + (5 << 30) + (2 << 60)), // id_l = 7; id_r = 5; op = ADD - Felt::new(7 + (3 << 30) + (1 << 60)), // id_l = 7; id_r = 3; op = MUL - Felt::new(2 + (6 << 30)), // id_l = 2; id_r = 6; op = SUB - Felt::new(1 + (1 << 30) + (1 << 60)), // id_l = 1; id_r = 1; op = MUL + Felt::new_unchecked(7 + (5 << 30) + (2 << 60)), // id_l = 7; id_r = 5; op = ADD + Felt::new_unchecked(7 + (3 << 30) + (1 << 60)), // id_l = 7; id_r = 3; op = MUL + Felt::new_unchecked(2 + (6 << 30)), // id_l = 2; id_r = 6; op = SUB + Felt::new_unchecked(1 + (1 << 30) + (1 << 60)), // id_l = 1; id_r = 1; op = MUL ] ) } @@ -255,7 +255,11 @@ fn generate_memory(circuit: &EncodedCircuit, inputs: &[QuadFelt]) -> Vec { // Inputs are store two by two in the fest set of words, followed by the instructions. let mut mem = Vec::with_capacity(2 * inputs.len() + circuit.encoded_circuit().len()); // Add inputs - mem.extend(inputs.iter().flat_map(|input| input.as_basis_coefficients_slice())); + mem.extend( + inputs + .iter() + .flat_map(miden_core::field::BasedVectorSpace::as_basis_coefficients_slice), + ); // Add circuit mem.extend(circuit.encoded_circuit().iter()); @@ -269,7 +273,6 @@ fn generate_memory(circuit: &EncodedCircuit, inputs: &[QuadFelt]) -> Vec { } /// Given an EvaluationContext -#[expect(clippy::needless_range_loop)] fn verify_trace(context: &CircuitEvaluation, num_read_rows: usize, num_eval_rows: usize) { let num_rows = num_read_rows + num_eval_rows; let mut columns: Vec<_> = (0..ACE_CHIPLET_NUM_COLS).map(|_| vec![ZERO; num_rows]).collect(); diff --git a/processor/src/trace/chiplets/ace/trace.rs b/processor/src/trace/chiplets/ace/trace.rs index d5948a8df3..95241c8d94 100644 --- a/processor/src/trace/chiplets/ace/trace.rs +++ b/processor/src/trace/chiplets/ace/trace.rs @@ -20,11 +20,6 @@ use super::{ }; use crate::{ContextId, errors::AceError}; -/// Number of LogUp fractions in the wiring bus for rows in the `READ` section. -pub const NUM_ACE_LOGUP_FRACTIONS_READ: usize = 2; -/// Number of LogUp fractions in the wiring bus for rows in the `EVAL` section. -pub const NUM_ACE_LOGUP_FRACTIONS_EVAL: usize = 3; - /// Contains the variable and evaluation nodes resulting from the evaluation of a circuit. /// The output value is checked to be equal to 0. /// diff --git a/processor/src/trace/chiplets/aux_trace/bus/ace.rs b/processor/src/trace/chiplets/aux_trace/bus/ace.rs deleted file mode 100644 index 69244fb693..0000000000 --- a/processor/src/trace/chiplets/aux_trace/bus/ace.rs +++ /dev/null @@ -1,126 +0,0 @@ -use core::fmt::{Display, Formatter, Result as FmtResult}; - -use miden_air::trace::{Challenges, MainTrace, RowIndex, chiplets::ace::ACE_INIT_LABEL}; -use miden_core::{Felt, ONE, field::ExtensionField}; - -use crate::debug::{BusDebugger, BusMessage}; - -// REQUESTS -// ============================================================================================== - -/// Builds requests made to the arithmetic circuit evaluation chiplet. -pub fn build_ace_chiplet_requests>( - main_trace: &MainTrace, - challenges: &Challenges, - row: RowIndex, - _debugger: &mut BusDebugger, -) -> E { - let clk = main_trace.clk(row); - let ctx = main_trace.ctx(row); - let ptr = main_trace.stack_element(0, row); - let num_read_rows = main_trace.stack_element(1, row); - let num_eval_rows = main_trace.stack_element(2, row); - - let ace_request_message = AceMessage { - op_label: ACE_INIT_LABEL, - clk, - ctx, - ptr, - num_read_rows, - num_eval_rows, - source: "ace request", - }; - - let value = ace_request_message.value(challenges); - - #[cfg(any(test, feature = "bus-debugger"))] - _debugger.add_request(alloc::boxed::Box::new(ace_request_message), challenges); - - value -} - -// RESPONSES -// ============================================================================================== - -/// Builds the response from the ace chiplet at `row`. -pub fn build_ace_chiplet_responses( - main_trace: &MainTrace, - row: RowIndex, - challenges: &Challenges, - _debugger: &mut BusDebugger, -) -> E -where - E: ExtensionField, -{ - let start_selector = main_trace.chiplet_ace_start_selector(row); - if start_selector == ONE { - let clk = main_trace.chiplet_ace_clk(row); - let ctx = main_trace.chiplet_ace_ctx(row); - let ptr = main_trace.chiplet_ace_ptr(row); - let num_eval_rows = main_trace.chiplet_ace_num_eval_rows(row) + ONE; - let id_0 = main_trace.chiplet_ace_id_0(row); - let num_read_rows = id_0 + ONE - num_eval_rows; - - let ace_message = AceMessage { - op_label: ACE_INIT_LABEL, - clk, - ctx, - ptr, - num_read_rows, - num_eval_rows, - source: "ace response", - }; - let value = ace_message.value(challenges); - - #[cfg(any(test, feature = "bus-debugger"))] - _debugger.add_response(alloc::boxed::Box::new(ace_message), challenges); - - value - } else { - E::ONE - } -} - -// MESSAGE -// =============================================================================================== - -#[derive(Debug)] -pub struct AceMessage { - pub op_label: Felt, - pub clk: Felt, - pub ctx: Felt, - pub ptr: Felt, - pub num_read_rows: Felt, - pub num_eval_rows: Felt, - pub source: &'static str, -} - -impl BusMessage for AceMessage -where - E: ExtensionField, -{ - fn value(&self, challenges: &Challenges) -> E { - challenges.encode([ - self.op_label, - self.clk, - self.ctx, - self.ptr, - self.num_read_rows, - self.num_eval_rows, - ]) - } - - fn source(&self) -> &str { - self.source - } -} - -impl Display for AceMessage { - fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - write!( - f, - "{{ op_label: {}, clk: {}, ctx: {}, ptr: {}, num_read_rows: {}, num_eval_rows: {} }}", - self.op_label, self.clk, self.ctx, self.ptr, self.num_read_rows, self.num_eval_rows - ) - } -} diff --git a/processor/src/trace/chiplets/aux_trace/bus/bitwise.rs b/processor/src/trace/chiplets/aux_trace/bus/bitwise.rs deleted file mode 100644 index 628fba3361..0000000000 --- a/processor/src/trace/chiplets/aux_trace/bus/bitwise.rs +++ /dev/null @@ -1,105 +0,0 @@ -use core::fmt::{Display, Formatter, Result as FmtResult}; - -use miden_air::trace::{ - Challenges, MainTrace, RowIndex, chiplets::bitwise::OP_CYCLE_LEN as BITWISE_OP_CYCLE_LEN, -}; -use miden_core::{Felt, ONE, ZERO, field::ExtensionField}; - -use super::get_op_label; -use crate::debug::{BusDebugger, BusMessage}; - -// REQUESTS -// ============================================================================================== - -/// Builds requests made to the bitwise chiplet. This can be either a request for the computation -/// of a `XOR` or an `AND` operation. -pub(super) fn build_bitwise_request>( - main_trace: &MainTrace, - is_xor: Felt, - challenges: &Challenges, - row: RowIndex, - _debugger: &mut BusDebugger, -) -> E { - let bitwise_request_message = BitwiseMessage { - op_label: get_op_label(ONE, ZERO, is_xor, ZERO), - a: main_trace.stack_element(0, row), - b: main_trace.stack_element(1, row), - z: main_trace.stack_element(0, row + 1), - source: if is_xor == ONE { "u32xor" } else { "u32and" }, - }; - - let value = bitwise_request_message.value(challenges); - - #[cfg(any(test, feature = "bus-debugger"))] - _debugger.add_request(alloc::boxed::Box::new(bitwise_request_message), challenges); - - value -} - -// RESPONSES -// ============================================================================================== - -/// Builds the response from the bitwise chiplet at `row`. -pub(super) fn build_bitwise_chiplet_responses( - main_trace: &MainTrace, - row: RowIndex, - challenges: &Challenges, - _debugger: &mut BusDebugger, -) -> E -where - E: ExtensionField, -{ - let is_xor = main_trace.chiplet_selector_2(row); - if row.as_usize() % BITWISE_OP_CYCLE_LEN == BITWISE_OP_CYCLE_LEN - 1 { - let bitwise_message = BitwiseMessage { - op_label: get_op_label(ONE, ZERO, is_xor, ZERO), - a: main_trace.chiplet_bitwise_a(row), - b: main_trace.chiplet_bitwise_b(row), - z: main_trace.chiplet_bitwise_z(row), - source: "bitwise chiplet", - }; - - let value = bitwise_message.value(challenges); - - #[cfg(any(test, feature = "bus-debugger"))] - _debugger.add_response(alloc::boxed::Box::new(bitwise_message), challenges); - - value - } else { - E::ONE - } -} - -// MESSAGE -// =============================================================================================== - -pub struct BitwiseMessage { - pub op_label: Felt, - pub a: Felt, - pub b: Felt, - pub z: Felt, - pub source: &'static str, -} - -impl BusMessage for BitwiseMessage -where - E: ExtensionField, -{ - fn value(&self, challenges: &Challenges) -> E { - challenges.encode([self.op_label, self.a, self.b, self.z]) - } - - fn source(&self) -> &str { - self.source - } -} - -impl Display for BitwiseMessage { - fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - write!( - f, - "{{ op_label: {}, a: {}, b: {}, z: {} }}", - self.op_label, self.a, self.b, self.z - ) - } -} diff --git a/processor/src/trace/chiplets/aux_trace/bus/hasher.rs b/processor/src/trace/chiplets/aux_trace/bus/hasher.rs deleted file mode 100644 index 80d659824b..0000000000 --- a/processor/src/trace/chiplets/aux_trace/bus/hasher.rs +++ /dev/null @@ -1,913 +0,0 @@ -use core::fmt::{Display, Formatter, Result as FmtResult}; - -use miden_air::trace::{ - Challenges, MainTrace, RowIndex, bus_message, - chiplets::{ - hasher, - hasher::{ - HASH_CYCLE_LEN, HASH_CYCLE_LEN_FELT, LAST_CYCLE_ROW, LAST_CYCLE_ROW_FELT, - LINEAR_HASH_LABEL, MP_VERIFY_LABEL, MR_UPDATE_NEW_LABEL, MR_UPDATE_OLD_LABEL, - RETURN_HASH_LABEL, RETURN_STATE_LABEL, - }, - }, - log_precompile::{ - HELPER_ADDR_IDX, HELPER_CAP_PREV_RANGE, STACK_CAP_NEXT_RANGE, STACK_COMM_RANGE, - STACK_R0_RANGE, STACK_R1_RANGE, STACK_TAG_RANGE, - }, -}; -use miden_core::{Felt, ONE, WORD_SIZE, ZERO, field::ExtensionField, operations::opcodes}; - -use super::get_op_label; -use crate::{ - Word, - debug::{BusDebugger, BusMessage}, -}; - -// HASHER MESSAGE ENCODING LAYOUT -// ================================================================================================ -// -// All hasher chiplet bus messages use a common encoding structure: -// -// challenges.alpha = alpha (randomness base, accessed directly) -// challenges.beta_powers[0] = beta^0 (label: transition type) -// challenges.beta_powers[1] = beta^1 (addr: hasher chiplet address) -// challenges.beta_powers[2] = beta^2 (node_index: Merkle path position, 0 for -// non-Merkle ops) challenges.beta_powers[3..10] = beta^3..beta^10 (state[0..7]: RATE0 || -// RATE1 in sponge order) challenges.beta_powers[11..14] = beta^11..beta^14 (capacity[0..3]: -// domain separation) -// -// Message encoding: alpha + beta^0*label + beta^1*addr + beta^2*node_index -// + beta^3*state[0] + ... + beta^10*state[7] -// + beta^11*capacity[0] + ... + beta^14*capacity[3] -// -// Different message types use different subsets of this layout: -// - Full state messages (HPERM, LOG_PRECOMPILE): all 12 state elements (rate + capacity) -// - Rate-only messages (SPAN, RESPAN): skip node_index and capacity, use label + addr + state[0..7] -// - Digest messages (END block): label + addr + RATE0 digest (state[0..3]) -// - Control block messages: rate + one capacity element (beta_powers[12]) for op_code -// - Tree operation messages (MPVERIFY, MRUPDATE): include node_index - -// HASHER MESSAGE CONSTANTS AND HELPERS -// ================================================================================================ - -const LABEL_OFFSET_START: Felt = Felt::new(16); -const LABEL_OFFSET_END: Felt = Felt::new(32); -const LINEAR_HASH_LABEL_START: Felt = Felt::new((LINEAR_HASH_LABEL + 16) as u64); -const LINEAR_HASH_LABEL_RESPAN: Felt = Felt::new((LINEAR_HASH_LABEL + 32) as u64); -const RETURN_HASH_LABEL_END: Felt = Felt::new((RETURN_HASH_LABEL + 32) as u64); -const RETURN_STATE_LABEL_END: Felt = Felt::new((RETURN_STATE_LABEL + 32) as u64); -const MP_VERIFY_LABEL_START: Felt = Felt::new((MP_VERIFY_LABEL + 16) as u64); -const MR_UPDATE_OLD_LABEL_START: Felt = Felt::new((MR_UPDATE_OLD_LABEL + 16) as u64); -const MR_UPDATE_NEW_LABEL_START: Felt = Felt::new((MR_UPDATE_NEW_LABEL + 16) as u64); - -/// Encodes hasher message as **alpha + ** -/// -/// Used for tree operations (MPVERIFY, MRUPDATE) and generic hasher messages with node_index. -#[inline(always)] -fn hasher_message_value( - challenges: &Challenges, - transition_label: Felt, - addr_next: Felt, - node_index: Felt, - state: [Felt; N], -) -> E -where - E: ExtensionField, -{ - let mut acc = challenges.alpha - + challenges.beta_powers[bus_message::LABEL_IDX] * transition_label - + challenges.beta_powers[bus_message::ADDR_IDX] * addr_next - + challenges.beta_powers[bus_message::NODE_INDEX_IDX] * node_index; - for (i, &elem) in state.iter().enumerate() { - acc += challenges.beta_powers[bus_message::STATE_START_IDX + i] * elem; - } - acc -} - -/// Encodes hasher message as **alpha + ** (skips node_index). -#[inline(always)] -fn header_rate_value( - challenges: &Challenges, - transition_label: Felt, - addr: Felt, - state: [Felt; hasher::RATE_LEN], -) -> E -where - E: ExtensionField, -{ - let mut acc = challenges.alpha - + challenges.beta_powers[bus_message::LABEL_IDX] * transition_label - + challenges.beta_powers[bus_message::ADDR_IDX] * addr; - for (i, &elem) in state.iter().enumerate() { - acc += challenges.beta_powers[bus_message::STATE_START_IDX + i] * elem; - } - acc -} - -/// Encodes hasher message as **alpha + ** (skips node_index, digest -/// is RATE0 only). -#[inline(always)] -fn header_digest_value( - challenges: &Challenges, - transition_label: Felt, - addr: Felt, - digest: [Felt; WORD_SIZE], -) -> E -where - E: ExtensionField, -{ - let mut acc = challenges.alpha - + challenges.beta_powers[bus_message::LABEL_IDX] * transition_label - + challenges.beta_powers[bus_message::ADDR_IDX] * addr; - for (i, &elem) in digest.iter().enumerate() { - acc += challenges.beta_powers[bus_message::STATE_START_IDX + i] * elem; - } - acc -} - -// REQUESTS -// ============================================================================================== - -/// Builds requests made to the hasher chiplet at the start of a control block. -pub(super) fn build_control_block_request>( - main_trace: &MainTrace, - decoder_hasher_state: [Felt; 8], - op_code_felt: Felt, - challenges: &Challenges, - row: RowIndex, - _debugger: &mut BusDebugger, -) -> E { - let message = ControlBlockRequestMessage { - transition_label: LINEAR_HASH_LABEL_START, - addr_next: main_trace.addr(row + 1), - op_code: op_code_felt, - decoder_hasher_state, - }; - - let value = message.value(challenges); - - #[cfg(any(test, feature = "bus-debugger"))] - _debugger.add_request(alloc::boxed::Box::new(message), challenges); - - value -} - -/// Builds requests made to the hasher chiplet at the start of a span block. -pub(super) fn build_span_block_request>( - main_trace: &MainTrace, - challenges: &Challenges, - row: RowIndex, - _debugger: &mut BusDebugger, -) -> E { - let span_block_message = SpanBlockMessage { - transition_label: LINEAR_HASH_LABEL_START, - addr_next: main_trace.addr(row + 1), - state: main_trace.decoder_hasher_state(row), - }; - - let value = span_block_message.value(challenges); - - #[cfg(any(test, feature = "bus-debugger"))] - _debugger.add_request(alloc::boxed::Box::new(span_block_message), challenges); - - value -} - -/// Builds requests made to the hasher chiplet at the start of a respan block. -pub(super) fn build_respan_block_request>( - main_trace: &MainTrace, - challenges: &Challenges, - row: RowIndex, - _debugger: &mut BusDebugger, -) -> E { - let respan_block_message = RespanBlockMessage { - transition_label: LINEAR_HASH_LABEL_RESPAN, - addr_next: main_trace.addr(row + 1), - state: main_trace.decoder_hasher_state(row), - }; - - let value = respan_block_message.value(challenges); - - #[cfg(any(test, feature = "bus-debugger"))] - _debugger.add_request(alloc::boxed::Box::new(respan_block_message), challenges); - - value -} - -/// Builds requests made to the hasher chiplet at the end of a block. -pub(super) fn build_end_block_request>( - main_trace: &MainTrace, - challenges: &Challenges, - row: RowIndex, - _debugger: &mut BusDebugger, -) -> E { - let end_block_message = EndBlockMessage { - addr: main_trace.addr(row) + LAST_CYCLE_ROW_FELT, - transition_label: RETURN_HASH_LABEL_END, - digest: main_trace.decoder_hasher_state(row)[..4] - .try_into() - .expect("decoder_hasher_state[0..4] must be 4 field elements"), - }; - - let value = end_block_message.value(challenges); - - #[cfg(any(test, feature = "bus-debugger"))] - _debugger.add_request(alloc::boxed::Box::new(end_block_message), challenges); - - value -} - -/// Builds `HPERM` requests made to the hash chiplet. -pub(super) fn build_hperm_request>( - main_trace: &MainTrace, - challenges: &Challenges, - row: RowIndex, - _debugger: &mut BusDebugger, -) -> E { - let helper_0 = main_trace.helper_register(0, row); - let s0 = main_trace.stack_element(0, row); - let s1 = main_trace.stack_element(1, row); - let s2 = main_trace.stack_element(2, row); - let s3 = main_trace.stack_element(3, row); - let s4 = main_trace.stack_element(4, row); - let s5 = main_trace.stack_element(5, row); - let s6 = main_trace.stack_element(6, row); - let s7 = main_trace.stack_element(7, row); - let s8 = main_trace.stack_element(8, row); - let s9 = main_trace.stack_element(9, row); - let s10 = main_trace.stack_element(10, row); - let s11 = main_trace.stack_element(11, row); - let s0_nxt = main_trace.stack_element(0, row + 1); - let s1_nxt = main_trace.stack_element(1, row + 1); - let s2_nxt = main_trace.stack_element(2, row + 1); - let s3_nxt = main_trace.stack_element(3, row + 1); - let s4_nxt = main_trace.stack_element(4, row + 1); - let s5_nxt = main_trace.stack_element(5, row + 1); - let s6_nxt = main_trace.stack_element(6, row + 1); - let s7_nxt = main_trace.stack_element(7, row + 1); - let s8_nxt = main_trace.stack_element(8, row + 1); - let s9_nxt = main_trace.stack_element(9, row + 1); - let s10_nxt = main_trace.stack_element(10, row + 1); - let s11_nxt = main_trace.stack_element(11, row + 1); - - let input_req = HasherMessage { - transition_label: LINEAR_HASH_LABEL_START, - addr_next: helper_0, - node_index: ZERO, - // Internal Poseidon2 state for HPERM is taken directly from the top 12 - // stack elements in order: [RATE0, RATE1, CAPACITY] = [s0..s11]. - hasher_state: [s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11], - source: "hperm input", - }; - let output_req = HasherMessage { - transition_label: RETURN_STATE_LABEL_END, - addr_next: helper_0 + LAST_CYCLE_ROW_FELT, - node_index: ZERO, - hasher_state: [ - s0_nxt, s1_nxt, s2_nxt, s3_nxt, s4_nxt, s5_nxt, s6_nxt, s7_nxt, s8_nxt, s9_nxt, - s10_nxt, s11_nxt, - ], - source: "hperm output", - }; - - let combined_value = input_req.value(challenges) * output_req.value(challenges); - - #[cfg(any(test, feature = "bus-debugger"))] - { - _debugger.add_request(alloc::boxed::Box::new(input_req), challenges); - _debugger.add_request(alloc::boxed::Box::new(output_req), challenges); - } - - combined_value -} - -/// Builds `LOG_PRECOMPILE` requests made to the hash chiplet. -/// -/// The operation absorbs `[TAG, COMM]` into the transcript via a Poseidon2 permutation with -/// capacity `CAP_PREV`, producing output `[R0, R1, CAP_NEXT]`. -/// -/// Stack layout (current row), structural (LSB-first) per word: -/// - `s0..s3`: `COMM[0..3]` -/// - `s4..s7`: `TAG[0..3]` -/// -/// Helper registers (current row): -/// - `h0`: hasher address -/// - `h1..h4`: `CAP_PREV[0..3]` -/// -/// Stack layout (next row): -/// - `s0..s3`: `R0[0..3]` -/// - `s4..s7`: `R1[0..3]` -/// - `s8..s11`: `CAP_NEXT[0..3]` -pub(super) fn build_log_precompile_request>( - main_trace: &MainTrace, - challenges: &Challenges, - row: RowIndex, - _debugger: &mut BusDebugger, -) -> E { - // Read helper registers - let addr = main_trace.helper_register(HELPER_ADDR_IDX, row); - - // Input state [COMM, TAG, CAP_PREV] in sponge order [RATE0, RATE1, CAP] - // Helper registers store capacity in sequential order [e0, e1, e2, e3] - let cap_prev = Word::from([ - main_trace.helper_register(HELPER_CAP_PREV_RANGE.start, row), - main_trace.helper_register(HELPER_CAP_PREV_RANGE.start + 1, row), - main_trace.helper_register(HELPER_CAP_PREV_RANGE.start + 2, row), - main_trace.helper_register(HELPER_CAP_PREV_RANGE.start + 3, row), - ]); - - // Stack stores words for log_precompile in structural (LSB-first) layout, - // so we read them directly as [w0, w1, w2, w3]. - let comm = main_trace.stack_word(STACK_COMM_RANGE.start, row); - let tag = main_trace.stack_word(STACK_TAG_RANGE.start, row); - // Internal Poseidon2 state is [RATE0, RATE1, CAPACITY] = [COMM, TAG, CAP_PREV] - let state_input = [comm, tag, cap_prev]; - - // Output state [R0, R1, CAP_NEXT] in sponge order - let r0 = main_trace.stack_word(STACK_R0_RANGE.start, row + 1); - let r1 = main_trace.stack_word(STACK_R1_RANGE.start, row + 1); - let cap_next = main_trace.stack_word(STACK_CAP_NEXT_RANGE.start, row + 1); - let state_output = [r0, r1, cap_next]; - - let input_req = HasherMessage { - transition_label: LINEAR_HASH_LABEL_START, - addr_next: addr, - node_index: ZERO, - hasher_state: Word::words_as_elements(&state_input) - .try_into() - .expect("log_precompile input state must be 12 field elements (3 words)"), - source: "log_precompile input", - }; - - let output_req = HasherMessage { - transition_label: RETURN_STATE_LABEL_END, - addr_next: addr + LAST_CYCLE_ROW_FELT, - node_index: ZERO, - hasher_state: Word::words_as_elements(&state_output) - .try_into() - .expect("log_precompile output state must be 12 field elements (3 words)"), - source: "log_precompile output", - }; - - let combined_value = input_req.value(challenges) * output_req.value(challenges); - - #[cfg(any(test, feature = "bus-debugger"))] - { - _debugger.add_request(alloc::boxed::Box::new(input_req), challenges); - _debugger.add_request(alloc::boxed::Box::new(output_req), challenges); - } - - combined_value -} - -/// Builds `MPVERIFY` requests made to the hash chiplet. -pub(super) fn build_mpverify_request>( - main_trace: &MainTrace, - challenges: &Challenges, - row: RowIndex, - _debugger: &mut BusDebugger, -) -> E { - // helper register holds (clk + 1) - let helper_0 = main_trace.helper_register(0, row); - let hash_cycle_len = HASH_CYCLE_LEN_FELT; - - let node_value = main_trace.stack_word(0, row); - let node_depth = main_trace.stack_element(4, row); - let node_index = main_trace.stack_element(5, row); - let merkle_tree_root = main_trace.stack_word(6, row); - - let node_word: [Felt; WORD_SIZE] = - node_value.as_elements().try_into().expect("word must be 4 field elements"); - let root_word: [Felt; WORD_SIZE] = merkle_tree_root - .as_elements() - .try_into() - .expect("word must be 4 field elements"); - - let input_value = - hasher_message_value(challenges, MP_VERIFY_LABEL_START, helper_0, node_index, node_word); - let output_value = hasher_message_value( - challenges, - RETURN_HASH_LABEL_END, - helper_0 + node_depth * hash_cycle_len - ONE, - ZERO, - root_word, - ); - - let combined_value = input_value * output_value; - - #[cfg(any(test, feature = "bus-debugger"))] - { - let mut node_state = [ZERO; hasher::STATE_WIDTH]; - node_state[..WORD_SIZE].copy_from_slice(&node_word); - - let input = HasherMessage { - transition_label: MP_VERIFY_LABEL_START, - addr_next: helper_0, - node_index, - hasher_state: node_state, - source: "mpverify input", - }; - - let mut root_state = [ZERO; hasher::STATE_WIDTH]; - root_state[..WORD_SIZE].copy_from_slice(&root_word); - - let output = HasherMessage { - transition_label: RETURN_HASH_LABEL_END, - addr_next: helper_0 + node_depth * hash_cycle_len - ONE, - node_index: ZERO, - hasher_state: root_state, - source: "mpverify output", - }; - - _debugger.add_request(alloc::boxed::Box::new(input), challenges); - _debugger.add_request(alloc::boxed::Box::new(output), challenges); - } - - combined_value -} - -/// Builds `MRUPDATE` requests made to the hash chiplet. -pub(super) fn build_mrupdate_request>( - main_trace: &MainTrace, - challenges: &Challenges, - row: RowIndex, - _debugger: &mut BusDebugger, -) -> E { - // helper register holds (clk + 1) - let helper_0 = main_trace.helper_register(0, row); - let hash_cycle_len = HASH_CYCLE_LEN_FELT; - let two_hash_cycles_len = hash_cycle_len + hash_cycle_len; - - let old_node_value = main_trace.stack_word(0, row); - let merkle_path_depth = main_trace.stack_element(4, row); - let node_index = main_trace.stack_element(5, row); - let old_root = main_trace.stack_word(6, row); - let new_node_value = main_trace.stack_word(10, row); - let new_root = main_trace.stack_word(0, row + 1); - - let old_node_word: [Felt; WORD_SIZE] = - old_node_value.as_elements().try_into().expect("word must be 4 field elements"); - let old_root_word: [Felt; WORD_SIZE] = - old_root.as_elements().try_into().expect("word must be 4 field elements"); - let new_node_word: [Felt; WORD_SIZE] = - new_node_value.as_elements().try_into().expect("word must be 4 field elements"); - let new_root_word: [Felt; WORD_SIZE] = - new_root.as_elements().try_into().expect("word must be 4 field elements"); - - let input_old_value = hasher_message_value( - challenges, - MR_UPDATE_OLD_LABEL_START, - helper_0, - node_index, - old_node_word, - ); - let output_old_value = hasher_message_value( - challenges, - RETURN_HASH_LABEL_END, - helper_0 + merkle_path_depth * hash_cycle_len - ONE, - ZERO, - old_root_word, - ); - let input_new_value = hasher_message_value( - challenges, - MR_UPDATE_NEW_LABEL_START, - helper_0 + merkle_path_depth * hash_cycle_len, - node_index, - new_node_word, - ); - let output_new_value = hasher_message_value( - challenges, - RETURN_HASH_LABEL_END, - helper_0 + merkle_path_depth * two_hash_cycles_len - ONE, - ZERO, - new_root_word, - ); - - let combined_value = input_old_value * output_old_value * input_new_value * output_new_value; - - #[cfg(any(test, feature = "bus-debugger"))] - { - let mut old_node_state = [ZERO; hasher::STATE_WIDTH]; - old_node_state[..WORD_SIZE].copy_from_slice(&old_node_word); - let mut old_root_state = [ZERO; hasher::STATE_WIDTH]; - old_root_state[..WORD_SIZE].copy_from_slice(&old_root_word); - let mut new_node_state = [ZERO; hasher::STATE_WIDTH]; - new_node_state[..WORD_SIZE].copy_from_slice(&new_node_word); - let mut new_root_state = [ZERO; hasher::STATE_WIDTH]; - new_root_state[..WORD_SIZE].copy_from_slice(&new_root_word); - - let input_old = HasherMessage { - transition_label: MR_UPDATE_OLD_LABEL_START, - addr_next: helper_0, - node_index, - hasher_state: old_node_state, - source: "mrupdate input_old", - }; - - let output_old = HasherMessage { - transition_label: RETURN_HASH_LABEL_END, - addr_next: helper_0 + merkle_path_depth * hash_cycle_len - ONE, - node_index: ZERO, - hasher_state: old_root_state, - source: "mrupdate output_old", - }; - - let input_new = HasherMessage { - transition_label: MR_UPDATE_NEW_LABEL_START, - addr_next: helper_0 + merkle_path_depth * hash_cycle_len, - node_index, - hasher_state: new_node_state, - source: "mrupdate input_new", - }; - - let output_new = HasherMessage { - transition_label: RETURN_HASH_LABEL_END, - addr_next: helper_0 + merkle_path_depth * two_hash_cycles_len - ONE, - node_index: ZERO, - hasher_state: new_root_state, - source: "mrupdate output_new", - }; - - _debugger.add_request(alloc::boxed::Box::new(input_old), challenges); - _debugger.add_request(alloc::boxed::Box::new(output_old), challenges); - _debugger.add_request(alloc::boxed::Box::new(input_new), challenges); - _debugger.add_request(alloc::boxed::Box::new(output_new), challenges); - } - - combined_value -} - -// RESPONSES -// ============================================================================================== - -/// Builds the response from the hasher chiplet at `row`. -pub(super) fn build_hasher_chiplet_responses( - main_trace: &MainTrace, - row: RowIndex, - challenges: &Challenges, - _debugger: &mut BusDebugger, -) -> E -where - E: ExtensionField, -{ - let mut multiplicand = E::ONE; - let selector0 = main_trace.chiplet_selector_0(row); - let selector1 = main_trace.chiplet_selector_1(row); - let selector2 = main_trace.chiplet_selector_2(row); - let selector3 = main_trace.chiplet_selector_3(row); - let op_label = get_op_label(selector0, selector1, selector2, selector3); - let addr_next = Felt::from(row + 1); - - // f_bp, f_mp, f_mv or f_mu == 1 - if row.as_usize().is_multiple_of(HASH_CYCLE_LEN) { - // Trace is already in sponge order [RATE0, RATE1, CAP] - let state = main_trace.chiplet_hasher_state(row); - let node_index = main_trace.chiplet_node_index(row); - let transition_label = op_label + LABEL_OFFSET_START; - - // f_bp == 1 - // v_all = v_h + v_a + v_b + v_c - if selector1 == ONE && selector2 == ZERO && selector3 == ZERO { - let hasher_message = HasherMessage { - transition_label, - addr_next, - node_index, - hasher_state: state, - source: "hasher", - }; - multiplicand = hasher_message.value(challenges); - - #[cfg(any(test, feature = "bus-debugger"))] - _debugger.add_response(alloc::boxed::Box::new(hasher_message), challenges); - } - - // f_mp or f_mv or f_mu == 1 - // v_leaf = v_h + (1 - b) * v_b + b * v_d - // In sponge order: RATE0 is at 0..4, RATE1 is at 4..8 - if selector1 == ONE && !(selector2 == ZERO && selector3 == ZERO) { - let bit = (node_index.as_canonical_u64() & 1) as u8; - let rate_word: [Felt; WORD_SIZE] = if bit == 0 { - state[..WORD_SIZE].try_into().expect("RATE0 word must be 4 field elements") - } else { - state[WORD_SIZE..hasher::RATE_LEN] - .try_into() - .expect("RATE1 word must be 4 field elements") - }; - - multiplicand = hasher_message_value( - challenges, - transition_label, - addr_next, - node_index, - rate_word, - ); - - #[cfg(any(test, feature = "bus-debugger"))] - { - let hasher_state = if bit == 0 { - [ - state[0], state[1], state[2], state[3], ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, - ZERO, ZERO, - ] - } else { - [ - state[4], state[5], state[6], state[7], ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, - ZERO, ZERO, - ] - }; - let hasher_message = HasherMessage { - transition_label, - addr_next, - node_index, - hasher_state, - source: "hasher", - }; - _debugger.add_response(alloc::boxed::Box::new(hasher_message), challenges); - } - } - } - - // f_hout, f_sout, f_abp == 1 - if row.as_usize() % HASH_CYCLE_LEN == LAST_CYCLE_ROW { - // Trace is already in sponge order [RATE0, RATE1, CAP] - let state = main_trace.chiplet_hasher_state(row); - let node_index = main_trace.chiplet_node_index(row); - let transition_label = op_label + LABEL_OFFSET_END; - - // f_hout == 1 - // v_res = v_h + v_b; - // Digest is at sponge positions 0..4 (RATE0) - if selector1 == ZERO && selector2 == ZERO && selector3 == ZERO { - let rate_word: [Felt; WORD_SIZE] = - state[..WORD_SIZE].try_into().expect("RATE0 word must be 4 field elements"); - multiplicand = hasher_message_value( - challenges, - transition_label, - addr_next, - node_index, - rate_word, - ); - - #[cfg(any(test, feature = "bus-debugger"))] - { - let hasher_message = HasherMessage { - transition_label, - addr_next, - node_index, - hasher_state: [ - state[0], state[1], state[2], state[3], ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, - ZERO, ZERO, - ], - source: "hasher", - }; - _debugger.add_response(alloc::boxed::Box::new(hasher_message), challenges); - } - } - - // f_sout == 1 - // v_all = v_h + v_a + v_b + v_c - if selector1 == ZERO && selector2 == ZERO && selector3 == ONE { - let hasher_message = HasherMessage { - transition_label, - addr_next, - node_index, - hasher_state: state, - source: "hasher", - }; - - multiplicand = hasher_message.value(challenges); - - #[cfg(any(test, feature = "bus-debugger"))] - _debugger.add_response(alloc::boxed::Box::new(hasher_message), challenges); - } - - // f_abp == 1 - // v_abp = v_h + v_b' + v_c' - v_b - v_c - if selector1 == ONE && selector2 == ZERO && selector3 == ZERO { - // Build the value from the hasher state just after absorption of new elements. - // Trace is in sponge order: RATE0 at indices 0..4, RATE1 at indices 4..8. - // Rate is mapped to lanes 0..7 with capacity lanes zeroed. - let state_nxt = main_trace.chiplet_hasher_state(row + 1); - let rate: [Felt; hasher::RATE_LEN] = state_nxt[..hasher::RATE_LEN] - .try_into() - .expect("rate portion must be 8 field elements"); - - multiplicand = - hasher_message_value(challenges, transition_label, addr_next, node_index, rate); - - #[cfg(any(test, feature = "bus-debugger"))] - { - let hasher_message = HasherMessage { - transition_label, - addr_next, - node_index, - hasher_state: [ - state_nxt[0], - state_nxt[1], - state_nxt[2], - state_nxt[3], - state_nxt[4], - state_nxt[5], - state_nxt[6], - state_nxt[7], - ZERO, - ZERO, - ZERO, - ZERO, - ], - source: "hasher", - }; - _debugger.add_response(alloc::boxed::Box::new(hasher_message), challenges); - } - } - } - multiplicand -} - -// CONTROL BLOCK REQUEST MESSAGE -// =============================================================================================== -pub struct ControlBlockRequestMessage { - pub transition_label: Felt, - pub addr_next: Felt, - pub op_code: Felt, - pub decoder_hasher_state: [Felt; 8], -} - -impl BusMessage for ControlBlockRequestMessage -where - E: ExtensionField, -{ - /// Encodes as **alpha + ** (skips - /// node_index). - fn value(&self, challenges: &Challenges) -> E { - // Header + rate portion + capacity domain element for op_code - let mut acc = header_rate_value( - challenges, - self.transition_label, - self.addr_next, - self.decoder_hasher_state, - ); - acc += challenges.beta_powers[bus_message::CAPACITY_DOMAIN_IDX] * self.op_code; - acc - } - - fn source(&self) -> &str { - let op_code = self.op_code.as_canonical_u64() as u8; - match op_code { - opcodes::JOIN => "join", - opcodes::SPLIT => "split", - opcodes::LOOP => "loop", - opcodes::CALL => "call", - opcodes::DYN => "dyn", - opcodes::DYNCALL => "dyncall", - opcodes::SYSCALL => "syscall", - _ => panic!("unexpected opcode: {op_code}"), - } - } -} - -impl Display for ControlBlockRequestMessage { - fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - write!( - f, - "{{ transition_label: {}, addr_next: {}, op_code: {}, decoder_hasher_state: {:?} }}", - self.transition_label, self.addr_next, self.op_code, self.decoder_hasher_state - ) - } -} - -// GENERIC HASHER MESSAGE -// =============================================================================================== - -pub struct HasherMessage { - pub transition_label: Felt, - pub addr_next: Felt, - pub node_index: Felt, - pub hasher_state: [Felt; hasher::STATE_WIDTH], - pub source: &'static str, -} - -impl BusMessage for HasherMessage -where - E: ExtensionField, -{ - fn value(&self, challenges: &Challenges) -> E { - hasher_message_value( - challenges, - self.transition_label, - self.addr_next, - self.node_index, - self.hasher_state, - ) - } - - fn source(&self) -> &str { - self.source - } -} - -impl Display for HasherMessage { - fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - write!( - f, - "{{ transition_label: {}, addr_next: {}, node_index: {}, hasher_state: {:?} }}", - self.transition_label, self.addr_next, self.node_index, self.hasher_state - ) - } -} - -// SPAN BLOCK MESSAGE -// =============================================================================================== - -pub struct SpanBlockMessage { - pub transition_label: Felt, - pub addr_next: Felt, - pub state: [Felt; 8], -} - -impl BusMessage for SpanBlockMessage -where - E: ExtensionField, -{ - fn value(&self, challenges: &Challenges) -> E { - header_rate_value(challenges, self.transition_label, self.addr_next, self.state) - } - - fn source(&self) -> &str { - "span" - } -} - -impl Display for SpanBlockMessage { - fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - write!( - f, - "{{ transition_label: {}, addr_next: {}, state: {:?} }}", - self.transition_label, self.addr_next, self.state - ) - } -} - -// RESPAN BLOCK MESSAGE -// =============================================================================================== - -pub struct RespanBlockMessage { - pub transition_label: Felt, - pub addr_next: Felt, - pub state: [Felt; 8], -} - -impl BusMessage for RespanBlockMessage -where - E: ExtensionField, -{ - fn value(&self, challenges: &Challenges) -> E { - header_rate_value(challenges, self.transition_label, self.addr_next - ONE, self.state) - } - - fn source(&self) -> &str { - "respan" - } -} - -impl Display for RespanBlockMessage { - fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - write!( - f, - "{{ transition_label: {}, addr_next: {}, state: {:?} }}", - self.transition_label, self.addr_next, self.state - ) - } -} - -// END BLOCK MESSAGE -// =============================================================================================== - -pub struct EndBlockMessage { - pub addr: Felt, - pub transition_label: Felt, - pub digest: [Felt; 4], -} - -impl BusMessage for EndBlockMessage -where - E: ExtensionField, -{ - fn value(&self, challenges: &Challenges) -> E { - header_digest_value(challenges, self.transition_label, self.addr, self.digest) - } - - fn source(&self) -> &str { - "end" - } -} - -impl Display for EndBlockMessage { - fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - write!( - f, - "{{ addr: {}, transition_label: {}, digest: {:?} }}", - self.addr, self.transition_label, self.digest - ) - } -} diff --git a/processor/src/trace/chiplets/aux_trace/bus/kernel.rs b/processor/src/trace/chiplets/aux_trace/bus/kernel.rs deleted file mode 100644 index 0455b292f6..0000000000 --- a/processor/src/trace/chiplets/aux_trace/bus/kernel.rs +++ /dev/null @@ -1,127 +0,0 @@ -use core::fmt::{Display, Formatter, Result as FmtResult}; - -use miden_air::trace::{ - Challenges, MainTrace, RowIndex, - chiplets::kernel_rom::{KERNEL_PROC_CALL_LABEL, KERNEL_PROC_INIT_LABEL}, -}; -use miden_core::{Felt, field::ExtensionField}; - -use crate::debug::{BusDebugger, BusMessage}; - -// RESPONSES -// ================================================================================================ - -/// Builds the response from the kernel chiplet at `row`. -/// -/// # Details -/// Each kernel procedure digest appears `n+1` times in the trace when requested `n` times by -/// the decoder (via SYSCALL). The first row for each unique digest produces a -/// `KernelRomInitMessage` response; the remaining `n` rows produce `KernelRomMessage` responses -/// matching decoder requests. -pub(super) fn build_kernel_chiplet_responses( - main_trace: &MainTrace, - row: RowIndex, - challenges: &Challenges, - _debugger: &mut BusDebugger, -) -> E -where - E: ExtensionField, -{ - let root0 = main_trace.chiplet_kernel_root_0(row); - let root1 = main_trace.chiplet_kernel_root_1(row); - let root2 = main_trace.chiplet_kernel_root_2(row); - let root3 = main_trace.chiplet_kernel_root_3(row); - - // The caller ensures this row is a kernel ROM row, so we just need to check if this is - // the first row for a unique procedure digest. - if main_trace.chiplet_kernel_is_first_hash_row(row) { - // Respond to the requests performed by the verifier when they initialize the bus - // column with the unique proc hashes. - let message = KernelRomInitMessage { - kernel_proc_digest: [root0, root1, root2, root3], - }; - let value = message.value(challenges); - - #[cfg(any(test, feature = "bus-debugger"))] - _debugger.add_response(alloc::boxed::Box::new(message), challenges); - - value - } else { - // Respond to decoder messages. - let message = KernelRomMessage { - kernel_proc_digest: [root0, root1, root2, root3], - }; - let value = message.value(challenges); - - #[cfg(any(test, feature = "bus-debugger"))] - _debugger.add_response(alloc::boxed::Box::new(message), challenges); - value - } -} - -// MESSAGES -// =============================================================================================== - -/// A message between the decoder and the kernel ROM to ensure a SYSCALL can only call procedures -///in the kernel as specified through public inputs. -pub struct KernelRomMessage { - pub kernel_proc_digest: [Felt; 4], -} - -impl BusMessage for KernelRomMessage -where - E: ExtensionField, -{ - #[inline(always)] - fn value(&self, challenges: &Challenges) -> E { - challenges.encode([ - KERNEL_PROC_CALL_LABEL, - self.kernel_proc_digest[0], - self.kernel_proc_digest[1], - self.kernel_proc_digest[2], - self.kernel_proc_digest[3], - ]) - } - - fn source(&self) -> &str { - "kernel rom" - } -} - -impl Display for KernelRomMessage { - fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - write!(f, "{{ proc digest: {:?} }}", self.kernel_proc_digest) - } -} - -/// A message linking unique kernel procedure hashes provided by public inputs, with hashes -/// contained in the kernel ROM chiplet trace. -pub struct KernelRomInitMessage { - pub kernel_proc_digest: [Felt; 4], -} - -impl BusMessage for KernelRomInitMessage -where - E: ExtensionField, -{ - #[inline(always)] - fn value(&self, challenges: &Challenges) -> E { - challenges.encode([ - KERNEL_PROC_INIT_LABEL, - self.kernel_proc_digest[0], - self.kernel_proc_digest[1], - self.kernel_proc_digest[2], - self.kernel_proc_digest[3], - ]) - } - - fn source(&self) -> &str { - "kernel rom init" - } -} - -impl Display for KernelRomInitMessage { - fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - write!(f, "{{ proc digest init: {:?} }}", self.kernel_proc_digest) - } -} diff --git a/processor/src/trace/chiplets/aux_trace/bus/memory.rs b/processor/src/trace/chiplets/aux_trace/bus/memory.rs deleted file mode 100644 index bd179571ac..0000000000 --- a/processor/src/trace/chiplets/aux_trace/bus/memory.rs +++ /dev/null @@ -1,660 +0,0 @@ -use core::fmt::{Display, Formatter, Result as FmtResult}; - -use miden_air::trace::{ - Challenges, MainTrace, RowIndex, - chiplets::{ - ace::{ACE_INSTRUCTION_ID1_OFFSET, ACE_INSTRUCTION_ID2_OFFSET}, - memory::{ - MEMORY_ACCESS_ELEMENT, MEMORY_ACCESS_WORD, MEMORY_READ_ELEMENT_LABEL, - MEMORY_READ_WORD_LABEL, MEMORY_WRITE_ELEMENT_LABEL, MEMORY_WRITE_WORD_LABEL, - }, - }, -}; -use miden_core::{ - FMP_ADDR, FMP_INIT_VALUE, Felt, ONE, ZERO, field::ExtensionField, operations::opcodes, -}; - -use crate::debug::{BusDebugger, BusMessage}; - -// CONSTANTS -// ================================================================================================ - -const FOUR: Felt = Felt::new(4); - -// REQUESTS -// ================================================================================================ - -/// Builds ACE chiplet read requests as part of the `READ` section made to the memory chiplet. -pub fn build_ace_memory_read_word_request>( - main_trace: &MainTrace, - challenges: &Challenges, - row: RowIndex, - _debugger: &mut BusDebugger, -) -> E { - let word = [ - main_trace.chiplet_ace_v_0_0(row), - main_trace.chiplet_ace_v_0_1(row), - main_trace.chiplet_ace_v_1_0(row), - main_trace.chiplet_ace_v_1_1(row), - ]; - let op_label = MEMORY_READ_WORD_LABEL; - let clk = main_trace.chiplet_ace_clk(row); - let ctx = main_trace.chiplet_ace_ctx(row); - let addr = main_trace.chiplet_ace_ptr(row); - - let message = MemoryWordMessage { - op_label: Felt::from_u8(op_label), - ctx, - addr, - clk, - word, - source: "read word ACE", - }; - - let value = message.value(challenges); - - #[cfg(any(test, feature = "bus-debugger"))] - _debugger.add_request(alloc::boxed::Box::new(message), challenges); - - value -} - -/// Builds ACE chiplet read requests as part of the `EVAL` section made to the memory chiplet. -pub fn build_ace_memory_read_element_request>( - main_trace: &MainTrace, - challenges: &Challenges, - row: RowIndex, - _debugger: &mut BusDebugger, -) -> E { - let element = main_trace.chiplet_ace_eval_op(row); - - let id_0 = main_trace.chiplet_ace_id_1(row); - let id_1 = main_trace.chiplet_ace_id_2(row); - let element = - id_0 + id_1 * ACE_INSTRUCTION_ID1_OFFSET + (element + ONE) * ACE_INSTRUCTION_ID2_OFFSET; - let op_label = MEMORY_READ_ELEMENT_LABEL; - let clk = main_trace.chiplet_ace_clk(row); - let ctx = main_trace.chiplet_ace_ctx(row); - let addr = main_trace.chiplet_ace_ptr(row); - - let message = MemoryElementMessage { - op_label: Felt::from_u8(op_label), - ctx, - addr, - clk, - element, - }; - - let value = message.value(challenges); - - #[cfg(any(test, feature = "bus-debugger"))] - _debugger.add_request(alloc::boxed::Box::new(message), challenges); - - value -} - -/// Builds `DYN` and `DYNCALL` read request made to the memory chiplet for the callee hash. -pub(super) fn build_dyn_dyncall_callee_hash_read_request>( - main_trace: &MainTrace, - op_code_felt: Felt, - challenges: &Challenges, - row: RowIndex, - _debugger: &mut BusDebugger, -) -> E { - let memory_req = MemoryWordMessage { - op_label: Felt::from_u8(MEMORY_READ_WORD_LABEL), - ctx: main_trace.ctx(row), - addr: main_trace.stack_element(0, row), - clk: main_trace.clk(row), - word: main_trace.decoder_hasher_state_first_half(row).into(), - source: if op_code_felt == Felt::from_u8(opcodes::DYNCALL) { - "dyncall" - } else { - "dyn" - }, - }; - - let value = memory_req.value(challenges); - - #[cfg(any(test, feature = "bus-debugger"))] - _debugger.add_request(alloc::boxed::Box::new(memory_req), challenges); - - value -} - -/// Builds a write request to initialize the frame pointer in memory when entering a new execution -/// context. -/// -/// Currently, this is done with `CALL` and `DYNCALL`. -pub(super) fn build_fmp_initialization_write_request>( - main_trace: &MainTrace, - challenges: &Challenges, - row: RowIndex, - _debugger: &mut BusDebugger, -) -> E { - // Note that `ctx` is taken from the next row, as the goal of this request is to write the - // initial FMP value to memory at the start of a new execution context, which happens - // immediately after the current row. - let memory_req = MemoryElementMessage { - op_label: Felt::from_u8(MEMORY_WRITE_ELEMENT_LABEL), - ctx: main_trace.ctx(row + 1), - addr: FMP_ADDR, - clk: main_trace.clk(row), - element: FMP_INIT_VALUE, - }; - - let value = memory_req.value(challenges); - - #[cfg(any(test, feature = "bus-debugger"))] - _debugger.add_request(alloc::boxed::Box::new(memory_req), challenges); - - value -} - -/// Builds `MLOADW` and `MSTOREW` requests made to the memory chiplet. -pub(super) fn build_mem_mloadw_mstorew_request>( - main_trace: &MainTrace, - op_label: u8, - challenges: &Challenges, - row: RowIndex, - _debugger: &mut BusDebugger, -) -> E { - // word[i] maps directly to stack position i. - let word = [ - main_trace.stack_element(0, row + 1), - main_trace.stack_element(1, row + 1), - main_trace.stack_element(2, row + 1), - main_trace.stack_element(3, row + 1), - ]; - let addr = main_trace.stack_element(0, row); - - debug_assert!(op_label == MEMORY_READ_WORD_LABEL || op_label == MEMORY_WRITE_WORD_LABEL); - let ctx = main_trace.ctx(row); - let clk = main_trace.clk(row); - - let message = MemoryWordMessage { - op_label: Felt::from_u8(op_label), - ctx, - addr, - clk, - word, - source: if op_label == MEMORY_READ_WORD_LABEL { - "mloadw" - } else { - "mstorew" - }, - }; - - let value = message.value(challenges); - - #[cfg(any(test, feature = "bus-debugger"))] - _debugger.add_request(alloc::boxed::Box::new(message), challenges); - - value -} - -/// Builds `MLOAD` and `MSTORE` requests made to the memory chiplet. -pub(super) fn build_mem_mload_mstore_request>( - main_trace: &MainTrace, - op_label: u8, - challenges: &Challenges, - row: RowIndex, - _debugger: &mut BusDebugger, -) -> E { - let element = main_trace.stack_element(0, row + 1); - let addr = main_trace.stack_element(0, row); - - debug_assert!(op_label == MEMORY_READ_ELEMENT_LABEL || op_label == MEMORY_WRITE_ELEMENT_LABEL); - - let ctx = main_trace.ctx(row); - let clk = main_trace.clk(row); - - let message = MemoryElementMessage { - op_label: Felt::from_u8(op_label), - ctx, - addr, - clk, - element, - }; - - let value = message.value(challenges); - - #[cfg(any(test, feature = "bus-debugger"))] - _debugger.add_request(alloc::boxed::Box::new(message), challenges); - - value -} - -/// Builds `MSTREAM` requests made to the memory chiplet. -pub(super) fn build_mstream_request>( - main_trace: &MainTrace, - challenges: &Challenges, - row: RowIndex, - _debugger: &mut BusDebugger, -) -> E { - let op_label = Felt::from_u8(MEMORY_READ_WORD_LABEL); - let addr = main_trace.stack_element(12, row); - let ctx = main_trace.ctx(row); - let clk = main_trace.clk(row); - - // word[0] is at stack position 0 (top). - // MSTREAM loads two words: first word (from addr) to s0-s3, second word (from addr+4) to s4-s7. - let mem_req_1 = MemoryWordMessage { - op_label, - ctx, - addr, - clk, - word: [ - main_trace.stack_element(0, row + 1), - main_trace.stack_element(1, row + 1), - main_trace.stack_element(2, row + 1), - main_trace.stack_element(3, row + 1), - ], - source: "mstream req 1", - }; - let mem_req_2 = MemoryWordMessage { - op_label, - ctx, - addr: addr + FOUR, - clk, - word: [ - main_trace.stack_element(4, row + 1), - main_trace.stack_element(5, row + 1), - main_trace.stack_element(6, row + 1), - main_trace.stack_element(7, row + 1), - ], - source: "mstream req 2", - }; - - let combined_value = mem_req_1.value(challenges) * mem_req_2.value(challenges); - - #[cfg(any(test, feature = "bus-debugger"))] - { - _debugger.add_request(alloc::boxed::Box::new(mem_req_1), challenges); - _debugger.add_request(alloc::boxed::Box::new(mem_req_2), challenges); - } - - combined_value -} - -/// Builds `PIPE` requests made to the memory chiplet. -pub(super) fn build_pipe_request>( - main_trace: &MainTrace, - challenges: &Challenges, - row: RowIndex, - _debugger: &mut BusDebugger, -) -> E { - let op_label = Felt::from_u8(MEMORY_WRITE_WORD_LABEL); - let addr = main_trace.stack_element(12, row); - let ctx = main_trace.ctx(row); - let clk = main_trace.clk(row); - - // word[0] is at stack position 0 (top). - // PIPE writes two words: first word (from s0-s3) to addr, second word (from s4-s7) to addr+4. - let mem_req_1 = MemoryWordMessage { - op_label, - ctx, - addr, - clk, - word: [ - main_trace.stack_element(0, row + 1), - main_trace.stack_element(1, row + 1), - main_trace.stack_element(2, row + 1), - main_trace.stack_element(3, row + 1), - ], - source: "pipe req 1", - }; - let mem_req_2 = MemoryWordMessage { - op_label, - ctx, - addr: addr + FOUR, - clk, - word: [ - main_trace.stack_element(4, row + 1), - main_trace.stack_element(5, row + 1), - main_trace.stack_element(6, row + 1), - main_trace.stack_element(7, row + 1), - ], - source: "pipe req 2", - }; - - let combined_value = mem_req_1.value(challenges) * mem_req_2.value(challenges); - - #[cfg(any(test, feature = "bus-debugger"))] - { - _debugger.add_request(alloc::boxed::Box::new(mem_req_1), challenges); - _debugger.add_request(alloc::boxed::Box::new(mem_req_2), challenges); - } - - combined_value -} - -/// Builds `CRYPTOSTREAM` requests made to the memory chiplet. -/// -/// CryptoStream reads two words from `src_ptr` and `src_ptr + 4`, and writes two words (the -/// ciphertext) to `dst_ptr` and `dst_ptr + 4`. The ciphertext is `plaintext + rate`, where -/// rate is the stack top before the operation. We derive the read (plaintext) values as -/// `ciphertext - rate`. -pub(super) fn build_crypto_stream_request>( - main_trace: &MainTrace, - challenges: &Challenges, - row: RowIndex, - _debugger: &mut BusDebugger, -) -> E { - let ctx = main_trace.ctx(row); - let clk = main_trace.clk(row); - let src_addr = main_trace.stack_element(12, row); - let dst_addr = main_trace.stack_element(13, row); - - // Ciphertext is on the stack after the operation (row + 1), positions 0..7. - let ciphertext: [Felt; 8] = core::array::from_fn(|i| main_trace.stack_element(i, row + 1)); - - // Rate is on the stack before the operation (row), positions 0..7. - let rate: [Felt; 8] = core::array::from_fn(|i| main_trace.stack_element(i, row)); - - // Plaintext = ciphertext - rate. - let plaintext: [Felt; 8] = core::array::from_fn(|i| ciphertext[i] - rate[i]); - - // Two read-word requests at src_addr and src_addr + 4. - let read_label = Felt::from_u8(MEMORY_READ_WORD_LABEL); - let read_req_1 = MemoryWordMessage { - op_label: read_label, - ctx, - addr: src_addr, - clk, - word: [plaintext[0], plaintext[1], plaintext[2], plaintext[3]], - source: "crypto_stream read 1", - }; - let read_req_2 = MemoryWordMessage { - op_label: read_label, - ctx, - addr: src_addr + FOUR, - clk, - word: [plaintext[4], plaintext[5], plaintext[6], plaintext[7]], - source: "crypto_stream read 2", - }; - - // Two write-word requests at dst_addr and dst_addr + 4. - let write_label = Felt::from_u8(MEMORY_WRITE_WORD_LABEL); - let write_req_1 = MemoryWordMessage { - op_label: write_label, - ctx, - addr: dst_addr, - clk, - word: [ciphertext[0], ciphertext[1], ciphertext[2], ciphertext[3]], - source: "crypto_stream write 1", - }; - let write_req_2 = MemoryWordMessage { - op_label: write_label, - ctx, - addr: dst_addr + FOUR, - clk, - word: [ciphertext[4], ciphertext[5], ciphertext[6], ciphertext[7]], - source: "crypto_stream write 2", - }; - - let combined_value = read_req_1.value(challenges) - * read_req_2.value(challenges) - * write_req_1.value(challenges) - * write_req_2.value(challenges); - - #[cfg(any(test, feature = "bus-debugger"))] - { - _debugger.add_request(alloc::boxed::Box::new(read_req_1), challenges); - _debugger.add_request(alloc::boxed::Box::new(read_req_2), challenges); - _debugger.add_request(alloc::boxed::Box::new(write_req_1), challenges); - _debugger.add_request(alloc::boxed::Box::new(write_req_2), challenges); - } - - combined_value -} - -/// Builds `HORNERBASE` requests made to the memory chiplet. -pub(super) fn build_hornerbase_eval_request>( - main_trace: &MainTrace, - challenges: &Challenges, - row: RowIndex, - _debugger: &mut BusDebugger, -) -> E { - let eval_point_0 = main_trace.helper_register(0, row); - let eval_point_1 = main_trace.helper_register(1, row); - let eval_point_ptr = main_trace.stack_element(13, row); - let op_label = Felt::from_u8(MEMORY_READ_ELEMENT_LABEL); - - let ctx = main_trace.ctx(row); - let clk = main_trace.clk(row); - - let mem_req_0 = MemoryElementMessage { - op_label, - ctx, - addr: eval_point_ptr, - clk, - element: eval_point_0, - }; - let mem_req_1 = MemoryElementMessage { - op_label, - ctx, - addr: eval_point_ptr + ONE, - clk, - element: eval_point_1, - }; - - let value = mem_req_0.value(challenges) * mem_req_1.value(challenges); - - #[cfg(any(test, feature = "bus-debugger"))] - { - _debugger.add_request(alloc::boxed::Box::new(mem_req_0), challenges); - _debugger.add_request(alloc::boxed::Box::new(mem_req_1), challenges); - } - - value -} - -/// Builds `HORNEREXT` requests made to the memory chiplet. -pub(super) fn build_hornerext_eval_request>( - main_trace: &MainTrace, - challenges: &Challenges, - row: RowIndex, - _debugger: &mut BusDebugger, -) -> E { - let eval_point_0 = main_trace.helper_register(0, row); - let eval_point_1 = main_trace.helper_register(1, row); - let mem_junk_0 = main_trace.helper_register(2, row); - let mem_junk_1 = main_trace.helper_register(3, row); - let eval_point_ptr = main_trace.stack_element(13, row); - let op_label = Felt::from_u8(MEMORY_READ_WORD_LABEL); - - let ctx = main_trace.ctx(row); - let clk = main_trace.clk(row); - - let mem_req = MemoryWordMessage { - op_label, - ctx, - addr: eval_point_ptr, - clk, - word: [eval_point_0, eval_point_1, mem_junk_0, mem_junk_1], - source: "hornerext_eval_* req", - }; - - let value = mem_req.value(challenges); - - #[cfg(any(test, feature = "bus-debugger"))] - { - _debugger.add_request(alloc::boxed::Box::new(mem_req), challenges); - } - - value -} - -// RESPONSES -// ================================================================================================ - -/// Builds the response from the memory chiplet at `row`. -pub(super) fn build_memory_chiplet_responses( - main_trace: &MainTrace, - row: RowIndex, - challenges: &Challenges, - _debugger: &mut BusDebugger, -) -> E -where - E: ExtensionField, -{ - let access_type = main_trace.chiplet_selector_4(row); - let op_label = { - let is_read = main_trace.chiplet_selector_3(row); - get_memory_op_label(is_read, access_type) - }; - let ctx = main_trace.chiplet_memory_ctx(row); - let clk = main_trace.chiplet_memory_clk(row); - let addr = { - let word = main_trace.chiplet_memory_word(row); - let idx0 = main_trace.chiplet_memory_idx0(row); - let idx1 = main_trace.chiplet_memory_idx1(row); - - word + idx1.double() + idx0 - }; - - if access_type == MEMORY_ACCESS_ELEMENT { - let idx0 = main_trace.chiplet_memory_idx0(row); - let idx1 = main_trace.chiplet_memory_idx1(row); - - let element = if idx1 == ZERO && idx0 == ZERO { - main_trace.chiplet_memory_value_0(row) - } else if idx1 == ZERO && idx0 == ONE { - main_trace.chiplet_memory_value_1(row) - } else if idx1 == ONE && idx0 == ZERO { - main_trace.chiplet_memory_value_2(row) - } else if idx1 == ONE && idx0 == ONE { - main_trace.chiplet_memory_value_3(row) - } else { - panic!("Invalid word indices. idx0: {idx0}, idx1: {idx1}"); - }; - - let message = MemoryElementMessage { op_label, ctx, addr, clk, element }; - - let value = message.value(challenges); - - #[cfg(any(test, feature = "bus-debugger"))] - _debugger.add_response(alloc::boxed::Box::new(message), challenges); - - value - } else if access_type == MEMORY_ACCESS_WORD { - let value0 = main_trace.chiplet_memory_value_0(row); - let value1 = main_trace.chiplet_memory_value_1(row); - let value2 = main_trace.chiplet_memory_value_2(row); - let value3 = main_trace.chiplet_memory_value_3(row); - - let message = MemoryWordMessage { - op_label, - ctx, - addr, - clk, - word: [value0, value1, value2, value3], - source: "memory chiplet", - }; - - let value = message.value(challenges); - - #[cfg(any(test, feature = "bus-debugger"))] - _debugger.add_response(alloc::boxed::Box::new(message), challenges); - - value - } else { - panic!("Invalid memory element/word column value: {access_type}"); - } -} - -// HELPER FUNCTIONS -// ================================================================================================ - -/// Returns the operation unique label for memory operations. -/// -/// The memory selector flags are `[1, 1, 0, is_read, is_word_access]`. -/// The flag is derived as the big-endian representation of these flags, plus one. -/// They are also defined in [`chiplets::memory`](miden_air::trace::chiplets::memory). -fn get_memory_op_label(is_read: Felt, is_word_access: Felt) -> Felt { - let is_read = (is_read == ONE) as u8; - let is_word_access = (is_word_access == ONE) as u8; - - const MEMORY_SELECTOR_FLAG_BASE: u8 = 0b011 + 1; - const OP_FLAG_SHIFT: u8 = 3; - - let op_flag = is_read + 2 * is_word_access; - - Felt::from_u8(MEMORY_SELECTOR_FLAG_BASE + (op_flag << OP_FLAG_SHIFT)) -} - -// MESSAGES -// =============================================================================================== - -pub struct MemoryWordMessage { - pub op_label: Felt, - pub ctx: Felt, - pub addr: Felt, - pub clk: Felt, - pub word: [Felt; 4], - pub source: &'static str, -} - -impl BusMessage for MemoryWordMessage -where - E: ExtensionField, -{ - fn value(&self, challenges: &Challenges) -> E { - challenges.encode([ - self.op_label, - self.ctx, - self.addr, - self.clk, - self.word[0], - self.word[1], - self.word[2], - self.word[3], - ]) - } - - fn source(&self) -> &str { - self.source - } -} - -impl Display for MemoryWordMessage { - fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - write!( - f, - "{{ op_label: {}, ctx: {}, addr: {}, clk: {}, word: {:?} }}", - self.op_label, self.ctx, self.addr, self.clk, self.word - ) - } -} - -pub struct MemoryElementMessage { - pub op_label: Felt, - pub ctx: Felt, - pub addr: Felt, - pub clk: Felt, - pub element: Felt, -} - -impl BusMessage for MemoryElementMessage -where - E: ExtensionField, -{ - fn value(&self, challenges: &Challenges) -> E { - challenges.encode([self.op_label, self.ctx, self.addr, self.clk, self.element]) - } - - fn source(&self) -> &str { - "memory element" - } -} - -impl Display for MemoryElementMessage { - fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - write!( - f, - "{{ op_label: {}, ctx: {}, addr: {}, clk: {}, element: {} }}", - self.op_label, self.ctx, self.addr, self.clk, self.element - ) - } -} diff --git a/processor/src/trace/chiplets/aux_trace/bus/mod.rs b/processor/src/trace/chiplets/aux_trace/bus/mod.rs deleted file mode 100644 index a222f0a5ae..0000000000 --- a/processor/src/trace/chiplets/aux_trace/bus/mod.rs +++ /dev/null @@ -1,335 +0,0 @@ -use ace::{build_ace_chiplet_requests, build_ace_chiplet_responses}; -use bitwise::{build_bitwise_chiplet_responses, build_bitwise_request}; -use hasher::{ - ControlBlockRequestMessage, build_control_block_request, build_end_block_request, - build_hasher_chiplet_responses, build_hperm_request, build_log_precompile_request, - build_mpverify_request, build_mrupdate_request, build_respan_block_request, - build_span_block_request, -}; -use kernel::{KernelRomMessage, build_kernel_chiplet_responses}; -use memory::{ - build_crypto_stream_request, build_dyn_dyncall_callee_hash_read_request, - build_fmp_initialization_write_request, build_hornerbase_eval_request, - build_hornerext_eval_request, build_mem_mload_mstore_request, build_mem_mloadw_mstorew_request, - build_memory_chiplet_responses, build_mstream_request, build_pipe_request, -}; -use miden_air::trace::{ - Challenges, MainTrace, RowIndex, - chiplets::{ - hasher::LINEAR_HASH_LABEL, - memory::{ - MEMORY_READ_ELEMENT_LABEL, MEMORY_READ_WORD_LABEL, MEMORY_WRITE_ELEMENT_LABEL, - MEMORY_WRITE_WORD_LABEL, - }, - }, -}; -use miden_core::{ONE, ZERO, field::ExtensionField, operations::opcodes}; - -use super::Felt; -use crate::{ - debug::{BusDebugger, BusMessage}, - trace::AuxColumnBuilder, -}; - -mod ace; -mod bitwise; -mod hasher; -mod kernel; -mod memory; - -pub use memory::{build_ace_memory_read_element_request, build_ace_memory_read_word_request}; - -// BUS COLUMN BUILDER -// ================================================================================================ - -/// Describes how to construct the execution trace of the chiplets bus auxiliary trace column. -pub struct BusColumnBuilder; - -impl AuxColumnBuilder for BusColumnBuilder -where - E: ExtensionField, -{ - /// Constructs the requests made by the VM-components to the chiplets at `row`. - fn get_requests_at( - &self, - main_trace: &MainTrace, - challenges: &Challenges, - row: RowIndex, - debugger: &mut BusDebugger, - ) -> E { - let op_code_felt = main_trace.get_op_code(row); - let op_code = op_code_felt.as_canonical_u64() as u8; - - match op_code { - opcodes::JOIN | opcodes::SPLIT | opcodes::LOOP => build_control_block_request( - main_trace, - main_trace.decoder_hasher_state(row), - op_code_felt, - challenges, - row, - debugger, - ), - opcodes::CALL => { - build_call_request(main_trace, op_code_felt, challenges, row, debugger) - }, - opcodes::DYN => build_dyn_request(main_trace, op_code_felt, challenges, row, debugger), - opcodes::DYNCALL => { - build_dyncall_request(main_trace, op_code_felt, challenges, row, debugger) - }, - opcodes::SYSCALL => { - build_syscall_block_request(main_trace, op_code_felt, challenges, row, debugger) - }, - opcodes::SPAN => build_span_block_request(main_trace, challenges, row, debugger), - opcodes::RESPAN => build_respan_block_request(main_trace, challenges, row, debugger), - opcodes::END => build_end_block_request(main_trace, challenges, row, debugger), - opcodes::U32AND => build_bitwise_request(main_trace, ZERO, challenges, row, debugger), - opcodes::U32XOR => build_bitwise_request(main_trace, ONE, challenges, row, debugger), - opcodes::MLOADW => build_mem_mloadw_mstorew_request( - main_trace, - MEMORY_READ_WORD_LABEL, - challenges, - row, - debugger, - ), - opcodes::MSTOREW => build_mem_mloadw_mstorew_request( - main_trace, - MEMORY_WRITE_WORD_LABEL, - challenges, - row, - debugger, - ), - opcodes::MLOAD => build_mem_mload_mstore_request( - main_trace, - MEMORY_READ_ELEMENT_LABEL, - challenges, - row, - debugger, - ), - opcodes::MSTORE => build_mem_mload_mstore_request( - main_trace, - MEMORY_WRITE_ELEMENT_LABEL, - challenges, - row, - debugger, - ), - opcodes::HORNERBASE => { - build_hornerbase_eval_request(main_trace, challenges, row, debugger) - }, - opcodes::HORNEREXT => { - build_hornerext_eval_request(main_trace, challenges, row, debugger) - }, - opcodes::MSTREAM => build_mstream_request(main_trace, challenges, row, debugger), - opcodes::CRYPTOSTREAM => { - build_crypto_stream_request(main_trace, challenges, row, debugger) - }, - opcodes::HPERM => build_hperm_request(main_trace, challenges, row, debugger), - opcodes::LOGPRECOMPILE => { - build_log_precompile_request(main_trace, challenges, row, debugger) - }, - opcodes::MPVERIFY => build_mpverify_request(main_trace, challenges, row, debugger), - opcodes::MRUPDATE => build_mrupdate_request(main_trace, challenges, row, debugger), - opcodes::PIPE => build_pipe_request(main_trace, challenges, row, debugger), - opcodes::EVALCIRCUIT => { - build_ace_chiplet_requests(main_trace, challenges, row, debugger) - }, - _ => E::ONE, - } - } - - /// Constructs the responses from the chiplets to the other VM-components at `row`. - fn get_responses_at( - &self, - main_trace: &MainTrace, - challenges: &Challenges, - row: RowIndex, - debugger: &mut BusDebugger, - ) -> E { - if main_trace.is_hash_row(row) { - build_hasher_chiplet_responses(main_trace, row, challenges, debugger) - } else if main_trace.is_bitwise_row(row) { - build_bitwise_chiplet_responses(main_trace, row, challenges, debugger) - } else if main_trace.is_memory_row(row) { - build_memory_chiplet_responses(main_trace, row, challenges, debugger) - } else if main_trace.is_ace_row(row) { - build_ace_chiplet_responses(main_trace, row, challenges, debugger) - } else if main_trace.is_kernel_row(row) { - build_kernel_chiplet_responses(main_trace, row, challenges, debugger) - } else { - E::ONE - } - } - - #[cfg(any(test, feature = "bus-debugger"))] - fn enforce_bus_balance(&self) -> bool { - // The chiplets bus final value encodes kernel procedure digest boundary terms, - // which are checked via reduced_aux_values. It does not balance to identity. - false - } -} - -// CHIPLETS REQUESTS TO MORE THAN ONE CHIPLET -// ================================================================================================ - -/// Encodes a control block request without hasher state (optimized for DYN/DYNCALL). -/// -/// Standard control block encoding includes state[0..7] which are always zero for DYN/DYNCALL. -/// This optimization skips those 8 multiplications. -/// -/// Encoding: `alpha + beta^0*label + beta^1*addr + beta^12*op_code` -/// where beta^12 is the capacity domain element at coeffs[13]. -#[inline(always)] -fn encode_control_block_without_state(challenges: &Challenges, addr: Felt, op_code: Felt) -> E -where - E: ExtensionField, -{ - use miden_air::trace::bus_message; - - challenges.alpha - + challenges.beta_powers[bus_message::LABEL_IDX] * Felt::from_u8(LINEAR_HASH_LABEL + 16) - + challenges.beta_powers[bus_message::ADDR_IDX] * addr - + challenges.beta_powers[bus_message::CAPACITY_DOMAIN_IDX] * op_code -} - -/// Builds requests made on a `DYN` operation. -fn build_dyn_request( - main_trace: &MainTrace, - op_code_felt: Felt, - challenges: &Challenges, - row: RowIndex, - _debugger: &mut BusDebugger, -) -> E -where - E: ExtensionField, -{ - let control_block_req_value = - encode_control_block_without_state(challenges, main_trace.addr(row + 1), op_code_felt); - - #[cfg(any(test, feature = "bus-debugger"))] - { - let control_block_req = ControlBlockRequestMessage { - transition_label: Felt::from_u8(LINEAR_HASH_LABEL + 16), - addr_next: main_trace.addr(row + 1), - op_code: op_code_felt, - // DYN encodes without state; keep it zeroed to match the request encoding. - decoder_hasher_state: [ZERO; 8], - }; - _debugger.add_request(alloc::boxed::Box::new(control_block_req), challenges); - } - - let callee_hash_read_req_value = build_dyn_dyncall_callee_hash_read_request( - main_trace, - op_code_felt, - challenges, - row, - _debugger, - ); - - control_block_req_value * callee_hash_read_req_value -} - -/// Builds requests made on a `DYNCALL` operation. -fn build_dyncall_request( - main_trace: &MainTrace, - op_code_felt: Felt, - challenges: &Challenges, - row: RowIndex, - _debugger: &mut BusDebugger, -) -> E -where - E: ExtensionField, -{ - let control_block_req_value = - encode_control_block_without_state(challenges, main_trace.addr(row + 1), op_code_felt); - - #[cfg(any(test, feature = "bus-debugger"))] - { - let control_block_req = ControlBlockRequestMessage { - transition_label: Felt::from_u8(LINEAR_HASH_LABEL + 16), - addr_next: main_trace.addr(row + 1), - op_code: op_code_felt, - // DYNCALL encodes without state; keep it zeroed to match the request encoding. - decoder_hasher_state: [ZERO; 8], - }; - _debugger.add_request(alloc::boxed::Box::new(control_block_req), challenges); - } - - let callee_hash_read_req_value = build_dyn_dyncall_callee_hash_read_request( - main_trace, - op_code_felt, - challenges, - row, - _debugger, - ); - - let fmp_write_req_value = - build_fmp_initialization_write_request(main_trace, challenges, row, _debugger); - - control_block_req_value * callee_hash_read_req_value * fmp_write_req_value -} - -fn build_call_request( - main_trace: &MainTrace, - op_code_felt: Felt, - challenges: &Challenges, - row: RowIndex, - _debugger: &mut BusDebugger, -) -> E -where - E: ExtensionField, -{ - let control_block_req_value = build_control_block_request( - main_trace, - main_trace.decoder_hasher_state(row), - op_code_felt, - challenges, - row, - _debugger, - ); - - let fmp_write_req_value = - build_fmp_initialization_write_request(main_trace, challenges, row, _debugger); - - control_block_req_value * fmp_write_req_value -} - -/// Builds requests made to kernel ROM chiplet when initializing a syscall block. -fn build_syscall_block_request( - main_trace: &MainTrace, - op_code_felt: Felt, - challenges: &Challenges, - row: RowIndex, - _debugger: &mut BusDebugger, -) -> E -where - E: ExtensionField, -{ - let control_block_req = ControlBlockRequestMessage { - transition_label: Felt::from_u8(LINEAR_HASH_LABEL + 16), - addr_next: main_trace.addr(row + 1), - op_code: op_code_felt, - decoder_hasher_state: main_trace.decoder_hasher_state(row), - }; - - let kernel_rom_req = KernelRomMessage { - kernel_proc_digest: main_trace.decoder_hasher_state(row)[0..4].try_into().unwrap(), - }; - - let combined_value = control_block_req.value(challenges) * kernel_rom_req.value(challenges); - - #[cfg(any(test, feature = "bus-debugger"))] - { - _debugger.add_request(alloc::boxed::Box::new(control_block_req), challenges); - _debugger.add_request(alloc::boxed::Box::new(kernel_rom_req), challenges); - } - - combined_value -} - -// HELPER FUNCTIONS -// ================================================================================================ - -/// Returns the operation unique label. -#[inline(always)] -fn get_op_label(s0: Felt, s1: Felt, s2: Felt, s3: Felt) -> Felt { - s3 * Felt::from_u16(1 << 3) + s2 * Felt::from_u16(1 << 2) + s1 * Felt::from_u16(2) + s0 + ONE -} diff --git a/processor/src/trace/chiplets/aux_trace/mod.rs b/processor/src/trace/chiplets/aux_trace/mod.rs deleted file mode 100644 index 06798577e4..0000000000 --- a/processor/src/trace/chiplets/aux_trace/mod.rs +++ /dev/null @@ -1,66 +0,0 @@ -use alloc::vec::Vec; - -use miden_air::trace::{Challenges, MainTrace}; -use miden_core::field::ExtensionField; -use wiring_bus::WiringBusBuilder; - -use super::{Felt, ace::AceHints}; -use crate::trace::AuxColumnBuilder; - -mod bus; -pub use bus::{ - BusColumnBuilder, build_ace_memory_read_element_request, build_ace_memory_read_word_request, -}; - -mod virtual_table; -pub use virtual_table::ChipletsVTableColBuilder; - -mod wiring_bus; - -/// Constructs the execution trace for chiplets-related auxiliary columns (used in multiset checks). -#[derive(Debug, Clone)] -pub struct AuxTraceBuilder { - ace_hints: AceHints, -} - -impl AuxTraceBuilder { - // CONSTRUCTORS - // -------------------------------------------------------------------------------------------- - - pub fn new(ace_hints: AceHints) -> Self { - Self { ace_hints } - } - - // COLUMN TRACE CONSTRUCTOR - // -------------------------------------------------------------------------------------------- - - /// Builds and returns the Chiplets's auxiliary trace columns. This consists of: - /// - /// 1. A bus column `b_chip` describing requests made by the stack and decoder and responses - /// received from the chiplets in the Chiplets module. It also responds to requests made by - /// the verifier with kernel procedure hashes included in the public inputs of the program. - /// 2. A column acting as - /// - a virtual table for the sibling table used by the hasher chiplet, - /// - a bus between the memory chiplet and the ACE chiplet. - /// 3. A column used as a bus to wire the gates of the ACE chiplet. - pub(crate) fn build_aux_columns>( - &self, - main_trace: &MainTrace, - challenges: &Challenges, - ) -> [Vec; 3] { - let v_table_col_builder = ChipletsVTableColBuilder; - let bus_col_builder = BusColumnBuilder; - let wiring_bus_builder = WiringBusBuilder::new(&self.ace_hints); - let t_chip = v_table_col_builder.build_aux_column(main_trace, challenges); - let b_chip = bus_col_builder.build_aux_column(main_trace, challenges); - let wiring_bus = wiring_bus_builder.build_aux_column(main_trace, challenges); - - // When debugging, check that the LogUp wiring bus balances. - // The vtable and chiplets bus final values are non-trivial (they encode public-input- - // dependent boundary terms) and are checked by the verifier in reduced_aux_values. - let log_up_final_value = wiring_bus.last().copied().unwrap_or(E::ZERO); - debug_assert_eq!(log_up_final_value, E::ZERO); - - [t_chip, b_chip, wiring_bus] - } -} diff --git a/processor/src/trace/chiplets/aux_trace/virtual_table.rs b/processor/src/trace/chiplets/aux_trace/virtual_table.rs deleted file mode 100644 index d97c20d6e7..0000000000 --- a/processor/src/trace/chiplets/aux_trace/virtual_table.rs +++ /dev/null @@ -1,250 +0,0 @@ -use miden_air::trace::{ - Challenges, LOG_PRECOMPILE_LABEL, MainTrace, RowIndex, - chiplets::hasher::DIGEST_LEN, - log_precompile::{HELPER_CAP_PREV_RANGE, STACK_CAP_NEXT_RANGE}, -}; -use miden_core::{ - Felt, field::ExtensionField, operations::opcodes, precompile::PrecompileTranscriptState, -}; - -use super::{build_ace_memory_read_element_request, build_ace_memory_read_word_request}; -use crate::{ - debug::{BusDebugger, BusMessage}, - trace::AuxColumnBuilder, -}; - -// CHIPLETS VIRTUAL TABLE -// ================================================================================================ - -/// Describes how to construct the execution trace of the chiplets virtual table auxiliary trace -/// column. This column enables communication between the different chiplets, in particular: -/// - Ensuring sharing of sibling nodes in a Merkle tree when one of its leaves is updated by the -/// hasher chiplet. -/// - Allowing memory access for the ACE chiplet. -/// -/// # Detail: -/// The hasher chiplet requires the bus to be empty whenever a Merkle tree update is requested. -/// This implies that the bus is also empty at the end of the trace containing the hasher rows. -/// On the other hand, communication between the ACE and memory chiplets requires the bus to be -/// contiguous, since messages are shared between these rows. -/// -/// Since the hasher chip is in the first position, the other chiplets can treat it as a shared bus. -/// However, this prevents any bus initialization via public inputs using boundary constraints -/// in the first row. If such constraints are required, they must be enforced via -/// `reduced_aux_values` in the last row of the trace. -/// -/// If public inputs are required for other chiplets, it is also possible to use the chiplet bus, -/// as is done for the kernel ROM chiplet. -pub struct ChipletsVTableColBuilder; - -impl AuxColumnBuilder for ChipletsVTableColBuilder -where - E: ExtensionField, -{ - fn get_requests_at( - &self, - main_trace: &MainTrace, - challenges: &Challenges, - row: RowIndex, - _debugger: &mut BusDebugger, - ) -> E { - let op_code = main_trace.get_op_code(row).as_canonical_u64() as u8; - let log_pc_request = if op_code == opcodes::LOGPRECOMPILE { - build_log_precompile_capacity_remove(main_trace, row, challenges, _debugger) - } else { - E::ONE - }; - - let request_ace = if main_trace.chiplet_ace_is_read_row(row) { - build_ace_memory_read_word_request(main_trace, challenges, row, _debugger) - } else if main_trace.chiplet_ace_is_eval_row(row) { - build_ace_memory_read_element_request(main_trace, challenges, row, _debugger) - } else { - E::ONE - }; - - chiplets_vtable_remove_sibling(main_trace, challenges, row) * request_ace * log_pc_request - } - - fn get_responses_at( - &self, - main_trace: &MainTrace, - challenges: &Challenges, - row: RowIndex, - _debugger: &mut BusDebugger, - ) -> E { - let op_code = main_trace.get_op_code(row).as_canonical_u64() as u8; - let log_pc_response = if op_code == opcodes::LOGPRECOMPILE { - build_log_precompile_capacity_insert(main_trace, row, challenges, _debugger) - } else { - E::ONE - }; - - chiplets_vtable_add_sibling(main_trace, challenges, row) * log_pc_response - } - - #[cfg(any(test, feature = "bus-debugger"))] - fn enforce_bus_balance(&self) -> bool { - // The chiplets vtable final value encodes transcript state boundary terms, - // which are checked via reduced_aux_values. It does not balance to identity. - false - } -} - -// VIRTUAL TABLE REQUESTS -// ================================================================================================ - -/// Range for RATE0 (first rate word) in sponge state. -const RATE0_RANGE: core::ops::Range = 0..DIGEST_LEN; -/// Range for RATE1 (second rate word) in sponge state. -const RATE1_RANGE: core::ops::Range = DIGEST_LEN..(2 * DIGEST_LEN); - -/// Node is left child (lsb=0), sibling is right child at RATE1: alpha + beta_powers[2]*index + -/// beta_powers[7..10]*sibling -const SIBLING_RATE1_LAYOUT: [usize; 5] = [2, 7, 8, 9, 10]; -/// Node is right child (lsb=1), sibling is left child at RATE0: alpha + beta_powers[2]*index + -/// beta_powers[3..6]*sibling -const SIBLING_RATE0_LAYOUT: [usize; 5] = [2, 3, 4, 5, 6]; - -/// Extracts the node index and sibling word from the trace and encodes a sibling table entry. -/// -/// The node index comes from `row`, while the sibling state comes from `state_row` -/// (which may be `row` or `row + 1` depending on whether this is an absorb or -/// absorb-next cycle). -#[inline(always)] -fn encode_sibling_from_trace>( - main_trace: &MainTrace, - challenges: &Challenges, - row: RowIndex, - state_row: RowIndex, -) -> E { - let index = main_trace.chiplet_node_index(row); - let lsb = index.as_canonical_u64() & 1; - let (layout, sibling) = if lsb == 0 { - // Node is left child, sibling is right child at RATE1 - (SIBLING_RATE1_LAYOUT, &main_trace.chiplet_hasher_state(state_row)[RATE1_RANGE]) - } else { - // Node is right child, sibling is left child at RATE0 - (SIBLING_RATE0_LAYOUT, &main_trace.chiplet_hasher_state(state_row)[RATE0_RANGE]) - }; - challenges.encode_sparse(layout, [index, sibling[0], sibling[1], sibling[2], sibling[3]]) -} - -/// Constructs the removals from the table when the hasher absorbs a new sibling node while -/// computing the new Merkle root. -fn chiplets_vtable_remove_sibling>( - main_trace: &MainTrace, - challenges: &Challenges, - row: RowIndex, -) -> E { - if main_trace.f_mu(row) { - encode_sibling_from_trace(main_trace, challenges, row, row) - } else if main_trace.f_mua(row) { - encode_sibling_from_trace(main_trace, challenges, row, row + 1) - } else { - E::ONE - } -} - -// VIRTUAL TABLE RESPONSES -// ================================================================================================ - -/// Constructs the inclusions to the table when the hasher absorbs a new sibling node while -/// computing the old Merkle root. -fn chiplets_vtable_add_sibling>( - main_trace: &MainTrace, - challenges: &Challenges, - row: RowIndex, -) -> E { - if main_trace.f_mv(row) { - encode_sibling_from_trace(main_trace, challenges, row, row) - } else if main_trace.f_mva(row) { - encode_sibling_from_trace(main_trace, challenges, row, row + 1) - } else { - E::ONE - } -} - -// LOG PRECOMPILE MESSAGES -// ================================================================================================ - -/// Message for log_precompile transcript-state tracking on the virtual table bus. -struct LogPrecompileMessage { - state: PrecompileTranscriptState, -} - -impl BusMessage for LogPrecompileMessage -where - E: ExtensionField, -{ - fn value(&self, challenges: &Challenges) -> E { - let state_elements: [Felt; 4] = self.state.into(); - challenges.encode([ - Felt::from_u8(LOG_PRECOMPILE_LABEL), - state_elements[0], - state_elements[1], - state_elements[2], - state_elements[3], - ]) - } - - fn source(&self) -> &str { - "log_precompile" - } -} - -impl core::fmt::Display for LogPrecompileMessage { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "{{ state: {:?} }}", self.state) - } -} - -/// Removes the previous transcript state (`CAP_PREV`) from the virtual table bus. -/// -/// Helper register layout for `log_precompile` is codified as: -/// - `h0` = hasher address, `h1..h4` = `CAP_PREV[0..3]`. -fn build_log_precompile_capacity_remove>( - main_trace: &MainTrace, - row: RowIndex, - challenges: &Challenges, - _debugger: &mut BusDebugger, -) -> E { - let state = PrecompileTranscriptState::from([ - main_trace.helper_register(HELPER_CAP_PREV_RANGE.start, row), - main_trace.helper_register(HELPER_CAP_PREV_RANGE.start + 1, row), - main_trace.helper_register(HELPER_CAP_PREV_RANGE.start + 2, row), - main_trace.helper_register(HELPER_CAP_PREV_RANGE.start + 3, row), - ]); - - let message = LogPrecompileMessage { state }; - let value = message.value(challenges); - - #[cfg(any(test, feature = "bus-debugger"))] - _debugger.add_request(alloc::boxed::Box::new(message), challenges); - - value -} - -/// Inserts the next transcript state (`CAP_NEXT`) into the virtual table bus. -fn build_log_precompile_capacity_insert>( - main_trace: &MainTrace, - row: RowIndex, - challenges: &Challenges, - _debugger: &mut BusDebugger, -) -> E { - let state: PrecompileTranscriptState = [ - main_trace.stack_element(STACK_CAP_NEXT_RANGE.start, row + 1), - main_trace.stack_element(STACK_CAP_NEXT_RANGE.start + 1, row + 1), - main_trace.stack_element(STACK_CAP_NEXT_RANGE.start + 2, row + 1), - main_trace.stack_element(STACK_CAP_NEXT_RANGE.start + 3, row + 1), - ] - .into(); - - let message = LogPrecompileMessage { state }; - let value = message.value(challenges); - - #[cfg(any(test, feature = "bus-debugger"))] - _debugger.add_response(alloc::boxed::Box::new(message), challenges); - - value -} diff --git a/processor/src/trace/chiplets/aux_trace/wiring_bus.rs b/processor/src/trace/chiplets/aux_trace/wiring_bus.rs deleted file mode 100644 index 352f8752f2..0000000000 --- a/processor/src/trace/chiplets/aux_trace/wiring_bus.rs +++ /dev/null @@ -1,69 +0,0 @@ -use alloc::vec::Vec; - -use miden_air::trace::{Challenges, MainTrace}; -use miden_core::{Felt, field::ExtensionField}; - -use super::super::ace::{AceHints, NUM_ACE_LOGUP_FRACTIONS_EVAL, NUM_ACE_LOGUP_FRACTIONS_READ}; - -/// Describes how to construct the execution trace of the ACE chiplet wiring bus column. -pub struct WiringBusBuilder<'a> { - ace_hints: &'a AceHints, -} -impl<'a> WiringBusBuilder<'a> { - pub(crate) fn new(ace_hints: &'a AceHints) -> Self { - Self { ace_hints } - } - - /// Builds the ACE chiplet wiring bus auxiliary trace column. - pub fn build_aux_column>( - &self, - main_trace: &MainTrace, - challenges: &Challenges, - ) -> Vec { - let mut wiring_bus = vec![E::ZERO; main_trace.num_rows()]; - - // compute divisors - let total_divisors = self.ace_hints.build_divisors(main_trace, challenges); - - // fill only the portion relevant to ACE chiplet - let mut trace_offset = self.ace_hints.offset(); - let mut divisors_offset = 0; - for section in self.ace_hints.sections.iter() { - let divisors = &total_divisors[divisors_offset - ..divisors_offset + NUM_ACE_LOGUP_FRACTIONS_READ * section.num_vars() as usize]; - - // read section - for (i, divisor_tuple) in divisors.chunks(NUM_ACE_LOGUP_FRACTIONS_READ).enumerate() { - let trace_row = i + trace_offset; - - let m_0 = main_trace.chiplet_ace_m_0(trace_row.into()); - let m_1 = main_trace.chiplet_ace_m_1(trace_row.into()); - let value = divisor_tuple[0] * m_0 + divisor_tuple[1] * m_1; - - wiring_bus[trace_row + 1] = wiring_bus[trace_row] + value; - } - - trace_offset += section.num_vars() as usize; - divisors_offset += NUM_ACE_LOGUP_FRACTIONS_READ * section.num_vars() as usize; - - // eval section - let divisors = &total_divisors[divisors_offset - ..divisors_offset + NUM_ACE_LOGUP_FRACTIONS_EVAL * section.num_evals() as usize]; - for (i, divisor_tuple) in divisors.chunks(NUM_ACE_LOGUP_FRACTIONS_EVAL).enumerate() { - let trace_row = i + trace_offset; - - let m_0 = main_trace.chiplet_ace_m_0(trace_row.into()); - let value = divisor_tuple[0] * m_0 - (divisor_tuple[1] + divisor_tuple[2]); - - wiring_bus[trace_row + 1] = wiring_bus[trace_row] + value; - } - - trace_offset += section.num_evals() as usize; - divisors_offset += NUM_ACE_LOGUP_FRACTIONS_EVAL * section.num_evals() as usize; - } - - assert_eq!(wiring_bus[trace_offset], E::ZERO); - - wiring_bus - } -} diff --git a/processor/src/trace/chiplets/bitwise/mod.rs b/processor/src/trace/chiplets/bitwise/mod.rs index 4840fc0a56..3623a3ce82 100644 --- a/processor/src/trace/chiplets/bitwise/mod.rs +++ b/processor/src/trace/chiplets/bitwise/mod.rs @@ -92,7 +92,7 @@ impl Bitwise { // the most significant limb. for bit_offset in (0..32).step_by(4).rev() { // append the previous row's result to the column for previous output values - self.trace[PREV_OUTPUT_COL_IDX].push(Felt::new(result)); + self.trace[PREV_OUTPUT_COL_IDX].push(Felt::new_unchecked(result)); // shift a and b so that the next 4-bit limb is in the least significant position let a = a >> bit_offset; let b = b >> bit_offset; @@ -107,10 +107,10 @@ impl Bitwise { // append the 4 bit result to the result accumulator, and save the current result into // the output column in the trace. result = (result << 4) | result_4_bit; - self.trace[OUTPUT_COL_IDX].push(Felt::new(result)); + self.trace[OUTPUT_COL_IDX].push(Felt::new_unchecked(result)); } - Ok(Felt::new(result)) + Ok(Felt::new_unchecked(result)) } /// Computes a bitwise XOR of `a` and `b` and returns the result. We assume that `a` and `b` @@ -127,7 +127,7 @@ impl Bitwise { // the most significant limb. for bit_offset in (0..32).step_by(4).rev() { // append the previous row's result to the column for previous output values - self.trace[PREV_OUTPUT_COL_IDX].push(Felt::new(result)); + self.trace[PREV_OUTPUT_COL_IDX].push(Felt::new_unchecked(result)); // shift a and b so that the next 4-bit limb is in the least significant position let a = a >> bit_offset; let b = b >> bit_offset; @@ -142,10 +142,10 @@ impl Bitwise { // append the 4 bit result to the result accumulator, and save the current result into // the output column in the trace. result = (result << 4) | result_4_bit; - self.trace[OUTPUT_COL_IDX].push(Felt::new(result)); + self.trace[OUTPUT_COL_IDX].push(Felt::new_unchecked(result)); } - Ok(Felt::new(result)) + Ok(Felt::new_unchecked(result)) } // EXECUTION TRACE GENERATION @@ -177,18 +177,18 @@ impl Bitwise { /// set elsewhere. fn add_bitwise_trace_row(&mut self, selector: Felt, a: u64, b: u64) { self.trace[0].push(selector); - self.trace[A_COL_IDX].push(Felt::new(a)); - self.trace[B_COL_IDX].push(Felt::new(b)); - - self.trace[A_COL_RANGE.start].push(Felt::new(a & 1)); - self.trace[A_COL_RANGE.start + 1].push(Felt::new((a >> 1) & 1)); - self.trace[A_COL_RANGE.start + 2].push(Felt::new((a >> 2) & 1)); - self.trace[A_COL_RANGE.start + 3].push(Felt::new((a >> 3) & 1)); - - self.trace[B_COL_RANGE.start].push(Felt::new(b & 1)); - self.trace[B_COL_RANGE.start + 1].push(Felt::new((b >> 1) & 1)); - self.trace[B_COL_RANGE.start + 2].push(Felt::new((b >> 2) & 1)); - self.trace[B_COL_RANGE.start + 3].push(Felt::new((b >> 3) & 1)); + self.trace[A_COL_IDX].push(Felt::new_unchecked(a)); + self.trace[B_COL_IDX].push(Felt::new_unchecked(b)); + + self.trace[A_COL_RANGE.start].push(Felt::new_unchecked(a & 1)); + self.trace[A_COL_RANGE.start + 1].push(Felt::new_unchecked((a >> 1) & 1)); + self.trace[A_COL_RANGE.start + 2].push(Felt::new_unchecked((a >> 2) & 1)); + self.trace[A_COL_RANGE.start + 3].push(Felt::new_unchecked((a >> 3) & 1)); + + self.trace[B_COL_RANGE.start].push(Felt::new_unchecked(b & 1)); + self.trace[B_COL_RANGE.start + 1].push(Felt::new_unchecked((b >> 1) & 1)); + self.trace[B_COL_RANGE.start + 2].push(Felt::new_unchecked((b >> 2) & 1)); + self.trace[B_COL_RANGE.start + 3].push(Felt::new_unchecked((b >> 3) & 1)); } } diff --git a/processor/src/trace/chiplets/bitwise/tests.rs b/processor/src/trace/chiplets/bitwise/tests.rs index 118b453c9b..52e5892e25 100644 --- a/processor/src/trace/chiplets/bitwise/tests.rs +++ b/processor/src/trace/chiplets/bitwise/tests.rs @@ -16,7 +16,6 @@ fn bitwise_init() { } #[test] -#[expect(clippy::needless_range_loop)] fn bitwise_and() { let mut bitwise = Bitwise::new(); @@ -49,8 +48,11 @@ fn bitwise_and() { let c2 = binary_and(trace[A_COL_RANGE.start + 2][i], trace[B_COL_RANGE.start + 2][i]); let c3 = binary_and(trace[A_COL_RANGE.start + 3][i], trace[B_COL_RANGE.start + 3][i]); - let result_4_bit = c0 + Felt::new(2) * c1 + Felt::new(4) * c2 + Felt::new(8) * c3; - let result = prev_result * Felt::new(16) + result_4_bit; + let result_4_bit = c0 + + Felt::new_unchecked(2) * c1 + + Felt::new_unchecked(4) * c2 + + Felt::new_unchecked(8) * c3; + let result = prev_result * Felt::new_unchecked(16) + result_4_bit; assert_eq!(prev_result, trace[PREV_OUTPUT_COL_IDX][i]); assert_eq!(result, trace[OUTPUT_COL_IDX][i]); @@ -60,7 +62,6 @@ fn bitwise_and() { } #[test] -#[expect(clippy::needless_range_loop)] fn bitwise_xor() { let mut bitwise = Bitwise::new(); @@ -93,8 +94,11 @@ fn bitwise_xor() { let c2 = binary_xor(trace[A_COL_RANGE.start + 2][i], trace[B_COL_RANGE.start + 2][i]); let c3 = binary_xor(trace[A_COL_RANGE.start + 3][i], trace[B_COL_RANGE.start + 3][i]); - let result_4_bit = c0 + Felt::new(2) * c1 + Felt::new(4) * c2 + Felt::new(8) * c3; - let result = prev_result * Felt::new(16) + result_4_bit; + let result_4_bit = c0 + + Felt::new_unchecked(2) * c1 + + Felt::new_unchecked(4) * c2 + + Felt::new_unchecked(8) * c3; + let result = prev_result * Felt::new_unchecked(16) + result_4_bit; assert_eq!(prev_result, trace[PREV_OUTPUT_COL_IDX][i]); assert_eq!(result, trace[OUTPUT_COL_IDX][i]); @@ -104,7 +108,6 @@ fn bitwise_xor() { } #[test] -#[expect(clippy::needless_range_loop)] fn bitwise_multiple() { let mut bitwise = Bitwise::new(); @@ -144,8 +147,11 @@ fn bitwise_multiple() { let c2 = binary_and(trace[A_COL_RANGE.start + 2][i], trace[B_COL_RANGE.start + 2][i]); let c3 = binary_and(trace[A_COL_RANGE.start + 3][i], trace[B_COL_RANGE.start + 3][i]); - let result_4_bit = c0 + Felt::new(2) * c1 + Felt::new(4) * c2 + Felt::new(8) * c3; - let result = prev_result * Felt::new(16) + result_4_bit; + let result_4_bit = c0 + + Felt::new_unchecked(2) * c1 + + Felt::new_unchecked(4) * c2 + + Felt::new_unchecked(8) * c3; + let result = prev_result * Felt::new_unchecked(16) + result_4_bit; assert_eq!(prev_result, trace[PREV_OUTPUT_COL_IDX][i]); assert_eq!(result, trace[OUTPUT_COL_IDX][i]); @@ -160,8 +166,11 @@ fn bitwise_multiple() { let c2 = binary_xor(trace[A_COL_RANGE.start + 2][i], trace[B_COL_RANGE.start + 2][i]); let c3 = binary_xor(trace[A_COL_RANGE.start + 3][i], trace[B_COL_RANGE.start + 3][i]); - let result_4_bit = c0 + Felt::new(2) * c1 + Felt::new(4) * c2 + Felt::new(8) * c3; - let result = prev_result * Felt::new(16) + result_4_bit; + let result_4_bit = c0 + + Felt::new_unchecked(2) * c1 + + Felt::new_unchecked(4) * c2 + + Felt::new_unchecked(8) * c3; + let result = prev_result * Felt::new_unchecked(16) + result_4_bit; assert_eq!(prev_result, trace[PREV_OUTPUT_COL_IDX][i]); assert_eq!(result, trace[OUTPUT_COL_IDX][i]); @@ -176,8 +185,11 @@ fn bitwise_multiple() { let c2 = binary_and(trace[A_COL_RANGE.start + 2][i], trace[B_COL_RANGE.start + 2][i]); let c3 = binary_and(trace[A_COL_RANGE.start + 3][i], trace[B_COL_RANGE.start + 3][i]); - let result_4_bit = c0 + Felt::new(2) * c1 + Felt::new(4) * c2 + Felt::new(8) * c3; - let result = prev_result * Felt::new(16) + result_4_bit; + let result_4_bit = c0 + + Felt::new_unchecked(2) * c1 + + Felt::new_unchecked(4) * c2 + + Felt::new_unchecked(8) * c3; + let result = prev_result * Felt::new_unchecked(16) + result_4_bit; assert_eq!(prev_result, trace[PREV_OUTPUT_COL_IDX][i]); assert_eq!(result, trace[OUTPUT_COL_IDX][i]); @@ -199,7 +211,6 @@ fn build_trace(bitwise: Bitwise, num_rows: usize) -> Vec> { trace } -#[expect(clippy::needless_range_loop)] fn check_decomposition(trace: &[Vec], start: usize, a: u64, b: u64) { let mut bit_offset = 28; @@ -207,18 +218,18 @@ fn check_decomposition(trace: &[Vec], start: usize, a: u64, b: u64) { let a = a >> bit_offset; let b = b >> bit_offset; - assert_eq!(Felt::new(a), trace[A_COL_IDX][i]); - assert_eq!(Felt::new(b), trace[B_COL_IDX][i]); + assert_eq!(Felt::new_unchecked(a), trace[A_COL_IDX][i]); + assert_eq!(Felt::new_unchecked(b), trace[B_COL_IDX][i]); - assert_eq!(Felt::new(a & 1), trace[A_COL_RANGE.start][i]); - assert_eq!(Felt::new((a >> 1) & 1), trace[A_COL_RANGE.start + 1][i]); - assert_eq!(Felt::new((a >> 2) & 1), trace[A_COL_RANGE.start + 2][i]); - assert_eq!(Felt::new((a >> 3) & 1), trace[A_COL_RANGE.start + 3][i]); + assert_eq!(Felt::new_unchecked(a & 1), trace[A_COL_RANGE.start][i]); + assert_eq!(Felt::new_unchecked((a >> 1) & 1), trace[A_COL_RANGE.start + 1][i]); + assert_eq!(Felt::new_unchecked((a >> 2) & 1), trace[A_COL_RANGE.start + 2][i]); + assert_eq!(Felt::new_unchecked((a >> 3) & 1), trace[A_COL_RANGE.start + 3][i]); - assert_eq!(Felt::new(b & 1), trace[B_COL_RANGE.start][i]); - assert_eq!(Felt::new((b >> 1) & 1), trace[B_COL_RANGE.start + 1][i]); - assert_eq!(Felt::new((b >> 2) & 1), trace[B_COL_RANGE.start + 2][i]); - assert_eq!(Felt::new((b >> 3) & 1), trace[B_COL_RANGE.start + 3][i]); + assert_eq!(Felt::new_unchecked(b & 1), trace[B_COL_RANGE.start][i]); + assert_eq!(Felt::new_unchecked((b >> 1) & 1), trace[B_COL_RANGE.start + 1][i]); + assert_eq!(Felt::new_unchecked((b >> 2) & 1), trace[B_COL_RANGE.start + 2][i]); + assert_eq!(Felt::new_unchecked((b >> 3) & 1), trace[B_COL_RANGE.start + 3][i]); bit_offset -= 4; } @@ -229,10 +240,10 @@ fn binary_and(a: Felt, b: Felt) -> Felt { } fn binary_xor(a: Felt, b: Felt) -> Felt { - a + b - Felt::new(2) * a * b + a + b - Felt::new_unchecked(2) * a * b } fn rand_u32() -> Felt { let value = rand_value::() as u32 as u64; - Felt::new(value) + Felt::new_unchecked(value) } diff --git a/processor/src/trace/chiplets/hasher/mod.rs b/processor/src/trace/chiplets/hasher/mod.rs index 0a90bd7a5b..0186fbac91 100644 --- a/processor/src/trace/chiplets/hasher/mod.rs +++ b/processor/src/trace/chiplets/hasher/mod.rs @@ -1,9 +1,10 @@ use alloc::collections::BTreeMap; use miden_air::trace::chiplets::hasher::{ - DIGEST_RANGE, LINEAR_HASH, MP_VERIFY, MR_UPDATE_NEW, MR_UPDATE_OLD, RATE_LEN, RETURN_HASH, - RETURN_STATE, STATE_WIDTH, Selectors, TRACE_WIDTH, + DIGEST_RANGE, HASH_CYCLE_LEN, LINEAR_HASH, MP_VERIFY, MR_UPDATE_NEW, MR_UPDATE_OLD, RATE_LEN, + RETURN_HASH, RETURN_STATE, STATE_WIDTH, Selectors, }; +use miden_core::chiplets::hasher::apply_permutation; use super::{ Felt, HasherState, MerklePath, MerkleRootUpdate, ONE, OpBatch, TraceFragment, Word as Digest, @@ -14,60 +15,104 @@ mod trace; use trace::HasherTrace; #[cfg(test)] +#[allow(clippy::needless_range_loop)] mod tests; // HASH PROCESSOR // ================================================================================================ +/// Key type for digest-based lookups. +type DigestKey = [u64; 4]; + +/// Key type for full-state lookups. +type StateKey = [u64; STATE_WIDTH]; + +/// Converts a Digest to a DigestKey for BTreeMap lookup. +fn digest_to_key(digest: Digest) -> DigestKey { + let elems = digest.as_elements(); + core::array::from_fn(|i| elems[i].as_canonical_u64()) +} + +/// Converts a HasherState to a StateKey for BTreeMap lookup. +fn state_to_key(state: &HasherState) -> StateKey { + core::array::from_fn(|i| state[i].as_canonical_u64()) +} + +/// Reconstructs a HasherState from a StateKey. +fn key_to_state(key: &StateKey) -> HasherState { + core::array::from_fn(|i| Felt::new_unchecked(key[i])) +} + /// Hash chiplet for the VM. /// -/// This component is responsible for performing all hash-related computations for the VM, as well -/// as building an execution trace for these computations. These computations include: -/// * Linear hashes, including simple 2-to-1 hashes, single and multiple permutations. -/// * Merkle path verification. -/// * Merkle root updates. +/// This component uses a controller/permutation split architecture: /// -/// ## Execution trace -/// Hasher execution trace consists of 16 columns as illustrated below: +/// - **Controller region** (s_perm=0): pairs of (input, output) rows for each permutation request. +/// Input rows (s0=1) capture the operation type and pre-permutation state. Output rows (s0=0, +/// s1=0) capture the post-permutation state. /// -/// s0 s1 s2 h0 h1 h2 h3 h4 h5 h6 h7 h8 h9 h10 h11 idx -/// ├────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴─────┴─────┴─────┤ +/// - **Permutation segment** (s_perm=1): one 16-row Poseidon2 cycle per unique input state. +/// Multiplicity is stored in the node_index column. Linked to controller rows via the hasher_perm +/// LogUp bus. /// -/// In the above, the meaning of the columns is as follows: -/// * Selector columns s0, s1, and s2 used to help select transition function for a given row. -/// * Hasher state columns h0 through h11 used to hold the hasher state for each round of hash -/// computation. The state is laid out as `[RATE0, RATE1, CAPACITY]`: -/// - The first eight columns (h0-h7) represent the rate elements of the state. These are used to -/// absorb the values to be hashed. Once a permutation is complete, hash output is located in -/// the first four rate columns (h0, h1, h2, h3). -/// - The last four columns (h8-h11) represent the capacity state of the sponge function. -/// * Node index column idx used to help with Merkle path verification and Merkle root update -/// computations. For all other computations the values in this column are set to 0s. +/// This architecture enables permutation deduplication: N requests with the same input state +/// produce N controller pairs but only one permutation cycle (with multiplicity N). /// -/// Each permutation of the hash function adds 8 rows to the execution trace. Thus, for Merkle -/// path verification, number of rows added to the trace is 8 * path.len(), and for Merkle root -/// update it is 16 * path.len(), since we need to perform two path verifications for each update. +/// ## Trace layout (20 columns) /// -/// In addition to the execution trace, the hash chiplet also maintains: -/// - an auxiliary trace builder, which can be used to construct a running product column describing -/// the state of the sibling table (used in Merkle root update operations). -/// - a map of memoized execution trace, which keeps track of start and end rows of the sections of -/// the trace of a control or span block that can be copied to be used later for program blocks -/// encountered with the same digest instead of building it from scratch everytime. The hash of -/// the block is used as the key here after converting it to a bytes array. +/// s0 s1 s2 h0..h11 idx mrupdate_id is_boundary direction_bit s_perm +/// ├────┴───┴───┴────────┴────┴────────────┴─────────┴─────────┴────────┤ #[derive(Debug, Default)] pub struct Hasher { trace: HasherTrace, - memoized_trace_map: BTreeMap<[u8; 32], (usize, usize)>, + /// Maps block digest -> (start_row, end_row) for memoized controller traces. + memoized_trace_map: BTreeMap, + /// Maps input state -> multiplicity for permutation deduplication. + /// During finalize_trace(), one 16-row perm cycle is emitted per entry. + perm_request_map: BTreeMap, + /// Monotonically increasing counter for MRUPDATE domain separation. + mrupdate_id: Felt, + /// Whether the permutation segment has been finalized. + finalized: bool, } impl Hasher { // STATE ACCESSORS // -------------------------------------------------------------------------------------------- - /// Returns current length of the execution trace stored in this hasher. + /// Returns the length of the execution trace. + /// + /// Before finalization, this returns an estimate based on the controller region length + /// plus the expected permutation segment size. The estimate is verified against the + /// actual length during `fill_trace()` via a debug assertion. pub(super) fn trace_len(&self) -> usize { - self.trace.trace_len() + if self.finalized { + self.trace.trace_len() + } else { + self.estimate_trace_len() + } + } + + /// Returns the layout of the hasher region as `(controller_len, perm_len)`, both exact + /// multiples of `HASH_CYCLE_LEN`. Must be called before `fill_trace()` consumes the hasher. + /// + /// `controller_len` includes the padding rows that `finalize_trace()` will later append to + /// round the raw controller count up to a cycle boundary; `perm_len` is the total span of + /// the permutation cycles that `finalize_trace()` will emit, one per unique input state. + pub(super) fn region_lengths(&self) -> (usize, usize) { + debug_assert!(!self.finalized, "region_lengths must be called before finalization"); + let controller_len = self.trace.trace_len().next_multiple_of(HASH_CYCLE_LEN); + let perm_len = self.perm_request_map.len() * HASH_CYCLE_LEN; + (controller_len, perm_len) + } + + /// Estimates the total trace length before finalization. + /// + /// This must match the actual length produced by `finalize_trace()`. The invariant is + /// verified by a debug assertion in `fill_trace()`. + fn estimate_trace_len(&self) -> usize { + let (controller_len, perm_len) = self.region_lengths(); + controller_len + perm_len } // HASHING METHODS @@ -76,22 +121,28 @@ impl Hasher { /// Applies a single permutation of the hash function to the provided state and records the /// execution trace of this computation. /// - /// The returned tuple contains the hasher state after the permutation and the row address of - /// the execution trace at which the permutation started. - pub fn permute(&mut self, mut state: HasherState) -> (Felt, HasherState) { + /// Returns (addr, permuted_state). + pub fn permute(&mut self, state: HasherState) -> (Felt, HasherState) { let addr = self.trace.next_row_addr(); - // perform the hash. - self.trace.append_permutation(&mut state, LINEAR_HASH, RETURN_STATE); + let permuted = self.append_controller_permutation( + LINEAR_HASH, + RETURN_STATE, + state, + ZERO, // input_node_index + ZERO, // output_node_index + ONE, // is_boundary_input = 1 (first input) + ONE, // is_boundary_output = 1 (final output) + ZERO, // input_direction_bit (non-Merkle) + ZERO, // output_direction_bit (non-Merkle) + ); - (addr, state) + (addr, permuted) } - /// Computes the hash of the control block by computing hash(h1, h2) and returns the result. - /// It also records the execution trace of this computation. + /// Computes hash(h1, h2) for a control block and returns the result. /// - /// The returned tuple also contains the row address of the execution trace at which the hash - /// computation started. + /// Returns (addr, digest). pub fn hash_control_block( &mut self, h1: Digest, @@ -99,110 +150,118 @@ impl Hasher { domain: Felt, expected_hash: Digest, ) -> (Felt, Digest) { - let addr = self.trace.next_row_addr(); - let mut state = init_state_from_words_with_domain(&h1, &h2, domain); - - if let Some((start_row, end_row)) = self.get_memoized_trace(expected_hash) { - // copy the trace of a block with same hash instead of building it again. - self.trace.copy_trace(&mut state, *start_row..*end_row); - } else { - // perform the hash. - self.trace.append_permutation(&mut state, LINEAR_HASH, RETURN_HASH); - - self.insert_to_memoized_trace_map(addr, expected_hash); - }; + if let Some(memoized) = self.replay_memoized_trace(expected_hash) { + return memoized; + } - let result = get_digest(&state); + let addr = self.trace.next_row_addr(); + let init_state = init_state_from_words_with_domain(&h1, &h2, domain); + // Single permutation: boundary on both input and output + let permuted = self.append_controller_permutation( + LINEAR_HASH, + RETURN_HASH, + init_state, + ZERO, + ZERO, // node_index: input, output + ONE, + ONE, // is_boundary: input=1, output=1 + ZERO, + ZERO, // direction_bit: non-Merkle + ); + self.insert_to_memoized_trace_map(addr, expected_hash); + let result = get_digest(&permuted); (addr, result) } - /// Computes a sequential hash of all operation batches in the list and returns the result. It - /// also records the execution trace of this computation. + /// Computes a sequential hash of all operation batches and returns the result. /// - /// The returned tuple also contains the row address of the execution trace at which the hash - /// computation started. + /// Returns (addr, digest). pub fn hash_basic_block( &mut self, op_batches: &[OpBatch], expected_hash: Digest, ) -> (Felt, Digest) { - const START: Selectors = LINEAR_HASH; - const RETURN: Selectors = RETURN_HASH; - // absorb selectors are the same as linear hash selectors, but absorb selectors are - // applied on the last row of a permutation cycle, while linear hash selectors are - // applied on the first row of a permutation cycle. - const ABSORB: Selectors = LINEAR_HASH; - // to continue linear hash we need retain the 2nd and 3rd selector flags and set the - // 1st flag to ZERO. - const CONTINUE: Selectors = [ZERO, LINEAR_HASH[1], LINEAR_HASH[2]]; + // Check memoization + if let Some(memoized) = self.replay_memoized_trace(expected_hash) { + return memoized; + } let addr = self.trace.next_row_addr(); - - // initialize the state and absorb the first operation batch into it - let mut state = init_state(op_batches[0].groups(), ZERO); - - // check if a span block with same hash has been encountered before in which case we can - // directly copy it's trace. - let (start_row, end_row, is_memoized) = - if let Some((start_row, end_row)) = self.get_memoized_trace(expected_hash) { - (*start_row, *end_row, true) - } else { - (0, 0, false) - }; + let init_state = init_state(op_batches[0].groups(), ZERO); let num_batches = op_batches.len(); - // if the span block is encountered for the first time and it's trace is not memoized, - // we need to build the trace from scratch. - if !is_memoized { - if num_batches == 1 { - // if there is only one batch to hash, we need only one permutation - self.trace.append_permutation(&mut state, START, RETURN); - } else { - // if there is more than one batch, we need to process the first, the last, and the - // middle permutations a bit differently. Specifically, selector flags for the - // permutations need to be set as follows: - // - first permutation: init linear hash on the first row, and absorb the next - // operation batch on the last row. - // - middle permutations: continue hashing on the first row, and absorb the next - // operation batch on the last row. - // - last permutation: continue hashing on the first row, and return the result on - // the last row. - self.trace.append_permutation(&mut state, START, ABSORB); - - for batch in op_batches.iter().take(num_batches - 1).skip(1) { - absorb_into_state(&mut state, batch.groups()); - - self.trace.append_permutation(&mut state, CONTINUE, ABSORB); - } - - absorb_into_state(&mut state, op_batches[num_batches - 1].groups()); - - self.trace.append_permutation(&mut state, CONTINUE, RETURN); - } + if num_batches == 1 { + // Single batch: boundary on both input and output + let permuted = self.append_controller_permutation( + LINEAR_HASH, + RETURN_HASH, + init_state, + ZERO, + ZERO, + ONE, + ONE, + ZERO, + ZERO, + ); self.insert_to_memoized_trace_map(addr, expected_hash); - } else { - self.trace.copy_trace(&mut state, start_row..end_row); + let result = get_digest(&permuted); + return (addr, result); } - let result = get_digest(&state); + // Multiple batches: + // First batch: boundary input only + let mut state = self.append_controller_permutation( + LINEAR_HASH, + RETURN_STATE, + init_state, + ZERO, + ZERO, + ONE, + ZERO, + ZERO, + ZERO, + ); + + // Middle batches: no boundary flags + for batch in op_batches.iter().take(num_batches - 1).skip(1) { + absorb_into_state(&mut state, batch.groups()); + state = self.append_controller_permutation( + LINEAR_HASH, + RETURN_STATE, + state, + ZERO, + ZERO, + ZERO, + ZERO, + ZERO, + ZERO, + ); + } + // Last batch: boundary output only + absorb_into_state(&mut state, op_batches[num_batches - 1].groups()); + let permuted = self.append_controller_permutation( + LINEAR_HASH, + RETURN_HASH, + state, + ZERO, + ZERO, + ZERO, + ONE, + ZERO, + ZERO, + ); + + self.insert_to_memoized_trace_map(addr, expected_hash); + let result = get_digest(&permuted); (addr, result) } /// Performs Merkle path verification computation and records its execution trace. /// - /// The computation consists of computing a Merkle root of the specified path for a node with - /// the specified value, located at the specified index. - /// - /// The returned tuple contains the root of the Merkle path and the row address of the - /// execution trace at which the computation started. - /// - /// # Panics - /// Panics if: - /// - The provided path does not contain any nodes. - /// - The provided index is out of range for the specified path. + /// Returns (addr, root). pub fn build_merkle_root( &mut self, value: Digest, @@ -210,26 +269,18 @@ impl Hasher { index: Felt, ) -> (Felt, Digest) { let addr = self.trace.next_row_addr(); - let root = self.verify_merkle_path( value, path, index.as_canonical_u64(), MerklePathContext::MpVerify, ); - (addr, root) } /// Performs Merkle root update computation and records its execution trace. /// - /// The computation consists of two Merkle path verifications, one for the old value of the - /// node (value before the update), and another for the new value (value after the update). - /// - /// # Panics - /// Panics if: - /// - The provided path does not contain any nodes. - /// - The provided index is out of range for the specified path. + /// Increments the mrupdate_id counter. Both MV and MU legs share the same id. pub fn update_merkle_root( &mut self, old_value: Digest, @@ -237,6 +288,9 @@ impl Hasher { path: &MerklePath, index: Felt, ) -> MerkleRootUpdate { + // Increment the mrupdate_id for this update operation + self.mrupdate_id += ONE; + let address = self.trace.next_row_addr(); let index = index.as_canonical_u64(); @@ -251,24 +305,110 @@ impl Hasher { // TRACE GENERATION // -------------------------------------------------------------------------------------------- - /// Fills the provided trace fragment with trace data from this hasher trace instance. This - /// also returns the trace builder for hasher-related auxiliary trace columns. - pub(super) fn fill_trace(self, trace: &mut TraceFragment) { - self.trace.fill_trace(trace) + /// Finalizes and fills the provided trace fragment with data from this hasher trace. + /// + /// Finalization pads the controller region and appends one 16-row permutation cycle + /// per unique input state. This is the only place where the perm segment is materialized. + pub(super) fn fill_trace(mut self, trace: &mut TraceFragment) { + if !self.finalized { + let estimated_len = self.estimate_trace_len(); + self.finalize_trace(); + debug_assert_eq!( + estimated_len, + self.trace.trace_len(), + "hasher trace length estimate ({}) diverged from actual ({})", + estimated_len, + self.trace.trace_len(), + ); + } + self.trace.fill_trace(trace); } - // HELPER METHODS + /// Finalizes the trace by padding the controller region and appending the permutation segment. + fn finalize_trace(&mut self) { + if self.finalized { + return; + } + + // Pad controller region to a multiple of HASH_CYCLE_LEN. + // Padding rows must carry the current mrupdate_id to satisfy the AIR progression + // constraint (mrupdate_id is constant on non-MV-start transitions). + self.trace.pad_to_cycle_boundary(self.mrupdate_id); + + // Append one 16-row permutation cycle per unique input state + for (key, multiplicity) in core::mem::take(&mut self.perm_request_map) { + let state = key_to_state(&key); + self.trace.append_permutation_cycle(&state, Felt::new_unchecked(multiplicity)); + } + + self.finalized = true; + } + + // CORE HELPER: CONTROLLER PERMUTATION // -------------------------------------------------------------------------------------------- - /// Computes a root of the provided Merkle path in the specified context. The path is assumed - /// to be for a node with the specified value at the specified index. + /// Appends a controller (input, output) pair and records the permutation request. + /// + /// Writes two rows to the controller region: + /// - Input row: `init_selectors` (s0=1), pre-permutation `state`, `input_node_index`, + /// `is_boundary_input`, `input_direction_bit`. + /// - Output row: `final_selectors` (s0=0), post-permutation state, `output_node_index`, + /// `is_boundary_output`, `output_direction_bit`. /// - /// This also records the execution trace of the Merkle path computation. + /// Both rows carry the current `mrupdate_id` for sibling table domain separation. + /// The pre-permutation state is also recorded in `perm_request_map` for deduplication. /// - /// # Panics - /// Panics if: - /// - The provided path does not contain any nodes. - /// - The provided index is out of range for the specified path. + /// For Merkle operations, `input_node_index` is the full tree index and + /// `output_node_index` is the shifted index (input >> 1). For non-Merkle operations, + /// both should be ZERO. + /// + /// Returns the post-permutation state. + fn append_controller_permutation( + &mut self, + init_selectors: Selectors, + final_selectors: Selectors, + state: HasherState, + input_node_index: Felt, + output_node_index: Felt, + is_boundary_input: Felt, + is_boundary_output: Felt, + input_direction_bit: Felt, + output_direction_bit: Felt, + ) -> HasherState { + // Append input controller row + self.trace.append_controller_row( + init_selectors, + &state, + input_node_index, + self.mrupdate_id, + is_boundary_input, + input_direction_bit, + ); + + // Apply the permutation + let mut permuted = state; + apply_permutation(&mut permuted); + + // Append output controller row + self.trace.append_controller_row( + final_selectors, + &permuted, + output_node_index, + self.mrupdate_id, + is_boundary_output, + output_direction_bit, + ); + + // Record this permutation request for deduplication + self.record_perm_request(&state); + + permuted + } + + // MERKLE PATH HELPERS + // -------------------------------------------------------------------------------------------- + + /// Computes a root of the provided Merkle path in the specified context. fn verify_merkle_path( &mut self, value: Digest, @@ -281,91 +421,107 @@ impl Hasher { index.checked_shr(path.len() as u32).unwrap_or(0) == 0, "invalid index for the path" ); - let mut root = value; - // determine selectors for the specified context let main_selectors = context.main_selectors(); - let part_selectors = context.part_selectors(); + let depth = path.len(); - if path.len() == 1 { - // handle path of length 1 separately because pattern for init and final selectors - // is different from other cases - self.verify_mp_leg(root, path[0], &mut index, main_selectors, RETURN_HASH) - } else { - // process the first node of the path; for this node, init and final selectors are - // the same - let sibling = path[0]; - root = self.verify_mp_leg(root, sibling, &mut index, main_selectors, main_selectors); - - // process all other nodes, except for the last one - for &sibling in &path[1..path.len() - 1] { - root = - self.verify_mp_leg(root, sibling, &mut index, part_selectors, main_selectors); - } - - // process the last node - let sibling = path[path.len() - 1]; - self.verify_mp_leg(root, sibling, &mut index, part_selectors, RETURN_HASH) + let mut root = value; + + for (i, &sibling) in path.iter().enumerate() { + let is_first = i == 0; + let is_last = i == depth - 1; + + // Determine boundary flags + let is_boundary_input = if is_first { ONE } else { ZERO }; + let is_boundary_output = if is_last { ONE } else { ZERO }; + + // Direction bit for this step: LSB of the current index + let b_i = index & 1; + let state = build_merge_state(&root, &sibling, b_i); + + // Input row carries the full index; output row carries the shifted index. + let input_node_idx = Felt::new_unchecked(index); + let output_node_idx = Felt::new_unchecked(index >> 1); + + // Direction bit for the NEXT step (forward propagation for routing constraint). + // On the last step there is no next step, so direction_bit = 0. + let b_next = if is_last { 0 } else { (index >> 1) & 1 }; + + let final_selectors = if is_last { RETURN_HASH } else { RETURN_STATE }; + + // Append controller pair with direction bits + let permuted = self.append_controller_permutation( + main_selectors, + final_selectors, + state, + input_node_idx, + output_node_idx, + is_boundary_input, + is_boundary_output, + Felt::new_unchecked(b_i), // input direction_bit: current step's bit + Felt::new_unchecked(b_next), // output direction_bit: next step's bit (propagated) + ); + + root = get_digest(&permuted); + index >>= 1; } + + root } - /// Verifies a single leg of a Merkle path. + // PERMUTATION DEDUPLICATION + // -------------------------------------------------------------------------------------------- + + /// Records a permutation request for the given input state. If the same state was already + /// seen, increments the multiplicity counter. + fn record_perm_request(&mut self, state: &HasherState) { + let key = state_to_key(state); + *self.perm_request_map.entry(key).or_insert(0) += 1; + } + + // MEMOIZATION + // -------------------------------------------------------------------------------------------- + + /// Attempts to replay a memoized controller trace for the given expected hash. /// - /// This function does the following: - /// - Builds the initial hasher state based on the least significant bit of the index. - /// - Applies a permutation to this state and records the resulting trace. - /// - Returns the result of the permutation and updates the index by removing its least - /// significant bit. - fn verify_mp_leg( - &mut self, - root: Digest, - sibling: Digest, - index: &mut u64, - init_selectors: Selectors, - final_selectors: Selectors, - ) -> Digest { - // build the hasher state based on the value of the least significant bit of the index - let index_bit = *index & 1; - let mut state = build_merge_state(&root, &sibling, index_bit); - - // determine values for the node index column for this permutation. if the first selector - // of init_selectors is not ZERO (i.e., we are processing the first leg of the Merkle - // path), the index for the first row is different from the index for the other rows; - // otherwise, indexes are the same. - let (init_index, rest_index) = if init_selectors[0] == ZERO { - (Felt::new(*index >> 1), Felt::new(*index >> 1)) - } else { - (Felt::new(*index), Felt::new(*index >> 1)) + /// If a memoized trace exists, copies it, re-registers permutation requests from copied + /// input rows, and returns `Some((addr, digest))`. Otherwise returns `None`. + fn replay_memoized_trace(&mut self, expected_hash: Digest) -> Option<(Felt, Digest)> { + let (start_row, end_row) = match self.get_memoized_trace(expected_hash) { + Some(&(s, e)) => (s, e), + None => return None, }; - // apply the permutation to the state and record its trace - self.trace.append_permutation_with_index( - &mut state, - init_selectors, - final_selectors, - init_index, - rest_index, - ); - - // remove the least significant bit from the index and return hash result - *index >>= 1; + let addr = self.trace.next_row_addr(); + let mut state = [ZERO; STATE_WIDTH]; + let append_start = self.trace.trace_len(); + self.trace.copy_trace(&mut state, start_row..end_row); + let append_end = self.trace.trace_len(); + + // Ensure mrupdate_id is consistent with the current counter for all copied rows. + self.trace + .overwrite_mrupdate_id_in_range(append_start..append_end, self.mrupdate_id); + + // Re-register permutation requests from copied input rows + let input_states = self.trace.input_states_in_range(append_start..append_end); + for input_state in input_states { + self.record_perm_request(&input_state); + } - get_digest(&state) + let result = get_digest(&state); + Some((addr, result)) } - /// Checks if a trace for a program block already exists and returns the start and end rows - /// of the memoized trace. Returns None otherwise. + /// Returns the start and end rows of a memoized block trace, if it exists. fn get_memoized_trace(&self, hash: Digest) -> Option<&(usize, usize)> { - let key: [u8; 32] = hash.into(); - self.memoized_trace_map.get(&key) + self.memoized_trace_map.get(&digest_to_key(hash)) } - /// Inserts start and end rows of trace for a program block to the memoized_trace_map. + /// Records the start and end rows of a block's controller trace for memoization. fn insert_to_memoized_trace_map(&mut self, addr: Felt, hash: Digest) { - let key: [u8; 32] = hash.into(); let start_row = addr.as_canonical_u64() as usize - 1; let end_row = self.trace.next_row_addr().as_canonical_u64() as usize - 1; - self.memoized_trace_map.insert(key, (start_row, end_row)); + self.memoized_trace_map.insert(digest_to_key(hash), (start_row, end_row)); } } @@ -387,29 +543,19 @@ enum MerklePathContext { impl MerklePathContext { /// Returns selector values for this context. - pub fn main_selectors(&self) -> Selectors { + pub fn main_selectors(self) -> Selectors { match self { Self::MpVerify => MP_VERIFY, Self::MrUpdateOld => MR_UPDATE_OLD, Self::MrUpdateNew => MR_UPDATE_NEW, } } - - /// Returns partial selector values for this context. Partial selector values are derived - /// from selector values by replacing the first selector with ZERO. - pub fn part_selectors(&self) -> Selectors { - let selectors = self.main_selectors(); - [ZERO, selectors[1], selectors[2]] - } } // HELPER FUNCTIONS // ================================================================================================ /// Combines two words into a hasher state for Merkle path computation. -/// -/// If index_bit = 0, the words are combined in the order (a, b), if index_bit = 1, the words are -/// combined in the order (b, a), otherwise, the function panics. #[inline(always)] fn build_merge_state(a: &Digest, b: &Digest, index_bit: u64) -> HasherState { match index_bit { @@ -419,18 +565,12 @@ fn build_merge_state(a: &Digest, b: &Digest, index_bit: u64) -> HasherState { } } -// TODO: Move these to another file. - // HASHER STATE MUTATORS // ================================================================================================ -/// Initializes hasher state with the first 8 elements to be absorbed. In accordance with the -/// Poseidon2 padding rule, the first capacity element is set with the provided padding flag, which -/// is assumed to be ZERO or ONE, depending on whether the number of elements to be absorbed is a -/// multiple of the rate or not. The remaining elements in the capacity portion of the state are set -/// to ZERO. +/// Initializes hasher state with the first 8 elements to be absorbed. /// -/// State layout: [R1, R2, CAP] where: +/// State layout: [RATE0, RATE1, CAP] where: /// - state[0..8] = init_values (rate) /// - state[8..12] = [padding_flag, ZERO, ZERO, ZERO] (capacity) #[inline(always)] @@ -439,43 +579,19 @@ pub fn init_state(init_values: &[Felt; RATE_LEN], padding_flag: Felt) -> [Felt; padding_flag == ZERO || padding_flag == ONE, "first capacity element must be 0 or 1" ); - [ - init_values[0], - init_values[1], - init_values[2], - init_values[3], - init_values[4], - init_values[5], - init_values[6], - init_values[7], - padding_flag, - ZERO, - ZERO, - ZERO, - ] + let mut state = [ZERO; STATE_WIDTH]; + state[..RATE_LEN].copy_from_slice(init_values); + state[RATE_LEN] = padding_flag; + state } -/// Initializes hasher state with the elements from the provided words. Because the length of the -/// input is a multiple of the rate, all capacity elements are initialized to zero, as specified by -/// the Poseidon2 padding rule. -/// -/// State layout: [RATE0, RATE1, CAP] where: -/// - state[0..4] = w1 (first rate word, also digest location) -/// - state[4..8] = w2 (second rate word) -/// - state[8..12] = capacity +/// Initializes hasher state from two words with zero capacity. #[inline(always)] pub fn init_state_from_words(w1: &Digest, w2: &Digest) -> [Felt; STATE_WIDTH] { init_state_from_words_with_domain(w1, w2, ZERO) } -/// Initializes hasher state with elements from the provided words. Sets the second element of the -/// capacity register to the provided domain. All other elements of the capacity register are set -/// to 0. -/// -/// State layout: [RATE0, RATE1, CAP] where: -/// - state[0..4] = w1 (first rate word, also digest location) -/// - state[4..8] = w2 (second rate word) -/// - state[8..12] = [ZERO, domain, ZERO, ZERO] (capacity) +/// Initializes hasher state from two words with a domain value in capacity[1]. #[inline(always)] pub fn init_state_from_words_with_domain( w1: &Digest, @@ -485,23 +601,13 @@ pub fn init_state_from_words_with_domain( [w1[0], w1[1], w1[2], w1[3], w2[0], w2[1], w2[2], w2[3], ZERO, domain, ZERO, ZERO] } -/// Absorbs the specified values into the provided state by overwriting the corresponding elements -/// in the rate portion of the state. -/// -/// State layout: rate is at state[0..8] +/// Absorbs values into the rate portion of the state. #[inline(always)] pub fn absorb_into_state(state: &mut [Felt; STATE_WIDTH], values: &[Felt; RATE_LEN]) { - state[0] = values[0]; - state[1] = values[1]; - state[2] = values[2]; - state[3] = values[3]; - state[4] = values[4]; - state[5] = values[5]; - state[6] = values[6]; - state[7] = values[7]; + state[..RATE_LEN].copy_from_slice(values); } -/// Returns elements representing the digest portion of the provided hasher's state. +/// Returns the digest portion of the hasher state. pub fn get_digest(state: &[Felt; STATE_WIDTH]) -> Digest { state[DIGEST_RANGE].try_into().expect("failed to get digest from hasher state") } diff --git a/processor/src/trace/chiplets/hasher/tests.rs b/processor/src/trace/chiplets/hasher/tests.rs index 7f9e8765e2..e4ff86e736 100644 --- a/processor/src/trace/chiplets/hasher/tests.rs +++ b/processor/src/trace/chiplets/hasher/tests.rs @@ -1,692 +1,757 @@ use alloc::vec::Vec; use miden_air::trace::chiplets::hasher::{ - DIGEST_LEN, HASH_CYCLE_LEN, NUM_ROUNDS, NUM_SELECTORS, STATE_COL_RANGE, + DIRECTION_BIT_COL_IDX, HASH_CYCLE_LEN, IS_BOUNDARY_COL_IDX, MRUPDATE_ID_COL_IDX, + NODE_INDEX_COL_IDX, S_PERM_COL_IDX, STATE_COL_RANGE, TRACE_WIDTH, }; use miden_core::{ ONE, ZERO, chiplets::hasher, crypto::merkle::{MerkleTree, NodeIndex}, - mast::{ - BasicBlockNodeBuilder, DecoratorId, JoinNodeBuilder, LoopNodeBuilder, MastForest, - MastForestContributor, MastNode, MastNodeExt, SplitNodeBuilder, - }, - operations::Operation, + mast::OpBatch, }; use miden_utils_testing::rand::rand_array; use super::{ Digest, Felt, Hasher, HasherState, LINEAR_HASH, MP_VERIFY, MR_UPDATE_NEW, MR_UPDATE_OLD, - MerklePath, RETURN_HASH, RETURN_STATE, Selectors, TRACE_WIDTH, TraceFragment, + RETURN_HASH, RETURN_STATE, Selectors, TraceFragment, absorb_into_state, get_digest, init_state, init_state_from_words, }; -// LINEAR HASH TESTS +// SPONGE MODE TESTS // ================================================================================================ #[test] fn hasher_permute() { - // --- test one permutation ----------------------------------------------- - - // initialize the hasher and perform one permutation + // --- test one permutation (HPERM) --- let mut hasher = Hasher::default(); let init_state: HasherState = rand_array(); let (addr, final_state) = hasher.permute(init_state); - - // address of the permutation should be ONE (as hasher address starts at ONE) assert_eq!(ONE, addr); - // make sure the result is correct let expected_state = apply_permutation(init_state); assert_eq!(expected_state, final_state); - // build the trace - let trace = build_trace(hasher, HASH_CYCLE_LEN); + let trace = build_trace(hasher); - // make sure the trace is correct - check_selector_trace(&trace, 0, LINEAR_HASH, RETURN_STATE); - check_hasher_state_trace(&trace, 0, init_state); - assert_eq!(trace.last().unwrap(), &[ZERO; HASH_CYCLE_LEN]); + // Controller region: 2 rows (1 pair), padded to 16 rows total. + // Perm segment: 1 packed 16-row cycle (1 unique state). + // Total hasher rows: 32. + assert_eq!(trace[0].len(), 2 * HASH_CYCLE_LEN); - // --- test two permutations ---------------------------------------------- + // Row 0: input (LINEAR_HASH, is_boundary=1, s_perm=0) + check_controller_input(&trace, 0, LINEAR_HASH, &init_state, ZERO, ONE, ZERO, ZERO); + // Row 1: output (RETURN_STATE, is_boundary=1, s_perm=0) + check_controller_output(&trace, 1, RETURN_STATE, &expected_state, ZERO, ONE, ZERO); + + // Perm segment starts at row 16 (after padding) + check_perm_segment(&trace, HASH_CYCLE_LEN, &init_state, ONE); +} - // initialize the hasher and perform two permutations +#[test] +fn hasher_permute_two() { let mut hasher = Hasher::default(); let init_state1: HasherState = rand_array(); + let init_state2: HasherState = rand_array(); let (addr1, final_state1) = hasher.permute(init_state1); - - let init_state2: HasherState = rand_array(); let (addr2, final_state2) = hasher.permute(init_state2); - // make sure the returned addresses are correct (they must be `HASH_CYCLE_LEN` rows apart) + // Addresses are 2 rows apart (controller pairs) assert_eq!(ONE, addr1); - assert_eq!(Felt::new(HASH_CYCLE_LEN as u64 + 1), addr2); + assert_eq!(Felt::from_u8(3), addr2); - // make sure the results are correct - let expected_state1 = apply_permutation(init_state1); - assert_eq!(expected_state1, final_state1); + assert_eq!(apply_permutation(init_state1), final_state1); + assert_eq!(apply_permutation(init_state2), final_state2); - let expected_state2 = apply_permutation(init_state2); - assert_eq!(expected_state2, final_state2); + let trace = build_trace(hasher); - // build the trace - let trace = build_trace(hasher, 2 * HASH_CYCLE_LEN); + // Controller region: 4 rows (2 pairs), padded to 16 rows total. + // Perm segment: 2 packed 16-row cycles = 32 rows. + // Total hasher rows: 48. + assert_eq!(trace[0].len(), HASH_CYCLE_LEN + 2 * HASH_CYCLE_LEN); - // make sure the trace is correct - check_selector_trace(&trace, 0, LINEAR_HASH, RETURN_STATE); - check_selector_trace(&trace, HASH_CYCLE_LEN, LINEAR_HASH, RETURN_STATE); - check_hasher_state_trace(&trace, 0, init_state1); - check_hasher_state_trace(&trace, HASH_CYCLE_LEN, init_state2); - assert_eq!(trace.last().unwrap(), &[ZERO; 2 * HASH_CYCLE_LEN]); + // Pair 1 + check_controller_input(&trace, 0, LINEAR_HASH, &init_state1, ZERO, ONE, ZERO, ZERO); + check_controller_output(&trace, 1, RETURN_STATE, &final_state1, ZERO, ONE, ZERO); + // Pair 2 + check_controller_input(&trace, 2, LINEAR_HASH, &init_state2, ZERO, ONE, ZERO, ZERO); + check_controller_output(&trace, 3, RETURN_STATE, &final_state2, ZERO, ONE, ZERO); } -// MERKLE TREE TESTS +// TREE MODE TESTS // ================================================================================================ -// -// These tests verify trace generation, not computed results. The Merkle roots are validated -// through `check_merkle_path`. +/// Merkle tree with 2 leaves (depth 1): +/// +/// ```text +/// root +/// / \ +/// L0 L1 +/// ``` +/// +/// Verifying the path from L0 to root requires 1 controller pair. #[test] -fn hasher_build_merkle_root() { - // --- Merkle tree with 2 leaves ------------------------------------------ - - // build a Merkle tree +fn hasher_build_merkle_root_depth_1() { let leaves = init_leaves(&[1, 2]); let tree = MerkleTree::new(&leaves).unwrap(); - // initialize the hasher and perform two Merkle branch verifications let mut hasher = Hasher::default(); let path0 = tree.get_path(NodeIndex::new(1, 0).unwrap()).unwrap(); + let (_, root) = hasher.build_merkle_root(leaves[0], &path0, ZERO); - let _ = hasher.build_merkle_root(leaves[0], &path0, ZERO); - - let path1 = tree.get_path(NodeIndex::new(1, 1).unwrap()).unwrap(); - - let _ = hasher.build_merkle_root(leaves[1], &path1, ONE); - - // build the trace - let trace = build_trace(hasher, 2 * HASH_CYCLE_LEN); + assert_eq!(root, tree.root()); - // make sure the trace is correct - check_selector_trace(&trace, 0, MP_VERIFY, RETURN_HASH); - check_selector_trace(&trace, HASH_CYCLE_LEN, MP_VERIFY, RETURN_HASH); - check_hasher_state_trace(&trace, 0, init_state_from_words(&leaves[0], &path0[0])); - check_hasher_state_trace(&trace, 0, init_state_from_words(&path1[0], &leaves[1])); - let node_idx_column = trace.last().unwrap(); - assert_eq!(node_idx_column.len(), 2 * HASH_CYCLE_LEN); - assert!(node_idx_column[..HASH_CYCLE_LEN].iter().all(|&v| v == ZERO)); - assert_eq!(node_idx_column[HASH_CYCLE_LEN], ONE); - assert!(node_idx_column[HASH_CYCLE_LEN + 1..].iter().all(|&v| v == ZERO)); + let trace = build_trace(hasher); - // --- Merkle tree with 8 leaves ------------------------------------------ + // Row 0: input (MP_VERIFY, is_boundary=1, node_index=0) + let init_state = init_state_from_words(&leaves[0], &path0[0]); + check_controller_input(&trace, 0, MP_VERIFY, &init_state, ZERO, ONE, ZERO, ZERO); + // Row 1: output (RETURN_HASH, is_boundary=1, node_index=0) + check_controller_output( + &trace, + 1, + RETURN_HASH, + &apply_permutation(init_state), + ZERO, + ONE, + ZERO, + ); +} - // build a Merkle tree +/// Merkle tree with 8 leaves (depth 3): +/// +/// ```text +/// root +/// / \ +/// N(1,0) N(1,1) +/// / \ / \ +/// N20 N21 N22 N23 +/// / \ / \ / \ / \ +/// L0 L1 L2 L3 L4 L5 L6 L7 +/// ``` +/// +/// Verifying the path from L5 (node_index=5) to root requires 3 controller pairs. +/// The node_index shifts right by 1 at each level: 5 -> 2 -> 1 -> 0. +#[test] +fn hasher_build_merkle_root_depth_3() { let leaves = init_leaves(&[1, 2, 3, 4, 5, 6, 7, 8]); let tree = MerkleTree::new(&leaves).unwrap(); - // initialize the hasher and perform one Merkle branch verifications let mut hasher = Hasher::default(); let path = tree.get_path(NodeIndex::new(3, 5).unwrap()).unwrap(); - let _ = hasher.build_merkle_root(leaves[5], &path, Felt::new(5)); - - // build and check the trace for validity - let trace = build_trace(hasher, path.len() * HASH_CYCLE_LEN); - check_merkle_path(&trace, 0, leaves[5], &path, 5, MP_VERIFY); + let (_, root) = hasher.build_merkle_root(leaves[5], &path, Felt::from_u8(5)); + + assert_eq!(root, tree.root()); + + let trace = build_trace(hasher); + + // Depth 3: 3 controller pairs = 6 rows + // Index=5 (binary 101): direction bits are LSBs at each level + // Pair 0 (rows 0-1): node_index 5 -> 2, b_0=5&1=1, b_next=(5>>1)&1=0 + check_merkle_controller_pair(&trace, 0, MP_VERIFY, 5, true, false, ZERO, ONE, ZERO); + // Pair 1 (rows 2-3): node_index 2 -> 1, b_1=2&1=0, b_next=(2>>1)&1=1 + check_merkle_controller_pair(&trace, 2, MP_VERIFY, 2, false, false, ZERO, ZERO, ONE); + // Pair 2 (rows 4-5): node_index 1 -> 0, b_2=1&1=1, b_next=0 (last step) + check_merkle_controller_pair(&trace, 4, MP_VERIFY, 1, false, true, ZERO, ONE, ZERO); + + // Capacity is zero on all tree-mode input rows + for row in [0, 2, 4] { + for cap_col in 11..15 { + assert_eq!( + trace[cap_col][row], ZERO, + "capacity should be zero on tree input row {row}, col {cap_col}" + ); + } + } +} - // --- Merkle tree with 8 leaves (multiple branches) ---------------------- +#[test] +fn hasher_update_merkle_root() { + let leaves = init_leaves(&[1, 2, 3, 4]); + let tree = MerkleTree::new(&leaves).unwrap(); - // initialize the hasher and perform one Merkle branch verifications let mut hasher = Hasher::default(); + let index = 1u64; + let path = tree.get_path(NodeIndex::new(2, index).unwrap()).unwrap(); + let new_leaf: Digest = [Felt::from_u8(100), ZERO, ZERO, ZERO].into(); + + let update = hasher.update_merkle_root( + leaves[index as usize], + new_leaf, + &path, + Felt::new_unchecked(index), + ); - let path0 = tree.get_path(NodeIndex::new(3, 0).unwrap()).unwrap(); + assert_eq!(update.get_old_root(), tree.root()); - let _ = hasher.build_merkle_root(leaves[0], &path0, ZERO); + let trace = build_trace(hasher); - let path3 = tree.get_path(NodeIndex::new(3, 3).unwrap()).unwrap(); + // Depth 2: 2 pairs for MV (old path) + 2 pairs for MU (new path) = 8 controller rows. + // All rows share mrupdate_id=1. - let _ = hasher.build_merkle_root(leaves[3], &path3, Felt::new(3)); + // MV leg (old path): rows 0-3 + // Index=1 (binary 01): direction bits are LSBs at each level + // Pair 0 (rows 0-1): node_index 1 -> 0, b_0=1&1=1, b_next=(1>>1)&1=0 + check_merkle_controller_pair(&trace, 0, MR_UPDATE_OLD, 1, true, false, ONE, ONE, ZERO); + // Pair 1 (rows 2-3): node_index 0 -> 0, b_1=0&1=0, b_next=0 (last step) + check_merkle_controller_pair(&trace, 2, MR_UPDATE_OLD, 0, false, true, ONE, ZERO, ZERO); - let path7 = tree.get_path(NodeIndex::new(3, 7).unwrap()).unwrap(); + // MU leg (new path): rows 4-7 + // Same index, same direction bits + // Pair 0 (rows 4-5): node_index 1 -> 0, b_0=1&1=1, b_next=(1>>1)&1=0 + check_merkle_controller_pair(&trace, 4, MR_UPDATE_NEW, 1, true, false, ONE, ONE, ZERO); + // Pair 1 (rows 6-7): node_index 0 -> 0, b_1=0&1=0, b_next=0 (last step) + check_merkle_controller_pair(&trace, 6, MR_UPDATE_NEW, 0, false, true, ONE, ZERO, ZERO); +} + +// PERM SEGMENT TESTS +// ================================================================================================ + +#[test] +fn perm_segment_structure() { + // One permutation -> perm segment has 1 cycle with multiplicity 1 + let mut hasher = Hasher::default(); + let init_state: HasherState = rand_array(); + let (addr, result) = hasher.permute(init_state); - let _ = hasher.build_merkle_root(leaves[7], &path7, Felt::new(7)); + // Verify returned address and permuted state + assert_eq!(addr, ONE, "first permutation should start at address 1"); + assert_eq!(result, apply_permutation(init_state), "permuted state should match"); - // path3 again + let trace = build_trace(hasher); - let _ = hasher.build_merkle_root(leaves[3], &path3, Felt::new(3)); + // Perm segment starts at HASH_CYCLE_LEN (after padding) + let perm_start = HASH_CYCLE_LEN; - // build and check the trace for validity - let trace = build_trace(hasher, 4 * path0.len() * HASH_CYCLE_LEN); - check_merkle_path(&trace, 0, leaves[0], &path0, 0, MP_VERIFY); - check_merkle_path(&trace, path0.len() * HASH_CYCLE_LEN, leaves[3], &path3, 3, MP_VERIFY); - check_merkle_path(&trace, 2 * path0.len() * HASH_CYCLE_LEN, leaves[7], &path7, 7, MP_VERIFY); - check_merkle_path(&trace, 3 * path0.len() * HASH_CYCLE_LEN, leaves[3], &path3, 3, MP_VERIFY); + // All perm rows have s_perm=1 + for row in perm_start..perm_start + HASH_CYCLE_LEN { + assert_eq!(trace[S_PERM_COL_IDX][row], ONE, "s_perm should be 1 at row {row}"); + } + + // On perm rows, s0/s1/s2 serve as witness columns for packed internal rounds. + // They are zero on external and boundary rows, but hold S-box witnesses on + // packed-internal rows (4-10) and the mixed int+ext row (11). + // Rows 0-3, 12-15: witnesses should be zero + for offset in [0, 1, 2, 3, 12, 13, 14, 15] { + let row = perm_start + offset; + assert_eq!(trace[0][row], ZERO, "perm row {row}: s0 should be zero"); + assert_eq!(trace[1][row], ZERO, "perm row {row}: s1 should be zero"); + assert_eq!(trace[2][row], ZERO, "perm row {row}: s2 should be zero"); + } + // Rows 4-10: s0, s1, s2 hold witness values (non-zero for non-trivial states) + // Row 11: s0 holds witness, s1 and s2 are zero + let row_11 = perm_start + 11; + assert_eq!(trace[1][row_11], ZERO, "perm row {row_11}: s1 should be zero on int+ext row"); + assert_eq!(trace[2][row_11], ZERO, "perm row {row_11}: s2 should be zero on int+ext row"); + + // Multiplicity in node_index column + assert_eq!(trace[NODE_INDEX_COL_IDX][perm_start], ONE); + + // is_boundary, direction_bit, mrupdate_id all zero on perm rows + for row in perm_start..perm_start + HASH_CYCLE_LEN { + assert_eq!(trace[IS_BOUNDARY_COL_IDX][row], ZERO); + assert_eq!(trace[DIRECTION_BIT_COL_IDX][row], ZERO); + assert_eq!(trace[MRUPDATE_ID_COL_IDX][row], ZERO); + } } #[test] -fn hasher_update_merkle_root() { - // --- Merkle tree with 2 leaves ------------------------------------------ +fn perm_deduplication() { + // Two permutations with the SAME input state -> perm segment has 1 cycle with multiplicity 2 + let mut hasher = Hasher::default(); + let init_state: HasherState = rand_array(); + let (addr1, result1) = hasher.permute(init_state); + let (addr2, result2) = hasher.permute(init_state); // same state - // build a Merkle tree - let leaves = init_leaves(&[1, 2]); - let mut tree = MerkleTree::new(&leaves).unwrap(); + // Both should produce the same result but at different addresses + assert_eq!(result1, result2, "same input should produce same output"); + assert_ne!(addr1, addr2, "second call should have a different address"); - // initialize the hasher and update both leaves - let mut hasher = Hasher::default(); + let trace = build_trace(hasher); - let path0 = tree.get_path(NodeIndex::new(1, 0).unwrap()).unwrap(); - let new_leaf0 = init_leaf(3); + // Controller: 4 rows (2 pairs), padded to 16. Perm: 1 cycle = 16 rows (deduped). Total: 32. + assert_eq!(trace[0].len(), 2 * HASH_CYCLE_LEN); - hasher.update_merkle_root(leaves[0], new_leaf0, &path0, ZERO); - tree.update_leaf(0, new_leaf0).unwrap(); + // Perm segment: multiplicity should be 2 + let perm_start = HASH_CYCLE_LEN; + assert_eq!(trace[NODE_INDEX_COL_IDX][perm_start], Felt::from_u8(2)); +} - let path1 = tree.get_path(NodeIndex::new(1, 1).unwrap()).unwrap(); - let new_leaf1 = init_leaf(4); +// MEMOIZATION TESTS +// ================================================================================================ - hasher.update_merkle_root(leaves[1], new_leaf1, &path1, ONE); - tree.update_leaf(1, new_leaf1).unwrap(); +#[test] +fn hash_memoization_control_blocks() { + let h1: Digest = rand_array::().into(); + let h2: Digest = rand_array::().into(); + let domain = Felt::from_u8(7); // arbitrary domain - // build the trace - let trace = build_trace(hasher, 4 * HASH_CYCLE_LEN); + // Compute the expected hash + let state = super::init_state_from_words_with_domain(&h1, &h2, domain); + let permuted = apply_permutation(state); + let expected_hash: Digest = get_digest(&permuted); - // make sure the trace is correct - check_selector_trace(&trace, 0, MR_UPDATE_OLD, RETURN_HASH); - check_selector_trace(&trace, HASH_CYCLE_LEN, MR_UPDATE_NEW, RETURN_HASH); - check_selector_trace(&trace, 2 * HASH_CYCLE_LEN, MR_UPDATE_OLD, RETURN_HASH); - check_selector_trace(&trace, 3 * HASH_CYCLE_LEN, MR_UPDATE_NEW, RETURN_HASH); - check_hasher_state_trace(&trace, 0, init_state_from_words(&leaves[0], &path0[0])); - check_hasher_state_trace(&trace, HASH_CYCLE_LEN, init_state_from_words(&new_leaf0, &path0[0])); - check_hasher_state_trace( - &trace, - 2 * HASH_CYCLE_LEN, - init_state_from_words(&path1[0], &leaves[1]), - ); - check_hasher_state_trace( - &trace, - 3 * HASH_CYCLE_LEN, - init_state_from_words(&path1[0], &new_leaf1), - ); - let node_idx_column = trace.last().unwrap(); - assert_eq!(node_idx_column.len(), 4 * HASH_CYCLE_LEN); - assert!(node_idx_column[..2 * HASH_CYCLE_LEN].iter().all(|&v| v == ZERO)); - assert_eq!(node_idx_column[2 * HASH_CYCLE_LEN], ONE); - assert!( - node_idx_column[2 * HASH_CYCLE_LEN + 1..3 * HASH_CYCLE_LEN] - .iter() - .all(|&v| v == ZERO) - ); - assert_eq!(node_idx_column[3 * HASH_CYCLE_LEN], ONE); - assert!(node_idx_column[3 * HASH_CYCLE_LEN + 1..].iter().all(|&v| v == ZERO)); + let mut hasher = Hasher::default(); - // --- Merkle tree with 8 leaves ------------------------------------------ + let (addr1, digest1) = hasher.hash_control_block(h1, h2, domain, expected_hash); + let (addr2, digest2) = hasher.hash_control_block(h1, h2, domain, expected_hash); - // build a Merkle tree - let leaves = init_leaves(&[1, 2, 3, 4, 5, 6, 7, 8]); - let mut tree = MerkleTree::new(&leaves).unwrap(); + assert_eq!(digest1, digest2); + assert_eq!(digest1, expected_hash); + // Second call uses memoized trace at a different address + assert_ne!(addr1, addr2); - // initialize the hasher - let mut hasher = Hasher::default(); + let trace = build_trace(hasher); - let path3 = tree.get_path(NodeIndex::new(3, 3).unwrap()).unwrap(); - let new_leaf3 = init_leaf(23); - - hasher.update_merkle_root(leaves[3], new_leaf3, &path3, Felt::new(3)); - tree.update_leaf(3, new_leaf3).unwrap(); - - let path6 = tree.get_path(NodeIndex::new(3, 6).unwrap()).unwrap(); - let new_leaf6 = init_leaf(25); - hasher.update_merkle_root(leaves[6], new_leaf6, &path6, Felt::new(6)); - tree.update_leaf(6, new_leaf6).unwrap(); - - // update leaf 3 again - let path3_2 = tree.get_path(NodeIndex::new(3, 3).unwrap()).unwrap(); - let new_leaf3_2 = init_leaf(27); - hasher.update_merkle_root(new_leaf3, new_leaf3_2, &path3_2, Felt::new(3)); - tree.update_leaf(3, new_leaf3_2).unwrap(); - assert_ne!(path3, path3_2); - - // build and check the trace for validity - let leg_rows = path3.len() * HASH_CYCLE_LEN; - let trace = build_trace(hasher, 6 * leg_rows); - check_merkle_path(&trace, 0, leaves[3], &path3, 3, MR_UPDATE_OLD); - check_merkle_path(&trace, leg_rows, new_leaf3, &path3, 3, MR_UPDATE_NEW); - check_merkle_path(&trace, 2 * leg_rows, leaves[6], &path6, 6, MR_UPDATE_OLD); - check_merkle_path(&trace, 3 * leg_rows, new_leaf6, &path6, 6, MR_UPDATE_NEW); - check_merkle_path(&trace, 4 * leg_rows, new_leaf3, &path3_2, 3, MR_UPDATE_OLD); - check_merkle_path(&trace, 5 * leg_rows, new_leaf3_2, &path3_2, 3, MR_UPDATE_NEW); + // Both calls produce controller pairs (4 rows), but share perm requests. + // Controller: 4 rows, padded to 16. Perm: 1 cycle (deduped). Total: 32. + assert_eq!(trace[0].len(), 2 * HASH_CYCLE_LEN); + + // Perm segment has multiplicity 2 (two requests for same state) + let perm_start = HASH_CYCLE_LEN; + assert_eq!(trace[NODE_INDEX_COL_IDX][perm_start], Felt::from_u8(2)); } -// MEMOIZATION TESTS +// BASIC BLOCK MEMOIZATION TESTS // ================================================================================================ #[test] -fn hash_memoization_control_blocks() { - // --- Join block with 2 same split blocks as children, having the same hasher execution trace. - // Join - // / \ - // / \ - // / \ - // Split1 Split2 (memoized) +fn hash_memoization_basic_blocks_single_batch() { + // Test that hashing the same single-batch basic block twice uses memoization: + // the second call copies the controller rows and reuses the perm cycle (multiplicity 2). + let mut hasher = Hasher::default(); + + let batches = make_single_batch(); + let expected_hash = compute_basic_block_hash(&batches); - let mut mast_forest = MastForest::new(); + let (addr1, digest1) = hasher.hash_basic_block(&batches, expected_hash); + let (addr2, digest2) = hasher.hash_basic_block(&batches, expected_hash); - let t_branch_id = BasicBlockNodeBuilder::new(vec![Operation::Push(ZERO)], Vec::new()) - .add_to_forest(&mut mast_forest) - .unwrap(); - let t_branch = mast_forest[t_branch_id].clone(); + assert_eq!(digest1, digest2, "memoized digest should match original"); + assert_eq!(digest1, expected_hash); + assert_ne!(addr1, addr2, "memoized call should have a different address"); - let f_branch_id = BasicBlockNodeBuilder::new(vec![Operation::Push(ONE)], Vec::new()) - .add_to_forest(&mut mast_forest) - .unwrap(); - let f_branch = mast_forest[f_branch_id].clone(); + let trace = build_trace(hasher); - let split1_id = SplitNodeBuilder::new([t_branch_id, f_branch_id]) - .add_to_forest(&mut mast_forest) - .unwrap(); - let split1 = mast_forest[split1_id].clone(); + // Single batch -> 1 controller pair per call = 4 rows total, padded to 16. + // Perm: 1 unique state with multiplicity 2 = 16 rows. Total: 32. + assert_eq!(trace[0].len(), 2 * HASH_CYCLE_LEN); - let split2_id = SplitNodeBuilder::new([t_branch_id, f_branch_id]) - .add_to_forest(&mut mast_forest) - .unwrap(); - let split2 = mast_forest[split2_id].clone(); + // Verify first call: rows 0-1 + check_controller_input( + &trace, + 0, + LINEAR_HASH, + &init_state(batches[0].groups(), ZERO), + ZERO, + ONE, + ZERO, + ZERO, + ); + check_controller_output( + &trace, + 1, + RETURN_HASH, + &apply_permutation(init_state(batches[0].groups(), ZERO)), + ZERO, + ONE, + ZERO, + ); - let _join_node_id = JoinNodeBuilder::new([split1_id, split2_id]) - .add_to_forest(&mut mast_forest) - .unwrap(); - let join_node = mast_forest[_join_node_id].clone(); + // Verify memoized call: rows 2-3 should match rows 0-1 in selectors and state + check_memoized_trace(&trace, 0..2, 2..4); - let mut hasher = Hasher::default(); - let h1: [Felt; DIGEST_LEN] = split1 - .digest() - .as_elements() - .try_into() - .expect("Could not convert slice to array"); - let h2: [Felt; DIGEST_LEN] = split2 - .digest() - .as_elements() - .try_into() - .expect("Could not convert slice to array"); - - let expected_hash = join_node.digest(); - - // builds the trace of the join block. - let (_, final_state) = - hasher.hash_control_block(h1.into(), h2.into(), join_node.domain(), expected_hash); - - // make sure the hash of the final state is the same as the expected hash. - assert_eq!(final_state, expected_hash); - - let h1: [Felt; DIGEST_LEN] = t_branch - .digest() - .as_elements() - .try_into() - .expect("Could not convert slice to array"); - let h2: [Felt; DIGEST_LEN] = f_branch - .digest() - .as_elements() - .try_into() - .expect("Could not convert slice to array"); - - let expected_hash = split1.digest(); - - // builds the hash execution trace of the first split block from scratch. - let (addr, final_state) = - hasher.hash_control_block(h1.into(), h2.into(), split1.domain(), expected_hash); - - let first_block_final_state = final_state; - - // make sure the hash of the final state of the first split block is the same as the expected - // hash. - assert_eq!(final_state, expected_hash); - - let start_row = addr.as_canonical_u64() as usize - 1; - let end_row = hasher.trace_len() - 1; - - let h1: [Felt; DIGEST_LEN] = t_branch - .digest() - .as_elements() - .try_into() - .expect("Could not convert slice to array"); - let h2: [Felt; DIGEST_LEN] = f_branch - .digest() - .as_elements() - .try_into() - .expect("Could not convert slice to array"); - let expected_hash = split2.digest(); - - // builds the hash execution trace of the second split block by copying it from the trace of - // the first split block. - let (addr, final_state) = - hasher.hash_control_block(h1.into(), h2.into(), split2.domain(), expected_hash); - - // make sure the hash of the final state of the second split block is the same as the expected - // hash. - assert_eq!(final_state, expected_hash); - // make sure the hash of the first and second split blocks is the same. - assert_eq!(first_block_final_state, final_state); - - let copied_start_row = addr.as_canonical_u64() as usize - 1; - let copied_end_row = hasher.trace_len() - 1; - - let trace = build_trace(hasher, copied_end_row + 1); - - // check the row address at which memoized block starts. - let hash_cycle_len: u64 = HASH_CYCLE_LEN.try_into().expect("Could not convert usize to u64"); - assert_eq!(Felt::new(hash_cycle_len * 2 + 1), addr); - // check the trace length of the final trace. - assert_eq!(trace.last().unwrap(), &[ZERO; HASH_CYCLE_LEN * 3]); - - // check correct copy of the memoized trace. - check_memoized_trace(&trace, start_row, end_row, copied_start_row, copied_end_row); + // Perm segment: multiplicity should be 2 (original + memoized) + let perm_start = HASH_CYCLE_LEN; + assert_eq!(trace[NODE_INDEX_COL_IDX][perm_start], Felt::from_u8(2)); } #[test] -fn hash_memoization_basic_blocks() { - // --- basic block with 1 batch ---------------------------------------------------------------- - hash_memoization_basic_blocks_check( - vec![Operation::Push(Felt::new(10)), Operation::Drop], - Vec::new(), - ); +fn hash_memoization_basic_blocks_multi_batch() { + // Test memoization of a multi-batch basic block (3 batches). + // The second call should copy all 3 controller pairs and re-register all 3 perm requests. + let mut hasher = Hasher::default(); - // --- basic block with multiple batches ------------------------------------------------------- - let ops = vec![ - Operation::Push(ONE), - Operation::Push(Felt::new(2)), - Operation::Push(Felt::new(3)), - Operation::Push(Felt::new(4)), - Operation::Push(Felt::new(5)), - Operation::Push(Felt::new(6)), - Operation::Push(Felt::new(7)), - Operation::Push(Felt::new(8)), - Operation::Push(Felt::new(9)), - Operation::Push(Felt::new(10)), - Operation::Push(Felt::new(11)), - Operation::Push(Felt::new(12)), - Operation::Push(Felt::new(13)), - Operation::Push(Felt::new(14)), - Operation::Push(Felt::new(15)), - Operation::Push(Felt::new(16)), - Operation::Push(Felt::new(17)), - Operation::Push(Felt::new(18)), - Operation::Drop, - Operation::Drop, - Operation::Drop, - Operation::Drop, - Operation::Drop, - Operation::Drop, - Operation::Drop, - Operation::Drop, - Operation::Drop, - Operation::Drop, - Operation::Drop, - Operation::Drop, - Operation::Drop, - Operation::Drop, - Operation::Drop, - Operation::Drop, - Operation::Drop, - Operation::Drop, - ]; - - hash_memoization_basic_blocks_check(ops, Vec::new()); + let batches = make_multi_batch(3); + let expected_hash = compute_basic_block_hash(&batches); + + let (addr1, digest1) = hasher.hash_basic_block(&batches, expected_hash); + let (addr2, digest2) = hasher.hash_basic_block(&batches, expected_hash); + + assert_eq!(digest1, digest2); + assert_eq!(digest1, expected_hash); + assert_ne!(addr1, addr2); + + let trace = build_trace(hasher); + + // 3 batches -> 3 controller pairs per call = 12 rows total, padded to 16. + // 3 unique perm states (each with multiplicity 2) = 3 * 16 = 48 rows. + // Total: 16 + 48 = 64 rows. + assert_eq!(trace[0].len(), HASH_CYCLE_LEN + 3 * HASH_CYCLE_LEN); + + // Verify first call: rows 0-5 (3 pairs) + // Row 0: first batch input, is_boundary=1 (start) + assert_eq!(trace[IS_BOUNDARY_COL_IDX][0], ONE); + assert_eq!(trace[DIRECTION_BIT_COL_IDX][0], ZERO); + // Row 1: first batch output, is_boundary=0 (not final) + assert_eq!(trace[IS_BOUNDARY_COL_IDX][1], ZERO); + assert_eq!(trace[DIRECTION_BIT_COL_IDX][1], ZERO); + // Row 2: second batch input, is_boundary=0 (continuation) + assert_eq!(trace[IS_BOUNDARY_COL_IDX][2], ZERO); + // Row 4: third batch input, is_boundary=0 (continuation) + assert_eq!(trace[IS_BOUNDARY_COL_IDX][4], ZERO); + // Row 5: third batch output, is_boundary=1 (final) + assert_eq!(trace[IS_BOUNDARY_COL_IDX][5], ONE); + + // Verify memoized call: rows 6-11 should match rows 0-5 + check_memoized_trace(&trace, 0..6, 6..12); + + // Perm segment: each of the 3 unique states should have multiplicity 2 + let perm_start = HASH_CYCLE_LEN; + for i in 0..3 { + let cycle_start = perm_start + i * HASH_CYCLE_LEN; + assert_eq!( + trace[NODE_INDEX_COL_IDX][cycle_start], + Felt::from_u8(2), + "perm cycle {i} should have multiplicity 2" + ); + } } -fn hash_memoization_basic_blocks_check( - operations: Vec, - decorators: Vec<(usize, DecoratorId)>, -) { - // Join block with a join and basic block as children. The child of the first join - // child node is the same as the basic block child of root join node. Here the hash execution - // trace of the second basic block is built by copying the trace built for the first same - // basic block. +#[test] +fn hash_memoization_basic_blocks_check() { + // Tree structure: + // // Join1 // / \ - // / \ - // / \ - // Join2 BB2 (memoized) - // / \ - // / \ - // / \ - // BB1 Loop - - let mut mast_forest = MastForest::new(); - - let basic_block_1_id = BasicBlockNodeBuilder::new(operations.clone(), decorators.clone()) - .add_to_forest(&mut mast_forest) - .unwrap(); - let basic_block_1 = mast_forest[basic_block_1_id].clone(); - - let loop_body_id = - BasicBlockNodeBuilder::new(vec![Operation::Pad, Operation::Eq, Operation::Not], Vec::new()) - .add_to_forest(&mut mast_forest) - .unwrap(); - - let loop_block_id = LoopNodeBuilder::new(loop_body_id).add_to_forest(&mut mast_forest).unwrap(); - let loop_block = mast_forest[loop_block_id].clone(); - - let join2_block_id = JoinNodeBuilder::new([basic_block_1_id, loop_block_id]) - .add_to_forest(&mut mast_forest) - .unwrap(); - let join2_block = mast_forest[join2_block_id].clone(); - - let basic_block_2_id = BasicBlockNodeBuilder::new(operations.clone(), decorators.clone()) - .add_to_forest(&mut mast_forest) - .unwrap(); - let basic_block_2 = mast_forest[basic_block_2_id].clone(); - - let join1_block_id = JoinNodeBuilder::new([join2_block_id, basic_block_2_id]) - .add_to_forest(&mut mast_forest) - .unwrap(); - let join1_block = mast_forest[join1_block_id].clone(); - + // Join2 BB2 (memoized from BB1) + // / \ + // BB1 Loop_body + // + // BB1 and BB2 are identical 2-batch basic blocks. When BB2 is hashed, + // it should be memoized from BB1's trace, so BB1's perm states get multiplicity 2. + // + // Expected controller row layout: + // Rows 0-3: BB1 (2 batches = 2 pairs) + // Rows 4-5: Loop body (1 batch = 1 pair) + // Rows 6-7: Join2 (1 pair) + // Rows 8-11: BB2 memoized (2 pairs, copied from BB1) + // Rows 12-13: Join1 (1 pair) let mut hasher = Hasher::default(); - let h1: [Felt; DIGEST_LEN] = join2_block - .digest() - .as_elements() - .try_into() - .expect("Could not convert slice to array"); - let h2: [Felt; DIGEST_LEN] = basic_block_2 - .digest() - .as_elements() - .try_into() - .expect("Could not convert slice to array"); - let expected_hash = join1_block.digest(); - - // builds the trace of the Join1 block. - let (_, final_state) = - hasher.hash_control_block(h1.into(), h2.into(), join1_block.domain(), expected_hash); - - // make sure the hash of the final state of Join1 is the same as the expected hash. - assert_eq!(final_state, expected_hash); - - let h1: [Felt; DIGEST_LEN] = basic_block_1 - .digest() - .as_elements() - .try_into() - .expect("Could not convert slice to array"); - let h2: [Felt; DIGEST_LEN] = loop_block - .digest() - .as_elements() - .try_into() - .expect("Could not convert slice to array"); - let expected_hash = join2_block.digest(); - - let (_, final_state) = - hasher.hash_control_block(h1.into(), h2.into(), join2_block.domain(), expected_hash); - - // make sure the hash of the final state of Join2 is the same as the expected hash. - assert_eq!(final_state, expected_hash); - - let basic_block_1_val = if let MastNode::Block(basic_block) = basic_block_1.clone() { - basic_block - } else { - unreachable!() - }; - - // builds the hash execution trace of the first basic block from scratch. - let (addr, final_state) = - hasher.hash_basic_block(basic_block_1_val.op_batches(), basic_block_1.digest()); - - let first_basic_block_final_state = final_state; - - // make sure the hash of the final state of basic block 1 is the same as the expected hash. - let expected_hash = basic_block_1.digest(); - assert_eq!(final_state, expected_hash); - - let start_row = addr.as_canonical_u64() as usize - 1; - let end_row = hasher.trace_len() - 1; - - let basic_block_2_val = if let MastNode::Block(basic_block) = basic_block_2.clone() { - basic_block - } else { - unreachable!() - }; - - // builds the hash execution trace of the second basic block by copying the sections of the - // trace corresponding to the first basic block with the same hash. - let (addr, final_state) = - hasher.hash_basic_block(basic_block_2_val.op_batches(), basic_block_2.digest()); - - let _num_batches = basic_block_2_val.op_batches().len(); - - let expected_hash = basic_block_2.digest(); - // make sure the hash of the final state of basic block 2 is the same as the expected hash. - assert_eq!(final_state, expected_hash); - - // make sure the hash of the first and second basic blocks is the same. - assert_eq!(first_basic_block_final_state, final_state); - - let copied_start_row = addr.as_canonical_u64() as usize - 1; - let copied_end_row = hasher.trace_len() - 1; - - let trace = build_trace(hasher, copied_end_row + 1); - - // check correct copy after memoization - check_memoized_trace(&trace, start_row, end_row, copied_start_row, copied_end_row); + + let batches = make_multi_batch(2); + let bb_hash = compute_basic_block_hash(&batches); + + // Hash a loop body (different block) to interleave + let loop_body_batches = make_single_batch(); + let loop_body_hash = compute_basic_block_hash(&loop_body_batches); + + // BB1: 2-batch basic block + let (bb1_addr, bb1_digest) = hasher.hash_basic_block(&batches, bb_hash); + assert_eq!(bb1_digest, bb_hash); + + // Loop body: different block in between + let (_loop_addr, loop_digest) = hasher.hash_basic_block(&loop_body_batches, loop_body_hash); + assert_eq!(loop_digest, loop_body_hash); + + // Hash Join2 = hash(BB1, Loop) + let join2_state = + super::init_state_from_words_with_domain(&bb1_digest, &loop_digest, Felt::from_u8(7)); + let join2_permuted = apply_permutation(join2_state); + let join2_hash = get_digest(&join2_permuted); + let (_join2_addr, join2_digest) = + hasher.hash_control_block(bb1_digest, loop_digest, Felt::from_u8(7), join2_hash); + assert_eq!(join2_digest, join2_hash); + + // BB2: identical to BB1 -- should be memoized + let (bb2_addr, bb2_digest) = hasher.hash_basic_block(&batches, bb_hash); + assert_eq!(bb2_digest, bb_hash); + assert_ne!(bb1_addr, bb2_addr, "memoized BB2 should have a different address"); + + // Hash Join1 = hash(Join2, BB2) + let join1_state = + super::init_state_from_words_with_domain(&join2_digest, &bb2_digest, Felt::from_u8(7)); + let join1_permuted = apply_permutation(join1_state); + let join1_hash = get_digest(&join1_permuted); + let (_join1_addr, join1_digest) = + hasher.hash_control_block(join2_digest, bb2_digest, Felt::from_u8(7), join1_hash); + assert_eq!(join1_digest, join1_hash); + + let trace = build_trace(hasher); + + // Verify BB2's controller rows (the memoized copy) match BB1's original rows. + // BB1 is at rows 0..4 (2 batches = 2 pairs = 4 rows). + // Loop body is at rows 4..6 (1 batch = 1 pair = 2 rows). + // Join2 is at rows 6..8 (1 pair). + // BB2 (memoized) is at rows 8..12. + // Join1 is at rows 12..14. + let bb1_start = bb1_addr.as_canonical_u64() as usize - 1; + let bb2_start = bb2_addr.as_canonical_u64() as usize - 1; + check_memoized_trace(&trace, bb1_start..bb1_start + 4, bb2_start..bb2_start + 4); + + // Verify perm multiplicities: BB1's 2 perm states should each have multiplicity 2 + // (original from BB1 + memoized from BB2). The loop body's perm state and the two + // join perm states should each have multiplicity 1. + let controller_rows: usize = 14; // 4 + 2 + 2 + 4 + 2 + let controller_padded_len = controller_rows.next_multiple_of(HASH_CYCLE_LEN); + + // Count unique perm states: BB1 has 2 unique states (2 batches), loop body has 1, + // join2 has 1, join1 has 1 = 5 unique states total (unless some coincide, which is + // astronomically unlikely with random groups). + // BB2 is memoized so its 2 states are the same as BB1's. + // Total perm cycles: at most 5 (could be less if join states happen to match). + + // Verify that the perm segment has correct multiplicities + let perm_start = controller_padded_len; + let total_len = trace[0].len(); + let num_perm_cycles = (total_len - perm_start) / HASH_CYCLE_LEN; + + // We should have at least 5 perm cycles (2 from BB + 1 loop + 2 joins) + assert!(num_perm_cycles >= 5, "expected at least 5 perm cycles, got {num_perm_cycles}"); + + // Count how many perm cycles have multiplicity 2 vs 1 + let mut mult_2_count = 0; + let mut mult_1_count = 0; + for i in 0..num_perm_cycles { + let cycle_start = perm_start + i * HASH_CYCLE_LEN; + let mult = trace[NODE_INDEX_COL_IDX][cycle_start]; + if mult == Felt::from_u8(2) { + mult_2_count += 1; + } else if mult == ONE { + mult_1_count += 1; + } + } + + // BB1's 2 perm states should have multiplicity 2 (from BB1 + BB2 memoized) + assert_eq!(mult_2_count, 2, "expected 2 perm cycles with multiplicity 2 (BB1's states)"); + // The remaining states (loop body, join2, join1) should have multiplicity 1 + assert_eq!(mult_1_count, 3, "expected 3 perm cycles with multiplicity 1"); } // HELPER FUNCTIONS // ================================================================================================ -/// Builds an execution trace for the provided hasher. The trace must have the number of rows -/// specified by num_rows. -fn build_trace(hasher: Hasher, num_rows: usize) -> Vec> { - let mut trace = (0..TRACE_WIDTH).map(|_| vec![ZERO; num_rows]).collect::>(); +/// Builds the full hasher trace (controller + perm segment). +fn build_trace(hasher: Hasher) -> Vec> { + let trace_len = hasher.trace_len(); + let mut trace = (0..TRACE_WIDTH).map(|_| vec![ZERO; trace_len]).collect::>(); let mut fragment = TraceFragment::trace_to_fragment(&mut trace); hasher.fill_trace(&mut fragment); trace } -/// Makes sure that the provided trace is consistent with verifying the specified Merkle path -/// in the context defined by init_selectors. -fn check_merkle_path( +/// Checks a controller input row. +fn check_controller_input( trace: &[Vec], - row_idx: usize, - leaf: Digest, - path: &MerklePath, - node_index: u64, - init_selectors: Selectors, + row: usize, + selectors: Selectors, + state: &HasherState, + node_index: Felt, + is_boundary: Felt, + mrupdate_id: Felt, + direction_bit: Felt, ) { - // make sure selectors were set correctly - let mid_selectors = [ZERO, init_selectors[1], init_selectors[2]]; - check_selector_trace(trace, row_idx, init_selectors, init_selectors); - for i in 1..path.len() - 1 { - check_selector_trace(trace, row_idx + i * HASH_CYCLE_LEN, mid_selectors, init_selectors); - } - let last_perm_row_addr = row_idx + (path.len() - 1) * HASH_CYCLE_LEN; - check_selector_trace(trace, last_perm_row_addr, mid_selectors, RETURN_HASH); - - // make sure hasher states are correct - let mut root = leaf; - for (i, &node) in path.iter().enumerate() { - let index_bit = (node_index >> i) & 1; - let old_root = root; - let init_state = if index_bit == 0 { - root = hasher::merge(&[root, node]); - init_state_from_words(&old_root, &node) - } else { - root = hasher::merge(&[node, root]); - init_state_from_words(&node, &old_root) - }; - check_hasher_state_trace(trace, row_idx + i * HASH_CYCLE_LEN, init_state); - } - - // make sure node index is set correctly - let node_idx_column = trace.last().unwrap(); - assert_eq!(Felt::new(node_index), node_idx_column[row_idx]); - let mut node_index = node_index >> 1; - for i in 1..HASH_CYCLE_LEN { - assert_eq!(Felt::new(node_index), node_idx_column[row_idx + i]) + // Selectors + assert_eq!(trace[0][row], selectors[0], "s0 at row {row}"); + assert_eq!(trace[1][row], selectors[1], "s1 at row {row}"); + assert_eq!(trace[2][row], selectors[2], "s2 at row {row}"); + + // State + for (i, &val) in state.iter().enumerate() { + assert_eq!(trace[STATE_COL_RANGE.start + i][row], val, "state[{i}] at row {row}"); } - for i in 1..path.len() { - node_index >>= 1; - for j in 0..HASH_CYCLE_LEN { - assert_eq!(Felt::new(node_index), node_idx_column[row_idx + i * HASH_CYCLE_LEN + j]) - } - } + // Control columns + assert_eq!(trace[NODE_INDEX_COL_IDX][row], node_index, "node_index at row {row}"); + assert_eq!(trace[IS_BOUNDARY_COL_IDX][row], is_boundary, "is_boundary at row {row}"); + assert_eq!(trace[DIRECTION_BIT_COL_IDX][row], direction_bit, "direction_bit at row {row}"); + assert_eq!(trace[S_PERM_COL_IDX][row], ZERO, "s_perm should be 0 on controller row {row}"); + assert_eq!(trace[MRUPDATE_ID_COL_IDX][row], mrupdate_id, "mrupdate_id at row {row}"); } -/// Makes sure that selector columns (columns 0, 1, 2) are valid for a `HASH_CYCLE_LEN`-row cycle -/// starting with row_idx. -fn check_selector_trace( +/// Checks a controller output row. +fn check_controller_output( trace: &[Vec], - row_idx: usize, - init_selectors: Selectors, - final_selectors: Selectors, + row: usize, + selectors: Selectors, + state: &HasherState, + node_index: Felt, + is_boundary: Felt, + direction_bit: Felt, ) { - let trace = &trace[0..3]; - let mid_selectors = [ZERO, init_selectors[1], init_selectors[2]]; + assert_eq!(trace[0][row], selectors[0], "s0 at row {row}"); + assert_eq!(trace[1][row], selectors[1], "s1 at row {row}"); + assert_eq!(trace[2][row], selectors[2], "s2 at row {row}"); - assert_row_equal(trace, row_idx, &init_selectors); - for i in 0..NUM_ROUNDS - 1 { - assert_row_equal(trace, row_idx + i + 1, &mid_selectors); + for (i, &val) in state.iter().enumerate() { + assert_eq!(trace[STATE_COL_RANGE.start + i][row], val, "state[{i}] at row {row}"); } - assert_row_equal(trace, row_idx + NUM_ROUNDS, &final_selectors); + + assert_eq!(trace[NODE_INDEX_COL_IDX][row], node_index, "node_index at row {row}"); + assert_eq!(trace[IS_BOUNDARY_COL_IDX][row], is_boundary, "is_boundary at row {row}"); + assert_eq!(trace[DIRECTION_BIT_COL_IDX][row], direction_bit, "direction_bit at row {row}"); + assert_eq!(trace[S_PERM_COL_IDX][row], ZERO, "s_perm should be 0 on controller row {row}"); } -/// Makes sure hasher state columns (columns 4 through 15) are valid for a `HASH_CYCLE_LEN`-row -/// cycle starting with row_idx. -fn check_hasher_state_trace(trace: &[Vec], row_idx: usize, init_state: HasherState) { - let trace = &trace[STATE_COL_RANGE]; - let mut state = init_state; +/// Checks both the input and output rows of a Merkle controller pair. +/// +/// A Merkle pair consists of: +/// - Input row (`input_row`): has `input_selectors`, `node_index`, `is_boundary_input` flag. +/// - Output row (`input_row + 1`): has `node_index >> 1`, `is_boundary_output` flag. +/// +/// Both rows must have `s_perm=0` and the given `mrupdate_id`. +fn check_merkle_controller_pair( + trace: &[Vec], + input_row: usize, + input_selectors: Selectors, + node_index: u64, + is_boundary_input: bool, + is_boundary_output: bool, + mrupdate_id: Felt, + input_direction_bit: Felt, + output_direction_bit: Felt, +) { + let output_row = input_row + 1; + let is_boundary_input_felt = if is_boundary_input { ONE } else { ZERO }; + let is_boundary_output_felt = if is_boundary_output { ONE } else { ZERO }; + + // Input row: selectors, node_index, is_boundary, direction_bit, s_perm=0 + assert_eq!(trace[0][input_row], input_selectors[0], "s0 at input row {input_row}"); + assert_eq!(trace[1][input_row], input_selectors[1], "s1 at input row {input_row}"); + assert_eq!(trace[2][input_row], input_selectors[2], "s2 at input row {input_row}"); + assert_eq!( + trace[NODE_INDEX_COL_IDX][input_row], + Felt::new_unchecked(node_index), + "node_index at input row {input_row}" + ); + assert_eq!( + trace[IS_BOUNDARY_COL_IDX][input_row], is_boundary_input_felt, + "is_boundary at input row {input_row}" + ); + assert_eq!( + trace[DIRECTION_BIT_COL_IDX][input_row], input_direction_bit, + "direction_bit at input row {input_row}" + ); + assert_eq!(trace[S_PERM_COL_IDX][input_row], ZERO, "s_perm at input row {input_row}"); + assert_eq!( + trace[MRUPDATE_ID_COL_IDX][input_row], mrupdate_id, + "mrupdate_id at input row {input_row}" + ); - assert_row_equal(trace, row_idx, &state); - for i in 0..NUM_ROUNDS { - hasher::apply_round(&mut state, i); - assert_row_equal(trace, row_idx + i + 1, &state); - } + // Output row: node_index >> 1, is_boundary, direction_bit, s_perm=0 + assert_eq!( + trace[NODE_INDEX_COL_IDX][output_row], + Felt::new_unchecked(node_index >> 1), + "node_index at output row {output_row}" + ); + assert_eq!( + trace[IS_BOUNDARY_COL_IDX][output_row], is_boundary_output_felt, + "is_boundary at output row {output_row}" + ); + assert_eq!( + trace[DIRECTION_BIT_COL_IDX][output_row], output_direction_bit, + "direction_bit at output row {output_row}" + ); + assert_eq!(trace[S_PERM_COL_IDX][output_row], ZERO, "s_perm at output row {output_row}"); + assert_eq!( + trace[MRUPDATE_ID_COL_IDX][output_row], mrupdate_id, + "mrupdate_id at output row {output_row}" + ); } -fn check_memoized_trace( +/// Checks a 16-row permutation cycle in the perm segment. +/// +/// The packed schedule records the PRE-transition state on each row: +/// - Row 0: initial state +/// - Row 1: state after init+ext1 +/// - Rows 2-3: state after ext2, ext3 +/// - Row 4: state after ext4 +/// - Rows 5-10: state after each packed-internal triple +/// - Row 11: state after packed-internal triple 6 +/// - Row 12: state after int22+ext5 +/// - Rows 13-14: state after ext6, ext7 +/// - Row 15: state after ext8 (= final permutation output) +fn check_perm_segment( trace: &[Vec], start_row: usize, - end_row: usize, - copied_start_row: usize, - copied_end_row: usize, + init_state: &HasherState, + expected_multiplicity: Felt, ) { - // make sure the number of copied rows are equal as the original. - assert_eq!(end_row - start_row, copied_end_row - copied_start_row); + use miden_core::chiplets::hasher::Hasher; - // make sure selector trace is copied correctly - let selector_trace = &trace[0..NUM_SELECTORS]; - for column in selector_trace.iter() { - assert_eq!(column[start_row..end_row], column[copied_start_row..copied_end_row]) + let mut state = *init_state; + + // Row 0: initial state + for (i, &val) in state.iter().enumerate() { + assert_eq!( + trace[STATE_COL_RANGE.start + i][start_row], + val, + "state[{i}] at perm row 0 (row {start_row})" + ); + } + assert_eq!(trace[NODE_INDEX_COL_IDX][start_row], expected_multiplicity); + assert_eq!(trace[S_PERM_COL_IDX][start_row], ONE); + + // Apply init+ext1, check row 1 + Hasher::apply_matmul_external(&mut state); + Hasher::add_rc(&mut state, &Hasher::ARK_EXT_INITIAL[0]); + Hasher::apply_sbox(&mut state); + Hasher::apply_matmul_external(&mut state); + check_state_at_row(trace, start_row + 1, &state, "after init+ext1"); + + // Apply ext2-4, check rows 2-4 + for r in 1..=3 { + Hasher::add_rc(&mut state, &Hasher::ARK_EXT_INITIAL[r]); + Hasher::apply_sbox(&mut state); + Hasher::apply_matmul_external(&mut state); + check_state_at_row(trace, start_row + 1 + r, &state, &alloc::format!("after ext{}", r + 1)); + } + + // Apply 7 packed internal triples, check rows 5-11 + for triple in 0..7_usize { + let base = triple * 3; + for k in 0..3 { + state[0] += Hasher::ARK_INT[base + k]; + state[0] = state[0].exp_const_u64::<7>(); + Hasher::matmul_internal(&mut state, Hasher::MAT_DIAG); + } + check_state_at_row( + trace, + start_row + 5 + triple, + &state, + &alloc::format!("after int triple {triple}"), + ); } - // make sure hasher state trace is copied correctly - let hasher_state_trace = &trace[STATE_COL_RANGE]; - for column in hasher_state_trace.iter() { - assert_eq!(column[start_row..end_row], column[copied_start_row..copied_end_row]) + // Apply int22+ext5, check row 12 + state[0] += Hasher::ARK_INT[21]; + state[0] = state[0].exp_const_u64::<7>(); + Hasher::matmul_internal(&mut state, Hasher::MAT_DIAG); + Hasher::add_rc(&mut state, &Hasher::ARK_EXT_TERMINAL[0]); + Hasher::apply_sbox(&mut state); + Hasher::apply_matmul_external(&mut state); + check_state_at_row(trace, start_row + 12, &state, "after int22+ext5"); + + // Apply ext6-8, check rows 13-15 + for r in 1..=3 { + Hasher::add_rc(&mut state, &Hasher::ARK_EXT_TERMINAL[r]); + Hasher::apply_sbox(&mut state); + Hasher::apply_matmul_external(&mut state); + check_state_at_row( + trace, + start_row + 12 + r, + &state, + &alloc::format!("after ext{}", r + 5), + ); } } -/// Makes sure that a row in the provided trace is equal to the provided values at the specified -/// row index. -fn assert_row_equal(trace: &[Vec], row_idx: usize, values: &[Felt]) { - for (column, &value) in trace.iter().zip(values.iter()) { - assert_eq!(column[row_idx], value); +/// Helper to check the hasher state at a specific trace row. +fn check_state_at_row(trace: &[Vec], row: usize, state: &HasherState, label: &str) { + for (i, &val) in state.iter().enumerate() { + assert_eq!(trace[STATE_COL_RANGE.start + i][row], val, "state[{i}] at row {row} ({label})"); } } @@ -700,5 +765,115 @@ fn init_leaves(values: &[u64]) -> Vec { } fn init_leaf(value: u64) -> Digest { - [Felt::new(value), ZERO, ZERO, ZERO].into() + [Felt::new_unchecked(value), ZERO, ZERO, ZERO].into() +} + +/// Verifies that a memoized (copied) range of controller rows matches the original range. +/// +/// Checks selectors (s0, s1, s2), state columns (h0..h11), and node_index. +/// Does NOT check mrupdate_id (which is overwritten by the hasher on copy). +fn check_memoized_trace( + trace: &[Vec], + original: core::ops::Range, + copied: core::ops::Range, +) { + assert_eq!( + original.len(), + copied.len(), + "original and copied ranges must have the same length" + ); + + for (orig_row, copy_row) in original.zip(copied) { + // Selectors s0, s1, s2 + for col in 0..3 { + assert_eq!( + trace[col][orig_row], trace[col][copy_row], + "selector col {col} mismatch: original row {orig_row} vs copied row {copy_row}" + ); + } + + // State columns h0..h11 + for col in STATE_COL_RANGE { + assert_eq!( + trace[col][orig_row], trace[col][copy_row], + "state col {col} mismatch: original row {orig_row} vs copied row {copy_row}" + ); + } + + // node_index + assert_eq!( + trace[NODE_INDEX_COL_IDX][orig_row], trace[NODE_INDEX_COL_IDX][copy_row], + "node_index mismatch: original row {orig_row} vs copied row {copy_row}" + ); + + // is_boundary, direction_bit should also match + assert_eq!( + trace[IS_BOUNDARY_COL_IDX][orig_row], trace[IS_BOUNDARY_COL_IDX][copy_row], + "is_boundary mismatch: original row {orig_row} vs copied row {copy_row}" + ); + assert_eq!( + trace[DIRECTION_BIT_COL_IDX][orig_row], trace[DIRECTION_BIT_COL_IDX][copy_row], + "direction_bit mismatch: original row {orig_row} vs copied row {copy_row}" + ); + + // s_perm should be 0 on all controller rows + assert_eq!( + trace[S_PERM_COL_IDX][copy_row], ZERO, + "s_perm should be 0 on copied controller row {copy_row}" + ); + } +} + +/// Creates a BasicBlockNode from the given operations and returns its op_batches. +/// +/// This is a helper for tests that need `&[OpBatch]` without building a full MAST forest. +fn make_basic_block_batches(ops: Vec) -> Vec { + use miden_core::mast::BasicBlockNodeBuilder; + + let node = BasicBlockNodeBuilder::new(ops, Vec::new()) + .build() + .expect("failed to build basic block"); + node.op_batches().to_vec() +} + +/// Creates a single OpBatch with a distinct operation (Pad) for testing. +/// +/// Uses Pad instead of Noop to ensure the groups differ from those produced by `make_multi_batch`. +fn make_single_batch() -> Vec { + use miden_core::operations::Operation; + make_basic_block_batches(vec![Operation::Pad]) +} + +/// Creates exactly `n` OpBatch objects for testing multi-batch basic blocks. +/// +/// Uses Noop operations to fill batches. Each batch holds 8 groups * 9 ops = 72 ops. +/// To produce exactly `n` batches, we use 72*(n-1) + 1 operations. +fn make_multi_batch(n: usize) -> Vec { + use miden_core::operations::Operation; + assert!(n >= 2, "use make_single_batch for n=1"); + + // 72 ops fills exactly 1 batch. To get n batches, we need 72*(n-1) + 1 ops. + let num_ops = 72 * (n - 1) + 1; + let ops = vec![Operation::Noop; num_ops]; + + let batches = make_basic_block_batches(ops); + assert_eq!(batches.len(), n, "expected exactly {n} batches, got {}", batches.len()); + batches +} + +/// Computes the expected hash for a basic block given its op batches. +/// +/// Mirrors the logic in `Hasher::hash_basic_block` without recording a trace. +fn compute_basic_block_hash(batches: &[OpBatch]) -> Digest { + assert!(!batches.is_empty()); + + let mut state = init_state(batches[0].groups(), ZERO); + hasher::apply_permutation(&mut state); + + for batch in batches.iter().skip(1) { + absorb_into_state(&mut state, batch.groups()); + hasher::apply_permutation(&mut state); + } + + get_digest(&state) } diff --git a/processor/src/trace/chiplets/hasher/trace.rs b/processor/src/trace/chiplets/hasher/trace.rs index cf031a685a..a4706bf075 100644 --- a/processor/src/trace/chiplets/hasher/trace.rs +++ b/processor/src/trace/chiplets/hasher/trace.rs @@ -1,25 +1,38 @@ use alloc::vec::Vec; use core::ops::Range; -use miden_air::trace::chiplets::hasher::NUM_ROUNDS; -use miden_core::chiplets::hasher::apply_round; +use miden_air::trace::chiplets::hasher::{HASH_CYCLE_LEN, TRACE_WIDTH}; +use miden_core::chiplets::hasher::Hasher; -use super::{Felt, HasherState, STATE_WIDTH, Selectors, TRACE_WIDTH, TraceFragment, ZERO}; +use super::{Felt, HasherState, ONE, STATE_WIDTH, Selectors, TraceFragment, ZERO}; // HASHER TRACE // ================================================================================================ /// Execution trace of the hasher component. /// -/// The trace consists of 16 columns grouped logically as follows: -/// - 3 selector columns. -/// - 12 columns describing hasher state. -/// - 1 node index column used for Merkle path related computations. +/// The trace consists of 20 columns grouped logically as follows: +/// - 3 selector columns (s0, s1, s2). +/// - 12 columns describing hasher state (h0..h11). +/// - 1 node_index column: holds the Merkle tree node index on controller rows. This column is +/// reused to hold the permutation request multiplicity on perm segment rows. +/// - 1 mrupdate_id column (domain separator for sibling table). +/// - 1 is_boundary column (1 on boundary rows: first input or last output, 0 otherwise). +/// - 1 direction_bit column (Merkle direction bit on controller rows, 0 elsewhere). +/// - 1 s_perm column (0 = controller region, 1 = permutation segment). +/// +/// The trace is divided into two regions: +/// - Controller region (s_perm=0): pairs of (input, output) rows per permutation request. +/// - Permutation segment (s_perm=1): one 16-row cycle per unique input state. #[derive(Debug, Default)] pub struct HasherTrace { selectors: [Vec; 3], hasher_state: [Vec; STATE_WIDTH], node_index: Vec, + mrupdate_id: Vec, + is_boundary: Vec, + direction_bit: Vec, + s_perm: Vec, } impl HasherTrace { @@ -37,86 +50,195 @@ impl HasherTrace { /// ONE at every row. Starting at ONE is needed for the decoder so that the address of the /// first code block is a non-zero value. pub fn next_row_addr(&self) -> Felt { - Felt::new(self.trace_len() as u64 + 1) + Felt::new_unchecked(self.trace_len() as u64 + 1) } - // TRACE MUTATORS + // CONTROLLER ROW METHODS // -------------------------------------------------------------------------------------------- - /// Appends 32 rows to the execution trace describing a single permutation of the hash function. - /// - /// The initial state of the hasher is provided via the `state` parameter. All subsequent - /// states are derived by applying a single round of the hash function to the previous state. - /// - /// Selector values for the first and last rows are provided via `init_selectors` and - /// `final_selectors` parameters. Selector values for all other rows are derived from the - /// selectors of the first row. - /// - /// Node index values are provided via `init_index` and `rest_index` parameters. The former is - /// used for the first row, and the latter for all subsequent rows. - pub fn append_permutation_with_index( + /// Appends a single controller row to the trace. + pub fn append_controller_row( &mut self, - state: &mut HasherState, - init_selectors: Selectors, - final_selectors: Selectors, - init_index: Felt, - rest_index: Felt, + selectors: Selectors, + state: &HasherState, + node_index: Felt, + mrupdate_id: Felt, + is_boundary: Felt, + direction_bit: Felt, ) { - // append the first row of the permutation cycle - self.append_row(init_selectors, state, init_index); - - // append the next NUM_ROUNDS - 1 rows of the permutation cycle. for these rows: - // - the last two selectors are carried over from row to row; the first selector is set to - // ZERO. - // - hasher state is updated by applying a single round of the hash function for every row. - let next_selectors = [ZERO, init_selectors[1], init_selectors[2]]; - for i in 0..NUM_ROUNDS - 1 { - apply_round(state, i); - self.append_row(next_selectors, state, rest_index); + for (trace_col, selector_val) in self.selectors.iter_mut().zip(selectors) { + trace_col.push(selector_val); + } + for (trace_col, &state_val) in self.hasher_state.iter_mut().zip(state) { + trace_col.push(state_val); + } + self.node_index.push(node_index); + self.mrupdate_id.push(mrupdate_id); + self.is_boundary.push(is_boundary); + self.direction_bit.push(direction_bit); + self.s_perm.push(ZERO); + } + + // PERMUTATION SEGMENT METHODS + // -------------------------------------------------------------------------------------------- + + /// Appends a 16-row permutation cycle to the trace. + /// + /// The 16-row packed schedule: + /// - Row 0: init linear + ext1 (merged) + /// - Rows 1-3: ext2, ext3, ext4 + /// - Rows 4-10: 7 packed triples of internal rounds (needs extra witnesses in s0,s1,s2) + /// - Row 11: int22 + ext5 (merged, extra witness in s0) + /// - Rows 12-14: ext6, ext7, ext8 + /// - Row 15: boundary (final state, no transition) + /// + /// The `multiplicity` is stored in the node_index column on all rows of the cycle and constant + /// within a cycle. + pub fn append_permutation_cycle(&mut self, init_state: &HasherState, multiplicity: Felt) { + let mut state = *init_state; + + // Row 0: initial state + self.append_perm_row_with_witnesses(&state, multiplicity, [ZERO; 3]); + + // Apply init linear + ext1 (merged: M_E, add RC, S-box, M_E) + Hasher::apply_matmul_external(&mut state); + Hasher::add_rc(&mut state, &Hasher::ARK_EXT_INITIAL[0]); + Hasher::apply_sbox(&mut state); + Hasher::apply_matmul_external(&mut state); + + // Rows 1-3: ext2, ext3, ext4 + for r in 1..=3 { + self.append_perm_row_with_witnesses(&state, multiplicity, [ZERO; 3]); + Hasher::add_rc(&mut state, &Hasher::ARK_EXT_INITIAL[r]); + Hasher::apply_sbox(&mut state); + Hasher::apply_matmul_external(&mut state); + } + + // Rows 4-10: packed 3x internal rounds + for triple in 0..7_usize { + let base = triple * 3; + let pre_state = state; + let mut witnesses = [ZERO; 3]; + for (k, witness) in witnesses.iter_mut().enumerate() { + // Witness = S-box output for lane 0 + let sbox_out = (state[0] + Hasher::ARK_INT[base + k]).exp_const_u64::<7>(); + *witness = sbox_out; + state[0] = sbox_out; + Hasher::matmul_internal(&mut state, Hasher::MAT_DIAG); + } + self.append_perm_row_with_witnesses(&pre_state, multiplicity, witnesses); + } + + // Row 11: int22 + ext5 (merged) + let pre_state = state; + let w0 = (state[0] + Hasher::ARK_INT[21]).exp_const_u64::<7>(); + state[0] = w0; + Hasher::matmul_internal(&mut state, Hasher::MAT_DIAG); + Hasher::add_rc(&mut state, &Hasher::ARK_EXT_TERMINAL[0]); + Hasher::apply_sbox(&mut state); + Hasher::apply_matmul_external(&mut state); + self.append_perm_row_with_witnesses(&pre_state, multiplicity, [w0, ZERO, ZERO]); + + // Rows 12-14: ext6, ext7, ext8 + for r in 1..=3 { + self.append_perm_row_with_witnesses(&state, multiplicity, [ZERO; 3]); + Hasher::add_rc(&mut state, &Hasher::ARK_EXT_TERMINAL[r]); + Hasher::apply_sbox(&mut state); + Hasher::apply_matmul_external(&mut state); } - // apply the last round and append the last row to the trace - apply_round(state, NUM_ROUNDS - 1); - self.append_row(final_selectors, state, rest_index); + // Row 15: boundary (final state) + self.append_perm_row_with_witnesses(&state, multiplicity, [ZERO; 3]); } - /// Appends 32 rows to the execution trace describing a single permutation of the hash function. + /// Appends a single permutation segment row (s_perm = 1). /// - /// This function is similar to the append_permutation_with_index() function above, but it sets - /// init_index and rest_index parameters to ZEROs. - #[inline(always)] - pub fn append_permutation( + /// On permutation rows, `s0, s1, s2` serve as witness columns for packed internal + /// rounds. The `witnesses` array provides values to write into these columns. + /// Control columns (mrupdate_id, is_boundary, direction_bit) are zero. + fn append_perm_row_with_witnesses( &mut self, - state: &mut HasherState, - init_selectors: Selectors, - final_selectors: Selectors, + state: &HasherState, + multiplicity: Felt, + witnesses: [Felt; 3], ) { - self.append_permutation_with_index(state, init_selectors, final_selectors, ZERO, ZERO); + self.selectors[0].push(witnesses[0]); + self.selectors[1].push(witnesses[1]); + self.selectors[2].push(witnesses[2]); + for (trace_col, &state_val) in self.hasher_state.iter_mut().zip(state) { + trace_col.push(state_val); + } + self.node_index.push(multiplicity); + self.mrupdate_id.push(ZERO); + self.is_boundary.push(ZERO); + self.direction_bit.push(ZERO); + self.s_perm.push(ONE); } - /// Appends a new row to the execution trace based on the supplied parameters. - fn append_row(&mut self, selectors: Selectors, state: &HasherState, index: Felt) { - for (trace_col, selector_val) in self.selectors.iter_mut().zip(selectors) { - trace_col.push(selector_val); + /// Appends padding rows to fill the controller region to a multiple of HASH_CYCLE_LEN. + /// + /// Padding rows have all columns set to zero except mrupdate_id, which must carry the + /// last value to satisfy the AIR progression constraint (mrupdate_id is constant on + /// non-MV-start transitions). + pub fn pad_to_cycle_boundary(&mut self, mrupdate_id: Felt) { + // Padding selectors: [0, 1, 0]. This combination is unused in the controller region + // (s0=0, s1=1 only appears in perm segment rows which have s_perm=1). Using it + // prevents padding rows from being mistaken for HOUT output rows ([0,0,0]) by the + // bus response builder. + let padding_selectors = [ZERO, ONE, ZERO]; + + let remainder = self.trace_len() % HASH_CYCLE_LEN; + if remainder != 0 { + let padding_rows = HASH_CYCLE_LEN - remainder; + for _ in 0..padding_rows { + self.append_controller_row( + padding_selectors, + &[ZERO; STATE_WIDTH], + ZERO, + mrupdate_id, + ZERO, + ZERO, + ); + } } - for (trace_col, &state_val) in self.hasher_state.iter_mut().zip(state) { - trace_col.push(state_val); + } + + // MEMOIZATION SUPPORT + // -------------------------------------------------------------------------------------------- + + /// Collects input states from controller input rows in the given range. + /// + /// A controller input row is identified by s0 == ONE and s_perm == ZERO. + /// Returns the hasher state for each such row. + pub fn input_states_in_range(&self, range: Range) -> Vec { + let mut states = Vec::new(); + for row in range { + // Controller input row: s0 = ONE and s_perm = ZERO + if self.selectors[0][row] == ONE && self.s_perm[row] == ZERO { + let mut state = [ZERO; STATE_WIDTH]; + for (col, hasher) in self.hasher_state.iter().enumerate() { + state[col] = hasher[row]; + } + states.push(state); + } } - self.node_index.push(index); + states } - /// Copies section of trace from the given range of start and end rows at the end of the trace. - /// The hasher state of the last row is copied to the provided state input. + /// Copies a section of the controller trace from the given range to the end of the trace. + /// Updates the provided state with the hasher state from the last row of the copied range. pub fn copy_trace(&mut self, state: &mut [Felt; STATE_WIDTH], range: Range) { for selector in self.selectors.iter_mut() { selector.extend_from_within(range.clone()); } - for hasher in self.hasher_state.iter_mut() { hasher.extend_from_within(range.clone()); } - self.node_index.extend_from_within(range.clone()); + self.mrupdate_id.extend_from_within(range.clone()); + self.is_boundary.extend_from_within(range.clone()); + self.direction_bit.extend_from_within(range.clone()); + self.s_perm.extend_from_within(range.clone()); // copy the latest hasher state to the provided state slice for (col, hasher) in self.hasher_state.iter().enumerate() { @@ -124,24 +246,30 @@ impl HasherTrace { } } + /// Overwrites mrupdate_id values in the given range. + pub fn overwrite_mrupdate_id_in_range(&mut self, range: Range, mrupdate_id: Felt) { + for row in range { + self.mrupdate_id[row] = mrupdate_id; + } + } + // EXECUTION TRACE GENERATION // -------------------------------------------------------------------------------------------- /// Fills the provided trace fragment with trace data from this hasher trace instance. pub fn fill_trace(self, trace: &mut TraceFragment) { - // make sure fragment dimensions are consistent with the dimensions of this trace debug_assert_eq!(self.trace_len(), trace.len(), "inconsistent trace lengths"); debug_assert_eq!(TRACE_WIDTH, trace.width(), "inconsistent trace widths"); - // collect all trace columns into a single vector let mut columns = Vec::new(); self.selectors.into_iter().for_each(|c| columns.push(c)); - self.hasher_state.into_iter().for_each(|c| columns.push(c)); columns.push(self.node_index); + columns.push(self.mrupdate_id); + columns.push(self.is_boundary); + columns.push(self.direction_bit); + columns.push(self.s_perm); - // copy trace into the fragment column-by-column - // TODO: this can be parallelized to copy columns in multiple threads (#2163) for (out_column, column) in trace.columns().zip(columns) { out_column.copy_from_slice(&column); } diff --git a/processor/src/trace/chiplets/kernel_rom/mod.rs b/processor/src/trace/chiplets/kernel_rom/mod.rs index 7a9e30bebc..184ca8ece9 100644 --- a/processor/src/trace/chiplets/kernel_rom/mod.rs +++ b/processor/src/trace/chiplets/kernel_rom/mod.rs @@ -1,6 +1,6 @@ use alloc::collections::BTreeMap; -use miden_air::trace::{RowIndex, chiplets::kernel_rom::TRACE_WIDTH}; +use miden_air::trace::{RowIndex, chiplets::KERNEL_ROM_TRACE_WIDTH}; use miden_core::field::PrimeCharacteristicRing; use super::{Felt, Kernel, TraceFragment, Word as Digest}; @@ -19,27 +19,21 @@ type ProcHashBytes = [u8; 32]; /// Kernel ROM chiplet for the VM. /// -/// This component is responsible for validating that kernel calls requested by the executing -/// program are made against procedures which are contained within the specified kernel. It also -/// tacks all calls to kernel procedures and this info is used to construct an execution trace of -/// all kernel accesses. +/// Validates that every SYSCALL targets a procedure declared in the kernel, and produces +/// exactly one trace row per declared procedure carrying the row's CALL-side multiplicity. /// /// # Execution trace -/// The layout of the execution trace of kernel procedure accesses is shown below: /// -/// s_first h0 h1 h2 h3 -/// ├─────────┴────┴────┴────┴────┤ +/// m h0 h1 h2 h3 +/// ├────┴────┴────┴────┴────┤ /// -/// In the above, the meaning of columns is as follows: -/// - `s_first` indicates that this is the first occurrence of a new block of kernel procedure -/// hashes. It also acts as a flag within the block indicating whether the hash should be sent to -/// the virtual table or the bus. -/// - `h0` - `h3` columns contain roots of procedures in a given kernel. +/// - `m` is the number of SYSCALLs to this procedure (0 if declared but never called). It gates the +/// chiplet-side CALL add; the INIT add is always emitted with multiplicity 1. +/// - `h0..h3` is the procedure root digest. #[derive(Debug)] pub struct KernelRom { access_map: BTreeMap, kernel: Kernel, - trace_len: usize, } impl KernelRom { @@ -50,21 +44,23 @@ impl KernelRom { /// The kernel ROM is populated with all procedures from the provided kernel. For each /// procedure the access count is set to 0. pub fn new(kernel: Kernel) -> Self { - let trace_len = kernel.proc_hashes().len(); let mut access_map = BTreeMap::new(); for &proc_hash in kernel.proc_hashes() { access_map.insert(proc_hash.into(), ProcAccessInfo::new(proc_hash)); } - Self { access_map, kernel, trace_len } + Self { access_map, kernel } } // PUBLIC ACCESSORS // -------------------------------------------------------------------------------------------- /// Returns length of execution trace required to describe kernel ROM. - pub const fn trace_len(&self) -> usize { - self.trace_len + /// + /// Under the all-LogUp layout this is exactly the number of declared kernel procedures + /// (one row per proc, regardless of access count). + pub fn trace_len(&self) -> usize { + self.access_map.len() } // STATE MUTATORS @@ -81,7 +77,6 @@ impl KernelRom { .get_mut(&proc_hash_bytes) .ok_or(OperationError::SyscallTargetNotInKernel { proc_root })?; - self.trace_len += 1; access_info.num_accesses += 1; Ok(()) } @@ -90,22 +85,24 @@ impl KernelRom { // -------------------------------------------------------------------------------------------- /// Populates the provided execution trace fragment with execution trace of this kernel ROM. + /// + /// Emits one row per declared kernel procedure: column 0 is the CALL-label multiplicity + /// (= number of SYSCALLs to this proc), columns 1..5 are the procedure digest. pub fn fill_trace(self, trace: &mut TraceFragment) { - debug_assert_eq!(TRACE_WIDTH, trace.width(), "inconsistent trace fragment width"); + debug_assert_eq!( + KERNEL_ROM_TRACE_WIDTH, + trace.width(), + "inconsistent trace fragment width" + ); let mut row = RowIndex::from(0); for access_info in self.access_map.values() { - // Always write an entry for this procedure hash responding to the requests in the - // requests in the virtual table. The verifier makes those requests by initializing - // the bus with the set of procedure hashes included in the public inputs. - access_info.write_into_trace(trace, row, true); + let multiplicity = Felt::from_u64(access_info.num_accesses as u64); + trace.set(row, 0, multiplicity); + trace.set(row, 1, access_info.proc_hash[0]); + trace.set(row, 2, access_info.proc_hash[1]); + trace.set(row, 3, access_info.proc_hash[2]); + trace.set(row, 4, access_info.proc_hash[3]); row += 1_u32; - - // For every access made by the decoder/trace, include an entry in the chiplet bus - // responding to those requests. - for _ in 0..access_info.num_accesses { - access_info.write_into_trace(trace, row, false); - row += 1_u32; - } } } @@ -133,14 +130,4 @@ impl ProcAccessInfo { pub fn new(proc_hash: Digest) -> Self { Self { proc_hash, num_accesses: 0 } } - - /// Writes a single row into the provided trace fragment for this procedure access entry. - pub fn write_into_trace(&self, trace: &mut TraceFragment, row: RowIndex, is_first: bool) { - let s_first = Felt::from_bool(is_first); - trace.set(row, 0, s_first); - trace.set(row, 1, self.proc_hash[0]); - trace.set(row, 2, self.proc_hash[1]); - trace.set(row, 3, self.proc_hash[2]); - trace.set(row, 4, self.proc_hash[3]); - } } diff --git a/processor/src/trace/chiplets/kernel_rom/tests.rs b/processor/src/trace/chiplets/kernel_rom/tests.rs index f72aba36eb..00a77c8d9e 100644 --- a/processor/src/trace/chiplets/kernel_rom/tests.rs +++ b/processor/src/trace/chiplets/kernel_rom/tests.rs @@ -2,7 +2,7 @@ use alloc::vec::Vec; use miden_core::{WORD_SIZE, field::PrimeCharacteristicRing}; -use super::{Felt, Kernel, KernelRom, TRACE_WIDTH, TraceFragment}; +use super::{Felt, KERNEL_ROM_TRACE_WIDTH, Kernel, KernelRom, TraceFragment}; use crate::{ONE, ZERO}; // CONSTANTS @@ -28,110 +28,57 @@ fn kernel_rom_invalid_access() { #[test] fn kernel_rom_no_access() { + // Each declared procedure gets one row with multiplicity 0 when never called; the INIT + // side of the chiplets bus still matches the public-input-injected remove. let kernel = build_kernel(); let rom = KernelRom::new(kernel); let expected_trace_len = 2; assert_eq!(expected_trace_len, rom.trace_len()); - // generate trace let trace = build_trace(rom, expected_trace_len); - // the first row of the trace should correspond to the first procedure - let row = 0; - - assert_eq!(trace[0][row], ONE); // s0 - assert_eq!(trace[1][row], PROC1_HASH[0]); - assert_eq!(trace[2][row], PROC1_HASH[1]); - assert_eq!(trace[3][row], PROC1_HASH[2]); - assert_eq!(trace[4][row], PROC1_HASH[3]); - - // the second row of the trace should correspond to the second procedure - let row = 1; - - assert_eq!(trace[0][row], ONE); // s0 - assert_eq!(trace[1][row], PROC2_HASH[0]); - assert_eq!(trace[2][row], PROC2_HASH[1]); - assert_eq!(trace[3][row], PROC2_HASH[2]); - assert_eq!(trace[4][row], PROC2_HASH[3]); + assert_row(&trace, 0, ZERO, PROC1_HASH); + assert_row(&trace, 1, ZERO, PROC2_HASH); } #[test] -#[expect(clippy::needless_range_loop)] fn kernel_rom_with_access() { + // 5 accesses: 3 for proc1, 2 for proc2 -> multiplicities (3, 2). let kernel = build_kernel(); let mut rom = KernelRom::new(kernel); - // generate 5 access: 3 for proc1 and 2 for proc2 rom.access_proc(PROC1_HASH.into()).unwrap(); rom.access_proc(PROC2_HASH.into()).unwrap(); rom.access_proc(PROC1_HASH.into()).unwrap(); rom.access_proc(PROC1_HASH.into()).unwrap(); rom.access_proc(PROC2_HASH.into()).unwrap(); - let expected_trace_len = 7; + let expected_trace_len = 2; assert_eq!(expected_trace_len, rom.trace_len()); - // generate trace let trace = build_trace(rom, expected_trace_len); - // the first 5 rows of the trace should correspond to the first procedure - for row in 0..4 { - let s_first = row == 0; - - assert_eq!(trace[0][row], Felt::from_bool(s_first)); // s_first - assert_eq!(trace[1][row], PROC1_HASH[0]); - assert_eq!(trace[2][row], PROC1_HASH[1]); - assert_eq!(trace[3][row], PROC1_HASH[2]); - assert_eq!(trace[4][row], PROC1_HASH[3]); - } - - // the remaining 2 rows of the trace should correspond to the second procedure - for row in 4..7 { - let s_first = row == 4; - - assert_eq!(trace[0][row], Felt::from_bool(s_first)); // s_first - assert_eq!(trace[1][row], PROC2_HASH[0]); - assert_eq!(trace[2][row], PROC2_HASH[1]); - assert_eq!(trace[3][row], PROC2_HASH[2]); - assert_eq!(trace[4][row], PROC2_HASH[3]); - } + assert_row(&trace, 0, Felt::from_u64(3), PROC1_HASH); + assert_row(&trace, 1, Felt::from_u64(2), PROC2_HASH); } #[test] -#[expect(clippy::needless_range_loop)] fn kernel_rom_with_single_access() { + // Mixed: proc1 accessed twice, proc2 never -> multiplicities (2, 0). let kernel = build_kernel(); let mut rom = KernelRom::new(kernel); - // generate 2 access for proc1 rom.access_proc(PROC1_HASH.into()).unwrap(); rom.access_proc(PROC1_HASH.into()).unwrap(); - let expected_trace_len = 4; + let expected_trace_len = 2; assert_eq!(expected_trace_len, rom.trace_len()); - // generate trace let trace = build_trace(rom, expected_trace_len); - // the first 3 rows of the trace should correspond to the first procedure - for row in 0..3 { - let s_first = row == 0; - - assert_eq!(trace[0][row], Felt::from_bool(s_first)); // s_first - assert_eq!(trace[1][row], PROC1_HASH[0]); - assert_eq!(trace[2][row], PROC1_HASH[1]); - assert_eq!(trace[3][row], PROC1_HASH[2]); - assert_eq!(trace[4][row], PROC1_HASH[3]); - } - - // the last row of the trace should correspond to the second procedure - let row = 3; - assert_eq!(trace[0][row], Felt::from_bool(true)); // s_first - assert_eq!(trace[1][row], PROC2_HASH[0]); - assert_eq!(trace[2][row], PROC2_HASH[1]); - assert_eq!(trace[3][row], PROC2_HASH[2]); - assert_eq!(trace[4][row], PROC2_HASH[3]); + assert_row(&trace, 0, Felt::from_u64(2), PROC1_HASH); + assert_row(&trace, 1, ZERO, PROC2_HASH); } // HELPER FUNCTIONS @@ -145,9 +92,18 @@ fn build_kernel() -> Kernel { /// Builds a trace of the specified length and fills it with data from the provided KernelRom /// instance. fn build_trace(kernel_rom: KernelRom, num_rows: usize) -> Vec> { - let mut trace = (0..TRACE_WIDTH).map(|_| vec![ZERO; num_rows]).collect::>(); + let mut trace = (0..KERNEL_ROM_TRACE_WIDTH).map(|_| vec![ZERO; num_rows]).collect::>(); let mut fragment = TraceFragment::trace_to_fragment(&mut trace); kernel_rom.fill_trace(&mut fragment); trace } + +/// Asserts that row `row` carries the given multiplicity and procedure digest. +fn assert_row(trace: &[Vec], row: usize, multiplicity: Felt, digest: [Felt; WORD_SIZE]) { + assert_eq!(trace[0][row], multiplicity, "multiplicity mismatch at row {row}"); + assert_eq!(trace[1][row], digest[0], "digest[0] mismatch at row {row}"); + assert_eq!(trace[2][row], digest[1], "digest[1] mismatch at row {row}"); + assert_eq!(trace[3][row], digest[2], "digest[2] mismatch at row {row}"); + assert_eq!(trace[4][row], digest[3], "digest[3] mismatch at row {row}"); +} diff --git a/processor/src/trace/chiplets/memory/mod.rs b/processor/src/trace/chiplets/memory/mod.rs index ff2ef64266..95c8fe723c 100644 --- a/processor/src/trace/chiplets/memory/mod.rs +++ b/processor/src/trace/chiplets/memory/mod.rs @@ -7,7 +7,7 @@ use miden_air::trace::{ CLK_COL_IDX, CTX_COL_IDX, D_INV_COL_IDX, D0_COL_IDX, D1_COL_IDX, FLAG_SAME_CONTEXT_AND_WORD, IDX0_COL_IDX, IDX1_COL_IDX, IS_READ_COL_IDX, IS_WORD_ACCESS_COL_IDX, MEMORY_ACCESS_ELEMENT, MEMORY_ACCESS_WORD, MEMORY_READ, - MEMORY_WRITE, V_COL_RANGE, WORD_COL_IDX, + MEMORY_WRITE, V_COL_RANGE, WORD_ADDR_HI_COL_IDX, WORD_ADDR_LO_COL_IDX, WORD_COL_IDX, }, }; @@ -53,8 +53,8 @@ const INIT_MEM_VALUE: Word = EMPTY_WORD; /// ## Execution trace /// The layout of the memory access trace is shown below. /// -/// rw ew ctx word_addr idx0 idx1 clk v0 v1 v2 v3 d0 d1 d_inv f_scw -/// ├────┴────┴────┴───────────┴──────┴──────┴────┴────┴────┴────┴────┴────┴────┴───────┴───────┤ +/// rw ew ctx word_addr idx0 idx1 clk v0 v1 v2 v3 d0 d1 d_inv f_scw w0 w1 +/// ├────┴────┴────┴──────────┴─────┴──────┴────┴────┴────┴────┴────┴────┴────┴─────┴─────┴───┴─┤ /// /// In the above, the meaning of the columns is as follows: /// - `rw` is a selector column used to identify whether the memory operation is a read or a write @@ -82,13 +82,18 @@ const INIT_MEM_VALUE: Word = EMPTY_WORD; /// - When the context remains the same but the word changes, these columns contain (`new_word` /// - `old_word`). /// - When both the context and the word remain the same, these columns contain (`new_clk` - -/// `old_clk` - 1). +/// `old_clk`). /// - `d_inv` contains the inverse of the delta between two consecutive context IDs, words, or clock /// cycles computed as described above. It is the field inverse of `(d_1 * 2^16) + d_0` /// - `f_scw` is a flag indicating whether the context and the word of the current row are the same /// as in the next row. +/// - `w0` contains the lower 16 bits of the word index (`word_addr / 4`). +/// - `w1` contains the upper 16 bits of the word index (`word_addr / 4`). Together with range +/// checks on `w0`, `w1`, and `4 * w1`, these columns prove that memory addresses are valid 32-bit +/// values. /// -/// For the first row of the trace, values in `d0`, `d1`, and `d_inv` are set to zeros. +/// For the first row of the trace, `prev_clk` is initialized to `first_clk - 1`, so the delta is +/// `1`. As a result, `d0` is set to `1`, `d1` to `0`, and `d_inv` to `1`. #[derive(Debug, Default)] pub struct Memory { /// Memory segment traces sorted by their execution context ID. @@ -248,10 +253,10 @@ impl Memory { /// [RangeChecker] chiplet instance, along with their row in the finalized execution trace. pub fn append_range_checks(&self, memory_start_row: RowIndex, range: &mut RangeChecker) { // set the previous address and clock cycle to the first address and clock cycle of the - // trace; we also adjust the clock cycle so that delta value for the first row would end - // up being ZERO. if the trace is empty, return without any further processing. + // trace; we also adjust the clock cycle back by 1 so that the delta for the first row + // equals 1. if the trace is empty, return without any further processing. let (mut prev_ctx, mut prev_addr, mut prev_clk) = match self.get_first_row_info() { - Some((ctx, addr, clk)) => (ctx, addr, clk.as_canonical_u64() - 1), + Some((ctx, addr, clk)) => (ctx, addr, clk.as_canonical_u64().wrapping_sub(1)), None => return, }; @@ -271,12 +276,23 @@ impl Memory { } else if prev_addr != addr { u64::from(addr - prev_addr) } else { - clk - prev_clk + clk.wrapping_sub(prev_clk) }; let (delta_hi, delta_lo) = split_u32_into_u16(delta); range.add_range_checks(row, &[delta_lo, delta_hi]); + // word index decomposition range checks: prove addr is a valid 32-bit value + // by checking w0, w1, and 4*w1 are all in [0, 2^16). + // Since addr is u32 and word_index = addr/4, w1 = word_index >> 16 < 2^14, + // so 4*w1 < 2^16 and fits by definition in u16. + let word_index = addr / WORD_SIZE as u32; + let w0 = (word_index & 0xffff) as u16; + let w1 = (word_index >> 16) as u16; + range.add_value(w0); + range.add_value(w1); + range.add_value(w1 << 2); + // update values for the next iteration of the loop prev_ctx = ctx; prev_addr = addr; @@ -291,16 +307,16 @@ impl Memory { pub fn fill_trace(self, trace: &mut TraceFragment) { debug_assert_eq!(self.trace_len(), trace.len(), "inconsistent trace lengths"); - // set the pervious address and clock cycle to the first address and clock cycle of the - // trace; we also adjust the clock cycle so that delta value for the first row would end - // up being ZERO. if the trace is empty, return without any further processing. + // set the previous address and clock cycle to the first address and clock cycle of the + // trace; we also adjust the clock cycle back by 1 so that the delta for the first row + // equals 1. if the trace is empty, return without any further processing. let (mut prev_ctx, mut prev_addr, mut prev_clk) = match self.get_first_row_info() { Some((ctx, addr, clk)) => (Felt::from(ctx), Felt::from_u32(addr), clk - ONE), None => return, }; // iterate through addresses in ascending order, and write trace row for each memory access - // into the trace. we expect the trace to be 15 columns wide. + // into the trace. we expect the trace to be 17 columns wide. let mut row: RowIndex = 0.into(); for (ctx, segment) in self.trace { @@ -363,6 +379,13 @@ impl Memory { trace.set(row, FLAG_SAME_CONTEXT_AND_WORD, ZERO); }; + // decompose word address into 16-bit limbs of word index + let word_index = addr / WORD_SIZE as u32; + let w0 = (word_index & 0xffff) as u16; + let w1 = (word_index >> 16) as u16; + trace.set(row, WORD_ADDR_LO_COL_IDX, Felt::from_u16(w0)); + trace.set(row, WORD_ADDR_HI_COL_IDX, Felt::from_u16(w1)); + // update values for the next iteration of the loop prev_ctx = ctx; prev_addr = felt_addr; diff --git a/processor/src/trace/chiplets/memory/segment.rs b/processor/src/trace/chiplets/memory/segment.rs index 16e92b6394..50dd97218a 100644 --- a/processor/src/trace/chiplets/memory/segment.rs +++ b/processor/src/trace/chiplets/memory/segment.rs @@ -53,7 +53,7 @@ impl MemorySegmentTrace { let (word_addr, _) = addr_to_word_addr_and_idx(addr); match self.0.get(&word_addr) { - Some(addr_trace) => Ok(addr_trace.last().map(|access| access.word())), + Some(addr_trace) => Ok(addr_trace.last().map(MemorySegmentAccess::word)), None => Ok(None), } } diff --git a/processor/src/trace/chiplets/memory/tests.rs b/processor/src/trace/chiplets/memory/tests.rs index c936b43375..fc1fcc672c 100644 --- a/processor/src/trace/chiplets/memory/tests.rs +++ b/processor/src/trace/chiplets/memory/tests.rs @@ -12,10 +12,10 @@ use miden_core::{ONE, WORD_SIZE, Word, ZERO, assert_matches, field::Field}; use super::{ CLK_COL_IDX, CTX_COL_IDX, D_INV_COL_IDX, D0_COL_IDX, D1_COL_IDX, EMPTY_WORD, Felt, Memory, - TraceFragment, V_COL_RANGE, WORD_COL_IDX, + TraceFragment, V_COL_RANGE, WORD_ADDR_HI_COL_IDX, WORD_ADDR_LO_COL_IDX, WORD_COL_IDX, segment::{MemoryAccessType, MemoryOperation}, }; -use crate::{ContextId, MemoryAddress, MemoryError}; +use crate::{ContextId, MemoryAddress, MemoryError, trace::range::RangeChecker}; #[test] fn mem_init() { @@ -137,7 +137,7 @@ fn mem_write() { // write a value into address 2; clk = 2 let addr2 = 2_u32; - let value5 = Felt::new(5); + let value5 = Felt::new_unchecked(5); mem.write(ContextId::root(), Felt::from_u32(addr2), 2.into(), value5).unwrap(); assert_eq!(value5, mem.get_value(ContextId::root(), addr2).unwrap()); assert_eq!(1, mem.num_accessed_words()); @@ -145,7 +145,7 @@ fn mem_write() { // write a value into address 1; clk = 3 let addr1 = 1_u32; - let value7 = Felt::new(7); + let value7 = Felt::new_unchecked(7); mem.write(ContextId::root(), Felt::from_u32(addr1), 3.into(), value7).unwrap(); assert_eq!(value7, mem.get_value(ContextId::root(), addr1).unwrap()); assert_eq!(1, mem.num_accessed_words()); @@ -153,7 +153,7 @@ fn mem_write() { // write a value into address 3; clk = 4 let addr3 = 3_u32; - let value9 = Felt::new(9); + let value9 = Felt::new_unchecked(9); mem.write(ContextId::root(), Felt::from_u32(addr3), 4.into(), value9).unwrap(); assert_eq!(value9, mem.get_value(ContextId::root(), addr3).unwrap()); assert_eq!(1, mem.num_accessed_words()); @@ -455,6 +455,17 @@ fn mem_get_state_at() { assert_eq!(mem.get_state_at(3.into(), clk), vec![]); } +#[test] +fn append_range_checks_does_not_panic_when_first_access_clk_is_zero() { + let mut mem = Memory::default(); + mem.write(ContextId::root(), ZERO, 0.into(), ONE).unwrap(); + + let mut range_checker = RangeChecker::new(); + mem.append_range_checks(0.into(), &mut range_checker); + + assert!(range_checker.trace_len() > 0); +} + // HELPER STRUCT & FUNCTIONS // ================================================================================================ @@ -577,6 +588,12 @@ fn build_trace_row( row[FLAG_SAME_CONTEXT_AND_WORD] = ZERO; } + // Word index decomposition: word_addr / 4 + let word_addr: u32 = word.as_canonical_u64() as u32; + let word_index = word_addr / WORD_SIZE as u32; + row[WORD_ADDR_LO_COL_IDX] = Felt::from_u16((word_index & 0xffff) as u16); + row[WORD_ADDR_HI_COL_IDX] = Felt::from_u16((word_index >> 16) as u16); + row } diff --git a/processor/src/trace/chiplets/mod.rs b/processor/src/trace/chiplets/mod.rs index e45690918e..33218cb788 100644 --- a/processor/src/trace/chiplets/mod.rs +++ b/processor/src/trace/chiplets/mod.rs @@ -14,32 +14,25 @@ use bitwise::Bitwise; mod hasher; use hasher::Hasher; -#[cfg(test)] -pub(crate) use hasher::init_state_from_words; mod memory; use memory::Memory; mod ace; -use ace::AceHints; pub use ace::{Ace, CircuitEvaluation, MAX_NUM_ACE_WIRES, PTR_OFFSET_ELEM, PTR_OFFSET_WORD}; mod kernel_rom; use kernel_rom::KernelRom; -mod aux_trace; - -pub use aux_trace::AuxTraceBuilder; - #[cfg(test)] +#[allow(clippy::needless_range_loop)] mod tests; // TRACE // ================================================================================================ pub struct ChipletsTrace { - pub(crate) trace: [Vec; CHIPLETS_WIDTH], - pub(crate) aux_builder: AuxTraceBuilder, + pub(crate) trace: Vec, } // CHIPLETS MODULE OF HASHER, BITWISE, MEMORY, ACE, AND KERNEL ROM CHIPLETS @@ -49,99 +42,88 @@ pub struct ChipletsTrace { /// and kernel ROM chiplets and is responsible for building a final execution trace from their /// stacked execution traces and chiplet selectors. /// -/// The module's trace can be thought of as 6 stacked segments in the following form: +/// The module's trace can be thought of as 6 stacked segments in the following form. /// -/// * Hasher segment: contains the trace and selector for the hasher chiplet. This segment fills the -/// first rows of the trace up to the length of the hasher `trace_len`. -/// - column 0: selector column with values set to ZERO -/// - columns 1-16: execution trace of hash chiplet -/// - columns 17-20: unused columns padded with ZERO +/// The chiplet system uses two physical selector columns (`s_ctrl = column 0` and +/// `s_perm = column 20`) plus the virtual `s0 = 1 - (s_ctrl + s_perm)` to partition +/// rows into three top-level regions. Columns 1-4 (`s1..s4`) subdivide the `s0` region. /// -/// * Bitwise segment: contains the trace and selectors for the bitwise chiplet. This segment begins -/// at the end of the hasher segment and fills the next rows of the trace for the `trace_len` of -/// the bitwise chiplet. -/// - column 0: selector column with values set to ONE -/// - column 1: selector column with values set to ZERO +/// * Hasher segment: fills the first rows of the trace up to the hasher `trace_len`. Split into +/// controller (s_ctrl=1, s_perm=0) and permutation (s_ctrl=0, s_perm=1) sub-regions. +/// - column 0 (s_ctrl): 1 on controller rows, 0 on permutation rows +/// - columns 1-19: execution trace of hash chiplet +/// - column 20 (s_perm): 0 on controller rows, 1 on permutation rows +/// +/// * Bitwise segment: begins at the end of the hasher segment. +/// - column 0 (s_ctrl): ZERO +/// - column 1 (s1): ZERO /// - columns 2-14: execution trace of bitwise chiplet /// - columns 15-20: unused columns padded with ZERO /// -/// * Memory segment: contains the trace and selectors for the memory chiplet. This segment begins -/// at the end of the bitwise segment and fills the next rows of the trace for the `trace_len` of -/// the memory chiplet. -/// - column 0-1: selector columns with values set to ONE -/// - column 2: selector column with values set to ZERO -/// - columns 3-17: execution trace of memory chiplet -/// - columns 18-20: unused columns padded with ZERO +/// * Memory segment: begins at the end of the bitwise segment. +/// - column 0 (s_ctrl): ZERO +/// - column 1 (s1): ONE +/// - column 2 (s2): ZERO +/// - columns 3-19: execution trace of memory chiplet +/// - column 20: unused column padded with ZERO /// -/// * ACE segment: contains the trace and selectors for the arithmetic circuit evaluation chiplet. -/// This segment begins at the end of the memory segment and fills the next rows of the trace for -/// the `trace_len` of the ACE chiplet. -/// - column 0-2: selector columns with values set to ONE -/// - column 3: selector column with values set to ZERO +/// * ACE segment: begins at the end of the memory segment. +/// - column 0 (s_ctrl): ZERO +/// - column 1-2 (s1, s2): ONE +/// - column 3 (s3): ZERO /// - columns 4-20: execution trace of ACE chiplet /// -/// * Kernel ROM segment: contains the trace and selectors for the kernel ROM chiplet * This segment -/// begins at the end of the memory segment and fills the next rows of the trace for the -/// `trace_len` of the kernel ROM chiplet. -/// - column 0-3: selector columns with values set to ONE -/// - column 4: selector column with values set to ZERO +/// * Kernel ROM segment: begins at the end of the ACE segment. +/// - column 0 (s_ctrl): ZERO +/// - columns 1-3 (s1, s2, s3): ONE +/// - column 4 (s4): ZERO /// - columns 5-9: execution trace of kernel ROM chiplet -/// - columns 10-20: unused column padded with ZERO +/// - columns 10-20: unused columns padded with ZERO /// -/// * Padding segment: unused. This segment begins at the end of the kernel ROM segment and fills -/// the rest of the execution trace minus the number of random rows. When it finishes, the -/// execution trace should have exactly enough rows remaining for the specified number of random -/// rows. -/// - columns 0-4: selector columns with values set to ONE +/// * Padding segment: fills the rest of the trace. +/// - column 0 (s_ctrl): ZERO +/// - columns 1-4 (s1..s4): ONE /// - columns 5-20: unused columns padded with ZERO /// /// /// The following is a pictorial representation of the chiplet module: /// /// ```text -/// +---+--------------------------------------------------------------+------+ -/// | 0 | |------| -/// | . | Hash chiplet |------| -/// | . | 16 columns |------| -/// | . | constraint degree 8 |------| -/// | 0 | |------| -/// +---+---+------------------------------------------------------+---+------+ -/// | 1 | 0 | |----------| -/// | . | . | Bitwise chiplet |----------| -/// | . | . | 13 columns |----------| -/// | . | . | constraint degree 5 |----------| -/// | . | . | |----------| -/// | . | 0 | |----------| -/// | . +---+---+--------------------------------------------------+-----+----+ -/// | . | 1 | 0 | |----| -/// | . | . | . | Memory chiplet |----| -/// | . | . | . | 15 columns |----| -/// | . | . | . | constraint degree 9 |----| -/// | . | . | 0 | |----| -/// | . + . +---+---+----------------------------------------------------+----+ -/// | . | . | 1 | 0 | | -/// | . | . | . | . | ACE chiplet | -/// | . | . | . | . | 16 columns | -/// | . | . | . | . | constraint degree 5 | -/// | . | . | . | 0 | | -/// | . + . | . +---+---+---------------------------+-------------------------+ -/// | . | . | . | 1 | 0 | |-------------------------| -/// | . | . | . | . | . | Kernel ROM chiplet |-------------------------| -/// | . | . | . | . | . | 5 columns |-------------------------| -/// | . | . | . | . | . | constraint degree 9 |-------------------------| -/// | . | . | . | . | 0 | |-------------------------| -/// | . + . | . | . +---+---+-----------------------+-------------------------+ -/// | . | . | . | . | 1 | 0 |-------------------------------------------------| -/// | . | . | . | . | . | . |-------------------------------------------------| -/// | . | . | . | . | . | . |-------------------------------------------------| -/// | . | . | . | . | . | . |-------------------------------------------------| -/// | . | . | . | . | . | . |-------------------- Padding --------------------| -/// | . + . | . | . | . | . |-------------------------------------------------| -/// | . | . | . | . | . | . |-------------------------------------------------| -/// | . | . | . | . | . | . |-------------------------------------------------| -/// | . | . | . | . | . | . |-------------------------------------------------| -/// | 1 | 1 | 1 | 1 | 1 | 0 |-------------------------------------------------| -/// +---+---+---+---+---------------------------------------------------------+ +/// s_ctrl s1 s2 s3 s4 s_perm +/// [0] [1] [2] [3] [4] [20] +/// +---+----------------------------------------------------------+---+ +/// ctrl | 1 | Hash chiplet (controller rows) | 0 | +/// | . | 20 columns | . | +/// | 1 | constraint degree 9 | 0 | +/// +---+ +---+ +/// perm | 0 | Hash chiplet (permutation rows) | 1 | +/// | . | | . | +/// | 0 | | 1 | +/// +---+---+------------------------------------------------------+---+ +/// | 0 | 0 | |---| +/// | . | . | Bitwise chiplet |---| +/// | . | . | 13 columns |---| +/// | 0 | 0 | constraint degree 5 |---| +/// | . +---+---+--------------------------------------------------+---+ +/// | . | 1 | 0 | |---| +/// | . | . | . | Memory chiplet |---| +/// | . | . | . | 17 columns |---| +/// | . | . | 0 | constraint degree 9 |---| +/// | . + . +---+---+----------------------------------------------+---+ +/// | . | . | 1 | 0 | |---| +/// | . | . | . | . | ACE chiplet |---| +/// | . | . | . | . | 16 columns |---| +/// | . | . | . | 0 | constraint degree 5 |---| +/// | . + . | . +---+---+-------------------------+--------------------+ +/// | . | . | . | 1 | 0 | |--------------------| +/// | . | . | . | . | . | Kernel ROM chiplet |--------------------| +/// | . | . | . | . | . | 5 columns |--------------------| +/// | . | . | . | . | 0 | constraint degree 9 |--------------------| +/// | . + . | . | . +---+-------------------------+--------------------+ +/// | . | . | . | . | 1 |-------- Padding ---------| | +/// | . | . | . | . | . | | | +/// | 0 | 1 | 1 | 1 | 1 | | 0 | +/// +---+---+---+---+---+--------------------------+-------------------+ /// ``` #[derive(Debug)] pub struct Chiplets { @@ -226,12 +208,14 @@ impl Chiplets { .collect::>() .try_into() .expect("failed to convert vector to array"); - let ace_hint = self.fill_trace(&mut trace); + self.fill_trace(&mut trace); - ChipletsTrace { - trace, - aux_builder: AuxTraceBuilder::new(ace_hint), + let mut row_flat = Vec::with_capacity(CHIPLETS_WIDTH * trace_len); + for row_idx in 0..trace_len { + row_flat.extend(trace.iter().map(|column| column[row_idx])); } + + ChipletsTrace { trace: row_flat } } // HELPER METHODS @@ -241,9 +225,11 @@ impl Chiplets { /// Hasher, Bitwise, Memory, ACE, and kernel ROM chiplets along with selector columns /// to identify each individual chiplet trace in addition to padding to fill the rest of /// the trace. - fn fill_trace(self, trace: &mut [Vec; CHIPLETS_WIDTH]) -> AceHints { - // get the rows where:usize chiplets begin. - let bitwise_start: usize = self.bitwise_start().into(); + fn fill_trace(self, trace: &mut [Vec; CHIPLETS_WIDTH]) { + // s_ctrl (trace[0]) is 1 on the hasher's controller rows and 0 elsewhere. + // The controller region is the padded prefix of the hasher region; `region_lengths` + // returns the same padded length that `finalize_trace` will materialize later. + let (hasher_ctrl_len, _hasher_perm_len) = self.hasher.region_lengths(); let memory_start: usize = self.memory_start().into(); let ace_start: usize = self.ace_start().into(); let kernel_rom_start: usize = self.kernel_rom_start().into(); @@ -251,106 +237,104 @@ impl Chiplets { let Chiplets { hasher, bitwise, memory, kernel_rom, ace } = self; - // populate external selector columns for all chiplets - trace[0][bitwise_start..].fill(ONE); + // Populate external selector columns. Each is a contiguous 0/1 indicator; the trace + // is zero-initialized, so we only memset the regions where the selector is ONE. + // s_perm (trace[20]) is written row-by-row by the hasher itself during fragment fill. + trace[0][..hasher_ctrl_len].fill(ONE); // s_ctrl: hasher controller rows trace[1][memory_start..].fill(ONE); trace[2][ace_start..].fill(ONE); trace[3][kernel_rom_start..].fill(ONE); trace[4][padding_start..].fill(ONE); - // allocate fragments to be filled with the respective execution traces of each chiplet - let mut hasher_fragment = TraceFragment::new(CHIPLETS_WIDTH, hasher.trace_len()); - let mut bitwise_fragment = TraceFragment::new(CHIPLETS_WIDTH, bitwise.trace_len()); - let mut memory_fragment = TraceFragment::new(CHIPLETS_WIDTH, memory.trace_len()); - let mut ace_fragment = TraceFragment::new(CHIPLETS_WIDTH, ace.trace_len()); - let mut kernel_rom_fragment = TraceFragment::new(CHIPLETS_WIDTH, kernel_rom.trace_len()); - - // add the hasher, bitwise, memory, ACE, and kernel ROM segments to their respective - // fragments so they can be filled with the chiplet traces - for (column_num, column) in trace.iter_mut().enumerate().skip(1) { - match column_num { - 1 => { - // column 1 is relevant only for the hasher - hasher_fragment.push_column_slice(column); - }, - 2 => { - // column 2 is relevant to the hasher and to bitwise chiplet - let rest = hasher_fragment.push_column_slice(column); - bitwise_fragment.push_column_slice(rest); - }, - 3 => { - // column 3 is relevant for hasher, bitwise, and memory chiplets - let rest = hasher_fragment.push_column_slice(column); - let rest = bitwise_fragment.push_column_slice(rest); - memory_fragment.push_column_slice(rest); - }, - 4 | 10..=14 => { - // columns 4 - 10 to 14 are relevant for hasher, bitwise, memory chiplets and - // ace chiplet - let rest = hasher_fragment.push_column_slice(column); - let rest = bitwise_fragment.push_column_slice(rest); - let rest = memory_fragment.push_column_slice(rest); - ace_fragment.push_column_slice(rest); - }, - 5..=9 => { - // columns 5 - 9 are relevant to all chiplets - let rest = hasher_fragment.push_column_slice(column); - let rest = bitwise_fragment.push_column_slice(rest); - let rest = memory_fragment.push_column_slice(rest); - let rest = ace_fragment.push_column_slice(rest); - kernel_rom_fragment.push_column_slice(rest); - }, - 15 | 16 => { - // columns 15 and 16 are relevant only for the hasher, memory and ace chiplets - let rest = hasher_fragment.push_column_slice(column); - // skip bitwise chiplet - let (_, rest) = rest.split_at_mut(bitwise.trace_len()); - let rest = memory_fragment.push_column_slice(rest); - ace_fragment.push_column_slice(rest); - }, - 17 => { - // column 17 is relevant only for the memory chiplet - // skip the hasher and bitwise chiplets - let (_, rest) = column.split_at_mut(hasher.trace_len() + bitwise.trace_len()); - let rest = memory_fragment.push_column_slice(rest); - ace_fragment.push_column_slice(rest); - }, - 18 | 19 => { - // column 18 and 19 are relevant only for the ACE chiplet - // skip the hasher, bitwise and memory chiplets - let (_, rest) = column.split_at_mut( - hasher.trace_len() + bitwise.trace_len() + memory.trace_len(), - ); - ace_fragment.push_column_slice(rest); - }, - _ => panic!("invalid column index"), + // Fill chiplet traces via fragments. The block scopes the fragment borrows. + { + // allocate fragments to be filled with the respective execution traces of each chiplet + let mut hasher_fragment = TraceFragment::new(CHIPLETS_WIDTH, hasher.trace_len()); + let mut bitwise_fragment = TraceFragment::new(CHIPLETS_WIDTH, bitwise.trace_len()); + let mut memory_fragment = TraceFragment::new(CHIPLETS_WIDTH, memory.trace_len()); + let mut ace_fragment = TraceFragment::new(CHIPLETS_WIDTH, ace.trace_len()); + let mut kernel_rom_fragment = + TraceFragment::new(CHIPLETS_WIDTH, kernel_rom.trace_len()); + + // add the hasher, bitwise, memory, ACE, and kernel ROM segments to their respective + // fragments so they can be filled with the chiplet traces + for (column_num, column) in trace.iter_mut().enumerate().skip(1) { + match column_num { + 1 => { + // column 1 is relevant only for the hasher + hasher_fragment.push_column_slice(column); + }, + 2 => { + // column 2 is relevant to the hasher and to bitwise chiplet + let rest = hasher_fragment.push_column_slice(column); + bitwise_fragment.push_column_slice(rest); + }, + 3 => { + // column 3 is relevant for hasher, bitwise, and memory chiplets + let rest = hasher_fragment.push_column_slice(column); + let rest = bitwise_fragment.push_column_slice(rest); + memory_fragment.push_column_slice(rest); + }, + 4 | 10..=14 => { + // columns 4 - 10 to 14 are relevant for hasher, bitwise, memory chiplets + // and ace chiplet + let rest = hasher_fragment.push_column_slice(column); + let rest = bitwise_fragment.push_column_slice(rest); + let rest = memory_fragment.push_column_slice(rest); + ace_fragment.push_column_slice(rest); + }, + 5..=9 => { + // columns 5 - 9 are relevant to all chiplets + let rest = hasher_fragment.push_column_slice(column); + let rest = bitwise_fragment.push_column_slice(rest); + let rest = memory_fragment.push_column_slice(rest); + let rest = ace_fragment.push_column_slice(rest); + kernel_rom_fragment.push_column_slice(rest); + }, + 15 | 16 => { + // columns 15 and 16 are relevant for the hasher, memory and ace chiplets + let rest = hasher_fragment.push_column_slice(column); + // skip bitwise chiplet + let (_, rest) = rest.split_at_mut(bitwise.trace_len()); + let rest = memory_fragment.push_column_slice(rest); + ace_fragment.push_column_slice(rest); + }, + 17..=19 => { + // columns 17-19 are relevant for hasher, memory, and ace chiplets + // (hasher: mrupdate_id/is_start/is_final; memory: f_scw/w0/w1; ace cols) + let rest = hasher_fragment.push_column_slice(column); + // skip bitwise chiplet + let (_, rest) = rest.split_at_mut(bitwise.trace_len()); + let rest = memory_fragment.push_column_slice(rest); + ace_fragment.push_column_slice(rest); + }, + 20 => { + // column 20 is relevant only for the hasher chiplet (s_perm) + hasher_fragment.push_column_slice(column); + }, + _ => panic!("invalid column index"), + } } - } - // fill the fragments with the execution trace from each chiplet in parallel - // The chiplets are independent and can be processed concurrently - - // Fill independent chiplets in parallel: hasher, bitwise, memory, kernel_rom - // Note: ACE must be processed separately since it returns a value - // Use ThreadPool::install() to prevent nested parallelism from column operations - rayon::scope(|s| { - s.spawn(move |_| { - hasher.fill_trace(&mut hasher_fragment); - }); - s.spawn(move |_| { - bitwise.fill_trace(&mut bitwise_fragment); - }); - s.spawn(move |_| { - memory.fill_trace(&mut memory_fragment); + // Fill all chiplets in parallel. + rayon::scope(|s| { + s.spawn(move |_| { + hasher.fill_trace(&mut hasher_fragment); + }); + s.spawn(move |_| { + bitwise.fill_trace(&mut bitwise_fragment); + }); + s.spawn(move |_| { + memory.fill_trace(&mut memory_fragment); + }); + s.spawn(move |_| { + kernel_rom.fill_trace(&mut kernel_rom_fragment); + }); + s.spawn(move |_| { + ace.fill_trace(&mut ace_fragment); + }); }); - s.spawn(move |_| { - kernel_rom.fill_trace(&mut kernel_rom_fragment); - }); - }); - - // Process ACE chiplet separately as it returns ace_sections - let ace_sections = ace.fill_trace(&mut ace_fragment); - AceHints::new(ace_start, ace_sections) + } } } diff --git a/processor/src/trace/chiplets/tests.rs b/processor/src/trace/chiplets/tests.rs index fe1327c6f0..34740e62e4 100644 --- a/processor/src/trace/chiplets/tests.rs +++ b/processor/src/trace/chiplets/tests.rs @@ -3,16 +3,16 @@ use alloc::vec::Vec; use miden_air::trace::{ CHIPLETS_RANGE, CHIPLETS_WIDTH, chiplets::{ - NUM_BITWISE_SELECTORS, NUM_KERNEL_ROM_SELECTORS, NUM_MEMORY_SELECTORS, - bitwise::{BITWISE_XOR, OP_CYCLE_LEN, TRACE_WIDTH as BITWISE_TRACE_WIDTH}, - hasher::{HASH_CYCLE_LEN, LAST_CYCLE_ROW, LINEAR_HASH, RETURN_STATE}, - kernel_rom::TRACE_WIDTH as KERNEL_ROM_TRACE_WIDTH, - memory::TRACE_WIDTH as MEMORY_TRACE_WIDTH, + KERNEL_ROM_TRACE_WIDTH, NUM_BITWISE_SELECTORS, NUM_KERNEL_ROM_SELECTORS, + NUM_MEMORY_SELECTORS, + bitwise::{self, BITWISE_XOR, OP_CYCLE_LEN}, + hasher::{CONTROLLER_ROWS_PER_PERMUTATION, HASH_CYCLE_LEN, LINEAR_HASH, S_PERM_COL_IDX}, + memory, }, }; use miden_core::{ Felt, ONE, Word, ZERO, - mast::{BasicBlockNodeBuilder, MastForest, MastForestContributor}, + mast::{BasicBlockNodeBuilder, CallNodeBuilder, MastForest, MastForestContributor}, program::{Program, StackInputs}, }; @@ -22,130 +22,183 @@ use crate::{ type ChipletsTrace = [Vec; CHIPLETS_WIDTH]; +// HASHER TRACE LENGTH HELPERS +// ================================================================================================ + +/// Computes the total hasher trace length given the number of controller rows and unique +/// permutations. +/// +/// The controller region (including padding) is rounded up to the next multiple of +/// HASH_CYCLE_LEN, then the perm segment appends `unique_perms * HASH_CYCLE_LEN` rows. +fn hasher_trace_len(controller_rows: usize, unique_perms: usize) -> usize { + let controller_padded = controller_rows.next_multiple_of(HASH_CYCLE_LEN); + let perm_segment = unique_perms * HASH_CYCLE_LEN; + controller_padded + perm_segment +} + +// TESTS +// ================================================================================================ + #[test] fn hasher_chiplet_trace() { - // --- single hasher permutation with no stack manipulation ----------------------------------- + // --- single hasher permutation with no stack manipulation --- + // The program is a single basic block containing HPerm. + // This produces: + // - 1 span hash (LINEAR_HASH input + RETURN_HASH output) = 2 controller rows, 1 perm + // - 1 HPERM (RETURN_STATE input + RETURN_STATE output) = 2 controller rows, 1 perm + // Total: 4 controller rows padded to 16, 2 unique perms (32 perm rows) = 48 hasher rows. let stack = [2, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0]; let operations = vec![Operation::HPerm]; - let (chiplets_trace, trace_len) = build_trace(&stack, operations, Kernel::default()); + let (chiplets_trace, _trace_len) = build_trace(&stack, operations, Kernel::default()); - // Skip the hash of the span block generated while building the trace to check only the HPerm. - let hasher_start = HASH_CYCLE_LEN; - let hasher_end = hasher_start + HASH_CYCLE_LEN; - validate_hasher_trace(&chiplets_trace, hasher_start, hasher_end); + let controller_rows = 2 * CONTROLLER_ROWS_PER_PERMUTATION; // span hash + HPerm + let unique_perms = 2; + let hasher_len = hasher_trace_len(controller_rows, unique_perms); + assert_eq!(hasher_len, 48); - // Validate that the trace was padded correctly. - validate_padding(&chiplets_trace, hasher_end, trace_len); + validate_hasher_trace(&chiplets_trace, hasher_len, controller_rows, unique_perms); } #[test] fn bitwise_chiplet_trace() { - // --- single bitwise operation with no stack manipulation ------------------------------------ + // --- single bitwise operation with no stack manipulation --- + // This produces: 1 span hash (2 controller rows, 1 perm) = 32 hasher rows, then 8 bitwise. let stack = [4, 8]; let operations = vec![Operation::U32xor]; - let (chiplets_trace, trace_len) = build_trace(&stack, operations, Kernel::default()); + let (chiplets_trace, _trace_len) = build_trace(&stack, operations, Kernel::default()); - let bitwise_end = HASH_CYCLE_LEN + OP_CYCLE_LEN; - validate_bitwise_trace(&chiplets_trace, HASH_CYCLE_LEN, bitwise_end); + let controller_rows = CONTROLLER_ROWS_PER_PERMUTATION; // span hash only + let unique_perms = 1; + let hasher_len = hasher_trace_len(controller_rows, unique_perms); + assert_eq!(hasher_len, 32); - // Validate that the trace was padded correctly. - validate_padding(&chiplets_trace, bitwise_end, trace_len - 1); + let bitwise_start = hasher_len; + let bitwise_end = bitwise_start + OP_CYCLE_LEN; + validate_bitwise_trace(&chiplets_trace, bitwise_start, bitwise_end); } #[test] fn memory_chiplet_trace() { - // --- single memory operation with no stack manipulation ------------------------------------- + // --- single memory operation with no stack manipulation --- + // This produces: 1 span hash (32 hasher rows), then 1 memory row. let addr = Felt::from_u32(4); let stack = [1, 2, 3, 4]; let operations = vec![Operation::Push(addr), Operation::MStoreW]; - let (chiplets_trace, trace_len) = build_trace(&stack, operations, Kernel::default()); - let memory_trace_len = 1; + let (chiplets_trace, _trace_len) = build_trace(&stack, operations, Kernel::default()); - // Skip the hash cycle created by the span block when building the trace. - // Check the memory trace. - let memory_end = HASH_CYCLE_LEN + memory_trace_len; - validate_memory_trace(&chiplets_trace, HASH_CYCLE_LEN, memory_end); + let controller_rows = CONTROLLER_ROWS_PER_PERMUTATION; + let unique_perms = 1; + let hasher_len = hasher_trace_len(controller_rows, unique_perms); + assert_eq!(hasher_len, 32); - // Validate that the trace was padded correctly. - validate_padding(&chiplets_trace, memory_end, trace_len); + let memory_start = hasher_len; + validate_memory_trace(&chiplets_trace, memory_start, memory_start + 1); } #[test] fn stacked_chiplet_trace() { - // --- operations in hasher, bitwise, and memory processors without stack manipulation -------- + // --- operations in hasher, bitwise, and memory processors --- + // Operations: U32xor, Push(0), MStoreW, HPerm + // This produces: + // - 1 span hash (2 controller rows, 1 perm) for the basic block + // - 1 HPerm (2 controller rows, 1 perm) + // Total hasher: 4 controller rows padded to 16, 2 unique perms = 48 rows + // Then: 8 bitwise rows (U32xor), then 1 memory row (MStoreW) let stack = [8, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 1]; let ops = vec![Operation::U32xor, Operation::Push(ZERO), Operation::MStoreW, Operation::HPerm]; let kernel = build_kernel(); - let (chiplets_trace, trace_len) = build_trace(&stack, ops, kernel); - let memory_len = 1; - let ace_len = 0; - let kernel_rom_len = 2; - - // Skip the hash of the span block generated while building the trace to check only the HPerm. - let hasher_start = HASH_CYCLE_LEN; - let hasher_end = hasher_start + HASH_CYCLE_LEN; - validate_hasher_trace(&chiplets_trace, hasher_start, hasher_end); - - // Expect 1 operation cycle in the bitwise trace - let bitwise_end = hasher_end + OP_CYCLE_LEN; - validate_bitwise_trace(&chiplets_trace, hasher_end, bitwise_end); - - // expect 1 row of memory trace - let memory_end = bitwise_end + memory_len; - validate_memory_trace(&chiplets_trace, bitwise_end, memory_end); - - let ace_end = memory_end + ace_len; - let kernel_rom_end = memory_end + ace_len + kernel_rom_len; - validate_kernel_rom_trace(&chiplets_trace, ace_end, kernel_rom_end); - - // Validate that the trace was padded correctly. - validate_padding(&chiplets_trace, kernel_rom_end, trace_len); + let (chiplets_trace, _trace_len) = build_trace(&stack, ops, kernel); + + let controller_rows = 2 * CONTROLLER_ROWS_PER_PERMUTATION; // span hash + HPerm + let unique_perms = 2; + let hasher_len = hasher_trace_len(controller_rows, unique_perms); + assert_eq!(hasher_len, 48); + + // Validate hasher region + validate_hasher_trace(&chiplets_trace, hasher_len, controller_rows, unique_perms); + + // Bitwise starts right after hasher + let bitwise_start = hasher_len; + let bitwise_end = bitwise_start + OP_CYCLE_LEN; + validate_bitwise_trace(&chiplets_trace, bitwise_start, bitwise_end); + + // Memory starts right after bitwise + let memory_start = bitwise_end; + validate_memory_trace(&chiplets_trace, memory_start, memory_start + 1); + + // After memory comes kernel ROM (2 entries from build_kernel) then padding + let kernel_rom_start = memory_start + 1; + let kernel_rom_end = kernel_rom_start + 2; // 2 kernel procedures + validate_kernel_rom_trace(&chiplets_trace, kernel_rom_start, kernel_rom_end); + + // Padding fills the remainder + let padding_start = kernel_rom_end; + let trace_rows = chiplets_trace[0].len(); + validate_padding(&chiplets_trace, padding_start, trace_rows); +} + +#[test] +fn regression_trace_build_does_not_panic_when_first_memory_access_clk_is_zero() { + let processor = FastProcessor::new(StackInputs::default()); + let mut host = DefaultHost::default(); + + // A CALL entrypoint records the callee frame pointer write before the processor clock is + // incremented, so the first memory access is captured at clk = 0. + let program = { + let mut forest = MastForest::new(); + + let callee = BasicBlockNodeBuilder::new(vec![Operation::Noop], Vec::new()) + .add_to_forest(&mut forest) + .unwrap(); + forest.make_root(callee); + + let entry = CallNodeBuilder::new(callee).add_to_forest(&mut forest).unwrap(); + forest.make_root(entry); + + Program::with_kernel(forest.into(), entry, Kernel::default()) + }; + + let trace_inputs = processor.execute_trace_inputs_sync(&program, &mut host).unwrap(); + + let _trace = crate::trace::build_trace(trace_inputs).unwrap(); } // HELPER FUNCTIONS // ================================================================================================ -/// Creates a kernel with two dummy procedures fn build_kernel() -> Kernel { let proc_hash1 = Word::from([1_u32, 0, 1, 0]); let proc_hash2 = Word::from([1_u32, 1, 1, 1]); Kernel::new(&[proc_hash1, proc_hash2]).unwrap() } -/// Builds a sample trace by executing a span block containing the specified operations. This -/// results in 1 additional hash cycle (8 rows) at the beginning of the hash chiplet. fn build_trace( stack_inputs: &[u64], operations: Vec, kernel: Kernel, ) -> (ChipletsTrace, usize) { - let stack_inputs: Vec = stack_inputs.iter().map(|v| Felt::new(*v)).collect(); + let stack_inputs: Vec = stack_inputs.iter().map(|v| Felt::new_unchecked(*v)).collect(); let processor = FastProcessor::new_with_options( StackInputs::new(&stack_inputs).unwrap(), AdviceInputs::default(), ExecutionOptions::default().with_core_trace_fragment_size(1 << 10).unwrap(), - ); + ) + .expect("processor advice inputs should fit advice map limits"); let mut host = DefaultHost::default(); let program = { let mut mast_forest = MastForest::new(); - let basic_block_id = BasicBlockNodeBuilder::new(operations, Vec::new()) .add_to_forest(&mut mast_forest) .unwrap(); mast_forest.make_root(basic_block_id); - Program::with_kernel(mast_forest.into(), basic_block_id, kernel) }; - let (execution_output, trace_generation_context) = - processor.execute_for_trace_sync(&program, &mut host).unwrap(); - let trace = - crate::trace::build_trace(execution_output, trace_generation_context, program.to_info()) - .unwrap(); + let trace_inputs = processor.execute_trace_inputs_sync(&program, &mut host).unwrap(); + let trace = crate::trace::build_trace(trace_inputs).unwrap(); let trace_len = trace.get_trace_len(); - ( trace .get_column_range(CHIPLETS_RANGE) @@ -155,109 +208,213 @@ fn build_trace( ) } -/// Validate the hasher trace output by the hperm operation. The full hasher trace is tested in -/// the Hasher module, so this just tests the ChipletsTrace selectors and the initial columns -/// of the hasher trace. -#[expect(clippy::needless_range_loop)] -fn validate_hasher_trace(trace: &ChipletsTrace, start: usize, end: usize) { - // The selectors should match the hasher selectors - for row in start..end { - // The selectors should match the selectors for the hasher segment - assert_eq!(ZERO, trace[0][row]); - - match row % HASH_CYCLE_LEN { - 0 => { - // in the first row, the expected start of the trace should hold the initial - // selectors - assert_eq!(LINEAR_HASH, [trace[1][row], trace[2][row], trace[3][row]]); +// VALIDATION FUNCTIONS +// ================================================================================================ + +/// Validates the hasher region of the chiplets trace. +/// +/// Checks: +/// - s_ctrl (column 0) = 1 on controller rows, 0 on permutation rows +/// - s_perm (column 20) = 0 on controller rows, 1 on permutation rows +/// - Controller rows (s_perm=0): correct selectors for operation type, is_start/is_final flags +/// - Padding rows: selectors [0, 1, 0], non-selector columns are zero +/// - Perm segment rows (s_perm=1): selectors are zero (don't-care), s_perm=1 +fn validate_hasher_trace( + trace: &ChipletsTrace, + expected_len: usize, + controller_rows: usize, + unique_perms: usize, +) { + // Column indices within chiplets trace. + // Column 0 = s_ctrl, column 20 = s_perm. Hasher internal columns start at column 1. + let s0_col = 1; // hasher selector s0 + let s1_col = 2; // hasher selector s1 + let s2_col = 3; // hasher selector s2 + let s_perm_col = 1 + S_PERM_COL_IDX; // s_perm in chiplets trace (= column 20) + + let controller_padded = controller_rows.next_multiple_of(HASH_CYCLE_LEN); + let perm_segment_start = controller_padded; + let perm_segment_len = unique_perms * HASH_CYCLE_LEN; + + assert_eq!(expected_len, controller_padded + perm_segment_len); + + // --- Check s_ctrl and s_perm for all hasher rows --- + // Controller rows (including padding): s_ctrl=1, s_perm=0 + for row in 0..controller_padded { + assert_eq!(trace[0][row], ONE, "s_ctrl should be 1 for controller row {row}"); + assert_eq!(trace[s_perm_col][row], ZERO, "s_perm should be 0 for controller row {row}"); + } + // Permutation rows: s_ctrl=0, s_perm=1 + for row in perm_segment_start..expected_len { + assert_eq!(trace[0][row], ZERO, "s_ctrl should be 0 for perm row {row}"); + assert_eq!(trace[s_perm_col][row], ONE, "s_perm should be 1 for perm row {row}"); + } + + // --- Check controller rows (s_perm = 0) --- + // Controller rows come in pairs: input row (is_start varies) + output row (is_final varies). + // For a span hash: input has LINEAR_HASH selectors, output has RETURN_HASH selectors. + // For HPerm: input has LINEAR_HASH selectors, output has RETURN_STATE selectors. + for row in 0..controller_rows { + let is_input_row = row % CONTROLLER_ROWS_PER_PERMUTATION == 0; + if is_input_row { + // Input rows have s0=1 (LINEAR_HASH[0]) + assert_eq!( + trace[s0_col][row], LINEAR_HASH[0], + "controller input row {row}: s0 should be {} (LINEAR_HASH)", + LINEAR_HASH[0] + ); + } else { + // Output rows have s0=0 (RETURN_HASH or RETURN_STATE) + assert_eq!( + trace[s0_col][row], ZERO, + "controller output row {row}: s0 should be 0 (RETURN_*)" + ); + } + } + + // --- Check padding rows --- + // Padding rows fill from controller_rows to controller_padded. + // Padding selectors are [0, 1, 0] (matching PERM_STEP pattern but in controller region). + let padding_start = controller_rows; + for row in padding_start..controller_padded { + // Padding selectors: s0=0, s1=1, s2=0 + assert_eq!(trace[s0_col][row], ZERO, "padding row {row}: s0 should be 0"); + assert_eq!(trace[s1_col][row], ONE, "padding row {row}: s1 should be 1"); + assert_eq!(trace[s2_col][row], ZERO, "padding row {row}: s2 should be 0"); + + // Non-selector hasher columns should be zero on padding rows. + // Hasher state columns (indices 4..16 in chiplets trace = hasher cols 3..15) + for col in 4..=CHIPLETS_WIDTH - 1 { + assert_eq!(trace[col][row], ZERO, "padding row {row}, col {col} should be zero"); + } + } + + // --- Check perm segment rows (s_perm = 1) --- + for row in perm_segment_start..expected_len { + // On perm rows, s0/s1/s2 serve as witness columns for packed internal rounds. + // They are zero on external/boundary rows (offsets 0-3, 12-15 within each cycle), + // and hold S-box witnesses on packed-internal rows (offsets 4-10) and the int+ext + // row (offset 11, s0 only). + let offset_in_cycle = (row - perm_segment_start) % HASH_CYCLE_LEN; + match offset_in_cycle { + 0..=3 | 12..=15 => { + assert_eq!(trace[s0_col][row], ZERO, "perm row {row}: s0 should be 0"); + assert_eq!(trace[s1_col][row], ZERO, "perm row {row}: s1 should be 0"); + assert_eq!(trace[s2_col][row], ZERO, "perm row {row}: s2 should be 0"); }, - r if r == LAST_CYCLE_ROW => { - // in the last row, the expected start of the trace should hold the final selectors - assert_eq!(RETURN_STATE, [trace[1][row], trace[2][row], trace[3][row]]); + 4..=10 => { + // Packed internal: all 3 witnesses may be nonzero (no assertion on value) }, - _ => { - // in the other rows, the expected start of the trace should hold the mid selectors - assert_eq!( - [ZERO, LINEAR_HASH[1], LINEAR_HASH[2]], - [trace[1][row], trace[2][row], trace[3][row]] - ); + 11 => { + // Int+ext: s0 holds witness, s1 and s2 are zero + assert_eq!(trace[s1_col][row], ZERO, "perm row {row}: s1 should be 0"); + assert_eq!(trace[s2_col][row], ZERO, "perm row {row}: s2 should be 0"); }, + _ => unreachable!(), } } } -/// Validate the bitwise trace output by the u32xor operation. The full bitwise trace is tested in -/// the Bitwise module, so this just tests the ChipletsTrace selectors, the initial columns -/// of the bitwise trace, and the final columns after the bitwise trace. +/// Validates the bitwise region of the chiplets trace. +/// +/// Checks: +/// - Chiplet selectors: s_ctrl=0, s1=0, s_perm=0 +/// - Bitwise operation selector = XOR +/// - Columns beyond bitwise trace width + selectors are zero fn validate_bitwise_trace(trace: &ChipletsTrace, start: usize, end: usize) { - // The selectors should match the bitwise selectors - for row in start..end { - // The selectors should match the selectors for the bitwise segment - assert_eq!(ONE, trace[0][row]); - assert_eq!(ZERO, trace[1][row]); - - // the expected start of the bitwise trace should hold the expected bitwise op selectors - assert_eq!(BITWISE_XOR, trace[2][row]); + // Bitwise uses NUM_BITWISE_SELECTORS (2) chiplet selector columns + bitwise::TRACE_WIDTH (13) + // internal columns = 15 columns total. Columns 15..CHIPLETS_WIDTH should be zero. + let bitwise_used_cols = NUM_BITWISE_SELECTORS + bitwise::TRACE_WIDTH; - // the final columns should be padded - for column in trace.iter().skip(BITWISE_TRACE_WIDTH + NUM_BITWISE_SELECTORS) { - assert_eq!(ZERO, column[row]); + for row in start..end { + // Chiplet selectors: s_ctrl=0, s1=0 (active via virtual s0 * !s1) + assert_eq!(ZERO, trace[0][row], "bitwise s_ctrl at row {row}"); + assert_eq!(ZERO, trace[1][row], "bitwise s1 at row {row}"); + + // Internal bitwise operation selector (XOR) + assert_eq!(BITWISE_XOR, trace[NUM_BITWISE_SELECTORS][row], "bitwise op at row {row}"); + + // Columns beyond bitwise trace should be zero + for col in bitwise_used_cols..CHIPLETS_WIDTH { + assert_eq!( + trace[col][row], ZERO, + "bitwise padding col {col} at row {row} should be zero" + ); } } } -/// Validate the bitwise trace output by the storew operation. The full memory trace is tested in -/// the Memory module, so this just tests the ChipletsTrace selectors and the final columns after -/// the memory trace. +/// Validates the memory region of the chiplets trace. +/// +/// Checks: +/// - Chiplet selectors: s_ctrl=0, s1=1, s2=0, s_perm=0 +/// - Column beyond memory trace width + selectors is zero fn validate_memory_trace(trace: &ChipletsTrace, start: usize, end: usize) { + // Memory uses NUM_MEMORY_SELECTORS (3) chiplet selector columns + memory::TRACE_WIDTH (17) + // internal columns = 20 columns total. Column 20 should be zero. + let memory_used_cols = NUM_MEMORY_SELECTORS + memory::TRACE_WIDTH; + for row in start..end { - // The selectors should match the memory selectors - assert_eq!(ONE, trace[0][row]); - assert_eq!(ONE, trace[1][row]); - assert_eq!(ZERO, trace[2][row]); - - // the final columns should be padded - for column in trace.iter().skip(MEMORY_TRACE_WIDTH + NUM_MEMORY_SELECTORS) { - assert_eq!(ZERO, column[row]); + // Chiplet selectors: s_ctrl=0, s1=1, s2=0 (active via virtual s0 * s1 * !s2) + assert_eq!(ZERO, trace[0][row], "memory s_ctrl at row {row}"); + assert_eq!(ONE, trace[1][row], "memory s1 at row {row}"); + assert_eq!(ZERO, trace[2][row], "memory s2 at row {row}"); + + // Columns beyond memory trace should be zero + for col in memory_used_cols..CHIPLETS_WIDTH { + assert_eq!( + trace[col][row], ZERO, + "memory padding col {col} at row {row} should be zero" + ); } } } -/// Validate the kernel ROM trace output for a kernel with two procedures and no access calls. The -/// full kernel ROM trace is tested in the KernelRom module, so this just tests the ChipletsTrace -/// selectors, the first column of the trace, and the final columns after the kernel ROM trace. +/// Validates the kernel ROM region of the chiplets trace. +/// +/// Checks: +/// - Chiplet selectors: s_ctrl=0, s1=1, s2=1, s3=1, s4=0, s_perm=0 +/// - Columns beyond kernel ROM trace width + selectors are zero fn validate_kernel_rom_trace(trace: &ChipletsTrace, start: usize, end: usize) { + // Kernel ROM uses NUM_KERNEL_ROM_SELECTORS (5) chiplet selector columns + + // KERNEL_ROM_TRACE_WIDTH (5) internal columns = 10 columns total. + let kernel_rom_used_cols = NUM_KERNEL_ROM_SELECTORS + KERNEL_ROM_TRACE_WIDTH; + for row in start..end { - // The selectors should match the kernel selectors - assert_eq!(ONE, trace[0][row]); - assert_eq!(ONE, trace[1][row]); - assert_eq!(ONE, trace[2][row]); - assert_eq!(ONE, trace[3][row]); - - // the s0 column of kernel ROM must be set to ZERO as there were no kernel accesses - assert_eq!(ZERO, trace[4][row]); - - // the final columns should be padded - for column in trace.iter().skip(KERNEL_ROM_TRACE_WIDTH + NUM_KERNEL_ROM_SELECTORS) { - assert_eq!(ZERO, column[row]); + // Chiplet selectors: s_ctrl=0, s1=1, s2=1, s3=1, s4=0 + // (active via virtual s0 * s1 * s2 * s3 * !s4) + assert_eq!(ZERO, trace[0][row], "kernel_rom s_ctrl at row {row}"); + assert_eq!(ONE, trace[1][row], "kernel_rom s1 at row {row}"); + assert_eq!(ONE, trace[2][row], "kernel_rom s2 at row {row}"); + assert_eq!(ONE, trace[3][row], "kernel_rom s3 at row {row}"); + assert_eq!(ZERO, trace[4][row], "kernel_rom s4 at row {row}"); + + // Columns beyond kernel ROM trace should be zero + for col in kernel_rom_used_cols..CHIPLETS_WIDTH { + assert_eq!( + trace[col][row], ZERO, + "kernel_rom padding col {col} at row {row} should be zero" + ); } } } -/// Checks that the final section of the chiplets module's trace after the kernel ROM chiplet is -/// padded and has the correct selectors. +/// Validates the padding region at the end of the chiplets trace. +/// +/// Checks: +/// - s_ctrl (column 0) = 0, s1..s4 (columns 1-4) = 1, s_perm (column 20) = 0 +/// - All remaining columns (5..CHIPLETS_WIDTH) are zero fn validate_padding(trace: &ChipletsTrace, start: usize, end: usize) { for row in start..end { - // selectors - assert_eq!(ONE, trace[0][row]); - assert_eq!(ONE, trace[1][row]); - assert_eq!(ONE, trace[2][row]); - assert_eq!(ONE, trace[3][row]); - assert_eq!(ONE, trace[4][row]); - - // padding - trace.iter().skip(5).for_each(|column| { - assert_eq!(ZERO, column[row]); - }); + // s_ctrl = 0 on padding rows + assert_eq!(ZERO, trace[0][row], "padding s_ctrl at row {row}"); + // s1..s4 = 1 on padding rows + for col in 1..5 { + assert_eq!(ONE, trace[col][row], "padding s{col} at row {row}"); + } + // All non-selector columns should be zero (including s_perm at column 20) + for col in 5..CHIPLETS_WIDTH { + assert_eq!(ZERO, trace[col][row], "padding data col {col} at row {row} should be zero"); + } } } diff --git a/processor/src/trace/decoder/aux_trace/block_hash_table.rs b/processor/src/trace/decoder/aux_trace/block_hash_table.rs deleted file mode 100644 index 523f7ebbc8..0000000000 --- a/processor/src/trace/decoder/aux_trace/block_hash_table.rs +++ /dev/null @@ -1,268 +0,0 @@ -use miden_air::trace::{Challenges, RowIndex}; -use miden_core::{Word, ZERO, field::ExtensionField, operations::opcodes}; - -use super::{AuxColumnBuilder, Felt, MainTrace, ONE}; -use crate::debug::BusDebugger; - -// BLOCK HASH TABLE COLUMN BUILDER -// ================================================================================================ - -/// Builds the execution trace of the decoder's `p2` column which describes the state of the block -/// hash table via multiset checks. -/// -/// At any point in time, the block hash table contains the hashes of the blocks whose parents have -/// been visited, and that remain to be executed. For example, when we encounter the beginning of a -/// JOIN block, we add both children to the table, since both will be executed at some point in the -/// future. However, when we encounter the beginning of a SPLIT block, we only push the left or the -/// right child, depending on the current value on the stack (since only one child gets executed in -/// a SPLIT block). When we encounter an `END` operation, we remove the block from the table that -/// corresponds to the block that just ended. The root block's hash is checked via -/// `reduced_aux_values`, since it doesn't have a parent and would never be added to the table -/// otherwise. -#[derive(Default)] -pub struct BlockHashTableColumnBuilder {} - -impl> AuxColumnBuilder for BlockHashTableColumnBuilder { - /// Removes a row from the block hash table. - fn get_requests_at( - &self, - main_trace: &MainTrace, - challenges: &Challenges, - row: RowIndex, - _debugger: &mut BusDebugger, - ) -> E { - let op_code = main_trace.get_op_code(row).as_canonical_u64() as u8; - - match op_code { - opcodes::END => BlockHashTableRow::from_end(main_trace, row).collapse(challenges), - _ => E::ONE, - } - } - - /// Adds a row to the block hash table. - fn get_responses_at( - &self, - main_trace: &MainTrace, - challenges: &Challenges, - row: RowIndex, - _debugger: &mut BusDebugger, - ) -> E { - let op_code = main_trace.get_op_code(row).as_canonical_u64() as u8; - - match op_code { - opcodes::JOIN => { - let left_child_row = BlockHashTableRow::from_join(main_trace, row, true); - let right_child_row = BlockHashTableRow::from_join(main_trace, row, false); - - left_child_row.collapse(challenges) * right_child_row.collapse(challenges) - }, - opcodes::SPLIT => BlockHashTableRow::from_split(main_trace, row).collapse(challenges), - opcodes::LOOP => BlockHashTableRow::from_loop(main_trace, row) - .map(|row| row.collapse(challenges)) - .unwrap_or(E::ONE), - opcodes::REPEAT => BlockHashTableRow::from_repeat(main_trace, row).collapse(challenges), - opcodes::DYN | opcodes::DYNCALL | opcodes::CALL | opcodes::SYSCALL => { - BlockHashTableRow::from_dyn_dyncall_call_syscall(main_trace, row) - .collapse(challenges) - }, - _ => E::ONE, - } - } - - #[cfg(any(test, feature = "bus-debugger"))] - fn enforce_bus_balance(&self) -> bool { - // The block hash table's final value encodes the program hash boundary term, - // which is checked via reduced_aux_values. It does not balance to identity. - false - } -} - -// BLOCK HASH TABLE ROW -// ================================================================================================ - -/// Describes a single entry in the block hash table. An entry in the block hash table is a tuple -/// (parent_id, block_hash, is_first_child, is_loop_body), where each column is defined as follows: -/// - parent_block_id: contains the ID of the current block. Note: the current block's ID is the -/// parent block's ID from the perspective of the block being added to the table. -/// - block_hash: these 4 columns hold the hash of the current block's child which will be executed -/// at some point in time in the future. -/// - is_first_child: set to true if the table row being added represents the first child of the -/// current block. If the current block has only one child, set to false. -/// - is_loop_body: Set to true when the current block block is a LOOP code block (and hence, the -/// current block's child being added to the table is the body of a loop). -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct BlockHashTableRow { - parent_block_id: Felt, - child_block_hash: Word, - is_first_child: bool, - is_loop_body: bool, -} - -impl BlockHashTableRow { - // CONSTRUCTORS - // ---------------------------------------------------------------------------------------------- - - /// Computes the row to be removed from the block hash table when encountering an `END` - /// operation. - pub fn from_end(main_trace: &MainTrace, row: RowIndex) -> Self { - let op_code_next = main_trace.get_op_code(row + 1).as_canonical_u64() as u8; - let parent_block_id = main_trace.addr(row + 1); - let child_block_hash = main_trace.decoder_hasher_state_first_half(row); - - // A block can only be a first child of a JOIN block; every other control block only - // executes one child. Hence, it is easier to identify the conditions that only a - // "second child" (i.e. a JOIN block's second child, as well as all other control - // block's child) can find itself in. That is, when the opcode of the next row is: - // - END: this marks the end of the parent block, which only a second child can be in - // - REPEAT: this means that the current block is the child of a LOOP block, and hence a - // "second child" - // - HALT: The end of the program, which a first child can't find itself in (since the - // second child needs to execute first) - let is_first_child = op_code_next != opcodes::END - && op_code_next != opcodes::REPEAT - && op_code_next != opcodes::HALT; - - let is_loop_body = match main_trace.is_loop_body_flag(row).as_canonical_u64() { - 0 => false, - 1 => true, - other => panic!("expected loop body flag to be 0 or 1, got {other}"), - }; - - Self { - parent_block_id, - child_block_hash, - is_first_child, - is_loop_body, - } - } - - /// Computes the row corresponding to the left or right child to add to the block hash table - /// when encountering a `JOIN` operation. - pub fn from_join(main_trace: &MainTrace, row: RowIndex, is_first_child: bool) -> Self { - let child_block_hash = if is_first_child { - main_trace.decoder_hasher_state_first_half(row) - } else { - main_trace.decoder_hasher_state_second_half(row) - }; - - Self { - parent_block_id: main_trace.addr(row + 1), - child_block_hash, - is_first_child, - is_loop_body: false, - } - } - - /// Computes the row to add to the block hash table when encountering a `SPLIT` operation. - pub fn from_split(main_trace: &MainTrace, row: RowIndex) -> Self { - let stack_top = main_trace.stack_element(0, row); - let parent_block_id = main_trace.addr(row + 1); - // Note: only one child of a split block is executed. Hence, `is_first_child` is always - // false. - let is_first_child = false; - let is_loop_body = false; - - if stack_top == ONE { - let left_child_block_hash = main_trace.decoder_hasher_state_first_half(row); - Self { - parent_block_id, - child_block_hash: left_child_block_hash, - is_first_child, - is_loop_body, - } - } else { - let right_child_block_hash = main_trace.decoder_hasher_state_second_half(row); - - Self { - parent_block_id, - child_block_hash: right_child_block_hash, - is_first_child, - is_loop_body, - } - } - } - - /// Computes the row (optionally) to add to the block hash table when encountering a `LOOP` - /// operation. That is, a loop will have a child to execute when the top of the stack is 1. - pub fn from_loop(main_trace: &MainTrace, row: RowIndex) -> Option { - let stack_top = main_trace.stack_element(0, row); - - if stack_top == ONE { - Some(Self { - parent_block_id: main_trace.addr(row + 1), - child_block_hash: main_trace.decoder_hasher_state_first_half(row), - is_first_child: false, - is_loop_body: true, - }) - } else { - None - } - } - - /// Computes the row to add to the block hash table when encountering a `REPEAT` operation. A - /// `REPEAT` marks the start of a new loop iteration, and hence the loop's child block needs to - /// be added to the block hash table once again (since it was removed in the previous `END` - /// instruction). - pub fn from_repeat(main_trace: &MainTrace, row: RowIndex) -> Self { - Self { - parent_block_id: main_trace.addr(row + 1), - child_block_hash: main_trace.decoder_hasher_state_first_half(row), - is_first_child: false, - is_loop_body: true, - } - } - - /// Computes the row to add to the block hash table when encountering a `DYN`, `DYNCALL`, `CALL` - /// or `SYSCALL` operation. - /// - /// The hash of the child node being called is expected to be in the first half of the decoder - /// hasher state. - pub fn from_dyn_dyncall_call_syscall(main_trace: &MainTrace, row: RowIndex) -> Self { - Self { - parent_block_id: main_trace.addr(row + 1), - child_block_hash: main_trace.decoder_hasher_state_first_half(row), - is_first_child: false, - is_loop_body: false, - } - } - - // COLLAPSE - // ---------------------------------------------------------------------------------------------- - - /// Collapses this row to a single field element in the field specified by E by taking a random - /// linear combination of all the columns. This requires 8 alpha values, which are assumed to - /// have been drawn randomly. - pub fn collapse>(&self, challenges: &Challenges) -> E { - let is_first_child = if self.is_first_child { ONE } else { ZERO }; - let is_loop_body = if self.is_loop_body { ONE } else { ZERO }; - challenges.encode([ - self.parent_block_id, - self.child_block_hash[0], - self.child_block_hash[1], - self.child_block_hash[2], - self.child_block_hash[3], - is_first_child, - is_loop_body, - ]) - } - - // TEST - // ---------------------------------------------------------------------------------------------- - - /// Returns a new [BlockHashTableRow] instantiated with the specified parameters. This is - /// used for test purpose only. - #[cfg(test)] - pub fn new_test( - parent_id: Felt, - block_hash: Word, - is_first_child: bool, - is_loop_body: bool, - ) -> Self { - Self { - parent_block_id: parent_id, - child_block_hash: block_hash, - is_first_child, - is_loop_body, - } - } -} diff --git a/processor/src/trace/decoder/aux_trace/block_stack_table.rs b/processor/src/trace/decoder/aux_trace/block_stack_table.rs deleted file mode 100644 index 74b2d4cb83..0000000000 --- a/processor/src/trace/decoder/aux_trace/block_stack_table.rs +++ /dev/null @@ -1,174 +0,0 @@ -use miden_air::trace::{Challenges, RowIndex}; -use miden_core::{field::ExtensionField, operations::opcodes}; - -use super::{AuxColumnBuilder, Felt, MainTrace, ONE, ZERO}; -use crate::debug::BusDebugger; - -// BLOCK STACK TABLE COLUMN BUILDER -// ================================================================================================ - -/// Builds the execution trace of the decoder's `p1` column which describes the state of the block -/// stack table via multiset checks. -#[derive(Default)] -pub struct BlockStackColumnBuilder {} - -impl> AuxColumnBuilder for BlockStackColumnBuilder { - /// Removes a row from the block stack table. - fn get_requests_at( - &self, - main_trace: &MainTrace, - challenges: &Challenges, - i: RowIndex, - _debugger: &mut BusDebugger, - ) -> E { - let op_code_felt = main_trace.get_op_code(i); - let op_code = op_code_felt.as_canonical_u64() as u8; - - match op_code { - opcodes::RESPAN => get_block_stack_table_respan_multiplicand(main_trace, i, challenges), - opcodes::END => get_block_stack_table_end_multiplicand(main_trace, i, challenges), - _ => E::ONE, - } - } - - /// Adds a row to the block stack table. - fn get_responses_at( - &self, - main_trace: &MainTrace, - challenges: &Challenges, - i: RowIndex, - _debugger: &mut BusDebugger, - ) -> E { - let op_code_felt = main_trace.get_op_code(i); - let op_code = op_code_felt.as_canonical_u64() as u8; - - match op_code { - opcodes::JOIN - | opcodes::SPLIT - | opcodes::SPAN - | opcodes::DYN - | opcodes::DYNCALL - | opcodes::LOOP - | opcodes::RESPAN - | opcodes::CALL - | opcodes::SYSCALL => { - get_block_stack_table_inclusion_multiplicand(main_trace, i, challenges, op_code) - }, - _ => E::ONE, - } - } - - #[cfg(any(test, feature = "bus-debugger"))] - fn enforce_bus_balance(&self) -> bool { - true - } -} - -// HELPER FUNCTIONS -// ================================================================================================ - -/// Computes the multiplicand representing the removal of a row from the block stack table when -/// encountering a RESPAN operation. -fn get_block_stack_table_respan_multiplicand>( - main_trace: &MainTrace, - i: RowIndex, - challenges: &Challenges, -) -> E { - let block_id = main_trace.addr(i); - let parent_id = main_trace.decoder_hasher_state_element(1, i + 1); - let is_loop = ZERO; - - challenges.encode([block_id, parent_id, is_loop]) -} - -/// Computes the multiplicand representing the removal of a row from the block stack table when -/// encountering an END operation. -fn get_block_stack_table_end_multiplicand>( - main_trace: &MainTrace, - i: RowIndex, - challenges: &Challenges, -) -> E { - let block_id = main_trace.addr(i); - let parent_id = main_trace.addr(i + 1); - let is_loop = main_trace.is_loop_flag(i); - - if main_trace.is_call_flag(i) == ONE || main_trace.is_syscall_flag(i) == ONE { - let parent_ctx = main_trace.ctx(i + 1); - let parent_stack_depth = main_trace.stack_depth(i + 1); - let parent_next_overflow_addr = main_trace.parent_overflow_address(i + 1); - let parent_fn_hash = main_trace.fn_hash(i + 1); - - challenges.encode([ - block_id, - parent_id, - is_loop, - parent_ctx, - parent_stack_depth, - parent_next_overflow_addr, - parent_fn_hash[0], - parent_fn_hash[1], - parent_fn_hash[2], - parent_fn_hash[3], - ]) - } else { - challenges.encode([block_id, parent_id, is_loop]) - } -} - -/// Computes the multiplicand representing the inclusion of a new row to the block stack table. -fn get_block_stack_table_inclusion_multiplicand>( - main_trace: &MainTrace, - i: RowIndex, - challenges: &Challenges, - op_code: u8, -) -> E { - let block_id = main_trace.addr(i + 1); - let parent_id = if op_code == opcodes::RESPAN { - main_trace.decoder_hasher_state_element(1, i + 1) - } else { - main_trace.addr(i) - }; - let is_loop = if op_code == opcodes::LOOP { - main_trace.stack_element(0, i) - } else { - ZERO - }; - - if op_code == opcodes::CALL || op_code == opcodes::SYSCALL { - let parent_ctx = main_trace.ctx(i); - let parent_stack_depth = main_trace.stack_depth(i); - let parent_next_overflow_addr = main_trace.parent_overflow_address(i); - let parent_fn_hash = main_trace.fn_hash(i); - challenges.encode([ - block_id, - parent_id, - is_loop, - parent_ctx, - parent_stack_depth, - parent_next_overflow_addr, - parent_fn_hash[0], - parent_fn_hash[1], - parent_fn_hash[2], - parent_fn_hash[3], - ]) - } else if op_code == opcodes::DYNCALL { - let parent_ctx = main_trace.ctx(i); - let parent_stack_depth = main_trace.decoder_hasher_state_element(4, i); - let parent_next_overflow_addr = main_trace.decoder_hasher_state_element(5, i); - let parent_fn_hash = main_trace.fn_hash(i); - challenges.encode([ - block_id, - parent_id, - is_loop, - parent_ctx, - parent_stack_depth, - parent_next_overflow_addr, - parent_fn_hash[0], - parent_fn_hash[1], - parent_fn_hash[2], - parent_fn_hash[3], - ]) - } else { - challenges.encode([block_id, parent_id, is_loop]) - } -} diff --git a/processor/src/trace/decoder/aux_trace/mod.rs b/processor/src/trace/decoder/aux_trace/mod.rs deleted file mode 100644 index f3cf796bf8..0000000000 --- a/processor/src/trace/decoder/aux_trace/mod.rs +++ /dev/null @@ -1,59 +0,0 @@ -use alloc::vec::Vec; - -use miden_air::trace::{Challenges, MainTrace}; -use miden_core::field::ExtensionField; - -use crate::{Felt, ONE, ZERO, trace::AuxColumnBuilder}; - -mod block_hash_table; -use block_hash_table::BlockHashTableColumnBuilder; -#[cfg(test)] -pub use block_hash_table::BlockHashTableRow; - -mod block_stack_table; -use block_stack_table::BlockStackColumnBuilder; - -mod op_group_table; -use op_group_table::OpGroupTableColumnBuilder; - -// AUXILIARY TRACE BUILDER -// ================================================================================================ - -/// Constructs the execution traces of stack-related auxiliary trace segment columns -/// (used in multiset checks). -#[derive(Debug, Default, Clone, Copy)] -pub struct AuxTraceBuilder {} - -impl AuxTraceBuilder { - /// Builds and returns decoder auxiliary trace columns p1, p2, and p3 describing states of block - /// stack, block hash, and op group tables respectively. - pub fn build_aux_columns>( - &self, - main_trace: &MainTrace, - challenges: &Challenges, - ) -> Vec> { - let block_stack_column_builder = BlockStackColumnBuilder::default(); - let block_hash_column_builder = BlockHashTableColumnBuilder::default(); - let op_group_table_column_builder = OpGroupTableColumnBuilder::default(); - - let p1 = block_stack_column_builder.build_aux_column(main_trace, challenges); - let p2 = block_hash_column_builder.build_aux_column(main_trace, challenges); - let p3 = op_group_table_column_builder.build_aux_column(main_trace, challenges); - - debug_assert_eq!( - *p1.last().unwrap(), - E::ONE, - "block stack table is not empty at the end of program execution" - ); - // p2 (block hash table) does NOT end at 1: the program hash boundary response - // is unmatched, so p2 ends at 1/program_hash_msg. This is verified by the - // verifier in reduced_aux_values. - debug_assert_eq!( - *p3.last().unwrap(), - E::ONE, - "op group table is not empty at the end of program execution" - ); - - vec![p1, p2, p3] - } -} diff --git a/processor/src/trace/decoder/aux_trace/op_group_table.rs b/processor/src/trace/decoder/aux_trace/op_group_table.rs deleted file mode 100644 index 3e984ac24f..0000000000 --- a/processor/src/trace/decoder/aux_trace/op_group_table.rs +++ /dev/null @@ -1,114 +0,0 @@ -use miden_air::trace::{ - Challenges, RowIndex, - decoder::{OP_BATCH_2_GROUPS, OP_BATCH_4_GROUPS, OP_BATCH_8_GROUPS}, -}; -use miden_core::{field::ExtensionField, operations::opcodes}; - -use super::{AuxColumnBuilder, Felt, MainTrace, ONE}; -use crate::debug::BusDebugger; - -// OP GROUP TABLE COLUMN -// ================================================================================================ - -/// Builds the execution trace of the decoder's `p3` column which describes the state of the op -/// group table via multiset checks. -#[derive(Default)] -pub struct OpGroupTableColumnBuilder {} - -impl> AuxColumnBuilder for OpGroupTableColumnBuilder { - /// Removes a row from the block hash table. - fn get_requests_at( - &self, - main_trace: &MainTrace, - challenges: &Challenges, - i: RowIndex, - _debugger: &mut BusDebugger, - ) -> E { - let delete_group_flag = main_trace.delta_group_count(i) * main_trace.is_in_span(i); - - if delete_group_flag == ONE { - get_op_group_table_removal_multiplicand(main_trace, i, challenges) - } else { - E::ONE - } - } - - /// Adds a row to the block hash table. - fn get_responses_at( - &self, - main_trace: &MainTrace, - challenges: &Challenges, - i: RowIndex, - _debugger: &mut BusDebugger, - ) -> E { - let op_code_felt = main_trace.get_op_code(i); - let op_code = op_code_felt.as_canonical_u64() as u8; - - match op_code { - opcodes::SPAN | opcodes::RESPAN => { - get_op_group_table_inclusion_multiplicand(main_trace, i, challenges) - }, - _ => E::ONE, - } - } - - #[cfg(any(test, feature = "bus-debugger"))] - fn enforce_bus_balance(&self) -> bool { - true - } -} - -// HELPER FUNCTIONS -// ================================================================================================ - -/// Computes the multiplicand representing the inclusion of a new row to the op group table. -fn get_op_group_table_inclusion_multiplicand>( - main_trace: &MainTrace, - i: RowIndex, - challenges: &Challenges, -) -> E { - let block_id = main_trace.addr(i + 1); - let group_count = main_trace.group_count(i); - let op_batch_flag = main_trace.op_batch_flag(i); - - if op_batch_flag == OP_BATCH_8_GROUPS { - let h = main_trace.decoder_hasher_state(i); - (1..8_u8).fold(E::ONE, |acc, k| { - acc * challenges.encode([block_id, group_count - Felt::from_u8(k), h[k as usize]]) - }) - } else if op_batch_flag == OP_BATCH_4_GROUPS { - let h = main_trace.decoder_hasher_state_first_half(i); - (1..4_u8).fold(E::ONE, |acc, k| { - acc * challenges.encode([block_id, group_count - Felt::from_u8(k), h[k as usize]]) - }) - } else if op_batch_flag == OP_BATCH_2_GROUPS { - let h = main_trace.decoder_hasher_state_first_half(i); - challenges.encode([block_id, group_count - ONE, h[1]]) - } else { - E::ONE - } -} - -/// Computes the multiplicand representing the removal of a row from the op group table. -fn get_op_group_table_removal_multiplicand>( - main_trace: &MainTrace, - i: RowIndex, - challenges: &Challenges, -) -> E { - let group_count = main_trace.group_count(i); - let block_id = main_trace.addr(i); - let group_value = { - let op_code = main_trace.get_op_code(i); - - if op_code == Felt::from_u8(opcodes::PUSH) { - main_trace.stack_element(0, i + 1) - } else { - let h0 = main_trace.decoder_hasher_state_first_half(i + 1)[0]; - - let op_prime = main_trace.get_op_code(i + 1); - h0 * Felt::from_u16(1 << 7) + op_prime - } - }; - - challenges.encode([block_id, group_count, group_value]) -} diff --git a/processor/src/trace/decoder/block_stack.rs b/processor/src/trace/decoder/block_stack.rs deleted file mode 100644 index af1e0565e8..0000000000 --- a/processor/src/trace/decoder/block_stack.rs +++ /dev/null @@ -1,198 +0,0 @@ -use alloc::vec::Vec; - -use miden_air::Felt; -use miden_core::{ONE, Word, ZERO}; - -use crate::ContextId; - -// BLOCK STACK -// ================================================================================================ - -/// Keeps track of code blocks which are currently being executed by the VM. -#[derive(Debug, Default, Clone)] -pub struct BlockStack { - blocks: Vec, -} - -impl BlockStack { - // STATE ACCESSORS AND MUTATORS - // -------------------------------------------------------------------------------------------- - - /// Pushes a new code block onto the block stack and returns the address of the block's parent. - /// - /// The block is identified by its address, and we also need to know what type of a block this - /// is. Additionally, for CALL, SYSCALL and DYNCALL blocks, execution context info must be - /// provided. Other information (i.e., the block's parent, whether the block is a body of a loop - /// or a first child of a JOIN block) is determined from the information already on the stack. - pub fn push( - &mut self, - addr: Felt, - block_type: BlockType, - ctx_info: Option, - ) -> Felt { - // make sure execution context was provided for CALL, SYSCALL and DYNCALL blocks - if block_type == BlockType::Call - || block_type == BlockType::SysCall - || block_type == BlockType::Dyncall - { - debug_assert!(ctx_info.is_some(), "no execution context provided for a CALL block"); - } else { - debug_assert!(ctx_info.is_none(), "execution context provided for a non-CALL block"); - } - - // determine additional info about the new block based on its parent - let (parent_addr, is_loop_body, _is_first_child) = match self.blocks.last() { - Some(parent) => match parent.block_type { - // if the parent block is a LOOP block, the new block must be a loop body - BlockType::Loop(loop_entered) => { - debug_assert!(loop_entered, "parent is un-entered loop"); - (parent.addr, true, false) - }, - // if the parent block is a JOIN block, figure out if the new block is the first - // or the second child - BlockType::Join(first_child_executed) => { - (parent.addr, false, !first_child_executed) - }, - _ => (parent.addr, false, false), - }, - // if the block stack is empty, a new block is neither a body of a loop nor the first - // child of a JOIN block; also, we set the parent address to ZERO. - None => (ZERO, false, false), - }; - - self.blocks.push(BlockInfo { - addr, - block_type, - parent_addr, - ctx_info, - is_loop_body, - }); - parent_addr - } - - /// Removes a block from the top of the stack and returns it. - pub fn pop(&mut self) -> BlockInfo { - let block = self.blocks.pop().expect("block stack is empty"); - // if the parent block is a JOIN block (i.e., we just finished executing a child of a JOIN - // block) and if the first_child_executed hasn't been set to true yet, set it to true - if let Some(parent) = self.blocks.last_mut() - && let BlockType::Join(first_child_executed) = parent.block_type - && !first_child_executed - { - parent.block_type = BlockType::Join(true); - } - block - } - - /// Returns true if the block stack is empty. - pub fn is_empty(&self) -> bool { - self.blocks.is_empty() - } - - /// Returns a reference to a block at the top of the stack. - pub fn peek(&self) -> &BlockInfo { - self.blocks.last().expect("block stack is empty") - } - - /// Returns a mutable reference to a block at the top of the stack. - pub fn peek_mut(&mut self) -> &mut BlockInfo { - self.blocks.last_mut().expect("block stack is empty") - } -} - -// BLOCK INFO -// ================================================================================================ - -/// Contains basic information about a code block. -#[derive(Debug, Clone)] -pub struct BlockInfo { - pub addr: Felt, - block_type: BlockType, - pub parent_addr: Felt, - pub ctx_info: Option, - pub is_loop_body: bool, -} - -impl BlockInfo { - /// Returns ONE if the this block is a LOOP block and the body of the loop was executed at - /// least once; otherwise, returns ZERO. - pub fn is_entered_loop(&self) -> Felt { - if self.block_type == BlockType::Loop(true) { - ONE - } else { - ZERO - } - } - - /// Returns ONE if this block is a body of a LOOP block; otherwise returns ZERO. - pub const fn is_loop_body(&self) -> Felt { - if self.is_loop_body { ONE } else { ZERO } - } - - /// Returns ONE if this block is a CALL or DYNCALL block; otherwise returns ZERO. - pub const fn is_call(&self) -> Felt { - match self.block_type { - BlockType::Call | BlockType::Dyncall => ONE, - _ => ZERO, - } - } - - /// Returns ONE if this block is a SYSCALL block; otherwise returns ZERO. - pub const fn is_syscall(&self) -> Felt { - match self.block_type { - BlockType::SysCall => ONE, - _ => ZERO, - } - } -} - -// EXECUTION CONTEXT INFO -// ================================================================================================ - -/// Contains information about an execution context. Execution contexts are relevant only for CALL -/// and SYSCALL blocks. -#[derive(Debug, Default, Clone, Copy)] -pub struct ExecutionContextInfo { - /// Context ID of the block's parent. - pub parent_ctx: ContextId, - /// Hash of the function which initiated execution of the block's parent. If the parent is a - /// root context, this will be set to [ZERO; 4]. - pub parent_fn_hash: Word, - /// Depth of the operand stack right before a CALL operation is executed. - pub parent_stack_depth: u32, - /// Address of the top row in the overflow table right before a CALL operations is executed. - pub parent_next_overflow_addr: Felt, -} - -impl ExecutionContextInfo { - /// Returns an new [ExecutionContextInfo] instantiated with the specified parameters. - pub fn new( - parent_ctx: ContextId, - parent_fn_hash: Word, - parent_stack_depth: u32, - parent_next_overflow_addr: Felt, - ) -> Self { - Self { - parent_fn_hash, - parent_ctx, - parent_stack_depth, - parent_next_overflow_addr, - } - } -} - -// BLOCK TYPE -// ================================================================================================ - -/// Specifies type of a code block with additional info for some block types. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum BlockType { - Join(bool), // internal value set to true when the first child is fully executed - Split, - Loop(bool), // internal value set to false if the loop is never entered - Call, - Dyn, - Dyncall, - SysCall, - BasicBlock, -} diff --git a/processor/src/trace/decoder/mod.rs b/processor/src/trace/decoder/mod.rs deleted file mode 100644 index 7233d72c99..0000000000 --- a/processor/src/trace/decoder/mod.rs +++ /dev/null @@ -1,25 +0,0 @@ -#[cfg(test)] -use miden_core::{Felt, mast::OP_GROUP_SIZE, operations::Operation}; - -mod aux_trace; -pub use aux_trace::AuxTraceBuilder; -#[cfg(test)] -pub use aux_trace::BlockHashTableRow; - -pub mod block_stack; - -// TEST HELPERS -// ================================================================================================ - -/// Build an operation group from the specified list of operations. -#[cfg(test)] -pub fn build_op_group(ops: &[Operation]) -> Felt { - let mut group = 0u64; - let mut i = 0; - for op in ops.iter() { - group |= (op.op_code() as u64) << (Operation::OP_BITS * i); - i += 1; - } - assert!(i <= OP_GROUP_SIZE, "too many ops"); - Felt::new(group) -} diff --git a/processor/src/trace/execution_tracer.rs b/processor/src/trace/execution_tracer.rs index 6f167d7e3d..4a5b387c42 100644 --- a/processor/src/trace/execution_tracer.rs +++ b/processor/src/trace/execution_tracer.rs @@ -1,16 +1,18 @@ use alloc::{sync::Arc, vec::Vec}; -use miden_air::trace::chiplets::hasher::{HASH_CYCLE_LEN, HASH_CYCLE_LEN_FELT, STATE_WIDTH}; +use miden_air::trace::chiplets::hasher::{ + CONTROLLER_ROWS_PER_PERM_FELT, CONTROLLER_ROWS_PER_PERMUTATION, STATE_WIDTH, +}; use miden_core::{FMP_ADDR, FMP_INIT_VALUE, operations::Operation}; use super::{ - decoder::block_stack::{BlockInfo, BlockStack, BlockType, ExecutionContextInfo}, + block_stack::{BlockInfo, BlockStack, ExecutionContextInfo}, stack::OverflowTable, trace_state::{ AceReplay, AdviceReplay, BitwiseReplay, BlockAddressReplay, BlockStackReplay, CoreTraceFragmentContext, CoreTraceState, DecoderState, ExecutionContextReplay, ExecutionContextSystemInfo, ExecutionReplay, HasherRequestReplay, HasherResponseReplay, - KernelReplay, MastForestResolutionReplay, MemoryReadsReplay, MemoryWritesReplay, NodeFlags, + KernelReplay, MastForestResolutionReplay, MemoryReadsReplay, MemoryWritesReplay, RangeCheckerReplay, StackOverflowReplay, StackState, SystemState, }, utils::split_u32_into_u16, @@ -42,6 +44,7 @@ struct StateSnapshot { // TRACE GENERATION CONTEXT // ================================================================================================ +#[derive(Debug)] pub struct TraceGenerationContext { /// The list of trace fragment contexts built during execution. pub core_trace_contexts: Vec, @@ -58,6 +61,10 @@ pub struct TraceGenerationContext { /// The number of rows per core trace fragment, except for the last fragment which may be /// shorter. pub fragment_size: usize, + + /// The maximum number of field elements allowed on the operand stack in an active execution + /// context. + pub max_stack_depth: usize, } /// Builder for recording the context to generate trace fragments during execution. @@ -110,6 +117,10 @@ pub struct ExecutionTracer { /// The number of rows per core trace fragment. fragment_size: usize, + /// The maximum number of field elements allowed on the operand stack in an active execution + /// context. + max_stack_depth: usize, + /// Flag set in `start_clock_cycle` when a Call/Syscall/Dyncall END is encountered, consumed /// in `finalize_clock_cycle` to call `overflow_table.restore_context()`. This is deferred to /// `finalize_clock_cycle` because `finalize_clock_cycle` is only called when the operation @@ -124,7 +135,7 @@ pub struct ExecutionTracer { impl ExecutionTracer { /// Creates a new `ExecutionTracer` with the given fragment size. #[inline(always)] - pub fn new(fragment_size: usize) -> Self { + pub fn new(fragment_size: usize, max_stack_depth: usize) -> Self { Self { state_snapshot: None, overflow_table: OverflowTable::default(), @@ -144,6 +155,7 @@ impl ExecutionTracer { external: MastForestResolutionReplay::default(), fragment_contexts: Vec::new(), fragment_size, + max_stack_depth, pending_restore_context: false, is_eval_circuit_op: false, } @@ -165,6 +177,7 @@ impl ExecutionTracer { hasher_for_chiplet: self.hasher_for_chiplet, ace_replay: self.ace, fragment_size: self.fragment_size, + max_stack_depth: self.max_stack_depth, } } @@ -233,7 +246,7 @@ impl ExecutionTracer { processor: &P, current_forest: &MastForest, ) { - let (ctx_info, block_type) = match node { + let ctx_info = match node { MastNode::Join(node) => { let child1_hash = current_forest .get_node_by_id(node.first()) @@ -250,7 +263,7 @@ impl ExecutionTracer { node.digest(), ); - (None, BlockType::Join(false)) + None }, MastNode::Split(node) => { let child1_hash = current_forest @@ -268,7 +281,7 @@ impl ExecutionTracer { node.digest(), ); - (None, BlockType::Split) + None }, MastNode::Loop(node) => { let body_hash = current_forest @@ -283,12 +296,7 @@ impl ExecutionTracer { node.digest(), ); - let loop_entered = { - let condition = processor.stack().get(0); - condition == ONE - }; - - (None, BlockType::Loop(loop_entered)) + None }, MastNode::Call(node) => { let callee_hash = current_forest @@ -303,22 +311,13 @@ impl ExecutionTracer { node.digest(), ); - let exec_ctx = { - let overflow_addr = self.overflow_table.last_update_clk_in_current_ctx(); - ExecutionContextInfo::new( - processor.system().ctx(), - processor.system().caller_hash(), - processor.stack().depth(), - overflow_addr, - ) - }; - let block_type = if node.is_syscall() { - BlockType::SysCall - } else { - BlockType::Call - }; - - (Some(exec_ctx), block_type) + let overflow_addr = self.overflow_table.last_update_clk_in_current_ctx(); + Some(ExecutionContextInfo::new( + processor.system().ctx(), + processor.system().caller_hash(), + processor.stack().depth(), + overflow_addr, + )) }, MastNode::Dyn(dyn_node) => { self.hasher_for_chiplet.record_hash_control_block( @@ -329,27 +328,37 @@ impl ExecutionTracer { ); if dyn_node.is_dyncall() { - let exec_ctx = { - let overflow_addr = self.overflow_table.last_update_clk_in_current_ctx(); - // Note: the stack depth to record is the `current_stack_depth - 1` due to - // the semantics of DYNCALL. That is, the top of the - // stack contains the memory address to where the - // address to dynamically call is located. Then, the - // DYNCALL operation performs a drop, and - // records the stack depth after the drop as the beginning of - // the new context. For more information, look at the docs for how the - // constraints are designed; it's a bit tricky but it works. - let stack_depth_after_drop = processor.stack().depth() - 1; - ExecutionContextInfo::new( - processor.system().ctx(), - processor.system().caller_hash(), - stack_depth_after_drop, - overflow_addr, - ) - }; - (Some(exec_ctx), BlockType::Dyncall) + // DYNCALL drops the top stack element (the memory address holding the + // callee hash) and records the stack state *after* the drop as the new + // context. + // + // `record_control_node_start()` is called *before* `decrement_stack_size()`, + // so we must compute the post-drop overflow address without actually + // performing the pop. We use `clk_after_pop_in_current_ctx()` which + // returns the clock of the second-to-last overflow entry (i.e. what + // `last_update_clk_in_current_ctx()` would return after the pop), or ZERO + // when the overflow stack has ≤1 entry and would become empty. + // + // When the stack is already at MIN_STACK_DEPTH the drop does not reduce + // the depth and the overflow address is ZERO — mirroring the same guard + // already present in the parallel-tracer path. See #2813 / PR #2904. + let (stack_depth_after_drop, overflow_addr) = + if processor.stack().depth() > MIN_STACK_DEPTH as u32 { + ( + processor.stack().depth() - 1, + self.overflow_table.clk_after_pop_in_current_ctx(), + ) + } else { + (processor.stack().depth(), ZERO) + }; + Some(ExecutionContextInfo::new( + processor.system().ctx(), + processor.system().caller_hash(), + stack_depth_after_drop, + overflow_addr, + )) } else { - (None, BlockType::Dyn) + None } }, MastNode::Block(_) => panic!( @@ -361,31 +370,21 @@ impl ExecutionTracer { }; let block_addr = self.hasher_chiplet_shim.record_hash_control_block(); - let parent_addr = self.block_stack.push(block_addr, block_type, ctx_info); + let parent_addr = self.block_stack.push(block_addr, ctx_info); self.block_stack_replay.record_node_start_parent_addr(parent_addr); } - /// Records the block address and flags for an END operation based on the block being popped. + /// Records the block address for an END operation based on the block being popped. #[inline(always)] fn record_node_end(&mut self, block_info: &BlockInfo) { - let flags = NodeFlags::new( - block_info.is_loop_body() == ONE, - block_info.is_entered_loop() == ONE, - block_info.is_call() == ONE, - block_info.is_syscall() == ONE, - ); let (prev_addr, prev_parent_addr) = if self.block_stack.is_empty() { (ZERO, ZERO) } else { let prev_block = self.block_stack.peek(); (prev_block.addr, prev_block.parent_addr) }; - self.block_stack_replay.record_node_end( - block_info.addr, - flags, - prev_addr, - prev_parent_addr, - ); + self.block_stack_replay + .record_node_end(block_info.addr, prev_addr, prev_parent_addr); } /// Records the execution context system info for CALL/SYSCALL/DYNCALL operations. @@ -546,7 +545,7 @@ impl Tracer for ExecutionTracer { let block_addr = self.hasher_chiplet_shim.record_hash_basic_block(basic_block_node); let parent_addr = - self.block_stack.push(block_addr, BlockType::BasicBlock, None); + self.block_stack.push(block_addr, None); self.block_stack_replay.record_node_start_parent_addr(parent_addr); }, MastNode::External(_) => unreachable!( @@ -554,7 +553,7 @@ impl Tracer for ExecutionTracer { ), }, Continuation::Respan { node_id: _, batch_index: _ } => { - self.block_stack.peek_mut().addr += HASH_CYCLE_LEN_FELT; + self.block_stack.peek_mut().addr += CONTROLLER_ROWS_PER_PERM_FELT; }, Continuation::FinishLoop { node_id: _, was_entered } if was_entered && processor.stack_get(0) == ONE => @@ -703,7 +702,7 @@ impl Tracer for ExecutionTracer { clk: RowIndex, ) { self.memory_reads.record_read_word(words[0], addr, ctx, clk); - self.memory_reads.record_read_word(words[1], addr + Felt::new(4), ctx, clk); + self.memory_reads.record_read_word(words[1], addr + PTR_OFFSET_WORD, ctx, clk); } #[inline(always)] @@ -731,17 +730,17 @@ impl Tracer for ExecutionTracer { ) { self.memory_reads.record_read_word(plaintext[0], src_addr, ctx, clk); self.memory_reads - .record_read_word(plaintext[1], src_addr + Felt::new(4), ctx, clk); + .record_read_word(plaintext[1], src_addr + PTR_OFFSET_WORD, ctx, clk); self.memory_writes.record_write_word(ciphertext[0], dst_addr, ctx, clk); self.memory_writes - .record_write_word(ciphertext[1], dst_addr + Felt::new(4), ctx, clk); + .record_write_word(ciphertext[1], dst_addr + PTR_OFFSET_WORD, ctx, clk); } #[inline(always)] fn record_pipe(&mut self, words: [Word; 2], addr: Felt, ctx: ContextId, clk: RowIndex) { self.advice.record_pop_stack_dword(words); self.memory_writes.record_write_word(words[0], addr, ctx, clk); - self.memory_writes.record_write_word(words[1], addr + Felt::new(4), ctx, clk); + self.memory_writes.record_write_word(words[1], addr + PTR_OFFSET_WORD, ctx, clk); } #[inline(always)] @@ -842,9 +841,8 @@ impl Tracer for ExecutionTracer { // HASHER CHIPLET SHIM // ================================================================================================ -/// The number of hasher rows per permutation operation. This is used to compute the address for -/// the next operation in the hasher chiplet. -const NUM_HASHER_ROWS_PER_PERMUTATION: u32 = HASH_CYCLE_LEN as u32; +/// The number of controller rows per permutation request (input + output = 2), as u32. +const NUM_HASHER_ROWS_PER_PERMUTATION: u32 = CONTROLLER_ROWS_PER_PERMUTATION as u32; /// Implements a shim for the hasher chiplet, where the responses of the hasher chiplet are emulated /// and recorded for later replay. diff --git a/processor/src/trace/mod.rs b/processor/src/trace/mod.rs index 2315bb3ea2..db6e86f2d6 100644 --- a/processor/src/trace/mod.rs +++ b/processor/src/trace/mod.rs @@ -2,32 +2,30 @@ use alloc::vec::Vec; #[cfg(any(test, feature = "testing"))] use core::ops::Range; -#[cfg(feature = "std")] -use miden_air::trace::PADDED_TRACE_WIDTH; use miden_air::{ - AirWitness, AuxBuilder, ProcessorAir, PublicInputs, debug, + AirWitness, ProcessorAir, PublicInputs, debug, trace::{ - DECODER_TRACE_OFFSET, MainTrace, STACK_TRACE_OFFSET, TRACE_WIDTH, + DECODER_TRACE_OFFSET, MainTrace, TRACE_WIDTH, decoder::{NUM_USER_OP_HELPERS, USER_OP_HELPERS_OFFSET}, }, }; +use miden_core::{crypto::hash::Blake3_256, serde::Serializable}; use crate::{ - AdviceProvider, Felt, MIN_STACK_DEPTH, ProgramInfo, StackInputs, StackOutputs, Word, ZERO, + Felt, MIN_STACK_DEPTH, Program, ProgramInfo, StackInputs, StackOutputs, Word, ZERO, fast::ExecutionOutput, - field::{ExtensionField, QuadFelt}, - precompile::{PrecompileRequest, PrecompileTranscript}, - utils::{ColMatrix, Matrix, RowMajorMatrix}, + field::QuadFelt, + precompile::{PrecompileRequest, PrecompileTranscript, PrecompileTranscriptDigest}, + utils::{Matrix, RowMajorMatrix}, }; pub(crate) mod utils; -use miden_air::trace::Challenges; -use utils::{AuxColumnBuilder, TraceFragment}; +use utils::TraceFragment; pub mod chiplets; -pub mod execution_tracer; +pub(crate) mod execution_tracer; -mod decoder; +mod block_stack; mod parallel; mod range; mod stack; @@ -39,10 +37,132 @@ mod tests; // RE-EXPORTS // ================================================================================================ +pub use execution_tracer::TraceGenerationContext; pub use miden_air::trace::RowIndex; pub use parallel::{CORE_TRACE_WIDTH, build_trace, build_trace_with_max_len}; pub use utils::{ChipletsLengths, TraceLenSummary}; +/// Inputs required to build an execution trace from pre-executed data. +#[derive(Debug)] +pub struct TraceBuildInputs { + trace_output: TraceBuildOutput, + trace_generation_context: TraceGenerationContext, + program_info: ProgramInfo, +} + +#[derive(Debug)] +pub(crate) struct TraceBuildOutput { + stack_outputs: StackOutputs, + final_precompile_transcript: PrecompileTranscript, + precompile_requests: Vec, + precompile_requests_digest: [u8; 32], +} + +impl TraceBuildOutput { + fn from_execution_output(execution_output: ExecutionOutput) -> Self { + let ExecutionOutput { + stack, + mut advice, + memory: _, + final_precompile_transcript, + } = execution_output; + + Self { + stack_outputs: stack, + final_precompile_transcript, + precompile_requests: advice.take_precompile_requests(), + precompile_requests_digest: [0; 32], + } + .with_precompile_requests_digest() + } + + fn with_precompile_requests_digest(mut self) -> Self { + self.precompile_requests_digest = + Blake3_256::hash(&self.precompile_requests.to_bytes()).into(); + self + } + + fn has_matching_precompile_requests_digest(&self) -> bool { + let expected_digest: [u8; 32] = + Blake3_256::hash(&self.precompile_requests.to_bytes()).into(); + self.precompile_requests_digest == expected_digest + } +} + +impl TraceBuildInputs { + pub(crate) fn from_execution( + program: &Program, + execution_output: ExecutionOutput, + trace_generation_context: TraceGenerationContext, + ) -> Self { + let trace_output = TraceBuildOutput::from_execution_output(execution_output); + let program_info = program.to_info(); + Self { + trace_output, + trace_generation_context, + program_info, + } + } + + /// Returns the stack outputs captured for the execution being replayed. + pub fn stack_outputs(&self) -> &StackOutputs { + &self.trace_output.stack_outputs + } + + /// Returns deferred precompile requests generated during execution. + pub fn precompile_requests(&self) -> &[PrecompileRequest] { + &self.trace_output.precompile_requests + } + + /// Returns the final precompile transcript observed during execution. + pub fn final_precompile_transcript(&self) -> &PrecompileTranscript { + &self.trace_output.final_precompile_transcript + } + + /// Returns the digest of the final precompile transcript observed during execution. + pub fn precompile_transcript_digest(&self) -> PrecompileTranscriptDigest { + self.final_precompile_transcript().finalize() + } + + /// Returns the program info captured for the execution being replayed. + pub fn program_info(&self) -> &ProgramInfo { + &self.program_info + } + + // Kept for mismatch and edge-case tests that mutate replay inputs directly. + #[cfg(any(test, feature = "testing"))] + #[cfg_attr(all(feature = "testing", not(test)), expect(dead_code))] + pub(crate) fn into_parts(self) -> (TraceBuildOutput, TraceGenerationContext, ProgramInfo) { + (self.trace_output, self.trace_generation_context, self.program_info) + } + + #[cfg(any(test, feature = "testing"))] + /// Returns the trace replay context captured during execution. + pub fn trace_generation_context(&self) -> &TraceGenerationContext { + &self.trace_generation_context + } + + // Kept for tests that force invalid replay contexts without widening the public API. + #[cfg(any(test, feature = "testing"))] + #[cfg_attr(all(feature = "testing", not(test)), expect(dead_code))] + pub(crate) fn trace_generation_context_mut(&mut self) -> &mut TraceGenerationContext { + &mut self.trace_generation_context + } + + #[cfg(test)] + pub(crate) fn from_parts( + trace_output: TraceBuildOutput, + trace_generation_context: TraceGenerationContext, + program_info: ProgramInfo, + ) -> Self { + Self { + trace_output, + trace_generation_context, + program_info, + } + } +} + // VM EXECUTION TRACE // ================================================================================================ @@ -50,18 +170,17 @@ pub use utils::{ChipletsLengths, TraceLenSummary}; /// /// The trace consists of the following components: /// - Main traces of System, Decoder, Operand Stack, Range Checker, and Chiplets. -/// - Auxiliary trace builders. /// - Information about the program (program hash and the kernel). -/// - Information about execution outputs (stack state, advice provider, and precompile transcript). +/// - Information about execution outputs (stack state, deferred precompile requests, and the final +/// precompile transcript). /// - Summary of trace lengths of the main trace components. #[derive(Debug)] pub struct ExecutionTrace { main_trace: MainTrace, - aux_trace_builders: AuxTraceBuilders, program_info: ProgramInfo, stack_outputs: StackOutputs, - advice: AdviceProvider, - final_pc_transcript: PrecompileTranscript, + precompile_requests: Vec, + final_precompile_transcript: PrecompileTranscript, trace_len_summary: TraceLenSummary, } @@ -69,20 +188,25 @@ impl ExecutionTrace { // CONSTRUCTOR // -------------------------------------------------------------------------------------------- - pub fn new_from_parts( + pub(crate) fn new_from_parts( program_info: ProgramInfo, - execution_output: ExecutionOutput, + trace_output: TraceBuildOutput, main_trace: MainTrace, - aux_trace_builders: AuxTraceBuilders, trace_len_summary: TraceLenSummary, ) -> Self { + let TraceBuildOutput { + stack_outputs, + final_precompile_transcript, + precompile_requests, + .. + } = trace_output; + Self { main_trace, - aux_trace_builders, program_info, - stack_outputs: execution_output.stack, - advice: execution_output.advice, - final_pc_transcript: execution_output.final_pc_transcript, + stack_outputs, + precompile_requests, + final_precompile_transcript, trace_len_summary, } } @@ -111,7 +235,7 @@ impl ExecutionTrace { self.program_info.clone(), self.init_stack_state(), self.stack_outputs, - self.final_pc_transcript.state(), + self.final_precompile_transcript.state(), ) } @@ -120,11 +244,6 @@ impl ExecutionTrace { self.public_inputs().to_elements() } - /// Returns a clone of the auxiliary trace builders. - pub fn aux_trace_builders(&self) -> AuxTraceBuilders { - self.aux_trace_builders.clone() - } - /// Returns a reference to the main trace. pub fn main_trace(&self) -> &MainTrace { &self.main_trace @@ -137,37 +256,40 @@ impl ExecutionTrace { /// Returns the precompile requests generated during program execution. pub fn precompile_requests(&self) -> &[PrecompileRequest] { - self.advice.precompile_requests() + &self.precompile_requests } - /// Moves all accumulated precompile requests out of the trace, leaving it empty. - /// - /// Intended for proof packaging, where requests are serialized into the proof and no longer - /// needed in the trace after consumption. - pub fn take_precompile_requests(&mut self) -> Vec { - self.advice.take_precompile_requests() + /// Returns the final precompile transcript observed during execution. + pub fn final_precompile_transcript(&self) -> PrecompileTranscript { + self.final_precompile_transcript } - /// Returns the final precompile transcript after executing all precompile requests. - pub fn final_precompile_transcript(&self) -> PrecompileTranscript { - self.final_pc_transcript + /// Returns the digest of the final precompile transcript observed during execution. + pub fn precompile_transcript_digest(&self) -> PrecompileTranscriptDigest { + self.final_precompile_transcript().finalize() + } + + /// Returns the owned execution outputs required for proof packaging. + pub fn into_outputs(self) -> (StackOutputs, Vec, PrecompileTranscript) { + (self.stack_outputs, self.precompile_requests, self.final_precompile_transcript) } /// Returns the initial state of the top 16 stack registers. pub fn init_stack_state(&self) -> StackInputs { let mut result = [ZERO; MIN_STACK_DEPTH]; + let row = RowIndex::from(0_u32); for (i, result) in result.iter_mut().enumerate() { - *result = self.main_trace.get_column(i + STACK_TRACE_OFFSET)[0]; + *result = self.main_trace.stack_element(i, row); } result.into() } /// Returns the final state of the top 16 stack registers. pub fn last_stack_state(&self) -> StackOutputs { - let last_step = self.last_step(); + let last_step = RowIndex::from(self.last_step()); let mut result = [ZERO; MIN_STACK_DEPTH]; for (i, result) in result.iter_mut().enumerate() { - *result = self.main_trace.get_column(i + STACK_TRACE_OFFSET)[last_step]; + *result = self.main_trace.stack_element(i, last_step); } result.into() } @@ -175,9 +297,9 @@ impl ExecutionTrace { /// Returns helper registers state at the specified `clk` of the VM pub fn get_user_op_helpers_at(&self, clk: u32) -> [Felt; NUM_USER_OP_HELPERS] { let mut result = [ZERO; NUM_USER_OP_HELPERS]; + let row = RowIndex::from(clk); for (i, result) in result.iter_mut().enumerate() { - *result = self.main_trace.get_column(DECODER_TRACE_OFFSET + USER_OP_HELPERS_OFFSET + i) - [clk as usize]; + *result = self.main_trace.get(row, DECODER_TRACE_OFFSET + USER_OP_HELPERS_OFFSET + i); } result } @@ -197,16 +319,6 @@ impl ExecutionTrace { &self.trace_len_summary } - /// Returns the final advice provider state. - pub fn advice_provider(&self) -> &AdviceProvider { - &self.advice - } - - /// Destructures this execution trace into the process’s final stack and advice states. - pub fn into_outputs(self) -> (StackOutputs, AdviceProvider) { - (self.stack_outputs, self.advice) - } - // DEBUG CONSTRAINT CHECKING // -------------------------------------------------------------------------------------------- @@ -227,8 +339,6 @@ impl ExecutionTrace { let (public_values, kernel_felts) = public_inputs.to_air_inputs(); let var_len_public_inputs: &[&[Felt]] = &[&kernel_felts]; - let aux_builder = self.aux_trace_builders(); - // Derive deterministic challenges by hashing public values with Poseidon2. // The 4-element digest maps directly to 2 QuadFelt challenges. let digest = crate::crypto::hash::Poseidon2::hash_elements(&public_values); @@ -236,23 +346,14 @@ impl ExecutionTrace { [QuadFelt::new([digest[0], digest[1]]), QuadFelt::new([digest[2], digest[3]])]; let witness = AirWitness::new(&trace_matrix, &public_values, var_len_public_inputs); - debug::check_constraints(&ProcessorAir, witness, &aux_builder, &challenges); + debug::check_constraints(&ProcessorAir, witness, &ProcessorAir, &challenges); } - /// Converts the main trace from column-major to row-major format. - /// - /// Only includes the first [`TRACE_WIDTH`] columns (excluding padding columns added for - /// Poseidon2 rate alignment), which is the width expected by the AIR. - // TODO: the padding columns can be removed once we use the lifted-stark's virtual trace - // alignment, which pads to the required rate width without materializing extra columns. + /// Returns the main trace as a row-major matrix for proving. pub fn to_row_major_matrix(&self) -> RowMajorMatrix { - let trace_len = self.get_trace_len(); - let mut col_major_data = Vec::with_capacity(TRACE_WIDTH * trace_len); - for col_idx in 0..TRACE_WIDTH { - col_major_data.extend_from_slice(self.main_trace.get_column(col_idx)); - } - let col_major_matrix = RowMajorMatrix::new(col_major_data, trace_len); - col_major_matrix.transpose() + let row_major = self.main_trace.to_row_major(); + debug_assert_eq!(row_major.width(), TRACE_WIDTH); + row_major } // HELPER METHODS @@ -267,15 +368,10 @@ impl ExecutionTrace { // -------------------------------------------------------------------------------------------- #[cfg(feature = "std")] pub fn print(&self) { - use miden_air::trace::TRACE_WIDTH; - - let mut row = [ZERO; PADDED_TRACE_WIDTH]; + let mut row = [ZERO; TRACE_WIDTH]; for i in 0..self.length() { self.main_trace.read_row_into(i, &mut row); - std::println!( - "{:?}", - row.iter().take(TRACE_WIDTH).map(|v| v.as_canonical_u64()).collect::>() - ); + std::println!("{:?}", row.map(|v| v.as_canonical_u64())); } } @@ -283,108 +379,4 @@ impl ExecutionTrace { pub fn get_column_range(&self, range: Range) -> Vec> { self.main_trace.get_column_range(range) } - - pub fn build_aux_trace(&self, rand_elements: &[E]) -> Option> - where - E: ExtensionField, - { - let aux_columns = - self.aux_trace_builders.build_aux_columns(&self.main_trace, rand_elements); - - Some(ColMatrix::new(aux_columns)) - } -} - -// AUX TRACE BUILDERS -// ================================================================================================ - -#[derive(Debug, Clone)] -pub struct AuxTraceBuilders { - pub(crate) decoder: decoder::AuxTraceBuilder, - pub(crate) stack: stack::AuxTraceBuilder, - pub(crate) range: range::AuxTraceBuilder, - pub(crate) chiplets: chiplets::AuxTraceBuilder, -} - -impl AuxTraceBuilders { - /// Builds auxiliary columns for all trace segments given the main trace and challenges. - /// - /// This is the internal column-major version used by the processor. - pub fn build_aux_columns(&self, main_trace: &MainTrace, challenges: &[E]) -> Vec> - where - E: ExtensionField, - { - // Expand raw challenges (alpha, beta) into coefficient array once, then pass - // the expanded challenges to all sub-builders. - let challenges = Challenges::::new(challenges[0], challenges[1]); - - let decoder_cols = self.decoder.build_aux_columns(main_trace, &challenges); - let stack_cols = self.stack.build_aux_columns(main_trace, &challenges); - let range_cols = self.range.build_aux_columns(main_trace, &challenges); - let chiplets_cols = self.chiplets.build_aux_columns(main_trace, &challenges); - - decoder_cols - .into_iter() - .chain(stack_cols) - .chain(range_cols) - .chain(chiplets_cols) - .collect() - } -} - -// PLONKY3 AUX TRACE BUILDER -// ================================================================================================ -// -// Implements the upstream `AuxBuilder` trait from `p3_miden_lifted_air` directly on -// `AuxTraceBuilders`. Plonky3 uses row-major matrices while our existing aux trace building logic -// uses column-major format. This impl adapts between the two by converting the main trace from -// row-major to column-major, delegating to the existing logic, and converting the result back. - -impl> AuxBuilder for AuxTraceBuilders { - fn build_aux_trace( - &self, - main: &RowMajorMatrix, - challenges: &[EF], - ) -> (RowMajorMatrix, Vec) { - let _span = tracing::info_span!("build_aux_trace").entered(); - - // Transpose the row-major main trace into column-major `MainTrace` needed by the - // auxiliary trace builders. The last program row is the point where the clock - // (column 0) stops incrementing. - let main_trace_col_major = { - let num_rows = main.height(); - // Detect last program row from row-major layout using column 0 (clock). - let last_program_row = (1..num_rows) - .find(|&i| { - main.get(i, 0).expect("valid indices") - != main.get(i - 1, 0).expect("valid indices") + Felt::ONE - }) - .map_or(num_rows - 1, |i| i - 1); - let transposed = main.transpose(); - let columns: Vec> = transposed.row_slices().map(|row| row.to_vec()).collect(); - MainTrace::new(ColMatrix::new(columns), last_program_row.into()) - }; - - // Build auxiliary columns in column-major format. - let aux_columns = self.build_aux_columns(&main_trace_col_major, challenges); - assert!(!aux_columns.is_empty(), "aux columns should not be empty"); - - // Flatten column-major aux columns into a contiguous buffer, then transpose - // to the row-major layout expected by the lifted prover. - let trace_len = main.height(); - let num_ef_cols = aux_columns.len(); - let mut col_major_data = Vec::with_capacity(trace_len * num_ef_cols); - for col in aux_columns { - col_major_data.extend_from_slice(&col); - } - let aux_trace = RowMajorMatrix::new(col_major_data, trace_len).transpose(); - - // Extract the last row from the row-major aux trace for Fiat-Shamir. - let last_row = aux_trace - .row_slice(trace_len - 1) - .expect("aux trace has at least one row") - .to_vec(); - - (aux_trace, last_row) - } } diff --git a/processor/src/trace/parallel/core_trace_fragment/mod.rs b/processor/src/trace/parallel/core_trace_fragment/mod.rs index 239182af8d..178e75a4d3 100644 --- a/processor/src/trace/parallel/core_trace_fragment/mod.rs +++ b/processor/src/trace/parallel/core_trace_fragment/mod.rs @@ -1,24 +1,11 @@ use miden_air::{Felt, trace::decoder::NUM_OP_BITS}; use miden_core::{mast::BasicBlockNode, operations::opcodes}; -use super::CORE_TRACE_WIDTH; use crate::errors::OperationError; #[cfg(test)] mod tests; -// CORE TRACE FRAGMENT -// ================================================================================================ - -/// The columns of the main trace fragment. These consist of the system, decoder, and stack columns. -/// -/// A fragment is a collection of columns of length `fragment_size` or less. Only the last fragment -/// is allowed to be shorter than `fragment_size`. -#[derive(Debug)] -pub struct CoreTraceFragment<'a> { - pub columns: [&'a mut [Felt]; CORE_TRACE_WIDTH], -} - // BASIC BLOCK CONTEXT // ================================================================================================ @@ -47,12 +34,12 @@ impl BasicBlockContext { Ok(Self { current_op_group: current_batch.groups()[0], - group_count_in_block: Felt::new( + group_count_in_block: Felt::new_unchecked( basic_block_node .op_batches() .iter() .skip(batch_index) - .map(|batch| batch.num_groups()) + .map(miden_core::mast::OpBatch::num_groups) .sum::() as u64, ), }) @@ -99,7 +86,9 @@ impl BasicBlockContext { // the current one, and so we would expect to shift `NUM_OP_BITS` by // `op_idx_in_group + 1`. However, we will apply that shift right before // writing to the trace, so we only shift by `op_idx_in_group` here. - Felt::new(current_op_group.as_canonical_u64() >> (NUM_OP_BITS * op_idx_in_group)) + Felt::new_unchecked( + current_op_group.as_canonical_u64() >> (NUM_OP_BITS * op_idx_in_group), + ) }; let group_count_in_block = { @@ -148,7 +137,7 @@ impl BasicBlockContext { /// Removes the operation that was just executed from the current operation group. pub(crate) fn remove_operation_from_current_op_group(&mut self) { let prev_op_group = self.current_op_group.as_canonical_u64(); - self.current_op_group = Felt::new(prev_op_group >> NUM_OP_BITS); + self.current_op_group = Felt::new_unchecked(prev_op_group >> NUM_OP_BITS); debug_assert!( prev_op_group >= self.current_op_group.as_canonical_u64(), diff --git a/processor/src/trace/parallel/core_trace_fragment/tests.rs b/processor/src/trace/parallel/core_trace_fragment/tests.rs index ec3818b612..ac00ec3897 100644 --- a/processor/src/trace/parallel/core_trace_fragment/tests.rs +++ b/processor/src/trace/parallel/core_trace_fragment/tests.rs @@ -2,7 +2,7 @@ use alloc::{sync::Arc, vec::Vec}; use miden_air::trace::{ CTX_COL_IDX, - chiplets::hasher::HASH_CYCLE_LEN_FELT, + chiplets::hasher::CONTROLLER_ROWS_PER_PERM_FELT, decoder::{ ADDR_COL_IDX, GROUP_COUNT_COL_IDX, HASHER_STATE_RANGE, IN_SPAN_COL_IDX, NUM_HASHER_COLUMNS, NUM_OP_BATCH_FLAGS, NUM_OP_BITS, OP_BATCH_1_GROUPS, OP_BATCH_2_GROUPS, OP_BATCH_4_GROUPS, @@ -23,17 +23,18 @@ use miden_core::{ use miden_utils_testing::rand::rand_value; use crate::{ - AdviceInputs, DefaultHost, ExecutionOptions, ExecutionTrace, FastProcessor, - event::NoopEventHandler, trace::build_trace, + AdviceInputs, DefaultHost, ExecutionOptions, FastProcessor, + event::NoopEventHandler, + trace::{ExecutionTrace, build_trace}, }; // CONSTANTS // ================================================================================================ -const TWO: Felt = Felt::new(2); -const EIGHT: Felt = Felt::new(8); -const NINE: Felt = Felt::new(9); -const FOURTEEN: Felt = Felt::new(14); +const TWO: Felt = Felt::new_unchecked(2); +const EIGHT: Felt = Felt::new_unchecked(8); +const NINE: Felt = Felt::new_unchecked(9); +const FOURTEEN: Felt = Felt::new_unchecked(14); const INIT_ADDR: Felt = ONE; const EMIT_EVENT: EventName = EventName::new("test::emit::event"); @@ -222,7 +223,7 @@ fn test_basic_block_small_with_emit_decoding() { #[test] fn test_basic_block_decoding() { - let iv = [ONE, TWO, Felt::new(3), Felt::new(4), Felt::new(5)]; + let iv = [ONE, TWO, Felt::new_unchecked(3), Felt::new_unchecked(4), Felt::new_unchecked(5)]; let ops = vec![ Operation::Push(iv[0]), Operation::Push(iv[1]), @@ -317,13 +318,13 @@ fn test_basic_block_with_respan_decoding() { let iv = [ ONE, TWO, - Felt::new(3), - Felt::new(4), - Felt::new(5), - Felt::new(6), - Felt::new(7), + Felt::new_unchecked(3), + Felt::new_unchecked(4), + Felt::new_unchecked(5), + Felt::new_unchecked(6), + Felt::new_unchecked(7), EIGHT, - Felt::new(9), + Felt::new_unchecked(9), ]; let ops = vec![ @@ -372,7 +373,7 @@ fn test_basic_block_with_respan_decoding() { // NOOP inserted by the processor to make sure the group doesn't end with a PUSH check_op_decoding(&trace, 8, INIT_ADDR, opcodes::NOOP, 4, 7, 1); // RESPAN since the previous batch is full - let batch1_addr = INIT_ADDR + HASH_CYCLE_LEN_FELT; + let batch1_addr = INIT_ADDR + CONTROLLER_ROWS_PER_PERM_FELT; check_op_decoding(&trace, 9, INIT_ADDR, opcodes::RESPAN, 4, 0, 0); check_op_decoding_with_imm(&trace, 10, batch1_addr, iv[7], 1, 3, 0, 1); check_op_decoding(&trace, 11, batch1_addr, opcodes::ADD, 2, 1, 1); @@ -462,12 +463,12 @@ fn test_join_node_decoding() { // --- check block address, op_bits, group count, op_index, and in_span columns --------------- check_op_decoding(&trace, 0, ZERO, opcodes::JOIN, 0, 0, 0); // starting first span - let span1_addr = INIT_ADDR + HASH_CYCLE_LEN_FELT; + let span1_addr = INIT_ADDR + CONTROLLER_ROWS_PER_PERM_FELT; check_op_decoding(&trace, 1, INIT_ADDR, opcodes::SPAN, 1, 0, 0); check_op_decoding(&trace, 2, span1_addr, opcodes::MUL, 0, 0, 1); check_op_decoding(&trace, 3, span1_addr, opcodes::END, 0, 0, 0); // starting second span - let span2_addr = span1_addr + HASH_CYCLE_LEN_FELT; + let span2_addr = span1_addr + CONTROLLER_ROWS_PER_PERM_FELT; check_op_decoding(&trace, 4, INIT_ADDR, opcodes::SPAN, 1, 0, 0); check_op_decoding(&trace, 5, span2_addr, opcodes::ADD, 0, 0, 1); check_op_decoding(&trace, 6, span2_addr, opcodes::END, 0, 0, 0); @@ -532,7 +533,7 @@ fn test_split_node_true_decoding() { let (trace, trace_len) = build_trace_helper(&[1], &program); // --- check block address, op_bits, group count, op_index, and in_span columns --------------- - let basic_block_addr = INIT_ADDR + HASH_CYCLE_LEN_FELT; + let basic_block_addr = INIT_ADDR + CONTROLLER_ROWS_PER_PERM_FELT; check_op_decoding(&trace, 0, ZERO, opcodes::SPLIT, 0, 0, 0); check_op_decoding(&trace, 1, INIT_ADDR, opcodes::SPAN, 1, 0, 0); check_op_decoding(&trace, 2, basic_block_addr, opcodes::MUL, 0, 0, 1); @@ -591,7 +592,7 @@ fn test_split_node_false_decoding() { let (trace, trace_len) = build_trace_helper(&[0], &program); // --- check block address, op_bits, group count, op_index, and in_span columns --------------- - let basic_block_addr = INIT_ADDR + HASH_CYCLE_LEN_FELT; + let basic_block_addr = INIT_ADDR + CONTROLLER_ROWS_PER_PERM_FELT; check_op_decoding(&trace, 0, ZERO, opcodes::SPLIT, 0, 0, 0); check_op_decoding(&trace, 1, INIT_ADDR, opcodes::SPAN, 1, 0, 0); check_op_decoding(&trace, 2, basic_block_addr, opcodes::ADD, 0, 0, 1); @@ -649,7 +650,7 @@ fn test_loop_node_decoding() { let (trace, trace_len) = build_trace_helper(&[1, 0], &program); // --- check block address, op_bits, group count, op_index, and in_span columns --------------- - let body_addr = INIT_ADDR + HASH_CYCLE_LEN_FELT; + let body_addr = INIT_ADDR + CONTROLLER_ROWS_PER_PERM_FELT; check_op_decoding(&trace, 0, ZERO, opcodes::LOOP, 0, 0, 0); check_op_decoding(&trace, 1, INIT_ADDR, opcodes::SPAN, 1, 0, 0); check_op_decoding(&trace, 2, body_addr, opcodes::PAD, 0, 0, 1); @@ -754,8 +755,8 @@ fn test_loop_node_repeat_decoding() { let (trace, trace_len) = build_trace_helper(&[1, 1, 0], &program); // --- check block address, op_bits, group count, op_index, and in_span columns --------------- - let iter1_addr = INIT_ADDR + HASH_CYCLE_LEN_FELT; - let iter2_addr = iter1_addr + HASH_CYCLE_LEN_FELT; + let iter1_addr = INIT_ADDR + CONTROLLER_ROWS_PER_PERM_FELT; + let iter2_addr = iter1_addr + CONTROLLER_ROWS_PER_PERM_FELT; check_op_decoding(&trace, 0, ZERO, opcodes::LOOP, 0, 0, 0); check_op_decoding(&trace, 1, INIT_ADDR, opcodes::SPAN, 1, 0, 0); @@ -812,7 +813,6 @@ fn test_loop_node_repeat_decoding() { #[test] #[rustfmt::skip] -#[expect(clippy::needless_range_loop)] fn test_call_decoding() { // build a program which looks like this: @@ -882,7 +882,7 @@ fn test_call_decoding() { let program_root_node = mast_forest[program_root_node_id].clone(); mast_forest.make_root(program_root_node_id); - let program = Program::with_kernel(mast_forest.into(), program_root_node_id, kernel.clone()); + let program = Program::with_kernel(mast_forest.into(), program_root_node_id, kernel); let (sys_trace, dec_trace, trace_len) = build_call_trace_helper(&program); @@ -892,11 +892,11 @@ fn test_call_decoding() { check_op_decoding(&dec_trace, row_idx, ZERO, opcodes::JOIN, 0, 0, 0); row_idx += 1; // starting the internal JOIN block - let inner_join_addr = INIT_ADDR + HASH_CYCLE_LEN_FELT; + let inner_join_addr = INIT_ADDR + CONTROLLER_ROWS_PER_PERM_FELT; check_op_decoding(&dec_trace, row_idx, INIT_ADDR, opcodes::JOIN, 0, 0, 0); row_idx += 1; // starting first SPAN block - let first_basic_block_addr = inner_join_addr + HASH_CYCLE_LEN_FELT; + let first_basic_block_addr = inner_join_addr + CONTROLLER_ROWS_PER_PERM_FELT; check_op_decoding(&dec_trace, row_idx, inner_join_addr, opcodes::SPAN, 4, 0, 0); row_idx += 1; check_op_decoding_with_imm(&dec_trace, row_idx, first_basic_block_addr, ONE, 1, 3, 0, 1); @@ -911,15 +911,15 @@ fn test_call_decoding() { row_idx += 1; // starting CALL block for bar - let call_addr = first_basic_block_addr + HASH_CYCLE_LEN_FELT; + let call_addr = first_basic_block_addr + CONTROLLER_ROWS_PER_PERM_FELT; check_op_decoding(&dec_trace, row_idx, inner_join_addr, opcodes::CALL, 0, 0, 0); row_idx += 1; // starting JOIN block inside bar - let bar_join_addr = call_addr + HASH_CYCLE_LEN_FELT; + let bar_join_addr = call_addr + CONTROLLER_ROWS_PER_PERM_FELT; check_op_decoding(&dec_trace, row_idx, call_addr, opcodes::JOIN, 0, 0, 0); row_idx += 1; // starting SPAN block inside bar - let bar_basic_block_addr = bar_join_addr + HASH_CYCLE_LEN_FELT; + let bar_basic_block_addr = bar_join_addr + CONTROLLER_ROWS_PER_PERM_FELT; check_op_decoding(&dec_trace, row_idx, bar_join_addr, opcodes::SPAN, 1, 0, 0); row_idx += 1; check_op_decoding(&dec_trace, row_idx, bar_basic_block_addr, opcodes::MUL, 0, 0, 1); @@ -928,11 +928,11 @@ fn test_call_decoding() { row_idx += 1; // starting CALL to foo - let syscall_addr = bar_basic_block_addr + HASH_CYCLE_LEN_FELT; + let syscall_addr = bar_basic_block_addr + CONTROLLER_ROWS_PER_PERM_FELT; check_op_decoding(&dec_trace, row_idx, bar_join_addr, opcodes::CALL, 0, 0, 0); row_idx += 1; // starting SPAN block within syscall - let syscall_basic_block_addr = syscall_addr + HASH_CYCLE_LEN_FELT; + let syscall_basic_block_addr = syscall_addr + CONTROLLER_ROWS_PER_PERM_FELT; check_op_decoding(&dec_trace, row_idx, syscall_addr, opcodes::SPAN, 1, 0, 0); row_idx += 1; check_op_decoding(&dec_trace, row_idx, syscall_basic_block_addr, opcodes::ADD, 0, 0, 1); @@ -954,7 +954,7 @@ fn test_call_decoding() { row_idx += 1; // starting the last SPAN block - let last_basic_block_addr = syscall_basic_block_addr + HASH_CYCLE_LEN_FELT; + let last_basic_block_addr = syscall_basic_block_addr + CONTROLLER_ROWS_PER_PERM_FELT; check_op_decoding(&dec_trace, row_idx, INIT_ADDR, opcodes::SPAN, 1, 0, 0); row_idx += 1; check_op_decoding(&dec_trace, row_idx, last_basic_block_addr, opcodes::DROP, 0, 0, 1); @@ -1106,7 +1106,6 @@ fn test_call_decoding() { #[test] #[rustfmt::skip] -#[expect(clippy::needless_range_loop)] fn test_syscall_decoding() { // build a program which looks like this: @@ -1184,7 +1183,7 @@ fn test_syscall_decoding() { let program_root_node = mast_forest[program_root_node_id].clone(); mast_forest.make_root(program_root_node_id); - let program = Program::with_kernel(mast_forest.into(), program_root_node_id, kernel.clone()); + let program = Program::with_kernel(mast_forest.into(), program_root_node_id, kernel); let (sys_trace, dec_trace, trace_len) = build_call_trace_helper(&program); @@ -1194,11 +1193,11 @@ fn test_syscall_decoding() { check_op_decoding(&dec_trace, row_idx, ZERO, opcodes::JOIN, 0, 0, 0); row_idx += 1; // starting the internal JOIN block - let inner_join_addr = INIT_ADDR + HASH_CYCLE_LEN_FELT; + let inner_join_addr = INIT_ADDR + CONTROLLER_ROWS_PER_PERM_FELT; check_op_decoding(&dec_trace, row_idx, INIT_ADDR, opcodes::JOIN, 0, 0, 0); row_idx += 1; // starting first SPAN block - let first_basic_block_addr = inner_join_addr + HASH_CYCLE_LEN_FELT; + let first_basic_block_addr = inner_join_addr + CONTROLLER_ROWS_PER_PERM_FELT; check_op_decoding(&dec_trace, row_idx, inner_join_addr, opcodes::SPAN, 4, 0, 0); row_idx += 1; check_op_decoding_with_imm(&dec_trace, row_idx, first_basic_block_addr, ONE, 1, 3, 0, 1); @@ -1213,15 +1212,15 @@ fn test_syscall_decoding() { row_idx += 1; // starting CALL block for bar - let call_addr = first_basic_block_addr + HASH_CYCLE_LEN_FELT; + let call_addr = first_basic_block_addr + CONTROLLER_ROWS_PER_PERM_FELT; check_op_decoding(&dec_trace, row_idx, inner_join_addr, opcodes::CALL, 0, 0, 0); row_idx += 1; // starting JOIN block inside bar - let bar_join_addr = call_addr + HASH_CYCLE_LEN_FELT; + let bar_join_addr = call_addr + CONTROLLER_ROWS_PER_PERM_FELT; check_op_decoding(&dec_trace, row_idx, call_addr, opcodes::JOIN, 0, 0, 0); row_idx += 1; // starting SPAN block inside bar - let bar_basic_block_addr = bar_join_addr + HASH_CYCLE_LEN_FELT; + let bar_basic_block_addr = bar_join_addr + CONTROLLER_ROWS_PER_PERM_FELT; check_op_decoding(&dec_trace, row_idx, bar_join_addr, opcodes::SPAN, 1, 0, 0); row_idx += 1; check_op_decoding(&dec_trace, row_idx, bar_basic_block_addr, opcodes::MUL, 0, 0, 1); @@ -1230,11 +1229,11 @@ fn test_syscall_decoding() { row_idx += 1; // starting SYSCALL block for bar - let syscall_addr = bar_basic_block_addr + HASH_CYCLE_LEN_FELT; + let syscall_addr = bar_basic_block_addr + CONTROLLER_ROWS_PER_PERM_FELT; check_op_decoding(&dec_trace, row_idx, bar_join_addr, opcodes::SYSCALL, 0, 0, 0); row_idx += 1; // starting SPAN block within syscall - let syscall_basic_block_addr = syscall_addr + HASH_CYCLE_LEN_FELT; + let syscall_basic_block_addr = syscall_addr + CONTROLLER_ROWS_PER_PERM_FELT; check_op_decoding(&dec_trace, row_idx, syscall_addr, opcodes::SPAN, 1, 0, 0); row_idx += 1; check_op_decoding(&dec_trace, row_idx, syscall_basic_block_addr, opcodes::ADD, 0, 0, 1); @@ -1256,7 +1255,7 @@ fn test_syscall_decoding() { row_idx += 1; // starting the last SPAN block - let last_basic_block_addr = syscall_basic_block_addr + HASH_CYCLE_LEN_FELT; + let last_basic_block_addr = syscall_basic_block_addr + CONTROLLER_ROWS_PER_PERM_FELT; check_op_decoding(&dec_trace, row_idx, INIT_ADDR, opcodes::SPAN, 1, 0, 0); row_idx += 1; check_op_decoding(&dec_trace, row_idx, last_basic_block_addr, opcodes::DROP, 0, 0, 1); @@ -1413,7 +1412,7 @@ fn test_dyn_node_decoding() { // end const FOO_ROOT_NODE_ADDR: u64 = 40; - const PUSH_40_OP: Operation = Operation::Push(Felt::new(FOO_ROOT_NODE_ADDR)); + const PUSH_40_OP: Operation = Operation::Push(Felt::new_unchecked(FOO_ROOT_NODE_ADDR)); let mut mast_forest = MastForest::new(); @@ -1465,15 +1464,15 @@ fn test_dyn_node_decoding() { // --- check block address, op_bits, group count, op_index, and in_span columns --------------- check_op_decoding(&trace, 0, ZERO, opcodes::JOIN, 0, 0, 0); // starting inner join - let join_addr = INIT_ADDR + HASH_CYCLE_LEN_FELT; + let join_addr = INIT_ADDR + CONTROLLER_ROWS_PER_PERM_FELT; check_op_decoding(&trace, 1, INIT_ADDR, opcodes::JOIN, 0, 0, 0); // starting first span - let mstorew_basic_block_addr = join_addr + HASH_CYCLE_LEN_FELT; + let mstorew_basic_block_addr = join_addr + CONTROLLER_ROWS_PER_PERM_FELT; check_op_decoding(&trace, 2, join_addr, opcodes::SPAN, 1, 0, 0); check_op_decoding(&trace, 3, mstorew_basic_block_addr, opcodes::MSTOREW, 0, 0, 1); check_op_decoding(&trace, 4, mstorew_basic_block_addr, opcodes::END, 0, 0, 0); // starting second span - let push_basic_block_addr = mstorew_basic_block_addr + HASH_CYCLE_LEN_FELT; + let push_basic_block_addr = mstorew_basic_block_addr + CONTROLLER_ROWS_PER_PERM_FELT; check_op_decoding(&trace, 5, join_addr, opcodes::SPAN, 2, 0, 0); check_op_decoding(&trace, 6, push_basic_block_addr, PUSH_40_OP.op_code(), 1, 0, 1); check_op_decoding(&trace, 7, push_basic_block_addr, opcodes::NOOP, 0, 1, 1); @@ -1483,8 +1482,8 @@ fn test_dyn_node_decoding() { // dyn check_op_decoding(&trace, 10, INIT_ADDR, opcodes::DYN, 0, 0, 0); // starting foo span - let dyn_addr = push_basic_block_addr + HASH_CYCLE_LEN_FELT; - let add_basic_block_addr = dyn_addr + HASH_CYCLE_LEN_FELT; + let dyn_addr = push_basic_block_addr + CONTROLLER_ROWS_PER_PERM_FELT; + let add_basic_block_addr = dyn_addr + CONTROLLER_ROWS_PER_PERM_FELT; check_op_decoding(&trace, 11, dyn_addr, opcodes::SPAN, 2, 0, 0); check_op_decoding_with_imm(&trace, 12, add_basic_block_addr, ONE, 1, 1, 0, 1); check_op_decoding(&trace, 13, add_basic_block_addr, opcodes::ADD, 0, 1, 1); @@ -1576,10 +1575,10 @@ fn set_user_op_helpers_many() { let expected = build_expected_hasher_state(&[ ZERO, ZERO, - Felt::new((check_1 as u16).into()), - Felt::new(((check_1 >> 16) as u16).into()), - Felt::new((check_2 as u16).into()), - Felt::new(((check_2 >> 16) as u16).into()), + Felt::new_unchecked((check_1 as u16).into()), + Felt::new_unchecked(((check_1 >> 16) as u16).into()), + Felt::new_unchecked((check_2 as u16).into()), + Felt::new_unchecked(((check_2 >> 16) as u16).into()), ]); assert_eq!(expected, hasher_state); @@ -1595,21 +1594,20 @@ const MAX_FRAGMENT_SIZE: usize = 1 << 20; /// Builds the trace using FastProcessor and parallel::build_trace, returning the decoder trace /// portion. fn build_trace_helper(stack_inputs: &[u64], program: &Program) -> (DecoderTrace, usize) { - let stack_inputs: Vec = stack_inputs.iter().map(|&v| Felt::new(v)).collect(); + let stack_inputs: Vec = stack_inputs.iter().map(|&v| Felt::new_unchecked(v)).collect(); let processor = FastProcessor::new_with_options( StackInputs::new(&stack_inputs).unwrap(), AdviceInputs::default(), ExecutionOptions::default() .with_core_trace_fragment_size(MAX_FRAGMENT_SIZE) .unwrap(), - ); + ) + .expect("processor advice inputs should fit advice map limits"); let mut host = DefaultHost::default(); host.register_handler(EMIT_EVENT, Arc::new(NoopEventHandler)).unwrap(); - let (execution_output, trace_generation_context) = - processor.execute_for_trace_sync(program, &mut host).unwrap(); - - let trace = build_trace(execution_output, trace_generation_context, program.to_info()).unwrap(); + let trace_inputs = processor.execute_trace_inputs_sync(program, &mut host).unwrap(); + let trace = build_trace(trace_inputs).unwrap(); // The trace_len_summary().main_trace_len() is the actual program row count (before padding) let trace_len = trace.trace_len_summary().main_trace_len(); @@ -1634,13 +1632,12 @@ fn build_call_trace_helper(program: &Program) -> (SystemTrace, DecoderTrace, usi ExecutionOptions::default() .with_core_trace_fragment_size(MAX_FRAGMENT_SIZE) .unwrap(), - ); + ) + .expect("processor advice inputs should fit advice map limits"); let mut host = DefaultHost::default(); - let (execution_output, trace_generation_context) = - processor.execute_for_trace_sync(program, &mut host).unwrap(); - - let trace = build_trace(execution_output, trace_generation_context, program.to_info()).unwrap(); + let trace_inputs = processor.execute_trace_inputs_sync(program, &mut host).unwrap(); + let trace = build_trace(trace_inputs).unwrap(); // The trace_len_summary().main_trace_len() is the actual program row count (before padding) let trace_len = trace.trace_len_summary().main_trace_len(); @@ -1684,13 +1681,21 @@ fn check_op_decoding( assert_eq!(trace[ADDR_COL_IDX][row_idx], addr, "address mismatch"); assert_eq!(expected_opcode, opcode, "opcode mismatch"); - assert_eq!(trace[IN_SPAN_COL_IDX][row_idx], Felt::new(in_span), "in_span mismatch"); + assert_eq!( + trace[IN_SPAN_COL_IDX][row_idx], + Felt::new_unchecked(in_span), + "in_span mismatch" + ); assert_eq!( trace[GROUP_COUNT_COL_IDX][row_idx], - Felt::new(group_count), + Felt::new_unchecked(group_count), "group count mismatch" ); - assert_eq!(trace[OP_INDEX_COL_IDX][row_idx], Felt::new(op_idx), "op index mismatch"); + assert_eq!( + trace[OP_INDEX_COL_IDX][row_idx], + Felt::new_unchecked(op_idx), + "op index mismatch" + ); let expected_batch_flags = if expected_opcode == opcodes::SPAN || expected_opcode == opcodes::RESPAN { @@ -1701,7 +1706,7 @@ fn check_op_decoding( }; for (i, flag_value) in OP_BATCH_FLAGS_RANGE.zip(expected_batch_flags) { - assert_eq!(trace[i][row_idx], flag_value, "op batch flag mismatch at column {}", i); + assert_eq!(trace[i][row_idx], flag_value, "op batch flag mismatch at column {i}"); } // make sure the op bit extra columns for degree reduction are set correctly @@ -1781,7 +1786,7 @@ fn build_op_batch_flags(num_groups: usize) -> [Felt; NUM_OP_BATCH_FLAGS] { use miden_air::trace::FN_HASH_RANGE; -fn get_fn_hash(trace: &SystemTrace, row_idx: usize) -> miden_core::Word { +fn get_fn_hash(trace: &SystemTrace, row_idx: usize) -> Word { let mut result = [ZERO; WORD_SIZE]; // FN_HASH_RANGE is relative to the full trace, but SystemTrace only has system columns // System trace columns are indexed 0..SYS_TRACE_WIDTH, and FN_HASH is columns 2-5 @@ -1809,7 +1814,7 @@ fn get_hasher_state(trace: &DecoderTrace, row_idx: usize) -> [Felt; NUM_HASHER_C result } -fn get_hasher_state1(trace: &DecoderTrace, row_idx: usize) -> miden_core::Word { +fn get_hasher_state1(trace: &DecoderTrace, row_idx: usize) -> Word { let mut result = [ZERO; WORD_SIZE]; for (result, column) in result.iter_mut().zip(trace[HASHER_STATE_RANGE].iter()) { *result = column[row_idx]; @@ -1817,7 +1822,7 @@ fn get_hasher_state1(trace: &DecoderTrace, row_idx: usize) -> miden_core::Word { result.into() } -fn get_hasher_state2(trace: &DecoderTrace, row_idx: usize) -> miden_core::Word { +fn get_hasher_state2(trace: &DecoderTrace, row_idx: usize) -> Word { let mut result = [ZERO; WORD_SIZE]; for (result, column) in result.iter_mut().zip(trace[HASHER_STATE_RANGE].iter().skip(4)) { *result = column[row_idx]; @@ -1848,5 +1853,5 @@ pub fn build_op_group(ops: &[Operation]) -> Felt { i += 1; } assert!(i <= OP_GROUP_SIZE, "too many ops"); - Felt::new(group) + Felt::new_unchecked(group) } diff --git a/processor/src/trace/parallel/mod.rs b/processor/src/trace/parallel/mod.rs index 696e6bc4b9..75eff9dc19 100644 --- a/processor/src/trace/parallel/mod.rs +++ b/processor/src/trace/parallel/mod.rs @@ -4,13 +4,11 @@ use itertools::Itertools; use miden_air::{ Felt, trace::{ - CLK_COL_IDX, CTX_COL_IDX, DECODER_TRACE_OFFSET, DECODER_TRACE_WIDTH, FN_HASH_RANGE, - MIN_TRACE_LEN, MainTrace, PADDED_TRACE_WIDTH, RowIndex, STACK_TRACE_OFFSET, - STACK_TRACE_WIDTH, SYS_TRACE_WIDTH, TRACE_WIDTH, + CLK_COL_IDX, DECODER_TRACE_OFFSET, DECODER_TRACE_WIDTH, MIN_TRACE_LEN, MainTrace, RowIndex, + STACK_TRACE_OFFSET, STACK_TRACE_WIDTH, SYS_TRACE_WIDTH, decoder::{ - ADDR_COL_IDX, GROUP_COUNT_COL_IDX, HASHER_STATE_OFFSET, IN_SPAN_COL_IDX, - NUM_HASHER_COLUMNS, NUM_OP_BATCH_FLAGS, NUM_OP_BITS, OP_BATCH_FLAGS_OFFSET, - OP_BITS_EXTRA_COLS_OFFSET, OP_BITS_OFFSET, OP_INDEX_COL_IDX, + HASHER_STATE_OFFSET, NUM_HASHER_COLUMNS, NUM_OP_BITS, OP_BITS_EXTRA_COLS_OFFSET, + OP_BITS_OFFSET, }, stack::{B0_COL_IDX, B1_COL_IDX, H0_COL_IDX, STACK_TOP_OFFSET}, }, @@ -20,8 +18,7 @@ use miden_core::{ field::batch_inversion_allow_zeros, mast::{MastForest, MastNode}, operations::opcodes, - program::{Kernel, MIN_STACK_DEPTH, ProgramInfo}, - utils::ColMatrix, + program::{Kernel, MIN_STACK_DEPTH}, }; use rayon::prelude::*; use tracing::instrument; @@ -30,11 +27,11 @@ use crate::{ ContextId, ExecutionError, continuation_stack::ContinuationStack, errors::MapExecErrNoCtx, - fast::ExecutionOutput, trace::{ - AuxTraceBuilders, ChipletsLengths, ExecutionTrace, TraceLenSummary, + ChipletsLengths, ExecutionTrace, TraceBuildInputs, TraceLenSummary, parallel::{processor::ReplayProcessor, tracer::CoreTraceGenerationTracer}, range::RangeChecker, + utils::RowMajorTraceWriter, }, }; @@ -47,16 +44,13 @@ pub const CORE_TRACE_WIDTH: usize = SYS_TRACE_WIDTH + DECODER_TRACE_WIDTH + STAC const MAX_TRACE_LEN: usize = 1 << 29; pub(crate) mod core_trace_fragment; -use core_trace_fragment::CoreTraceFragment; mod processor; mod tracer; use super::{ chiplets::Chiplets, - decoder::AuxTraceBuilder as DecoderAuxTraceBuilder, execution_tracer::TraceGenerationContext, - stack::AuxTraceBuilder as StackAuxTraceBuilder, trace_state::{ AceReplay, BitwiseOp, BitwiseReplay, CoreTraceFragmentContext, CoreTraceState, ExecutionReplay, HasherOp, HasherRequestReplay, KernelReplay, MemoryWritesReplay, @@ -71,18 +65,25 @@ mod tests; // ================================================================================================ /// Builds the main trace from the provided trace states in parallel. +/// +/// # Example +/// ``` +/// use miden_assembly::Assembler; +/// use miden_processor::{DefaultHost, FastProcessor, StackInputs}; +/// +/// let program = Assembler::default().assemble_program("begin push.1 drop end").unwrap(); +/// let mut host = DefaultHost::default(); +/// +/// let trace_inputs = FastProcessor::new(StackInputs::default()) +/// .execute_trace_inputs_sync(&program, &mut host) +/// .unwrap(); +/// let trace = miden_processor::trace::build_trace(trace_inputs).unwrap(); +/// +/// assert_eq!(*trace.program_hash(), program.hash()); +/// ``` #[instrument(name = "build_trace", skip_all)] -pub fn build_trace( - execution_output: ExecutionOutput, - trace_generation_context: TraceGenerationContext, - program_info: ProgramInfo, -) -> Result { - build_trace_with_max_len( - execution_output, - trace_generation_context, - program_info, - MAX_TRACE_LEN, - ) +pub fn build_trace(inputs: TraceBuildInputs) -> Result { + build_trace_with_max_len(inputs, MAX_TRACE_LEN) } /// Same as [`build_trace`], but with a custom hard cap. @@ -90,11 +91,21 @@ pub fn build_trace( /// When the trace would go over `max_trace_len`, this returns /// [`ExecutionError::TraceLenExceeded`]. pub fn build_trace_with_max_len( - execution_output: ExecutionOutput, - trace_generation_context: TraceGenerationContext, - program_info: ProgramInfo, + inputs: TraceBuildInputs, max_trace_len: usize, ) -> Result { + let TraceBuildInputs { + trace_output, + trace_generation_context, + program_info, + } = inputs; + + if !trace_output.has_matching_precompile_requests_digest() { + return Err(ExecutionError::Internal( + "trace inputs do not match deferred precompile requests", + )); + } + let TraceGenerationContext { core_trace_contexts, range_checker_replay, @@ -104,6 +115,7 @@ pub fn build_trace_with_max_len( hasher_for_chiplet, ace_replay, fragment_size, + max_stack_depth, } = trace_generation_context; // Before any trace generation, check that the number of core trace rows doesn't exceed the @@ -140,14 +152,14 @@ pub fn build_trace_with_max_len( let range_checker = initialize_range_checker(range_checker_replay, &chiplets); - let mut core_trace_columns = generate_core_trace_columns( + let mut core_trace_data = generate_core_trace_row_major( core_trace_contexts, program_info.kernel().clone(), fragment_size, + max_stack_depth, )?; - // Calculate trace length - let core_trace_len = core_trace_columns[0].len(); + let core_trace_len = core_trace_data.len() / CORE_TRACE_WIDTH; // Get the number of rows for the range checker let range_table_len = range_checker.get_number_range_checker_rows(); @@ -159,47 +171,32 @@ pub fn build_trace_with_max_len( let main_trace_len = compute_main_trace_length(core_trace_len, range_table_len, chiplets.trace_len()); - let ((), (range_checker_trace, chiplets_trace)) = rayon::join( - || pad_trace_columns(&mut core_trace_columns, main_trace_len), + let ((range_checker_trace, chiplets_trace), ()) = rayon::join( || { rayon::join( || range_checker.into_trace_with_table(range_table_len, main_trace_len), || chiplets.into_trace(main_trace_len), ) }, + || pad_core_row_major(&mut core_trace_data, main_trace_len), ); - // Padding to make the number of columns a multiple of 8 i.e., the Poseidon2 permutation rate - let padding_columns = vec![vec![ZERO; main_trace_len]; PADDED_TRACE_WIDTH - TRACE_WIDTH]; - - // Chain all trace columns together - let trace_columns: Vec> = core_trace_columns - .into_iter() - .chain(range_checker_trace.trace) - .chain(chiplets_trace.trace) - .chain(padding_columns) - .collect(); - // Create the MainTrace let main_trace = { let last_program_row = RowIndex::from((core_trace_len as u32).saturating_sub(1)); - let col_matrix = ColMatrix::new(trace_columns); - MainTrace::new(col_matrix, last_program_row) - }; - - // Create aux trace builders - let aux_trace_builders = AuxTraceBuilders { - decoder: DecoderAuxTraceBuilder::default(), - range: range_checker_trace.aux_builder, - chiplets: chiplets_trace.aux_builder, - stack: StackAuxTraceBuilder, + MainTrace::from_parts( + core_trace_data, + chiplets_trace.trace, + range_checker_trace.trace, + main_trace_len, + last_program_row, + ) }; Ok(ExecutionTrace::new_from_parts( program_info, - execution_output, + trace_output, main_trace, - aux_trace_builders, trace_len_summary, )) } @@ -220,14 +217,17 @@ fn compute_main_trace_length( core::cmp::max(trace_len, MIN_TRACE_LEN) } -/// Generates core trace fragments in parallel from the provided trace fragment contexts. -fn generate_core_trace_columns( +/// Generates row-major core trace in parallel from the provided trace fragment contexts. +fn generate_core_trace_row_major( core_trace_contexts: Vec, kernel: Kernel, fragment_size: usize, -) -> Result>, ExecutionError> { - let mut core_trace_columns: Vec> = - vec![vec![ZERO; core_trace_contexts.len() * fragment_size]; CORE_TRACE_WIDTH]; + max_stack_depth: usize, +) -> Result, ExecutionError> { + let num_fragments = core_trace_contexts.len(); + let total_allocated_rows = num_fragments * fragment_size; + + let mut core_trace_data: Vec = vec![ZERO; total_allocated_rows * CORE_TRACE_WIDTH]; // Save the first stack top for initialization let first_stack_top = if let Some(first_context) = core_trace_contexts.first() { @@ -236,15 +236,18 @@ fn generate_core_trace_columns( vec![ZERO; MIN_STACK_DEPTH] }; - let mut fragments = create_fragments_from_trace_columns(&mut core_trace_columns, fragment_size); + let writers: Vec> = core_trace_data + .chunks_exact_mut(fragment_size * CORE_TRACE_WIDTH) + .map(|chunk| RowMajorTraceWriter::new(chunk, CORE_TRACE_WIDTH)) + .collect(); // Build the core trace fragments in parallel let fragment_results: Result, ExecutionError> = core_trace_contexts .into_par_iter() - .zip(fragments.par_iter_mut()) - .map(|(trace_state, fragment)| { + .zip(writers.into_par_iter()) + .map(|(trace_state, writer)| { let (mut processor, mut tracer, mut continuation_stack, mut current_forest) = - split_trace_fragment_context(trace_state, fragment, fragment_size); + split_trace_fragment_context(trace_state, writer, fragment_size, max_stack_depth); processor.execute( &mut continuation_stack, @@ -258,7 +261,6 @@ fn generate_core_trace_columns( .collect(); let fragment_results = fragment_results?; - // Separate fragments, stack_rows, and system_rows let mut stack_rows = Vec::new(); let mut system_rows = Vec::new(); let mut total_core_trace_rows = 0; @@ -271,7 +273,7 @@ fn generate_core_trace_columns( // Fix up stack and system rows fixup_stack_and_system_rows( - &mut core_trace_columns, + &mut core_trace_data, fragment_size, &stack_rows, &system_rows, @@ -282,19 +284,27 @@ fn generate_core_trace_columns( // This must be done after fixup_stack_and_system_rows since that function overwrites the first // row of each fragment with non-inverted values. { - let h0_column = &mut core_trace_columns[STACK_TRACE_OFFSET + H0_COL_IDX]; - h0_column[..total_core_trace_rows] - .par_chunks_mut(fragment_size) - .for_each(batch_inversion_allow_zeros); + let h0_col_offset = STACK_TRACE_OFFSET + H0_COL_IDX; + let w = CORE_TRACE_WIDTH; + core_trace_data[..total_core_trace_rows * w] + .par_chunks_mut(fragment_size * w) + .for_each(|fragment_chunk| { + let num_rows = fragment_chunk.len() / w; + let mut h0_vals: Vec = + (0..num_rows).map(|r| fragment_chunk[r * w + h0_col_offset]).collect(); + batch_inversion_allow_zeros(&mut h0_vals); + for (r, &val) in h0_vals.iter().enumerate() { + fragment_chunk[r * w + h0_col_offset] = val; + } + }); } // Truncate the core trace columns to the actual number of rows written. - for col in core_trace_columns.iter_mut() { - col.truncate(total_core_trace_rows); - } + core_trace_data.truncate(total_core_trace_rows * CORE_TRACE_WIDTH); push_halt_opcode_row( - &mut core_trace_columns, + &mut core_trace_data, + total_core_trace_rows, system_rows.last().ok_or(ExecutionError::Internal( "no trace fragments provided in the trace generation context", ))?, @@ -303,37 +313,7 @@ fn generate_core_trace_columns( ))?, ); - Ok(core_trace_columns) -} - -/// Splits the core trace columns into fragments of the specified size, returning a vector of -/// `CoreTraceFragment`s that each borrow from the original columns. -fn create_fragments_from_trace_columns( - core_trace_columns: &mut [Vec], - fragment_size: usize, -) -> Vec> { - let mut column_chunks: Vec<_> = core_trace_columns - .iter_mut() - .map(|col| col.chunks_exact_mut(fragment_size)) - .collect(); - let mut core_trace_fragments = Vec::new(); - - loop { - let fragment_cols: Vec<&mut [Felt]> = - column_chunks.iter_mut().filter_map(|col_chunk| col_chunk.next()).collect(); - assert!( - fragment_cols.is_empty() || fragment_cols.len() == CORE_TRACE_WIDTH, - "column chunks don't all have the same size" - ); - - if fragment_cols.is_empty() { - return core_trace_fragments; - } else { - core_trace_fragments.push(CoreTraceFragment { - columns: fragment_cols.try_into().expect("fragment has CORE_TRACE_WIDTH columns"), - }); - } - } + Ok(core_trace_data) } /// Initializing the first row of each fragment with the appropriate stack and system state. @@ -343,136 +323,91 @@ fn create_fragments_from_trace_columns( /// the last row of any given fragment cannot be written in parallel, since any given fragment /// filler doesn't have access to the next fragment's first row. fn fixup_stack_and_system_rows( - core_trace_columns: &mut [Vec], + core_trace_data: &mut [Felt], fragment_size: usize, stack_rows: &[[Felt; STACK_TRACE_WIDTH]], system_rows: &[[Felt; SYS_TRACE_WIDTH]], first_stack_top: &[Felt], ) { - const MIN_STACK_DEPTH_FELT: Felt = Felt::new(MIN_STACK_DEPTH as u64); - - let system_state_first_row = [ - ZERO, // clk starts at 0 - ZERO, // ctx starts at 0 (root context) - ZERO, // fn_hash[0] starts as 0 - ZERO, // fn_hash[1] starts as 0 - ZERO, // fn_hash[2] starts as 0 - ZERO, // fn_hash[3] starts as 0 - ]; - - // Initialize the first fragment with first_stack_top + [16, 0, 0] and first_system_state + const MIN_STACK_DEPTH_FELT: Felt = Felt::new_unchecked(MIN_STACK_DEPTH as u64); + let w = CORE_TRACE_WIDTH; + { - // Set system state - for (col_idx, &value) in system_state_first_row.iter().enumerate() { - core_trace_columns[col_idx][0] = value; - } + let row = &mut core_trace_data[..w]; - // Set stack top (16 elements) - // Note: we call `rev()` here because the stack order is reversed in the trace. - // trace: [top, ..., bottom] vs stack: [bottom, ..., top] + // Stack order in the trace is reversed vs `first_stack_top`. for (stack_col_idx, &value) in first_stack_top.iter().rev().enumerate() { - core_trace_columns[STACK_TRACE_OFFSET + STACK_TOP_OFFSET + stack_col_idx][0] = value; + row[STACK_TRACE_OFFSET + STACK_TOP_OFFSET + stack_col_idx] = value; } - // Set stack helpers: [16, 0, 0] - core_trace_columns[STACK_TRACE_OFFSET + B0_COL_IDX][0] = MIN_STACK_DEPTH_FELT; - core_trace_columns[STACK_TRACE_OFFSET + B1_COL_IDX][0] = ZERO; - core_trace_columns[STACK_TRACE_OFFSET + H0_COL_IDX][0] = ZERO; + row[STACK_TRACE_OFFSET + B0_COL_IDX] = MIN_STACK_DEPTH_FELT; + row[STACK_TRACE_OFFSET + B1_COL_IDX] = ZERO; + row[STACK_TRACE_OFFSET + H0_COL_IDX] = ZERO; } - // Determine the starting row indices for each fragment after the first. - // We skip the first due to it already being initialized above. - let fragment_start_row_indices = { - let num_fragments = core_trace_columns[0].len() / fragment_size; + let total_rows = core_trace_data.len() / w; + let num_fragments = total_rows / fragment_size; - (0..).step_by(fragment_size).take(num_fragments).skip(1) - }; + for frag_idx in 1..num_fragments { + let row_idx = frag_idx * fragment_size; + let row_start = row_idx * w; + let system_row = &system_rows[frag_idx - 1]; + let stack_row = &stack_rows[frag_idx - 1]; - // Initialize subsequent fragments with their corresponding rows from the previous fragment - for (row_idx, (system_row, stack_row)) in - fragment_start_row_indices.zip(system_rows.iter().zip(stack_rows.iter())) - { - // Copy the system_row to the first row of this fragment - for (col_idx, &value) in system_row.iter().enumerate() { - core_trace_columns[col_idx][row_idx] = value; - } + core_trace_data[row_start..row_start + SYS_TRACE_WIDTH].copy_from_slice(system_row); - // Copy the stack_row to the first row of this fragment - for (col_idx, &value) in stack_row.iter().enumerate() { - core_trace_columns[STACK_TRACE_OFFSET + col_idx][row_idx] = value; - } + let stack_start = row_start + STACK_TRACE_OFFSET; + core_trace_data[stack_start..stack_start + STACK_TRACE_WIDTH].copy_from_slice(stack_row); } } -/// Appends a row with the HALT opcode to the end of the last fragment. +/// Appends a HALT row (`num_rows_before` is the row count before append). /// /// This ensures that the trace ends with at least one HALT operation, which is necessary to satisfy /// the constraints. fn push_halt_opcode_row( - core_trace_columns: &mut [Vec], + core_trace_data: &mut Vec, + num_rows_before: usize, last_system_state: &[Felt; SYS_TRACE_WIDTH], last_stack_state: &[Felt; STACK_TRACE_WIDTH], ) { + let w = CORE_TRACE_WIDTH; + let mut row = [ZERO; CORE_TRACE_WIDTH]; + // system columns // --------------------------------------------------------------------------------------- - for (col_idx, &value) in last_system_state.iter().enumerate() { - core_trace_columns[col_idx].push(value); - } + row[..SYS_TRACE_WIDTH].copy_from_slice(last_system_state); // stack columns // --------------------------------------------------------------------------------------- - for (col_idx, &value) in last_stack_state.iter().enumerate() { - core_trace_columns[STACK_TRACE_OFFSET + col_idx].push(value); - } - - // decoder columns: padding with final decoder state - // --------------------------------------------------------------------------------------- - // Pad addr trace (decoder block address column) with ZEROs - core_trace_columns[DECODER_TRACE_OFFSET + ADDR_COL_IDX].push(ZERO); + row[STACK_TRACE_OFFSET..STACK_TRACE_OFFSET + STACK_TRACE_WIDTH] + .copy_from_slice(last_stack_state); // Pad op_bits columns with HALT opcode bits let halt_opcode = opcodes::HALT; for bit_idx in 0..NUM_OP_BITS { - let bit_value = Felt::from_u8((halt_opcode >> bit_idx) & 1); - core_trace_columns[DECODER_TRACE_OFFSET + OP_BITS_OFFSET + bit_idx].push(bit_value); + row[DECODER_TRACE_OFFSET + OP_BITS_OFFSET + bit_idx] = + Felt::from_u8((halt_opcode >> bit_idx) & 1); } // Pad hasher state columns (8 columns) // - First 4 columns: copy the last value (to propagate program hash) // - Remaining 4 columns: fill with ZEROs - for hasher_col_idx in 0..NUM_HASHER_COLUMNS { - let col_idx = DECODER_TRACE_OFFSET + HASHER_STATE_OFFSET + hasher_col_idx; - if hasher_col_idx < 4 { - // For first 4 hasher columns, copy the last value to propagate program hash - let last_row_idx = core_trace_columns[col_idx].len() - 1; - let last_hasher_value = core_trace_columns[col_idx][last_row_idx]; - core_trace_columns[col_idx].push(last_hasher_value); - } else { - // For remaining 4 hasher columns, fill with ZEROs - core_trace_columns[col_idx].push(ZERO); + if num_rows_before > 0 { + let last_row_start = (num_rows_before - 1) * w; + // For first 4 hasher columns, copy the last value to propagate program hash + for hasher_col_idx in 0..4 { + let col_idx = DECODER_TRACE_OFFSET + HASHER_STATE_OFFSET + hasher_col_idx; + row[col_idx] = core_trace_data[last_row_start + col_idx]; } } - // Pad in_span column with ZEROs - core_trace_columns[DECODER_TRACE_OFFSET + IN_SPAN_COL_IDX].push(ZERO); - - // Pad group_count column with ZEROs - core_trace_columns[DECODER_TRACE_OFFSET + GROUP_COUNT_COL_IDX].push(ZERO); - - // Pad op_idx column with ZEROs - core_trace_columns[DECODER_TRACE_OFFSET + OP_INDEX_COL_IDX].push(ZERO); - - // Pad op_batch_flags columns (3 columns) with ZEROs - for batch_flag_idx in 0..NUM_OP_BATCH_FLAGS { - let col_idx = DECODER_TRACE_OFFSET + OP_BATCH_FLAGS_OFFSET + batch_flag_idx; - core_trace_columns[col_idx].push(ZERO); - } - // Pad op_bit_extra columns (2 columns) - // - First column: fill with ZEROs (HALT doesn't use this) + // - First column: do nothing (pre-filled with ZEROs, HALT doesn't use this) // - Second column: fill with ONEs (product of two most significant HALT bits, both are 1) - core_trace_columns[DECODER_TRACE_OFFSET + OP_BITS_EXTRA_COLS_OFFSET].push(ZERO); - core_trace_columns[DECODER_TRACE_OFFSET + OP_BITS_EXTRA_COLS_OFFSET + 1].push(ONE); + row[DECODER_TRACE_OFFSET + OP_BITS_EXTRA_COLS_OFFSET + 1] = ONE; + + core_trace_data.extend_from_slice(&row); } /// Initializes the ranger checker from the recorded range checks during execution and returns it. @@ -658,80 +593,48 @@ fn initialize_chiplets( Ok(chiplets) } -fn pad_trace_columns(trace_columns: &mut [Vec], main_trace_len: usize) { - let total_program_rows = trace_columns[0].len(); +/// Pads the core trace to `main_trace_len` rows (HALT template, CLK incremented per row). +fn pad_core_row_major(core_trace_data: &mut Vec, main_trace_len: usize) { + let w = CORE_TRACE_WIDTH; + let total_program_rows = core_trace_data.len() / w; assert!(total_program_rows <= main_trace_len); + assert!(total_program_rows > 0); let num_padding_rows = main_trace_len - total_program_rows; - - // System columns - // ------------------------ - - // Pad CLK trace - fill with index values - for padding_row_idx in 0..num_padding_rows { - trace_columns[CLK_COL_IDX] - .push(Felt::from_u32((total_program_rows + padding_row_idx) as u32)); - } - - // Pad CTX trace - fill with ZEROs (root context) - trace_columns[CTX_COL_IDX].resize(main_trace_len, ZERO); - - // Pad FN_HASH traces (4 columns) - fill with ZEROs as program execution must always end in the - // root context. - for fn_hash_col_idx in FN_HASH_RANGE { - trace_columns[fn_hash_col_idx].resize(main_trace_len, ZERO); + if num_padding_rows == 0 { + return; } + let last_row_start = (total_program_rows - 1) * w; // Decoder columns // ------------------------ - // Pad addr trace (decoder block address column) with ZEROs - trace_columns[DECODER_TRACE_OFFSET + ADDR_COL_IDX].resize(main_trace_len, ZERO); - + let mut template = [ZERO; CORE_TRACE_WIDTH]; // Pad op_bits columns with HALT opcode bits let halt_opcode = opcodes::HALT; for i in 0..NUM_OP_BITS { let bit_value = Felt::from_u8((halt_opcode >> i) & 1); - trace_columns[DECODER_TRACE_OFFSET + OP_BITS_OFFSET + i].resize(main_trace_len, bit_value); + template[DECODER_TRACE_OFFSET + OP_BITS_OFFSET + i] = bit_value; } - // Pad hasher state columns (8 columns) // - First 4 columns: copy the last value (to propagate program hash) // - Remaining 4 columns: fill with ZEROs for i in 0..NUM_HASHER_COLUMNS { let col_idx = DECODER_TRACE_OFFSET + HASHER_STATE_OFFSET + i; - if i < 4 { + template[col_idx] = if i < 4 { // For first 4 hasher columns, copy the last value to propagate program hash // Safety: per our documented safety guarantees, we know that `total_program_rows > 0`, // and row `total_program_rows - 1` is initialized. - let last_hasher_value = trace_columns[col_idx][total_program_rows - 1]; - trace_columns[col_idx].resize(main_trace_len, last_hasher_value); + core_trace_data[last_row_start + col_idx] } else { - // For remaining 4 hasher columns, fill with ZEROs - trace_columns[col_idx].resize(main_trace_len, ZERO); - } - } - - // Pad in_span column with ZEROs - trace_columns[DECODER_TRACE_OFFSET + IN_SPAN_COL_IDX].resize(main_trace_len, ZERO); - - // Pad group_count column with ZEROs - trace_columns[DECODER_TRACE_OFFSET + GROUP_COUNT_COL_IDX].resize(main_trace_len, ZERO); - - // Pad op_idx column with ZEROs - trace_columns[DECODER_TRACE_OFFSET + OP_INDEX_COL_IDX].resize(main_trace_len, ZERO); - - // Pad op_batch_flags columns (3 columns) with ZEROs - for i in 0..NUM_OP_BATCH_FLAGS { - trace_columns[DECODER_TRACE_OFFSET + OP_BATCH_FLAGS_OFFSET + i] - .resize(main_trace_len, ZERO); + ZERO + }; } // Pad op_bit_extra columns (2 columns) - // - First column: fill with ZEROs (HALT doesn't use this) + // - First column: do nothing (filled with ZEROs, HALT doesn't use this) // - Second column: fill with ONEs (product of two most significant HALT bits, both are 1) - trace_columns[DECODER_TRACE_OFFSET + OP_BITS_EXTRA_COLS_OFFSET].resize(main_trace_len, ZERO); - trace_columns[DECODER_TRACE_OFFSET + OP_BITS_EXTRA_COLS_OFFSET + 1].resize(main_trace_len, ONE); + template[DECODER_TRACE_OFFSET + OP_BITS_EXTRA_COLS_OFFSET + 1] = ONE; // Stack columns // ------------------------ @@ -741,17 +644,32 @@ fn pad_trace_columns(trace_columns: &mut [Vec], main_trace_len: usize) { let col_idx = STACK_TRACE_OFFSET + i; // Safety: per our documented safety guarantees, we know that `total_program_rows > 0`, // and row `total_program_rows - 1` is initialized. - let last_stack_value = trace_columns[col_idx][total_program_rows - 1]; - trace_columns[col_idx].resize(main_trace_len, last_stack_value); + template[col_idx] = core_trace_data[last_row_start + col_idx]; } + + // System columns + // ------------------------ + + // Pad CLK trace - fill with index values + + let pad_start = total_program_rows * w; + core_trace_data.resize(pad_start + num_padding_rows * w, ZERO); + core_trace_data[pad_start..] + .par_chunks_mut(w) + .enumerate() + .for_each(|(idx, row)| { + row.copy_from_slice(&template); + row[CLK_COL_IDX] = Felt::from_u32((total_program_rows + idx) as u32); + }); } /// Uses the provided `CoreTraceFragmentContext` to build and return a `ReplayProcessor` and /// `CoreTraceGenerationTracer` that can be used to execute the fragment. fn split_trace_fragment_context<'a>( fragment_context: CoreTraceFragmentContext, - fragment: &'a mut CoreTraceFragment<'a>, + writer: RowMajorTraceWriter<'a, Felt>, fragment_size: usize, + max_stack_depth: usize, ) -> ( ReplayProcessor, CoreTraceGenerationTracer<'a>, @@ -784,10 +702,11 @@ fn split_trace_fragment_context<'a>( memory_reads_replay, hasher_response_replay, mast_forest_resolution_replay, + max_stack_depth, fragment_size.into(), ); let tracer = - CoreTraceGenerationTracer::new(fragment, decoder, block_address_replay, block_stack_replay); + CoreTraceGenerationTracer::new(writer, decoder, block_address_replay, block_stack_replay); (processor, tracer, continuation, initial_mast_forest) } diff --git a/processor/src/trace/parallel/processor.rs b/processor/src/trace/parallel/processor.rs index 2ad9504a1d..e0957f4717 100644 --- a/processor/src/trace/parallel/processor.rs +++ b/processor/src/trace/parallel/processor.rs @@ -16,7 +16,7 @@ use super::super::trace_state::{ MemoryReadsReplay, StackOverflowReplay, StackState, SystemState, }; use crate::{ - BreakReason, ContextId, ExecutionError, Host, Stopper, + BaseHost, BreakReason, ContextId, ExecutionError, Stopper, continuation_stack::{Continuation, ContinuationStack}, errors::OperationError, execution::{ @@ -41,8 +41,8 @@ use crate::{ /// maximum clock cycle, at which point it stops execution (due to the [`ReplayStopper`]). /// /// The replay structures and initial system and stack state are built by the -/// [`crate::execution_tracer::ExecutionTracer`] in conjunction with -/// [`crate::FastProcessor::execute_for_trace`]. +/// [`crate::trace::execution_tracer::ExecutionTracer`] in conjunction with +/// [`crate::FastProcessor::execute_trace_inputs`]. #[derive(Debug)] pub(crate) struct ReplayProcessor { pub system: SystemState, @@ -54,6 +54,10 @@ pub(crate) struct ReplayProcessor { pub hasher_response_replay: HasherResponseReplay, pub mast_forest_resolution_replay: MastForestResolutionReplay, + /// The maximum number of field elements allowed on the operand stack in an active execution + /// context. + pub max_stack_depth: usize, + /// The maximum clock cycle at which this processor should stop execution. pub maximum_clock: RowIndex, } @@ -62,8 +66,8 @@ impl ReplayProcessor { /// Creates a new instance of the [`ReplayProcessor`]. /// /// The parameters are expected to be built by the - /// [`crate::execution_tracer::ExecutionTracer`] when used in conjunction with - /// [`crate::FastProcessor::execute_for_trace`]. + /// [`crate::trace::execution_tracer::ExecutionTracer`] when used in conjunction with + /// [`crate::FastProcessor::execute_trace_inputs`]. pub fn new( initial_system: SystemState, initial_stack: StackState, @@ -73,6 +77,7 @@ impl ReplayProcessor { memory_reads_replay: MemoryReadsReplay, hasher_response_replay: HasherResponseReplay, mast_forest_resolution_replay: MastForestResolutionReplay, + max_stack_depth: usize, num_clocks_to_execute: RowIndex, ) -> Self { let maximum_clock = initial_system.clk + num_clocks_to_execute.as_usize(); @@ -86,6 +91,7 @@ impl ReplayProcessor { memory_reads_replay, hasher_response_replay, mast_forest_resolution_replay, + max_stack_depth, maximum_clock, } } @@ -334,7 +340,13 @@ impl StackInterface for ReplayProcessor { } fn increment_size(&mut self) -> Result<(), ExecutionError> { - const SENTINEL_VALUE: Felt = Felt::new(Felt::ORDER_U64 - 1); + const SENTINEL_VALUE: Felt = Felt::new_unchecked(Felt::ORDER_U64 - 1); + + let depth = self.depth() as usize + 1; + let max = self.max_stack_depth; + if depth > max { + return Err(ExecutionError::StackDepthLimitExceeded { depth, max }); + } // push the last element on the overflow table { @@ -443,7 +455,7 @@ impl Processor for ReplayProcessor { &self, _node_id: MastNodeId, _current_forest: &MastForest, - _host: &mut impl Host, + _host: &mut impl BaseHost, ) -> ControlFlow { // do nothing - we don't execute decorators in this processor ControlFlow::Continue(()) @@ -453,7 +465,7 @@ impl Processor for ReplayProcessor { &self, _node_id: MastNodeId, _current_forest: &MastForest, - _host: &mut impl Host, + _host: &mut impl BaseHost, ) -> ControlFlow { // do nothing - we don't execute decorators in this processor ControlFlow::Continue(()) @@ -464,7 +476,7 @@ impl Processor for ReplayProcessor { _node_id: MastNodeId, _op_idx_in_block: usize, _current_forest: &MastForest, - _host: &mut impl Host, + _host: &mut impl BaseHost, ) -> ControlFlow { // do nothing - we don't execute decorators in this processor ControlFlow::Continue(()) @@ -475,7 +487,7 @@ impl Processor for ReplayProcessor { _basic_block_node: &BasicBlockNode, _node_id: MastNodeId, _current_forest: &Arc, - _host: &mut impl Host, + _host: &mut impl BaseHost, ) -> ControlFlow { // do nothing - we don't execute decorators in this processor ControlFlow::Continue(()) diff --git a/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_01.snap b/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_01.snap index 7bb8930453..0c87d82a44 100644 --- a/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_01.snap +++ b/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_01.snap @@ -2,4 +2,4 @@ source: processor/src/trace/parallel/tests.rs expression: DeterministicTrace(&trace_from_fragments) --- -ExecutionTrace { main_trace: MainTrace { columns: ColMatrix { columns: [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 33, 33, 1, 65, 97, 97, 65, 129, 129, 65, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [11959214793721861949, 35, 0, 11959214793721861949, 5598651459581075585, 34, 0, 5598651459581075585, 8, 0, 3358534066525179769, 4141253528664299662, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273], [11044849754686238278, 0, 1, 11044849754686238278, 7804753453550466256, 0, 65, 7804753453550466256, 0, 65, 9365253138981608257, 4690506171811599662, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113], [5121401795821831283, 0, 0, 5121401795821831283, 17777748786253636403, 0, 0, 17777748786253636403, 0, 0, 4243893038989355703, 7471531250255239926, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602], [3548930057165921670, 0, 0, 3548930057165921670, 9435312778805252724, 0, 0, 9435312778805252724, 0, 0, 2372900269115514267, 16928201695930024468, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552], [4141253528664299662, 0, 0, 0, 3358534066525179769, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [4690506171811599662, 0, 0, 0, 9365253138981608257, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [7471531250255239926, 0, 0, 0, 4243893038989355703, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [16928201695930024468, 0, 0, 0, 2372900269115514267, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 2, 2, 2, 2, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [2, 2, 2, 3, 3, 3, 3, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5], [3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2187, 4374, 6561, 8748, 10935, 13122, 15309, 17496, 19683, 21870, 24057, 26244, 28431, 30618, 32805, 34992, 37179, 39366, 41553, 43740, 45927, 48114, 50301, 52488, 54675, 56862, 59049, 61236, 63423, 64152, 64881, 65124, 65367, 65448, 65529, 65532, 65535, 65535], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [11959214793721861949, 11724006094392302789, 18248966067159614734, 14997726253538871503, 8817287785847965336, 7563891540952433248, 4929456476937587212, 11106581516038722988, 13463537305496517162, 10651632781918411385, 9981866502219755654, 3808288102601471056, 4944845091089272806, 14634692017250583903, 4938442710501308657, 15019076788922615346, 12046519037910030840, 12002553001135911279, 6648246339606676671, 13611030331766854764, 10789879208843041511, 6935978728922643823, 7357466921077553394, 7069639777384924144, 10796630853015597058, 9600475765342551835, 15539063566397429438, 694626006296126791, 10333172214933120836, 3750356548306982137, 12302499613655276109, 6116677274871151273, 35, 350, 5140376474314663948, 5151077999657789073, 16885380856972561696, 4396313619195267116, 5306671686393489364, 7956822041329119795, 17818361021916066381, 14033097286562039884, 7821625366477940937, 16833029552007335772, 8428385927199104618, 1983549081678798610, 9947044966489369966, 13964889898869345750, 11121186483480785338, 9818108804633787874, 4883454229697807874, 7144378034515727713, 4313511094695098159, 3382507463453404844, 1457665291681272839, 12934070243418782738, 1587788786427634902, 8220166220981689928, 1303361134214255144, 15371623169605597371, 17525379757599431696, 15824846667317041360, 8992618192991263654, 11959214793721861949, 5598651459581075585, 644336023812026242, 8962397996249942813, 6385487366266632060, 15421658280337698465, 10565312036761368185, 12143712587225756222, 17266990262046250797, 10756948069435380801, 13737908976648726909, 17026264676264380541, 7825754886390455440, 16047304773895114845, 2736732063999892145, 13983789395651571583, 13470168189302134725, 1436972360246592622, 3363240447642516424, 11460348809250776143, 6982982338498759911, 7828293012926775020, 16631334376547321750, 3136253412904926398, 12922287692448102380, 9001750416037636327, 9873548594897521512, 12362167187142713720, 12998286769972940151, 14911169987988052811, 15100444854223162361, 7731918223558949955, 4141253528664299662, 34, 340, 14059267169109730234, 15746924929585133009, 471985631500087772, 16946433723443173275, 4595135147820207091, 2053997855496151567, 18402496786565368100, 387609426153233273, 8469665991798416914, 7881354678273462636, 11816560343993810599, 9054561158700241520, 7881520773741268125, 1631726701000003728, 9048332065221759951, 11440521690988525934, 11399562976973524004, 5295775600298609171, 16854936978988550164, 4555566089436281371, 8045874719633055695, 11420674364099598202, 11942861833844189240, 15820096964950298640, 4263756598719013378, 7647209523022736387, 13465875315346524402, 17464705757459592393, 14751425303934963720, 5598651459581075585, 8, 80, 16253482711025978099, 16690839578921925157, 11755424915479552417, 17934377671577204140, 15509754874715907467, 6426721221030580337, 11049594146888643723, 14912334368661229147, 17657273147290084056, 9105126057127804171, 13430225876739607206, 3614830725909060912, 14569284676797348998, 4705513459362295944, 424917224365117418, 2835737623710330612, 1964100172858915134, 14896843043547784767, 15482419984058848245, 18437547705335910066, 3162257106529980441, 5297995970636059087, 9661978795293871188, 10128143329575104151, 770728251595531533, 9782965673735423214, 1347942901513492691, 12086966446141742548, 10239457018222882008, 3358534066525179769, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [11044849754686238278, 1065714023649388913, 13590585102940813084, 13603816939964373123, 3385249563011961849, 112536514236739072, 1106452645962150895, 10661905560677698362, 15195193333392427571, 1271054956149481152, 2058632847676165296, 14347073347558249169, 9693072255291891063, 14859780105168189871, 5613057382731574150, 5623448817324608138, 7997999549850776178, 5693866887050036020, 14258871931331407358, 2547009721703928454, 4107508461331672257, 5068231609320466245, 14744046358319534345, 364669749717258, 12759453666142542994, 15815678790725651452, 17691418632824774891, 5288331248614959742, 15557683662491153084, 12209140182523723096, 17383410983291524378, 10392133002436897113, 0, 280, 3739327994472119619, 9855163346786806166, 7272719153662087111, 10277182995998348622, 1557779935350354179, 12598977243905958375, 5757159540459665691, 3544925687412308625, 4454290108164189834, 10562329593955594288, 13328511337210905323, 12548482778894690532, 18303351465385086236, 10622473817836825208, 10391858004672883604, 9244678019206311862, 4905634085052053166, 12384227405658404185, 5878623689014611519, 5361442612107937799, 5203395718336603194, 12505885186641282427, 1657982123928418916, 14802316224598370353, 17429829341045194126, 12187663825740955518, 8834060796313238365, 856881534780831669, 8614320689815223473, 11044849754686238278, 7804753453550466256, 10860407685663036622, 13564283360082851490, 16294057552644672316, 6097183689626534496, 5142791099649335720, 16773516463636660187, 10484693517503369961, 15510754792097734964, 5061563839137660876, 2683909803925041834, 7997738108478273878, 5467755257223357975, 14923583333953915684, 13294611871319191983, 10569196959361608760, 13906642922547692513, 2845656992888419272, 13828314707091500290, 2951356764607352638, 4406743315212729130, 16360792604504139514, 4146070061564888443, 16122102826540224213, 623220105874852865, 3573414414778802861, 7652433402428128865, 1221918952773084874, 9684204095164476815, 17702995505216793489, 10675603116079282076, 4690506171811599662, 0, 272, 15833028045737259664, 379315838026506093, 8581974592770288933, 17442451301272882541, 16579750051606898066, 5674487159031204202, 1541891846645406613, 8209041782659254452, 11966225502153548517, 9096730616149686024, 15618906860941665577, 14146738543483816160, 1119526938685078607, 8710432271010401746, 13282504786121257878, 1858131981777548381, 12223656597910297554, 11826686549344788050, 4472804247539583969, 7599118004690938513, 8277718642341650597, 8460103377465445883, 4568736565087160671, 4933680726900799861, 16645964836945405904, 3680609073412509534, 16176623117443515258, 15081244610133230814, 6410948793715747581, 7804753453550466256, 0, 64, 5751576643258238090, 7830268710878889486, 4868320831660690795, 7042762868047858013, 1028615964620729689, 12270587957620579653, 7267371538363991280, 16125626865182516658, 16950134439933558852, 13427183447069512151, 16117382505273595827, 2222792985740553749, 6517696895688418945, 15516128650333221731, 6357034143715229949, 12960707821770488929, 12451444460344609421, 8786747128188560390, 7634329044629047826, 7741107824034642016, 10975559322169081956, 6007758954686348362, 13971256108093330407, 16868860295450858142, 434120282701603474, 11571634562637977474, 5581285869985960561, 6581368197537384623, 17661012293298952642, 9365253138981608257, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [5121401795821831283, 14666269722110737492, 9590621322847534573, 12932191302609726157, 17918869724719667108, 14326240507681405072, 13067917358519389481, 6815648073963386989, 12352345465945418691, 11261296525909619502, 7689378518287963220, 10584893895333648109, 1804101714182174693, 14360593671180620787, 10105110162171772438, 12398505852787426318, 9692172226490565230, 11964900944541509452, 13385745375779151291, 2217858628481308506, 4621662715196065678, 16647480880251479677, 2589374608845270941, 6809248840077290249, 5129749784462500037, 3245840590205743440, 1922074210551113159, 14644738552419224397, 1598739907793205518, 14526700523373973306, 16517594411296145407, 10134148635057625602, 0, 70, 12197195286374413309, 10427073607190553707, 533047373605454411, 10580779234737523528, 15741781055361060589, 7164202101070087014, 9765809951316535147, 1782081390036413323, 8331595035611127917, 9697859497182376308, 7215394876392616273, 6137901882901182614, 6110992258367195164, 9375455911463634413, 2858682112359859723, 11530371422565574919, 14558386734229473932, 5193748514123930238, 4405616242805307371, 7842663293116063328, 13893940361375217996, 78901366432993105, 3701164965690212066, 3898705475678625899, 4285338701077916719, 1106459456301114152, 8610620161032996227, 1345962755312618543, 5938021660540313570, 5121401795821831283, 17777748786253636403, 12906637371964794674, 15320836901220842229, 9687580313089453282, 4646487368895915296, 14821642720711744364, 8047695355547001029, 10749686584146612549, 2375067891701857361, 12672901980323560015, 13290437551032339902, 11956271016055823946, 12186036345271050649, 10541464479696610661, 5847635127357093482, 2710785219086425297, 13630517663920473907, 16007826574763812566, 8148616449491580734, 458107884374711321, 17819043892120276345, 12445943926803700033, 9955553630570974315, 1387322623565652732, 4082304616394368279, 14346319199041833303, 13848956826511295359, 18438638174686917351, 10202942699122698773, 7439539809669146478, 13477200069544690909, 7471531250255239926, 0, 68, 4457596741936238930, 12529581077675993243, 303974201734355881, 13345903392866909652, 9586267930884889862, 5178817950472007665, 6608322246477847509, 4070515537963445793, 9312477480709452614, 8889792067304111866, 11078425489498232713, 636055309231688517, 8580323529307502020, 12246954824275240956, 13948398243979685168, 14683551372837095812, 4744943918536266830, 10091391594533925883, 11270159100715194202, 16104697287955959682, 2983615207234436698, 10804815118997327370, 139420663301414639, 11145521977996788455, 1535579717520953536, 14470422183799365804, 208588932528011586, 11685358340804306780, 2822178276157738566, 17777748786253636403, 0, 16, 7110029021941723513, 10115409991715085575, 11428668827299215140, 4015039023438705588, 3732466887400149035, 5870841944205588609, 8421627027326523148, 8231214549142439222, 10318470559229280016, 15171283498151438808, 12477430934852872037, 3853779543897991795, 14662750186533371679, 7423988381383082226, 13549468426633458145, 11079168775731474830, 12471207782095033761, 17595325414333663547, 7042468264080735391, 17650115337646869205, 14946074228061446423, 4655654314239637986, 11187552516160183253, 18115881480442018545, 899748567092010447, 14020868337400209874, 15417366235984526759, 3331301994171189600, 15814677761660135474, 4243893038989355703, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [3548930057165921670, 11599182054654736187, 4885112663983886856, 12798756157498171562, 8555258669059245167, 12593636579411959551, 1751015532861688472, 13019009039270359101, 10174923844635011062, 15012513810591484516, 16650490536433444505, 1428273348489524024, 5693483119278040520, 12915240062722269861, 8183805712769991021, 1654142869540548129, 8049024691721442269, 8293446604021081650, 3020690079986249537, 9829005565890494186, 3079504282059755968, 4458043056162108579, 751694847316855704, 17801775841166869486, 9610894500726595609, 11754871869039418305, 3106011472540779982, 5534818333558495963, 6265664197169483681, 9801143914278062154, 2114471287922017076, 12864813595450034552, 0, 70, 8260931550665656557, 11893740670479805498, 1829926574142237762, 1594484475404924132, 6975828079371970675, 6084696993723509491, 9595530987647092729, 15971750173693346214, 11203921366229716627, 4563063455320265667, 11788904100176198733, 5330429808657306820, 7735824317535531109, 320993418766884621, 17183008147454152591, 12480600709687621128, 10013781853527055299, 10535753745093412026, 1262088577389795166, 11216661268945885709, 139199134922249731, 5046795949307964432, 17871092368823791710, 11987849509093694665, 2910522803612995552, 8688806902442064031, 9527459414368740643, 17392858720163980888, 500779098360895522, 3548930057165921670, 9435312778805252724, 12594665258064570664, 7059236745058640735, 9552556216292266897, 4246851900171193724, 14051544049298817271, 11784642469202829877, 7043511220559324099, 2923239127151948080, 3593801949375944745, 12822730519972797871, 8453074578285752653, 9394265395193498181, 2676701676156012803, 9897038047323897370, 13273146919350422539, 8734416771856167315, 10836844319802726945, 164526851958521730, 17195525663426568111, 10288960109250570842, 10886225029528628150, 17237759664671057052, 295310595529849583, 1818311521513634717, 289062595793298208, 5959646737238852401, 13643407453100925757, 9822906574365710103, 17892016949428967969, 9033576496544593982, 16928201695930024468, 0, 68, 8186419089203192999, 15318603549361168513, 7911471416782656233, 14239435248344205979, 2133634484310994464, 8097913535946941412, 113263425049039362, 248987352426060274, 10939256691674299939, 17358468187481791647, 12423884741952977957, 56617284060232395, 1868806426895026968, 222259776750343599, 15059516987340721081, 8741184015917561905, 2066403566980848459, 3696239822839219697, 15367181090448289261, 8349149003644261348, 10280553347796952088, 7301079719327054003, 6885778115777578237, 12504375544103392076, 9288443086735636960, 4503182154932177101, 17461402434481489861, 10152174670869705735, 6117144343302310887, 9435312778805252724, 0, 16, 3208043314804619251, 6920597847411412414, 17985619796195836408, 11907191178709112742, 16377455862733420451, 15572876043608056600, 9466912758182965715, 17480763791598773801, 15029113851915312964, 1953587265841775225, 7175742902791404624, 6820764940134875350, 16069841829669607101, 15548451706938320654, 11760680638795846495, 1560700914733041660, 762367990279432470, 2603436428456411224, 6200990949184863170, 11673627333152839295, 7804486006334068097, 1006207264024395366, 11193609705356653459, 5704515878100803393, 14918729158665343812, 10658508130485449873, 380737719356524599, 12870561906904032245, 6984680585936259437, 2372900269115514267, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [4141253528664299662, 7535227198536906721, 13157788436891508553, 12242844110543519517, 14956019708245712821, 10570950564294000321, 17480412968160901529, 4150746739043008211, 7668476027270202579, 16656590512852921222, 6540695355644326389, 2062361183656478066, 6992883056491326847, 11699589910980507023, 15900656105857229467, 6696171278998449226, 13168835889056955304, 12256719005104851107, 3837048139847179361, 3160764979077625659, 260627379830442974, 11253217769249016375, 12385338833843346575, 13819086418675951632, 685348230246056503, 8109480959271599370, 15257531885396120213, 3680188101282186784, 7206583663178666402, 18199569338713260127, 11998802949255523211, 8214490973132607971, 0, 175, 18424611315455665672, 8660762125905589832, 17127340306827455573, 2784948507084849054, 3893738632331286853, 3285198522433859694, 8347633294012310580, 1716176048133035367, 17973624234065242957, 16459952452199547026, 16037889673287918578, 10274502539576810724, 8768898256362256567, 9056849240288317429, 5470591020023050699, 4574304056007112162, 8410472682472513857, 16137982984163538210, 17597264692962831013, 15736663856375030006, 17727370521374436910, 8474944897236640626, 637885636686826709, 14676123610051724022, 6045066589466757281, 14903105088638349433, 9178488780906183949, 572497659895507109, 14724337405152116499, 12030454825456445148, 3358534066525179769, 2539641719046213740, 14597771066871753553, 5977340097238271765, 7707653349895837404, 750410385838623118, 17202523259145509542, 9826125054086633997, 10704182720413467090, 14182542421389276936, 1208823412034618259, 17538680525690853062, 16486686521840942874, 14299802542131844724, 4141923705337186001, 15072716099695791702, 13709137995402237101, 1759841724041652075, 8081765454289246423, 8476759162841806182, 8627241529856509742, 4347076460454100596, 1495131601817209461, 626496362396505138, 12905076793136293016, 7898562997016536225, 4051444777808751499, 10985547818594749595, 14333518987829918669, 17843924827166978222, 10647867748676596435, 8523492539397344614, 0, 170, 13502722698945446624, 10582364865337924932, 8264438684589566467, 7775924941916048886, 7506941477585260226, 13559643900430805558, 14624701183045087851, 16810498729905278091, 3617722030424605287, 12209401598010007429, 14622001497128700788, 7124074456411373593, 11046353624103181594, 16506916834573600874, 2763493011778369288, 4381652925229768341, 9935322272824673857, 864619558035150967, 1868429356172715569, 6908757966622831414, 14123318794287563052, 4877497612363750655, 2105400693641679480, 8941132592749341698, 12124737918817624189, 15847492668873519030, 7578220797847929864, 9410406960468072857, 4811333449307081983, 5256913258227871425, 0, 40, 18130890293586930078, 18252951749527557342, 4460903658820341507, 859505755654562117, 5961685480015386121, 12134776249586726543, 11174658189737631113, 18385152961050631924, 9881471501704199804, 9636744945302995714, 12323181865658998064, 14903454669611502952, 1490539036394497080, 11688514875590095153, 16093513520259190726, 7731471377060742735, 5247500963110975116, 5269361527156951110, 13733877647296302634, 11865469401112846356, 7643242142337524006, 15572658687280648106, 9345628789826937825, 3291248301730279223, 16808111015808513609, 16274730253017522022, 12243901590027926887, 6559275936659510680, 17224785255700525855, 1390310476158884261, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [4690506171811599662, 2737440767612572473, 11521696315622895181, 1112809250875085271, 12021362864117640865, 18151871077622688335, 9897941768997576086, 4026157395886157229, 10359334248806725290, 4146117248162417047, 17246235733851217304, 10866279963718241802, 11383920474028743559, 6348426772268882755, 4713833248608103744, 10090565134847963788, 10865777585291872469, 3995119331147317584, 1039809878544438546, 9281899713308431529, 894389675194381154, 14912731377283108791, 2518971765323930332, 14554524254203776994, 14524699810240327783, 2026981110418907406, 12320900210322448034, 6520538036510347086, 6198597980723382916, 7473328648066901490, 1026110231435118088, 4584625016228750380, 0, 140, 8710514240711102938, 3087828367487460915, 8550318671602553781, 4930631020140393563, 1021301660011942544, 3073595205709678428, 2828555514110129215, 4454529496924239314, 4850807088481902893, 8327420331623942113, 5731477673914408028, 9865807300278005609, 453077352291409865, 12820055819705071946, 17847152132518767621, 8150970536507693114, 4592469706020729085, 8591936306357206220, 9734673703119078710, 11269239869586993393, 13212629127542823790, 8294118794714299790, 18005585695632222469, 5850018245424229562, 3823107055299292863, 11302847087529014346, 6890858608219888881, 10680339138669917038, 9892588909603237147, 14743087584632180635, 9365253138981608257, 9113412038486870528, 12891440258701617795, 10322300200196682981, 17715988767376665360, 12529577197437921705, 6552591582707442459, 4758921283651545108, 2473371596923514175, 4508995650639757747, 8913958469585669066, 3583695132258196536, 12251718655020006238, 17851199719794441593, 8176730118494162678, 9396959786745583185, 3556146813643685764, 10220987366360269577, 875353240064010198, 3230914141298165225, 12763806424191572386, 13303243524843396217, 6289147021348404787, 12692366118122891151, 8285789034090944076, 14023237997722359599, 17743718519616976296, 14731468822320978999, 2543793480285047170, 17021793130360212806, 11915740833798992018, 13282343245327117747, 0, 136, 16864340361327671903, 2636070061904000825, 1539270658943308645, 8663103496298937284, 797155414931197277, 7929222985705309752, 5418421295167202847, 16520350781038259800, 11697635461652845634, 10326065236143981873, 4672452207442160023, 9236109584144478544, 2355139499180822246, 7782053902926446231, 2620978815438101291, 3668923621194401622, 246363526423127035, 10353083146864436335, 3430895131654614161, 12564495361718767183, 4982750975383300564, 14559648290526166949, 6242143746593499460, 11140632426269699329, 3028234720115016827, 6653412960111738263, 17564919688262005304, 284282844772359316, 7938696543505248162, 17100537000217132265, 0, 32, 10452764368937945515, 6969997263492352670, 15570786589164252178, 16136993048454358354, 16378352067056606124, 11747573379431147483, 12296464969648251345, 8155132212936940581, 2470200969414032680, 18126939303114916528, 16736276280592238734, 15549342782445497049, 9033882039108268313, 5121596298161079296, 14336897502470956191, 6301009824137139871, 16614860627935231068, 10383378433371415142, 10330363517752279308, 10937466001850040595, 16305844076412050396, 7189713532379018536, 7568236447715590536, 10805187342082326609, 7424874700566577356, 13861219118264849665, 7052270251739242825, 17586339544079318164, 14071176523136369481, 12282546735285148319, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [7471531250255239926, 957106104872100553, 8426354436255247671, 14696972132215546141, 16692922442306646447, 8874979589420119367, 875297058086066175, 17626443192502070146, 10085921208436197132, 7288928467232887868, 17085775336106720298, 2718833903563323199, 7078253443595954934, 13309456694532316914, 5975284652827254996, 4866716465241707365, 9487238857935659569, 17181552195820469706, 8127338887120154462, 11933049108483241248, 179996691661177615, 3374573212837962242, 4025363669025839136, 8885320358009245035, 7362303317308040642, 10721260413929615658, 11637817792474845578, 13461475369693849006, 10395653141429564317, 12120812098909026742, 14623333492544617469, 7448701979965755247, 0, 35, 13745802786964652170, 10807941376803729065, 11967821891194701924, 2468953284439066013, 14003176497724809129, 4195286142867428231, 16235476345222743147, 16311400958482462738, 1275416753317277649, 7827742839669371295, 15144275993610658984, 17059326124115937407, 1609065912712094319, 1953375973007785317, 4662315141802736133, 2648588484571064605, 10314135606564051297, 17798108062832293769, 17976467869316326526, 10521545375054979384, 5478438738361095924, 4079016485765258670, 6409557376003924138, 9751499496869829327, 17630322765550216924, 17889552338200421323, 13578840114630190185, 2119568863265536467, 8158174533637128652, 804908825530740834, 4243893038989355703, 8922317147540258088, 7976296880270099068, 279851189829800217, 1629791578136936575, 9250281207577685312, 16325213226883592903, 14233424972710589898, 1150752289248225959, 13420723953151700222, 13103867886586495168, 10246367578585743447, 9749713722270402553, 17275110341684860619, 6783090395235209659, 17969645096023124419, 4121935965911645088, 4288337514646499477, 7084144568226748800, 6029442255508906403, 10924085850925815890, 8369007777733896382, 8232780781393445755, 9118931780992437842, 3679317166559661163, 5036788400317364302, 4470738656604083779, 8115411932938273702, 6422638912707970220, 16012433424607683700, 6326608805282345628, 16657610054734022844, 0, 34, 6567391571487826395, 5204289601743072522, 3431536436519013066, 18098398151169262506, 7669185665212226764, 5455708142000104069, 9902960937688969164, 16439153306838678161, 9116909952501731628, 259487815978835763, 11207509487307725092, 13598970521047669184, 13294225392413433281, 17974846784869714720, 1531979193630020279, 8742633689618768661, 12951219828222672250, 1272063647175062154, 1015593294205135440, 1601391529726059156, 6891640398393941397, 9120291006888379304, 10474372360890458437, 5584077426972546342, 6680864214558642932, 2419346771478639592, 9600963709893327666, 7733975108380115257, 3435995547523177385, 10362535235958450122, 0, 8, 9114363797835460134, 5446076396314160376, 12863008906537145423, 10008421878335836436, 9952321233871043669, 12872379155893703237, 7266552182027361169, 1266036355585216796, 2621902104176569009, 8791105532651972211, 6351975813451610601, 11821139808280113179, 11281913023757770338, 3277134497757048289, 13219080767636598429, 10181825490691565485, 2766637533497216499, 5527857141123489970, 8463471033597650592, 16863468430858262436, 4521466714741486225, 2112404415880305855, 6776665887355979100, 4283028800297139078, 17448147405455891940, 2672696094870261596, 654959311657763753, 15404879372302137522, 458610335793450516, 11708893791522292939, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [16928201695930024468, 13316048579382449360, 2713831240363482992, 17933860786448377030, 12140276230850597158, 1606372307127613897, 3188770991194636906, 14438001176756564964, 16448487398099419345, 9918214746375746352, 18110219924373985313, 7493603045769629260, 745957266720787386, 208949971747081929, 17140128915513269672, 10592811345979549626, 17407028959895176066, 8512417397041248917, 7287596669447050848, 9095813259348077504, 12193512270869861572, 13556169973586801756, 14690878971952130243, 3851130964131028937, 5140683189548028765, 4356298339163646871, 3363935513258073239, 6101475308358905031, 15929576060773374367, 9238706649514600628, 6772806779673451094, 12849137552501188796, 0, 35, 6548375970637655697, 12966884757436832352, 8617173377985249829, 14369692677316723198, 7988737883003214917, 199454479220437296, 16488861457711574881, 7336046662918934307, 15030081564191678849, 2458019052558535305, 3971043898284956979, 169011925839529283, 247484960726213991, 11098826393785027594, 6337173918784738400, 11606973446973456199, 1842388487495083111, 3843434841734991971, 17692030742991723124, 11518912608009699621, 12820002738657995668, 7568893198878892067, 7859209399338136233, 14455157706277846466, 4973217863350539721, 16132832657712782617, 18189457662137520245, 17447468029829501860, 5366612376176920228, 15978537433270792071, 2372900269115514267, 7638869850317184912, 9869196225863171361, 6918765821995287137, 1369739146488483681, 1289422996858358477, 3642389184556912711, 3891108637149977246, 15140294830527696728, 5009228872137272209, 7715172072574760928, 1421290680685617214, 14403164863632503479, 10265245098090210711, 7174788237318142123, 6381427654975252574, 7602994898079563251, 15302356383007635999, 15586805931977175637, 18437766594761332377, 11240603387110570141, 15093603048951386807, 7035853470370737247, 1835696655621331722, 8169021299801629244, 14781376510855187932, 9409022898528060781, 10695296899698374978, 17063170837522968299, 3702512996340883595, 2628586313169132635, 10245076951199455280, 0, 34, 13313027311321423572, 9192034959170904294, 14701500658652215925, 3854356596578551734, 5718692378574184090, 17501390179378757090, 8526809416150489728, 6507550884061463423, 7814960517829781662, 2939637999200097803, 780950602796552578, 4118107554308446430, 8555475415255527439, 14714307830357033751, 15614510648083677054, 17171454789201612359, 15897739400545916002, 5578273266312075011, 10191353484336583572, 2940473809902205523, 14962502826274181007, 2115641271859045975, 7064236544478437245, 10824702985925635247, 12931918488324919856, 8429882718924461151, 11244752067809188397, 2111913529644288504, 6112640616610282754, 6599190416745833044, 0, 8, 6104172690014223231, 3119855977255645286, 2700229040680838768, 4228220371303630837, 12976691418076017877, 15391527008624099592, 15522155400452634037, 17655908650961725957, 5157987610310047621, 13664486701019622043, 12908699189677656287, 14840926611057477527, 6092037682822283700, 15181448373122947619, 2083722204849270202, 1893419523737526751, 11329911669537538562, 12331432886354737271, 9636585409664050258, 5131588463040403759, 10248116973079783912, 2136665268102207704, 17448444978654544666, 11945433761064128885, 4462464721020457233, 17579935132869425842, 7098417589530391109, 15343623253038912080, 7762335122892638892, 10310226363807226654, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 6419744430976403982, 3447697248540225808, 10044864192452182412, 7058340312231756422, 11424300291678555912, 15031231631039778878, 2669622821021436503, 14911345319478414189, 5914533097243323078, 8371470863620210867, 2533220603754125879, 14376937495131853153, 8539659581227571270, 10662827764253743390, 17166726581641984506, 11280387487817815677, 15742094452256624479, 8912948444301774054, 14703675557715690630, 7196421200244503747, 2515843481723679483, 9280041324473036738, 9451078778045131871, 18129703980105207203, 16085683684539047157, 7181119043238227738, 17090649967623261857, 7951988307407900542, 13025686387588160039, 10950281275289859162, 677561570464011141, 0, 175, 14697063750404833549, 5887611756450648665, 4390455106880745190, 12605921110673978057, 3909247147397492340, 9689010753727301488, 9581721436999738864, 16354053311311796732, 7989095941327388146, 15260860572373553109, 9500012181060025316, 18019646022591970627, 9649122197052954943, 2900327270128075, 14086650041861556859, 3689293233291605771, 13498186418617526222, 15088669255793884845, 8596529378407272747, 16168113363552219541, 15854163065073538636, 9399437128660150397, 7202708241142113012, 14757940169676147698, 6949143047896273946, 15186394770637938057, 3979322074577621357, 5317810489943751161, 13663234493876910991, 12876040067831025585, 0, 1061325914286080806, 16723391107514202352, 9754566926160679801, 12819365845000407643, 9991664912056245947, 9847657839340877601, 9218945951971409528, 17937489760159731410, 6898590972078729604, 8642762389205548177, 5286310130352931456, 3192683419970405684, 7291895670920337828, 9471733465477014135, 5916843872480033571, 15161469576939421414, 10084364066798723299, 8948842015142234828, 11061922567205483533, 4596163035992380964, 16524077373781301709, 3948990276587207306, 17492638446874188318, 14193096602587779175, 7319641733964937743, 8739778943225234768, 5782681438096211376, 11891715600478694595, 5580010029452924235, 1761218265234642115, 11605105809497505058, 0, 170, 946461078672821334, 16281780351388912901, 2935418863412242354, 14713353090133347394, 1791207195906381248, 1092415958346704160, 8319785044806982194, 11182822967626325795, 16809587424157045315, 2244733962249620937, 16303706249485479712, 845878992383212753, 5921002467687226204, 4434027484725189444, 15967620315457307754, 17386925554974145101, 13158427748622481094, 6196246176234489731, 8582026933349467190, 611778401982756412, 16288180016347524015, 16434619985909351985, 1145514137751095479, 5160952971387430527, 8451565207539691282, 5967893180517848182, 7714774968702541161, 14978023560208702638, 18014742166879778909, 5450578834500306709, 0, 40, 1560947813056021755, 6935064976442414148, 9999441144135002932, 10354700837586583171, 6040781227937012106, 4698117391978117444, 4735711626023545756, 11217844833019453026, 3130590714605394722, 2809204122464618686, 10935232469327759448, 18335893537613898174, 10868401885487323501, 15799177281014635734, 17187052562019754838, 4027411046406207040, 11879721967266924677, 3613659344771632047, 1846469577394958972, 14668357323201408029, 14939045883642543835, 2885718226990976376, 4969257074069595075, 10824274197210729467, 13212275138420405274, 10563919532671437398, 12234598862193668129, 14653607410806008848, 2498958194485300229, 3512215170452429648, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [87, 7416632953558849265, 17594999963544064287, 12743397052876062010, 16793498368204377302, 11520998711037823747, 7102906674716336449, 5413886510672963560, 1869688954383701255, 2779549538868222645, 2240230247124034957, 1133217540165824186, 15083342046854437444, 16448963681750067902, 1360814798563974092, 10806646336881251745, 7783394201341070849, 3435210620583322514, 6672417563265002316, 8185266593862172618, 11336008056438129603, 11885558902631228328, 2880459223621017435, 5581858847773628805, 5641110601962994164, 11691200044195449244, 18247981403702122132, 5440276046356043250, 17479206923733922587, 8202861560648587401, 6069495537705640, 6253001344519856608, 0, 140, 11345515238018223131, 2946171615755015016, 10503353101665672276, 15589073729373314001, 13718116689255862703, 4274061922998936105, 6661690865570834646, 2350105156607890338, 11848223112496568240, 575220748088635860, 14463381670682493434, 6239522938056088373, 5225807468457901577, 5430077683379130363, 2608178208619376380, 17198482303941924567, 3796686867992995838, 13906033972215271083, 16841535128816011006, 3862251867639640526, 2035529259540079632, 9756998763275612257, 1710277459229142915, 16231968704214022931, 11354865285620231158, 2004972393153402371, 12504370868862613699, 7450671729747196018, 11869180945716319347, 10995045216798627929, 87, 6657939908049969746, 18076794411180476280, 205142327694293412, 16544719539062425474, 2678151302770396230, 4629674588184701527, 4756922096433783348, 6601966437239502772, 11244080601096335225, 6649199742327408095, 1784797448120793789, 14231596045603977911, 4619347748135638900, 670946413872621524, 9168306336221214796, 2712598845436515249, 4708938355998137236, 12719783652674704119, 17571986815953822221, 10053747442208350154, 9541903258826307302, 16365489308483642755, 9446845463763503898, 12491857199480659906, 8850778807446174241, 10733909952514206486, 15234998934151879467, 9571493212894702614, 4393284534245665333, 7926227231583287531, 15430453444364458588, 0, 136, 10841411014448826746, 10924324070009278511, 4390811061445162297, 10665404042695900090, 11148796663006115025, 16584177158338467512, 15369021590994653978, 13860609558593370204, 3837193053542887320, 7652640894347806080, 683219561750944695, 4006536353767232614, 4047796662675347846, 1149920536684206111, 1698301089048909092, 6224704259817574157, 4439284651749775339, 16476516570230330168, 10834199646006576067, 16282481854654492091, 6659294847490221927, 12242894720083399562, 7156478509869523727, 9996508607909856718, 17045153176928915002, 4097937233975335255, 13892339685592049122, 3881709886225480466, 10446442293007407525, 1539493896147927159, 0, 32, 9302012295643728416, 424328237663665361, 17748121622218558811, 6681769685034042719, 10907932526941371789, 14996603190997478665, 13982878080104642188, 3336783822228111865, 7403528606603453519, 7309352233404946366, 11509327586943808925, 6803943428138467537, 12870260590513220077, 3798257798625653324, 15652192157997003684, 8260391000410661595, 9099897743400681933, 16067207775248165408, 7640841583197908852, 16739199083410292994, 1998275509994500625, 10688417071827877337, 16160081185811655577, 2725954513011781037, 3040692668058239811, 15097072321276989567, 7813293313258815644, 15261763399945716285, 2258772319189190202, 6756061023037720295, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 11356706632132474470, 2358849405739495388, 8252049255686697090, 1550389821256969487, 6750324157015485381, 604741251465830172, 17676294546444101345, 1421326959851451806, 16490161619089770695, 7767675836373196892, 2198451335895548750, 14472480345778371117, 4528209626244081470, 18204665069024529476, 11966881683411871471, 15889763672746314463, 4160946893194356300, 15047282824503396386, 16648027271626045172, 17326536692088196432, 13311336675659068295, 10920522191757572329, 6554220297842488502, 5028468445182081313, 10053567802826673403, 9039178885558385498, 8545236135635685226, 10069135081496908116, 4751010459333335795, 15084214110056267454, 1607381721595724854, 0, 35, 809326793687057962, 13043350793597586415, 3445826420292422918, 15832983954926147440, 13006453459232495210, 6690439008924914176, 14925506152061129229, 7686554446337042304, 1386567235067272296, 18336554683084823555, 13461715534861002386, 6450595223101539903, 16347954830762298502, 15583422763378897975, 5985288376766257087, 9084874200639035992, 17711582701900015634, 865108223448999540, 16640836306313302925, 2841702098020816448, 10239653893689953177, 16135446855619161594, 14211710812292436619, 4482236293883987028, 7541264006304433571, 12592463296509852982, 9966350562627740919, 10317133817946706776, 2674823044861603020, 8201489714833429310, 0, 13425232862973212709, 7318735608001207147, 2870457579998112786, 8435616415860238896, 196396598284240198, 15030346739460637318, 11783104108423427368, 6893308270453759366, 1186051241082879855, 5410658890137048512, 10911572374110245694, 3704568930318998699, 15085014690020902180, 10285804549311169869, 9214751878561195125, 10949533612894576728, 4512217941150685160, 3355391310977906543, 2378656381642692957, 1495035938694254211, 1628981830846711491, 1657549910326762005, 2033490153416681362, 15310508516972009936, 9202695474221693202, 2288182338723422425, 1229088437375601266, 2390601416181918661, 7303237900174645421, 2453521579710367516, 11406074192870264875, 0, 34, 8422262931452347509, 13885570107923725144, 235244799151795110, 17975760300270072840, 21645088928215528, 13378438338434245321, 11260622121353286786, 13136688320626048612, 17881560939567828117, 16601834208041636644, 2350599886583381643, 3676641047171560447, 2612703737764640459, 6165448709088710825, 9702561415374819789, 14396227383672448392, 2871975363154349452, 13084396173640101372, 15953404371899770169, 14377272925308367884, 5291380804534138171, 576711179775643850, 11287382459948400014, 9324129603955102500, 10503620158827014837, 6130889055094603538, 5442709211693844142, 2968563472347562608, 10528964699829495885, 358459342719025633, 0, 8, 7519454690376123692, 7627104070861575574, 17604686071836489236, 14277148259130460564, 8312218486680706135, 8395439642754559152, 17307771294890409643, 9298206908486537717, 3027629924013931359, 2933551330348935458, 1450485994192951386, 8585052201707081835, 10624425952582111111, 16773523322999621677, 13337622149287916761, 17874287708894504070, 14164897610403484003, 11216401648549709020, 911970190394256131, 3202853507803349037, 14616902435260689479, 14924823153427050614, 4881022900440414264, 9723366934152472594, 16335725686098559697, 8087897843744270993, 11437013713086863200, 7627258546495067733, 18044191572661655945, 16490279521751489469, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 2156162188207533858, 1652445317709542069, 9710174156710538584, 3687395741963426550, 18198216273587752711, 1838753262326158154, 17157485573110166020, 15957089851173678739, 18249894041959305436, 4865827667628828701, 13002397426121818840, 2056311725258650732, 10926587116602338049, 5861292583325103670, 7147743639536563769, 17793738412709433040, 7010314501210327907, 14741490826925726048, 11016711855241315519, 2381487671462803904, 2201441872551078055, 12296957712116650503, 10199495361398762521, 17597473646777692775, 8352767355705497400, 6369472266524549650, 3523683736119512174, 16946656379378628774, 5583968744804760129, 12827986113643603592, 11319208922614274152, 0, 35, 8353595870573531205, 2540346347559199959, 15905617593867500462, 15206447585345432360, 9587574406720228419, 13962042635878587483, 12647708209366536631, 5660351957917038651, 2686094179381860856, 6724344971643611017, 7730484900119681480, 17496531794766962548, 9582673736768413052, 5090730089788327507, 16316669523444224399, 15180713067843619854, 3366467649642622206, 3781233238795801028, 5780865724855930643, 4603482683901152330, 6284610136599748777, 5490240700537832368, 3009248399805477246, 6182266765615504635, 10157260196426992044, 11702418701530435943, 16215780421699068990, 12595602375369553246, 14007226435224111078, 13655239822733173662, 0, 595597012989057201, 17139781905758323226, 3995355680811906625, 8414041561969840147, 6056580584982795553, 2275917558381110739, 1213850852525589804, 12621557274381914353, 8183226668403108743, 3186362008740620984, 13198139370097152194, 2958463820434100861, 6175120933459995736, 605479756900086202, 9130478176053651155, 5046313161028350213, 6401077792884902899, 6554586936759661283, 17551059730726512380, 4149682069832499543, 18155642743356144121, 7818664772328532886, 10601663807010949823, 13981378283476746869, 8981534628391844134, 12415014162240143946, 12267765271876857143, 16738431774071597762, 639602489095149029, 13916262071165774844, 6409620289494267476, 0, 34, 9168769012195838974, 8757246072351383525, 15819587373362991575, 6330331124468459419, 17594449485955496857, 5094615699180819390, 10468588157075103568, 17500241837984025274, 12590769989805218521, 10257339134394161483, 6020533408585278677, 9887559600989616103, 17174772404727048357, 8260989830322406645, 15331894718426588199, 13817494132369433237, 7270842089806116389, 14464987003178196376, 12856235623981550070, 6446968933011398838, 4625298604721424009, 7537989708572581312, 8773062848621227780, 7997392847552644982, 12295542285792207282, 2236820296563710856, 6411496154095679628, 96618257160083950, 2708395562256972928, 13820925760592258770, 0, 8, 17781582622500481192, 12847902632736061277, 12021499907877242591, 16751519355106661703, 9062087890172095618, 3834953580385337540, 2969703856153678454, 11604562295556139307, 10447912046373566534, 12987934619706800857, 12352596220492768030, 14816150974992525275, 2172600571554701126, 18086375044546604023, 16313093185369681775, 14997664071320688070, 347950016295486690, 9206182676441692601, 3566552483989599402, 4925983231752336365, 1728701557101400581, 7087476601458867917, 9759961360999781392, 12569092891286895547, 14206292953735333262, 16422952955631166803, 6294107725304445883, 9537940691512987143, 15535806100011306333, 7080716573279759555, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] }, last_program_row: RowIndex(13) }, program_info: ProgramInfo { program_hash: Word([6116677274871151273, 10392133002436897113, 10134148635057625602, 12864813595450034552]), kernel: Kernel([]) }, stack_outputs: StackOutputs { elements: [0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, merkle_store_nodes: {Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571]): (Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350]), Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350])), Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484]): (Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693]), Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693])), Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781]): (Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874]), Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874])), Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171]): (Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361]), Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361])), Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815]): (Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305]), Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305])), Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689]): (Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195]), Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195])), Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362]): (Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063]), Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063])), Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848]): (Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661]), Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661])), Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352]): (Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829]), Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829])), Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444]): (Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223]), Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223])), Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386]): (Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388]), Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388])), Word([13190842942618341421, 17548956981569849952, 15418963848144418856, 730733050713174879]): (Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144]), Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144])), Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874]): (Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675]), Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675])), Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594]): (Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115]), Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115])), Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809]): (Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257]), Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257])), Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777]): (Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555]), Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555])), Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509]): (Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882]), Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882])), Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725]): (Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979]), Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979])), Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134]): (Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987]), Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987])), Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828]): (Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910]), Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910])), Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830]): (Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054]), Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054])), Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228]): (Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742]), Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742])), Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443]): (Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928]), Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928])), Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643]): (Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979]), Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979])), Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758]): (Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106]), Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106])), Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580]): (Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594]), Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594])), Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765]): (Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045]), Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045])), Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766]): (Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281]), Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281])), Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385]): (Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828]), Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828])), Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579]): (Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171]), Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171])), Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212]): (Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992]), Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992])), Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463]): (Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004]), Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004])), Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502]): (Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023]), Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023])), Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539]): (Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537]), Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537])), Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865]): (Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225]), Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225])), Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690]): (Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947]), Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947])), Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202]): (Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552]), Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552])), Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079]): (Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444]), Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444])), Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850]): (Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548]), Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548])), Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448]): (Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987]), Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987])), Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041]): (Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035]), Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035])), Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301]): (Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414]), Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414])), Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414]): (Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212]), Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212])), Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703]): (Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439]), Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439])), Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271]): (Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955]), Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955])), Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882]): (Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802]), Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802])), Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152]): (Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887]), Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887])), Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028]): (Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948]), Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948])), Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331]): (Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093]), Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093])), Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394]): (Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134]), Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134])), Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546]): (Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228]), Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228])), Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620]): (Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414]), Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414])), Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800]): (Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703]), Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703])), Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671]): (Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205]), Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205])), Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537]): (Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011]), Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011])), Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516]): (Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301]), Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301])), Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831]): (Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986]), Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986])), Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415]): (Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057]), Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057])), Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722]): (Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689]), Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689])), Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144]): (Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682]), Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682])), Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295]): (Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268]), Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268])), Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818]): (Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513]), Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513])), Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241]): (Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565]), Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565])), Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439]): (Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012]), Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012])), Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512]): (Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850]), Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850])), Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986]): (Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865]), Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865])), Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982]): (Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777]), Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777])), Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808]): (Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394]), Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394])), Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979]): (Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690]), Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690])), Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093]): (Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620]), Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620])), Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902]): (Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789]), Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789])), Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542]): (Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094]), Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094])), Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057]): (Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362]), Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362])), Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205]): (Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961]), Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961])), Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401]): (Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580]), Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580])), Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553]): (Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960]), Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960])), Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169]): (Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031]), Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031])), Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682]): (Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053]), Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053])), Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118]): (Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562]), Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562])), Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725]): (Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666]), Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666])), Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661]): (Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897]), Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897])), Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981]): (Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447]), Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447])), Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072]): (Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646]), Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646])), Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140]): (Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404]), Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404])), Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515]): (Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152]), Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152])), Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709]): (Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664]), Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664])), Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800]): (Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103]), Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103])), Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741]): (Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169]), Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169])), Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005]): (Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758]), Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758])), Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802]): (Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070]), Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070])), Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159]): (Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005]), Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005])), Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350]): (Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443]), Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443])), Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697]): (Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573]), Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573])), Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928]): (Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331]), Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331])), Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320]): (Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166]), Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166])), Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814]): (Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079]), Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079])), Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447]): (Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820]), Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820])), Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284]): (Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057]), Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057])), Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697]): (Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131]), Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131])), Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955]): (Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290]), Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290])), Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910]): (Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202]), Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202])), Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910]): (Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822]), Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822])), Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106]): (Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847]), Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847])), Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404]): (Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441]), Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441])), Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796]): (Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186]), Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186])), Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053]): (Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516]), Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516])), Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992]): (Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818]), Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818])), Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957]): (Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315]), Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315])), Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709]): (Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794]), Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794])), Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091]): (Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539]), Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539])), Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664]): (Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558]), Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558])), Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294]): (Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579]), Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579])), Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947]): (Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502]), Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502])), Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829]): (Word([0, 0, 0, 0]), Word([0, 0, 0, 0])), Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045]): (Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137]), Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137])), Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914]): (Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041]), Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041])), Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573]): (Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378]), Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378])), Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699]): (Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873]), Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873])), Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225]): (Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262]), Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262])), Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057]): (Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692]), Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692])), Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131]): (Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997]), Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997])), Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555]): (Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385]), Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385])), Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195]): (Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709]), Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709])), Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166]): (Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542]), Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542])), Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027]): (Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373]), Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373])), Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378]): (Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509]), Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509])), Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097]): (Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553]), Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553])), Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217]): (Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815]), Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815])), Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873]): (Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864]), Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864])), Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997]): (Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722]), Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722])), Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887]): (Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766]), Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766])), Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589]): (Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757]), Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757])), Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539]): (Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665]), Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665])), Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129]): (Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229]), Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229])), Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137]): (Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312]), Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312])), Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019]): (Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378]), Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378])), Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331]): (Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713]), Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713])), Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]): (Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980]), Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980])), Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325]): (Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546]), Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546])), Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170]): (Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822]), Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822])), Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054]): (Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295]), Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295])), Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925]): (Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848]), Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848])), Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909]): (Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796]), Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796])), Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540]): (Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170]), Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170])), Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214]): (Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448]), Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448])), Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317]): (Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294]), Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294])), Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757]): (Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416]), Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416])), Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378]): (Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091]), Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091])), Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263]): (Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463]), Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463])), Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666]): (Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361]), Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361])), Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174]): (Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992]), Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992])), Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470]): (Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401]), Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401])), Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665]): (Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957]), Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957])), Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262]): (Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144]), Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144])), Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229]): (Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284]), Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284])), Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134]): (Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325]), Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325])), Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855]): (Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765]), Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765])), Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115]): (Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814]), Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814])), Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441]): (Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831]), Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831])), Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977]): (Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446]), Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446])), Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880]): (Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005]), Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005])), Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789]): (Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995]), Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995])), Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000]): (Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267]), Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267])), Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998]): (Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982]), Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982])), Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995]): (Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539]), Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539])), Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507]): (Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512]), Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512])), Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305]): (Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118]), Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118])), Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219]): (Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009]), Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009])), Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416]): (Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089]), Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089])), Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980]): (Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445]), Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445])), Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063]): (Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140]), Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140])), Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713]): (Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159]), Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159])), Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031]): (Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809]), Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809])), Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932]): (Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037]), Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037])), Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094]): (Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925]), Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925])), Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315]): (Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386]), Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386])), Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446]): (Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721]), Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721])), Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742]): (Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981]), Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981])), Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661]): (Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072]), Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072])), Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979]): (Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671]), Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671])), Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361]): (Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269]), Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269])), Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558]): (Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571]), Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571])), Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290]): (Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902]), Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902])), Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987]): (Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741]), Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741])), Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902]): (Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515]), Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515])), Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497]): (Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028]), Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028])), Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948]): (Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709]), Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709])), Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009]): (Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725]), Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725])), Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387]): (Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317]), Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317])), Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159]): (Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808]), Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808])), Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394]): (Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699]), Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699])), Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312]): (Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000]), Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000])), Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987]): (Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821]), Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821])), Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046]): (Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909]), Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909])), Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565]): (Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028]), Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028])), Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269]): (Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352]), Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352])), Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847]): (Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271]), Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271])), Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513]): (Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800]), Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800])), Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054]): (Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394]), Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394])), Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004]): (Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977]), Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977])), Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675]): (Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800]), Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800])), Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692]): (Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159]), Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159])), Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909]): (Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932]), Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932])), Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814]): (Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697]), Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697])), Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186]): (Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387]), Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387])), Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445]): (Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470]), Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470])), Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966]): (Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507]), Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507])), Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548]): (Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253]), Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253])), Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897]): (Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783]), Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783])), Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208]): (Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054]), Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054])), Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268]): (Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661]), Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661])), Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388]): (Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643]), Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643])), Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257]): (Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174]), Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174])), Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960]): (Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241]), Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241])), Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721]): (Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046]), Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046])), Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822]): (Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217]), Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217])), Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253]): (Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697]), Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697])), Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054]): (Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019]), Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019])), Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821]): (Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432]), Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432])), Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864]): (Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105]), Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105])), Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373]): (Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855]), Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855])), Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646]): (Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830]), Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830])), Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460]): (Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208]), Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208])), Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033]): (Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214]), Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214])), Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105]): (Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129]), Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129])), Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281]): (Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909]), Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909])), Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028]): (Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027]), Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027])), Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012]): (Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054]), Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054])), Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562]): (Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589]), Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589])), Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037]): (Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097]), Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097])), Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355]): (Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460]), Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460])), Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223]): (Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355]), Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355])), Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089]): (Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306]), Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306])), Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035]): (Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219]), Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219])), Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432]): (Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297]), Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297])), Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693]): (Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263]), Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263])), Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794]): (Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484]), Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484])), Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552]): (Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941]), Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941])), Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267]): (Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814]), Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814])), Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992]): (Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415]), Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415])), Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941]): (Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966]), Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966])), Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822]): (Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320]), Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320])), Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306]): (Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902]), Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902])), Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820]): (Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880]), Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880])), Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361]): (Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725]), Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725])), Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005]): (Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914]), Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914])), Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783]): (Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781]), Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781])), Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011]): (Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033]), Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033])), Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297]): (Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910]), Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910])), Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070]): (Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134]), Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134])), Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144]): (Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331]), Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331])), Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023]): (Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497]), Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497])), Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103]): (Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540]), Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540])), Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961]): (Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998]), Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998])), Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414]): (Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]), Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]))}, trace_len_summary: TraceLenSummary { main_trace_len: 14, range_trace_len: 39, chiplets_trace_len: ChipletsLengths { hash_chiplet_len: 160, bitwise_chiplet_len: 0, memory_chiplet_len: 0, kernel_rom_len: 0 } } } +ExecutionTrace { main_trace: MainTrace { storage: Parts { core_rm: [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 14618787401296499486, 12175440663040620259, 17580394656599216612, 9332791485604804823, 11950369617180951798, 9444935041463352282, 8315531457715846029, 9889393354952375157, 0, 0, 0, 0, 0, 0, 1, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 35, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 2, 0, 0, 0, 0, 0, 3, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 3, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 1, 1, 1, 14618787401296499486, 12175440663040620259, 17580394656599216612, 9332791485604804823, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 4, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1942941126776981551, 9461460041610899538, 7600020670677266955, 3257731577738044347, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 0, 0, 0, 0, 0, 0, 1, 0, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 5, 0, 0, 0, 0, 0, 5, 0, 1, 1, 0, 1, 0, 1, 34, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 6, 0, 0, 0, 0, 0, 7, 0, 1, 0, 0, 0, 1, 0, 0, 5, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 7, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 1, 1, 1, 1942941126776981551, 9461460041610899538, 7600020670677266955, 3257731577738044347, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 8, 0, 0, 0, 0, 0, 5, 0, 1, 1, 0, 1, 0, 1, 8, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 9, 0, 0, 0, 0, 0, 9, 0, 0, 0, 1, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 10, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 1, 1, 1, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 11, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 1, 1, 1, 11950369617180951798, 9444935041463352282, 8315531457715846029, 9889393354952375157, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 12, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 31, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 33, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 39, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 43, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 47, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 50, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 51, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 53, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 54, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 55, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 59, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 60, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 61, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 67, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 69, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 70, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 71, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 72, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 73, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 74, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 75, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 76, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 77, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 78, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 79, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 81, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 82, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 83, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 86, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 87, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 88, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 89, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 90, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 91, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 92, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 93, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 94, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 97, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 98, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 99, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 101, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 102, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 103, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 104, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 105, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 106, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 107, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 108, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 109, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 110, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 111, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 112, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 113, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 114, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 115, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 116, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 117, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 118, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 119, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 120, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 121, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 122, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 123, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 124, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 125, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 126, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 127, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0], chiplets_rm: [1, 1, 0, 0, 14618787401296499486, 12175440663040620259, 17580394656599216612, 9332791485604804823, 11950369617180951798, 9444935041463352282, 8315531457715846029, 9889393354952375157, 0, 87, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 12230109559590207045, 16524836159467994993, 15355865270174544634, 1391859963977339721, 12022620756870035528, 14989772180267129899, 13982693476036346567, 4019135314604422332, 0, 0, 1, 0, 0, 1, 1, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 14618787401296499486, 12175440663040620259, 17580394656599216612, 9332791485604804823, 7798791211572712091, 16041868217785231203, 6640187881380078347, 235747346370324341, 13046105914206547188, 17104930832431035898, 3750541143739447161, 16424211063756942915, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1942941126776981551, 9461460041610899538, 7600020670677266955, 3257731577738044347, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 0, 87, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 11950369617180951798, 9444935041463352282, 8315531457715846029, 9889393354952375157, 5389779285479201372, 17553508332489815141, 15087772099628732551, 5347478766541373443, 10896571887744929962, 11129997511013985752, 8670230788026367137, 9164328147053886136, 0, 0, 1, 0, 0, 1, 1, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1942941126776981551, 9461460041610899538, 7600020670677266955, 3257731577738044347, 15558099059781162807, 12870793504304295307, 12385397219736869043, 13164551900610862841, 279187929191844389, 3949603689257433549, 17380497166734391477, 5117931133682798382, 0, 0, 1, 0, 0, 1, 1, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 1244837894821529086, 14023738310468542470, 9319458442815716445, 5220020845190256514, 18381067342435073896, 15418184987737128626, 17753079332212842976, 12382717352847060954, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1532070872953744281, 11675978725956395507, 8258108365434236190, 8977540451988253054, 8832291907404336605, 16801197610032323372, 8498902414702613411, 2217861947967210820, 14648106445605106304, 5194857384255130698, 4543357020291533691, 1677011855369223059, 1, 0, 0, 0, 1, 0, 0, 0, 0, 18164368745351378969, 665130184182531292, 14548211377038648988, 9026463808500414994, 12372059324693434695, 8512906579977137276, 10951940384741553765, 2990681100436043903, 15463650459774420968, 6115025020360005524, 13619612156045325099, 9915559200666512746, 1, 0, 0, 0, 1, 0, 0, 0, 0, 73542357038484620, 16275608702285065538, 15615370514429573107, 11554047591217380375, 9626234372118459069, 14043139718664795091, 7172345985251039651, 13714446996516992992, 14079807935308074442, 17175342044195045043, 16936021968982853164, 3883665509408281322, 1, 0, 0, 0, 1, 0, 8133824218287649370, 1205363866316521559, 7923953289074004648, 1611370566290075655, 12516876786630134052, 16156412840636435500, 16066365782016562356, 12209717470970729826, 648151295134950813, 8424608506935970051, 941071657155810425, 12476535243066524999, 13046835168670418046, 13563090428318398174, 10213204276953300366, 1, 0, 0, 0, 1, 0, 11656233811569695541, 16780366708706866018, 10469348806910132738, 12317597613336433996, 16800450568443907772, 7958196127911254005, 5580405360121542127, 17991322909541306091, 9587008055009063413, 917862094456531518, 17636182943787095305, 5347924966817937746, 15791860137463552476, 5352122275530338033, 8207615265206228485, 1, 0, 0, 0, 1, 0, 13280747180546192023, 13818056542207317059, 12768869371961439487, 2029833730308772760, 3067168931363951888, 630426464913806566, 13807710542081112496, 10340529818978391824, 8301137772228612306, 18032943025979156234, 5571856761516233924, 15102755171792177729, 1386022355796901548, 10780164990569095481, 14005839963275167003, 1, 0, 0, 0, 1, 0, 8161514060541966002, 5430054846479849757, 855673369941768792, 8583346124368767357, 7152703336258374657, 4793816855328822248, 1475819744300266017, 5162097063446717296, 9158417383194264473, 17323069022182310843, 17309666448184518221, 16540233824244985004, 13271685073550397851, 3683818685539825395, 12883632168742702763, 1, 0, 0, 0, 1, 0, 14889661894667616899, 13319328534492736282, 511216470843933116, 5414088302741599345, 16030190225904238830, 6111859869108706126, 4321093113239299552, 4706826096768711507, 11021679444547674749, 15678561454143187205, 15168765916033556420, 7046395423559884948, 3431032212531228618, 9443306432483343000, 6291224588853575811, 1, 0, 0, 0, 1, 0, 11384512740043719026, 17996531901144166752, 4183594834611630116, 17695445402585642319, 15258305803668890228, 17106752205417894410, 13259786553689259064, 15859967842550332610, 5138368225191856866, 8345451659183769670, 4299979085769618674, 10058172520180004407, 16132576493934338934, 312707111584502977, 8025187035739711204, 1, 0, 0, 0, 1, 0, 17152042124522816142, 9826569971726481595, 8959076337043698126, 1987260706895490300, 17423289859865292784, 12258188545233319580, 4291864820252135891, 2950910453815263271, 852440029525711434, 1223549137263517018, 605327998629874385, 3009980753663636725, 8722464778364467857, 17216818427461180092, 13380853612843880678, 1, 0, 0, 0, 1, 0, 7979264206910945674, 0, 0, 7448791324579059841, 1050285053399784347, 16767087000176263535, 14849165193424062452, 2498996933077132011, 13658177069616805094, 495936213960522537, 13576872019913404781, 7640966386182958606, 4271515987309482058, 13463445006653778819, 12292225704634605892, 1, 0, 0, 0, 1, 0, 0, 0, 0, 6053040396430810733, 2172892474788961636, 18161859984545851402, 13488248907260320483, 8430623432188198915, 3055646124754645267, 4245215712607391946, 2243958878529225177, 14990440908620774864, 3080921390696878855, 595284666932255390, 6192940699035995377, 1, 0, 0, 0, 1, 0, 0, 0, 0, 14921496778760644502, 16662036864627516510, 6434377642684009725, 1840544361770929313, 15074823591915634941, 5258982948465254673, 2683768063818053258, 238295676214993337, 17552036469726894364, 15877921873938893194, 14734786106453693759, 1371624439541100057, 1, 0, 0, 0, 1, 0, 0, 0, 0, 516742705862090749, 5947805230277704319, 5952541516123965670, 9026915957393505056, 5986317686192419732, 75717367401824328, 8923961895635206791, 17106810061565988432, 7157463081631406163, 150940732863733992, 15657864298531798718, 12227344478922314236, 1, 0, 0, 0, 1, 0, 0, 0, 0, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 1244837894821529086, 14023738310468542470, 9319458442815716445, 5220020845190256514, 18381067342435073896, 15418184987737128626, 17753079332212842976, 12382717352847060954, 1, 0, 0, 0, 1, 0, 0, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 10338918064798200754, 15286122942437340674, 6004213370540561229, 11077881500896133090, 15185046381229794929, 4025060549564442513, 16691190932080263388, 17911971684749301267, 1792647895939561414, 11040149027552020115, 16788268171496683395, 6690778673349798915, 1, 0, 0, 0, 1, 0, 0, 0, 0, 18207620435178905496, 4478894291978491061, 8126565228616187566, 14565598150868720008, 486704718504877876, 5092068149414351847, 4895519870785798161, 18320934558859357026, 4783600071858140824, 7590991738963063833, 15020058681279762757, 8502154501231846969, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1790253480113930875, 11472368064126754753, 16140937904922483949, 12784262958320173457, 8992534124131108063, 17197330755228127793, 17888648586033704362, 3783608546885852925, 11488181860237317371, 6520363121033018355, 5666192756396478125, 14698764588926429548, 1, 0, 0, 0, 1, 0, 4775960838571449442, 12355201513767393906, 16893169864929129892, 3067820580898613927, 4037642048582652770, 6463406968300557513, 1334655449937755180, 16454962669178338822, 3423416796618681452, 15635204112556936010, 11367217176161227780, 15846919749025709683, 8739705468185832455, 1695606868833824155, 14902201197695023622, 1, 0, 0, 0, 1, 0, 7270109453425771694, 6393439473671243944, 5763178267509538253, 87155278506862768, 17182682045085641378, 13669966515951696363, 6730246632471569917, 11015850215265080242, 5781848723365073595, 14722218108828704340, 12249120524157518956, 15530817548594619752, 2571721876460128542, 1124203808167418458, 4658355789422303197, 1, 0, 0, 0, 1, 0, 619730554607827397, 2707784357837694055, 10389429507854625814, 412437114519718435, 17010823019251866220, 8496853728750345058, 3962235926057627964, 7293691342607609411, 4966485821032368622, 17523850342152507329, 16165780461118504337, 6833077136448453098, 18408644517259086000, 13790345385092960681, 1118981994890433291, 1, 0, 0, 0, 1, 0, 2870832816007467384, 2873570063945483268, 5260498635996294368, 10072735002004767449, 7363233941642473793, 10401385213219539176, 9719773007613995950, 10216717372939649307, 13022711033487370480, 9232213967333586262, 3354429439844650126, 13306058477265011029, 3840400538830937486, 15100916108359921929, 12686728912814672715, 1, 0, 0, 0, 1, 0, 10126186915863966894, 13849382609137246799, 14871056570003924152, 4577474152973240700, 10319035267502935180, 1107109480596608884, 910001863439660317, 17323775771861278671, 11990539141370178689, 1895237968841058140, 3069611939766785355, 13990132518689115799, 9158955820349235201, 3334355584256728822, 6532229842765454575, 1, 0, 0, 0, 1, 0, 8418794997351000750, 1324633730077053524, 7680826640634201152, 6943155698572158851, 4119721600018041835, 10160115415927000034, 13670021867743170174, 10426040451143237205, 12527054859506162043, 693011963436135866, 15847427063003354492, 1193915807921269299, 5530767236037587666, 4498758928312101948, 1668396433795256171, 1, 0, 0, 0, 1, 0, 12474497430381571234, 3486558176421926303, 176934443909317952, 8642603494321417085, 13568047686929876305, 13873699071648888616, 5469909543377435991, 1153721650762048262, 6332701647560212482, 14750767280279403533, 3863562993110808460, 10010469643426778773, 13610145136323473859, 13803405503382348517, 10066622964560025039, 1, 0, 0, 0, 1, 0, 6502239097904837007, 0, 0, 11596242931973405682, 7569447524345075040, 11402732351667273497, 17726124048449719654, 2143489115939838335, 2291345291252627066, 13774221459002946228, 5704848367751370496, 14844994802213729480, 13325648093707576188, 655937328333223270, 12601714085039449766, 1, 0, 0, 0, 1, 0, 0, 0, 0, 10080683606039484932, 557142253253508029, 11861574744773262883, 17479297133692971328, 13431343265670357832, 5107644268576628652, 5672451077690842648, 10697999158618521351, 13783189127611294708, 6370270522833708976, 16602411989536803847, 17535824353652041621, 1, 0, 0, 0, 1, 0, 0, 0, 0, 18221718971044951820, 11123331110225556773, 17884963006522019435, 13581862227015801716, 3539406162482662008, 12779267696302831166, 17568889654867020374, 14043625177809463809, 10953842550742243459, 17624483884859046607, 16829866994010956924, 10383254959407238075, 1, 0, 0, 0, 1, 0, 0, 0, 0, 7704989128662250393, 7731722432250559639, 1104300072480693820, 12966826694165085383, 5898355191387204970, 418343475844287535, 17504741557362850364, 11212567254567942759, 4585972511305465500, 831671821010246741, 1347174724805777450, 9978241385511108600, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1942941126776981551, 9461460041610899538, 7600020670677266955, 3257731577738044347, 15558099059781162807, 12870793504304295307, 12385397219736869043, 13164551900610862841, 279187929191844389, 3949603689257433549, 17380497166734391477, 5117931133682798382, 1, 0, 0, 0, 1, 0, 0, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 2844174837506797768, 14770415536338085095, 8053473190425314497, 12810585393750772644, 12517162067313615795, 6708309406641442601, 9752285986344000829, 14839297145466054073, 8534874634076336098, 14795338728791802759, 16467940132402131085, 13518949717672180282, 1, 0, 0, 0, 1, 0, 0, 0, 0, 197345143463752877, 11590552548391007208, 8513135180731923185, 4789498072246113352, 11303926357913784691, 11723443921595997802, 14952876297128645088, 4864312901193078229, 6947659381816817219, 1746178727761685368, 12918373769842417551, 8684596229708270516, 1, 0, 0, 0, 1, 0, 0, 0, 0, 3198805477847978589, 13930889360803740657, 15057872115125399602, 10921141672562986793, 5789960870644177461, 15608139912666005512, 12683155364689979788, 18346811491373252273, 10487394721802866951, 11974532682130534845, 1519861526503586143, 1098638899502132867, 1, 0, 0, 0, 1, 0, 17128804603859274179, 15425440231805738567, 2171332404261207924, 12061940714814445323, 16550302237377331826, 12740022639409649481, 4788619492523060974, 12101496647901663530, 12627924597542725825, 4538464495267088575, 7655969430543094352, 17740697538393183772, 1276333715732019707, 14173930302505429451, 13814834917482380980, 1, 0, 0, 0, 1, 0, 13522108978497478647, 15326000623266678192, 3937153401353680192, 5391465844431065097, 18248340349342647871, 15368790604451050198, 14035485820573370176, 16386022069680258207, 9349013130282144239, 1551611900277525346, 9934003659359682927, 4355136691411596250, 6906369583230328082, 6194111766557181711, 7090430103975125421, 1, 0, 0, 0, 1, 0, 6858104153104953844, 2783142950383804293, 8584815630276621541, 13736751627541767595, 14322019951421583643, 7328081675331405521, 2919878666094336280, 18265421608060798137, 847119850511152679, 6488028398833527134, 14030107144688032001, 16464054037947062503, 11306313446221145933, 2618902231753980169, 7111715274719427805, 1, 0, 0, 0, 1, 0, 14207818010411458005, 10702031730649360848, 1427799141318779075, 587927478659780999, 15271511291908440421, 1631153249982564447, 14860375384915403614, 5053574427925446505, 16185831982250091643, 5313306335957257312, 14408389614090560738, 3446934167305825216, 6924078255851134462, 1944495675792485669, 9381181653175935358, 1, 0, 0, 0, 1, 0, 1514501911734050528, 2103447129935109946, 15243544860712411446, 15662501863724208746, 13145679926921004363, 4622578459096655813, 15178320922885462585, 6934952687117461169, 6429901021776189429, 8190297765436449986, 17289740015790507499, 5474448770498973057, 14426481937239015119, 15225288135317750243, 9334877092232131090, 1, 0, 0, 0, 1, 0, 17039418869353369367, 5045115566370760009, 4671027510138840984, 7061837181192953446, 12931235775561067332, 13176020926551886014, 2651979372862304957, 6448209114888282956, 14113477446789099358, 14604918207559224688, 8862983295294549605, 16863262536586421908, 9999167437358985507, 9478876837144190569, 5194157795194187382, 1, 0, 0, 0, 1, 0, 10651133333257123943, 11101110287260233241, 650894676042466653, 15832539727497904498, 16656333065661736860, 18369789225665462210, 2693003614851431067, 772790696866677272, 2480179799990567291, 17304358978184667075, 6187736184647340944, 17237712361917640397, 14072736642225359273, 10623410937495095553, 3019557709101931446, 1, 0, 0, 0, 1, 0, 3558792632055854276, 0, 0, 18279620994548222363, 7537712095633077660, 17235753368900772495, 10138479632844764387, 10676334012313161836, 10151433255181272788, 4221944602571779671, 14378476772841555006, 12143502102929103640, 11730678005747995442, 5601143081558686791, 9280411157191944580, 1, 0, 0, 0, 1, 0, 0, 0, 0, 16884818255031608393, 13045713162430805835, 3600896491691629579, 2370161244647043179, 661552320621341973, 5193471677143062225, 4344568064600414577, 6287012165400024744, 16771346841353293653, 11496244803188049682, 13192283114216253262, 1468753321492310312, 1, 0, 0, 0, 1, 0, 0, 0, 0, 10180755850695837534, 6978965227021412920, 3137528352086851557, 4639410328460555037, 12740940713361972140, 6139739720960649901, 6992560805366421671, 5664952048525874594, 15115584234380815111, 6423836987080682296, 16291666223467597742, 9479232376233529718, 1, 0, 0, 0, 1, 0, 0, 0, 0, 10733409993326982567, 1953734515310810079, 14379372350324944355, 1719086499025241451, 3695292032734759229, 13442410518056192242, 5600036575840165991, 16476082167990762462, 13437881851625150616, 9220830330798622848, 10959186559397338078, 3278679000955332681, 1, 0, 0, 0, 1, 0, 0, 0, 0, 14618787401296499486, 12175440663040620259, 17580394656599216612, 9332791485604804823, 7798791211572712091, 16041868217785231203, 6640187881380078347, 235747346370324341, 13046105914206547188, 17104930832431035898, 3750541143739447161, 16424211063756942915, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1942941126776981551, 9461460041610899538, 7600020670677266955, 3257731577738044347, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 0, 87, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 3140855868878816939, 13853610777244465556, 7305682856568545034, 17768394568131058378, 4102628019324006119, 4284053222036732600, 702918224602433827, 10375695918533438253, 11152995795829941880, 5169004732887479405, 15116124983681184313, 11068900437831795240, 1, 0, 0, 0, 1, 0, 0, 0, 0, 14674311818750931642, 15727102992101643424, 10209637917493742085, 14433760483016802213, 15023858318134776079, 13617465913120919705, 11153310337321385356, 12991360735056054606, 3550460033083965293, 13918925059933519570, 14012164523634193404, 9616156815711922050, 1, 0, 0, 0, 1, 0, 0, 0, 0, 10332893761271738825, 4468346375378916401, 9749151272711495276, 8699061724169347090, 9834940708477034873, 5947156991246950325, 14409035433392705531, 628920525634910939, 11788382252656375499, 4818566561319754770, 14056028560156009139, 14939415572295847861, 1, 0, 0, 0, 1, 0, 5517847790939712612, 17084191072185647983, 4373790465892097554, 4225331220542153300, 2130235836373540041, 11014336955587517267, 13261921604701925672, 13681942946271658553, 12034991783627364558, 1627804654564744257, 2932739946223714750, 6512410412877608540, 6097164629377042547, 13231886920322033342, 11051251506011467161, 1, 0, 0, 0, 1, 0, 6837868493616672931, 3932850543815016562, 5993352762837579443, 17042968652914390951, 10638038987314268392, 827661294420902564, 12480026891102399910, 15584776283300553616, 16018818694656253476, 174727052104985970, 6997609737938415989, 18257746455231651762, 2120214735299642538, 343151165640891818, 10759684562283919705, 1, 0, 0, 0, 1, 0, 9492867381892087299, 16262800480453112023, 17322872276971640738, 14643806196666560377, 15595136242254344950, 7518181154580928497, 1317098796508350392, 10963738407742121793, 909342354741125081, 11768528957432122607, 8394540270261060467, 6404191905775366043, 9794215422759310631, 3090225984746935786, 14584417906224674271, 1, 0, 0, 0, 1, 0, 13612281739545428458, 14760519749949005735, 11059096111732277153, 8127477948862304659, 2899450088585457524, 7178383302195079413, 4080342379963224440, 15065835405932063604, 7174159973314940261, 7866236788120069085, 18372302221082695790, 6755863915990177867, 16393276955272037238, 6508850325341530182, 485362918438249523, 1, 0, 0, 0, 1, 0, 4372640031216207607, 5629259567684105503, 4719933692909427189, 12089107207026598168, 12364521740255563281, 15126929415582004941, 9583199887191732065, 8988068388491896607, 10885812525421994040, 3179713771850761109, 3646259631192899507, 2420177325979175775, 10058704817135704897, 328248192680369153, 1212206002969597043, 1, 0, 0, 0, 1, 0, 16719971632373437139, 8913437407619212875, 12445715620888469070, 14590495590496016249, 12591982458207239898, 3518540272376153691, 13537778478631670985, 5768862501974313259, 6641802290415749520, 2619647825741307367, 5310404789838069255, 2813523707389681640, 6001123487053466814, 13283119919073385632, 3027180794999366288, 1, 0, 0, 0, 1, 0, 16985432419746479334, 1732148218874634898, 10732456770751424600, 6298968617386740411, 5222599433923214178, 18313080032108507945, 16008519283195378358, 13531413419888790066, 2081323533358520207, 15255353550768211576, 17138176985304544396, 15815114409447852656, 390133022963677303, 9368984280090759390, 4226326679630301281, 1, 0, 0, 0, 1, 0, 10878179176838766787, 0, 0, 15143079744491591624, 122684593814478623, 17881594072631522907, 7229419957503946158, 12940017521193772991, 10151817482573032909, 8733418387703005516, 1319594737760624758, 14880293583396293735, 5898942779435783768, 16811128745251295765, 1109240219058196190, 1, 0, 0, 0, 1, 0, 0, 0, 0, 17097058137364766519, 12170170828128327789, 8827354137729360970, 14939098920471879539, 17594240265564849285, 12594120096976711335, 11639588720238971595, 2961214099077550944, 2199574547323924831, 11634736545140098063, 16804232943677874803, 715700715650088406, 1, 0, 0, 0, 1, 0, 0, 0, 0, 8947505233582573905, 6678598843273392764, 3725073892233240125, 7720092071903033897, 5255970636116417070, 12681977177382299121, 9779623946328742809, 268997569335911479, 13033985248158052224, 7447389216002042151, 7736891773241144274, 1940240082052736870, 1, 0, 0, 0, 1, 0, 0, 0, 0, 6118821869453917786, 2608197264550826766, 9411170196077201442, 6661421389020413469, 14375230321868528117, 3141438207172205564, 6958632034797014787, 17400815499287696997, 9312329466912734898, 5143036856532903190, 7161333884680390469, 8058403803683718142, 1, 0, 0, 0, 1, 0, 0, 0, 0, 11950369617180951798, 9444935041463352282, 8315531457715846029, 9889393354952375157, 5389779285479201372, 17553508332489815141, 15087772099628732551, 5347478766541373443, 10896571887744929962, 11129997511013985752, 8670230788026367137, 9164328147053886136, 1, 0, 0, 0, 1, 0, 0, 0, 0, 14618787401296499486, 12175440663040620259, 17580394656599216612, 9332791485604804823, 11950369617180951798, 9444935041463352282, 8315531457715846029, 9889393354952375157, 0, 87, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 12075365935646826911, 12555112468856587408, 11785226375886997917, 4824245574712348149, 6698272548511662058, 7437332431719550829, 8805294974760200296, 13665174347101618099, 6738391298770517604, 7192645425446594991, 9388817984500446763, 5794113475247796131, 1, 0, 0, 0, 1, 0, 0, 0, 0, 12970026081624744192, 12744187783136811240, 2410348887864631027, 12978945726327275454, 1554921798601148240, 11229913696364167708, 8973022178183201081, 139928186177466980, 13649876187837155162, 10757898852954163787, 1183567474340415150, 18328332676029395445, 1, 0, 0, 0, 1, 0, 0, 0, 0, 13115145854204970892, 17983425541226801902, 503096672456724597, 17391026586069653618, 11975412188970431284, 12728070322904945002, 12583843770217265045, 5648611480833313028, 5270318028794710036, 9198234540668451702, 15227185125669186823, 13442379348215607242, 1, 0, 0, 0, 1, 0, 7938014903722142143, 4026985013879105156, 15433899134283001186, 5518543654937541191, 7811482114300450425, 18246857844067051489, 5066330555278535354, 12777013593391110699, 12191575961919955189, 17344099196019282708, 13114270510039317151, 14016355395255073114, 6427069658768868190, 2211726190322481583, 4862466322566539257, 1, 0, 0, 0, 1, 0, 6295390960602027128, 1672635780379469502, 5514393169316646408, 15268698329081358799, 6358521007699847181, 8905575183526941079, 6308301555581432298, 2713628301395331598, 15644594447494294958, 2471335144483071788, 7634628028118476493, 8705396367530590759, 510439172729197823, 5910464539270739337, 11313308155928141, 1, 0, 0, 0, 1, 0, 16526896907746924406, 3520066619418494561, 5902635986331447140, 4398972274698089981, 12631024732346185051, 8386841573792151210, 12218015928704154046, 10432140379698280314, 11468177025236775618, 13346741951457031181, 11864092150902575386, 1957967507142109539, 1187524630546802447, 6811974332530919582, 1674557656829922128, 1, 0, 0, 0, 1, 0, 1584868061124279887, 9442704715127069304, 1641023224966192349, 6329396367180888266, 404888665587209724, 1712028768453542123, 9636831554872487700, 11205546840421184087, 14264854432675592118, 4651572474102722880, 2600150713028016700, 7671260856915471824, 13564816252723126852, 12833222284634831992, 3051460357884001758, 1, 0, 0, 0, 1, 0, 428341091691738800, 18339284103630472679, 7870616161402447553, 15334351080828855345, 1972261447295035604, 17003628149811009423, 13559543871756207414, 12791588703509816612, 16874590433396658583, 10546926997829974134, 1613237926847090038, 5103230212642319031, 1275403119419295716, 12931787129843438351, 9482922846676968945, 1, 0, 0, 0, 1, 0, 3664885029783550679, 11363752911665810183, 9134704894151526337, 13215878359575686624, 18224453919930723109, 14701830073355456188, 7627101113505064542, 16932075092084463114, 13716504142013330150, 998335944076440638, 12137387735186731363, 17058369724013530208, 1767224174321722467, 602199799565625282, 4204601874695641395, 1, 0, 0, 0, 1, 0, 7106463660950754017, 7750176763733153254, 7574864206138859398, 4526848524085695537, 12851507948139845134, 12194522465304354477, 203045723268582723, 13800072724692742244, 6219761752233525772, 578458477173417489, 12409381620398170328, 3611444773280584194, 8973301930488357361, 6492541737016997329, 7829849934035424392, 1, 0, 0, 0, 1, 0, 4777343346630271661, 0, 0, 15040112894884950263, 12254503491494638924, 10905362093557669084, 12506798032013022761, 15503156871268737834, 10398894083161474515, 15562472066553605377, 9297592479728714122, 15171127217706380424, 9656102210084357377, 6955904167393062211, 12517713541538021270, 1, 0, 0, 0, 1, 0, 0, 0, 0, 16222821967647715914, 18236388426739201624, 10359860344541184143, 1153281584568447720, 11215911684698899438, 1590480596834601729, 5406804875063937073, 902825103749099378, 4476247383648377898, 6603681318758243995, 7979346268508668223, 9081216985780183305, 1, 0, 0, 0, 1, 0, 0, 0, 0, 7115759549889295004, 17795973162642491077, 3118063002769479276, 3375328991910866222, 14829673264916467260, 17032170639409509898, 15296986551515876803, 17801462043040480905, 12194152217648072934, 15515146157726073849, 587062581941150380, 292701116829680586, 1, 0, 0, 0, 1, 0, 0, 0, 0, 571143354463273441, 9666544608273691458, 12872042550989601583, 10652410992593235579, 11969486770687628423, 5473191134781977608, 6282849523905673255, 17953708178661470530, 9124580738322974913, 3090550876749265149, 6178971316333817527, 17953687842851871221, 1, 0, 0, 0, 1, 0, 0, 0, 0, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 12230109559590207045, 16524836159467994993, 15355865270174544634, 1391859963977339721, 12022620756870035528, 14989772180267129899, 13982693476036346567, 4019135314604422332, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], range_checker_cols: [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2187, 4374, 6561, 8748, 10935, 13122, 15309, 17496, 19683, 21870, 24057, 26244, 28431, 30618, 32805, 34992, 37179, 39366, 41553, 43740, 45927, 48114, 50301, 52488, 54675, 56862, 59049, 61236, 63423, 64152, 64881, 65124, 65367, 65448, 65529, 65532, 65535, 65535]], num_rows: 128 }, last_program_row: RowIndex(13) }, program_info: ProgramInfo { program_hash: Word([10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048]), kernel: Kernel([]) }, stack_outputs: StackOutputs { elements: [0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, precompile_requests: [], final_precompile_transcript: PrecompileTranscript { state: Word([0, 0, 0, 0]) }, trace_len_summary: TraceLenSummary { main_trace_len: 14, range_trace_len: 39, chiplets_trace_len: ChipletsLengths { hash_chiplet_len: 96, bitwise_chiplet_len: 0, memory_chiplet_len: 0, ace_chiplet_len: 0, kernel_rom_len: 0 } } } diff --git a/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_02.snap b/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_02.snap index 7bb8930453..0c87d82a44 100644 --- a/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_02.snap +++ b/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_02.snap @@ -2,4 +2,4 @@ source: processor/src/trace/parallel/tests.rs expression: DeterministicTrace(&trace_from_fragments) --- -ExecutionTrace { main_trace: MainTrace { columns: ColMatrix { columns: [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 33, 33, 1, 65, 97, 97, 65, 129, 129, 65, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [11959214793721861949, 35, 0, 11959214793721861949, 5598651459581075585, 34, 0, 5598651459581075585, 8, 0, 3358534066525179769, 4141253528664299662, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273, 6116677274871151273], [11044849754686238278, 0, 1, 11044849754686238278, 7804753453550466256, 0, 65, 7804753453550466256, 0, 65, 9365253138981608257, 4690506171811599662, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113, 10392133002436897113], [5121401795821831283, 0, 0, 5121401795821831283, 17777748786253636403, 0, 0, 17777748786253636403, 0, 0, 4243893038989355703, 7471531250255239926, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602, 10134148635057625602], [3548930057165921670, 0, 0, 3548930057165921670, 9435312778805252724, 0, 0, 9435312778805252724, 0, 0, 2372900269115514267, 16928201695930024468, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552, 12864813595450034552], [4141253528664299662, 0, 0, 0, 3358534066525179769, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [4690506171811599662, 0, 0, 0, 9365253138981608257, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [7471531250255239926, 0, 0, 0, 4243893038989355703, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [16928201695930024468, 0, 0, 0, 2372900269115514267, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 2, 2, 2, 2, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [2, 2, 2, 3, 3, 3, 3, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5], [3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2187, 4374, 6561, 8748, 10935, 13122, 15309, 17496, 19683, 21870, 24057, 26244, 28431, 30618, 32805, 34992, 37179, 39366, 41553, 43740, 45927, 48114, 50301, 52488, 54675, 56862, 59049, 61236, 63423, 64152, 64881, 65124, 65367, 65448, 65529, 65532, 65535, 65535], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [11959214793721861949, 11724006094392302789, 18248966067159614734, 14997726253538871503, 8817287785847965336, 7563891540952433248, 4929456476937587212, 11106581516038722988, 13463537305496517162, 10651632781918411385, 9981866502219755654, 3808288102601471056, 4944845091089272806, 14634692017250583903, 4938442710501308657, 15019076788922615346, 12046519037910030840, 12002553001135911279, 6648246339606676671, 13611030331766854764, 10789879208843041511, 6935978728922643823, 7357466921077553394, 7069639777384924144, 10796630853015597058, 9600475765342551835, 15539063566397429438, 694626006296126791, 10333172214933120836, 3750356548306982137, 12302499613655276109, 6116677274871151273, 35, 350, 5140376474314663948, 5151077999657789073, 16885380856972561696, 4396313619195267116, 5306671686393489364, 7956822041329119795, 17818361021916066381, 14033097286562039884, 7821625366477940937, 16833029552007335772, 8428385927199104618, 1983549081678798610, 9947044966489369966, 13964889898869345750, 11121186483480785338, 9818108804633787874, 4883454229697807874, 7144378034515727713, 4313511094695098159, 3382507463453404844, 1457665291681272839, 12934070243418782738, 1587788786427634902, 8220166220981689928, 1303361134214255144, 15371623169605597371, 17525379757599431696, 15824846667317041360, 8992618192991263654, 11959214793721861949, 5598651459581075585, 644336023812026242, 8962397996249942813, 6385487366266632060, 15421658280337698465, 10565312036761368185, 12143712587225756222, 17266990262046250797, 10756948069435380801, 13737908976648726909, 17026264676264380541, 7825754886390455440, 16047304773895114845, 2736732063999892145, 13983789395651571583, 13470168189302134725, 1436972360246592622, 3363240447642516424, 11460348809250776143, 6982982338498759911, 7828293012926775020, 16631334376547321750, 3136253412904926398, 12922287692448102380, 9001750416037636327, 9873548594897521512, 12362167187142713720, 12998286769972940151, 14911169987988052811, 15100444854223162361, 7731918223558949955, 4141253528664299662, 34, 340, 14059267169109730234, 15746924929585133009, 471985631500087772, 16946433723443173275, 4595135147820207091, 2053997855496151567, 18402496786565368100, 387609426153233273, 8469665991798416914, 7881354678273462636, 11816560343993810599, 9054561158700241520, 7881520773741268125, 1631726701000003728, 9048332065221759951, 11440521690988525934, 11399562976973524004, 5295775600298609171, 16854936978988550164, 4555566089436281371, 8045874719633055695, 11420674364099598202, 11942861833844189240, 15820096964950298640, 4263756598719013378, 7647209523022736387, 13465875315346524402, 17464705757459592393, 14751425303934963720, 5598651459581075585, 8, 80, 16253482711025978099, 16690839578921925157, 11755424915479552417, 17934377671577204140, 15509754874715907467, 6426721221030580337, 11049594146888643723, 14912334368661229147, 17657273147290084056, 9105126057127804171, 13430225876739607206, 3614830725909060912, 14569284676797348998, 4705513459362295944, 424917224365117418, 2835737623710330612, 1964100172858915134, 14896843043547784767, 15482419984058848245, 18437547705335910066, 3162257106529980441, 5297995970636059087, 9661978795293871188, 10128143329575104151, 770728251595531533, 9782965673735423214, 1347942901513492691, 12086966446141742548, 10239457018222882008, 3358534066525179769, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [11044849754686238278, 1065714023649388913, 13590585102940813084, 13603816939964373123, 3385249563011961849, 112536514236739072, 1106452645962150895, 10661905560677698362, 15195193333392427571, 1271054956149481152, 2058632847676165296, 14347073347558249169, 9693072255291891063, 14859780105168189871, 5613057382731574150, 5623448817324608138, 7997999549850776178, 5693866887050036020, 14258871931331407358, 2547009721703928454, 4107508461331672257, 5068231609320466245, 14744046358319534345, 364669749717258, 12759453666142542994, 15815678790725651452, 17691418632824774891, 5288331248614959742, 15557683662491153084, 12209140182523723096, 17383410983291524378, 10392133002436897113, 0, 280, 3739327994472119619, 9855163346786806166, 7272719153662087111, 10277182995998348622, 1557779935350354179, 12598977243905958375, 5757159540459665691, 3544925687412308625, 4454290108164189834, 10562329593955594288, 13328511337210905323, 12548482778894690532, 18303351465385086236, 10622473817836825208, 10391858004672883604, 9244678019206311862, 4905634085052053166, 12384227405658404185, 5878623689014611519, 5361442612107937799, 5203395718336603194, 12505885186641282427, 1657982123928418916, 14802316224598370353, 17429829341045194126, 12187663825740955518, 8834060796313238365, 856881534780831669, 8614320689815223473, 11044849754686238278, 7804753453550466256, 10860407685663036622, 13564283360082851490, 16294057552644672316, 6097183689626534496, 5142791099649335720, 16773516463636660187, 10484693517503369961, 15510754792097734964, 5061563839137660876, 2683909803925041834, 7997738108478273878, 5467755257223357975, 14923583333953915684, 13294611871319191983, 10569196959361608760, 13906642922547692513, 2845656992888419272, 13828314707091500290, 2951356764607352638, 4406743315212729130, 16360792604504139514, 4146070061564888443, 16122102826540224213, 623220105874852865, 3573414414778802861, 7652433402428128865, 1221918952773084874, 9684204095164476815, 17702995505216793489, 10675603116079282076, 4690506171811599662, 0, 272, 15833028045737259664, 379315838026506093, 8581974592770288933, 17442451301272882541, 16579750051606898066, 5674487159031204202, 1541891846645406613, 8209041782659254452, 11966225502153548517, 9096730616149686024, 15618906860941665577, 14146738543483816160, 1119526938685078607, 8710432271010401746, 13282504786121257878, 1858131981777548381, 12223656597910297554, 11826686549344788050, 4472804247539583969, 7599118004690938513, 8277718642341650597, 8460103377465445883, 4568736565087160671, 4933680726900799861, 16645964836945405904, 3680609073412509534, 16176623117443515258, 15081244610133230814, 6410948793715747581, 7804753453550466256, 0, 64, 5751576643258238090, 7830268710878889486, 4868320831660690795, 7042762868047858013, 1028615964620729689, 12270587957620579653, 7267371538363991280, 16125626865182516658, 16950134439933558852, 13427183447069512151, 16117382505273595827, 2222792985740553749, 6517696895688418945, 15516128650333221731, 6357034143715229949, 12960707821770488929, 12451444460344609421, 8786747128188560390, 7634329044629047826, 7741107824034642016, 10975559322169081956, 6007758954686348362, 13971256108093330407, 16868860295450858142, 434120282701603474, 11571634562637977474, 5581285869985960561, 6581368197537384623, 17661012293298952642, 9365253138981608257, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [5121401795821831283, 14666269722110737492, 9590621322847534573, 12932191302609726157, 17918869724719667108, 14326240507681405072, 13067917358519389481, 6815648073963386989, 12352345465945418691, 11261296525909619502, 7689378518287963220, 10584893895333648109, 1804101714182174693, 14360593671180620787, 10105110162171772438, 12398505852787426318, 9692172226490565230, 11964900944541509452, 13385745375779151291, 2217858628481308506, 4621662715196065678, 16647480880251479677, 2589374608845270941, 6809248840077290249, 5129749784462500037, 3245840590205743440, 1922074210551113159, 14644738552419224397, 1598739907793205518, 14526700523373973306, 16517594411296145407, 10134148635057625602, 0, 70, 12197195286374413309, 10427073607190553707, 533047373605454411, 10580779234737523528, 15741781055361060589, 7164202101070087014, 9765809951316535147, 1782081390036413323, 8331595035611127917, 9697859497182376308, 7215394876392616273, 6137901882901182614, 6110992258367195164, 9375455911463634413, 2858682112359859723, 11530371422565574919, 14558386734229473932, 5193748514123930238, 4405616242805307371, 7842663293116063328, 13893940361375217996, 78901366432993105, 3701164965690212066, 3898705475678625899, 4285338701077916719, 1106459456301114152, 8610620161032996227, 1345962755312618543, 5938021660540313570, 5121401795821831283, 17777748786253636403, 12906637371964794674, 15320836901220842229, 9687580313089453282, 4646487368895915296, 14821642720711744364, 8047695355547001029, 10749686584146612549, 2375067891701857361, 12672901980323560015, 13290437551032339902, 11956271016055823946, 12186036345271050649, 10541464479696610661, 5847635127357093482, 2710785219086425297, 13630517663920473907, 16007826574763812566, 8148616449491580734, 458107884374711321, 17819043892120276345, 12445943926803700033, 9955553630570974315, 1387322623565652732, 4082304616394368279, 14346319199041833303, 13848956826511295359, 18438638174686917351, 10202942699122698773, 7439539809669146478, 13477200069544690909, 7471531250255239926, 0, 68, 4457596741936238930, 12529581077675993243, 303974201734355881, 13345903392866909652, 9586267930884889862, 5178817950472007665, 6608322246477847509, 4070515537963445793, 9312477480709452614, 8889792067304111866, 11078425489498232713, 636055309231688517, 8580323529307502020, 12246954824275240956, 13948398243979685168, 14683551372837095812, 4744943918536266830, 10091391594533925883, 11270159100715194202, 16104697287955959682, 2983615207234436698, 10804815118997327370, 139420663301414639, 11145521977996788455, 1535579717520953536, 14470422183799365804, 208588932528011586, 11685358340804306780, 2822178276157738566, 17777748786253636403, 0, 16, 7110029021941723513, 10115409991715085575, 11428668827299215140, 4015039023438705588, 3732466887400149035, 5870841944205588609, 8421627027326523148, 8231214549142439222, 10318470559229280016, 15171283498151438808, 12477430934852872037, 3853779543897991795, 14662750186533371679, 7423988381383082226, 13549468426633458145, 11079168775731474830, 12471207782095033761, 17595325414333663547, 7042468264080735391, 17650115337646869205, 14946074228061446423, 4655654314239637986, 11187552516160183253, 18115881480442018545, 899748567092010447, 14020868337400209874, 15417366235984526759, 3331301994171189600, 15814677761660135474, 4243893038989355703, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [3548930057165921670, 11599182054654736187, 4885112663983886856, 12798756157498171562, 8555258669059245167, 12593636579411959551, 1751015532861688472, 13019009039270359101, 10174923844635011062, 15012513810591484516, 16650490536433444505, 1428273348489524024, 5693483119278040520, 12915240062722269861, 8183805712769991021, 1654142869540548129, 8049024691721442269, 8293446604021081650, 3020690079986249537, 9829005565890494186, 3079504282059755968, 4458043056162108579, 751694847316855704, 17801775841166869486, 9610894500726595609, 11754871869039418305, 3106011472540779982, 5534818333558495963, 6265664197169483681, 9801143914278062154, 2114471287922017076, 12864813595450034552, 0, 70, 8260931550665656557, 11893740670479805498, 1829926574142237762, 1594484475404924132, 6975828079371970675, 6084696993723509491, 9595530987647092729, 15971750173693346214, 11203921366229716627, 4563063455320265667, 11788904100176198733, 5330429808657306820, 7735824317535531109, 320993418766884621, 17183008147454152591, 12480600709687621128, 10013781853527055299, 10535753745093412026, 1262088577389795166, 11216661268945885709, 139199134922249731, 5046795949307964432, 17871092368823791710, 11987849509093694665, 2910522803612995552, 8688806902442064031, 9527459414368740643, 17392858720163980888, 500779098360895522, 3548930057165921670, 9435312778805252724, 12594665258064570664, 7059236745058640735, 9552556216292266897, 4246851900171193724, 14051544049298817271, 11784642469202829877, 7043511220559324099, 2923239127151948080, 3593801949375944745, 12822730519972797871, 8453074578285752653, 9394265395193498181, 2676701676156012803, 9897038047323897370, 13273146919350422539, 8734416771856167315, 10836844319802726945, 164526851958521730, 17195525663426568111, 10288960109250570842, 10886225029528628150, 17237759664671057052, 295310595529849583, 1818311521513634717, 289062595793298208, 5959646737238852401, 13643407453100925757, 9822906574365710103, 17892016949428967969, 9033576496544593982, 16928201695930024468, 0, 68, 8186419089203192999, 15318603549361168513, 7911471416782656233, 14239435248344205979, 2133634484310994464, 8097913535946941412, 113263425049039362, 248987352426060274, 10939256691674299939, 17358468187481791647, 12423884741952977957, 56617284060232395, 1868806426895026968, 222259776750343599, 15059516987340721081, 8741184015917561905, 2066403566980848459, 3696239822839219697, 15367181090448289261, 8349149003644261348, 10280553347796952088, 7301079719327054003, 6885778115777578237, 12504375544103392076, 9288443086735636960, 4503182154932177101, 17461402434481489861, 10152174670869705735, 6117144343302310887, 9435312778805252724, 0, 16, 3208043314804619251, 6920597847411412414, 17985619796195836408, 11907191178709112742, 16377455862733420451, 15572876043608056600, 9466912758182965715, 17480763791598773801, 15029113851915312964, 1953587265841775225, 7175742902791404624, 6820764940134875350, 16069841829669607101, 15548451706938320654, 11760680638795846495, 1560700914733041660, 762367990279432470, 2603436428456411224, 6200990949184863170, 11673627333152839295, 7804486006334068097, 1006207264024395366, 11193609705356653459, 5704515878100803393, 14918729158665343812, 10658508130485449873, 380737719356524599, 12870561906904032245, 6984680585936259437, 2372900269115514267, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [4141253528664299662, 7535227198536906721, 13157788436891508553, 12242844110543519517, 14956019708245712821, 10570950564294000321, 17480412968160901529, 4150746739043008211, 7668476027270202579, 16656590512852921222, 6540695355644326389, 2062361183656478066, 6992883056491326847, 11699589910980507023, 15900656105857229467, 6696171278998449226, 13168835889056955304, 12256719005104851107, 3837048139847179361, 3160764979077625659, 260627379830442974, 11253217769249016375, 12385338833843346575, 13819086418675951632, 685348230246056503, 8109480959271599370, 15257531885396120213, 3680188101282186784, 7206583663178666402, 18199569338713260127, 11998802949255523211, 8214490973132607971, 0, 175, 18424611315455665672, 8660762125905589832, 17127340306827455573, 2784948507084849054, 3893738632331286853, 3285198522433859694, 8347633294012310580, 1716176048133035367, 17973624234065242957, 16459952452199547026, 16037889673287918578, 10274502539576810724, 8768898256362256567, 9056849240288317429, 5470591020023050699, 4574304056007112162, 8410472682472513857, 16137982984163538210, 17597264692962831013, 15736663856375030006, 17727370521374436910, 8474944897236640626, 637885636686826709, 14676123610051724022, 6045066589466757281, 14903105088638349433, 9178488780906183949, 572497659895507109, 14724337405152116499, 12030454825456445148, 3358534066525179769, 2539641719046213740, 14597771066871753553, 5977340097238271765, 7707653349895837404, 750410385838623118, 17202523259145509542, 9826125054086633997, 10704182720413467090, 14182542421389276936, 1208823412034618259, 17538680525690853062, 16486686521840942874, 14299802542131844724, 4141923705337186001, 15072716099695791702, 13709137995402237101, 1759841724041652075, 8081765454289246423, 8476759162841806182, 8627241529856509742, 4347076460454100596, 1495131601817209461, 626496362396505138, 12905076793136293016, 7898562997016536225, 4051444777808751499, 10985547818594749595, 14333518987829918669, 17843924827166978222, 10647867748676596435, 8523492539397344614, 0, 170, 13502722698945446624, 10582364865337924932, 8264438684589566467, 7775924941916048886, 7506941477585260226, 13559643900430805558, 14624701183045087851, 16810498729905278091, 3617722030424605287, 12209401598010007429, 14622001497128700788, 7124074456411373593, 11046353624103181594, 16506916834573600874, 2763493011778369288, 4381652925229768341, 9935322272824673857, 864619558035150967, 1868429356172715569, 6908757966622831414, 14123318794287563052, 4877497612363750655, 2105400693641679480, 8941132592749341698, 12124737918817624189, 15847492668873519030, 7578220797847929864, 9410406960468072857, 4811333449307081983, 5256913258227871425, 0, 40, 18130890293586930078, 18252951749527557342, 4460903658820341507, 859505755654562117, 5961685480015386121, 12134776249586726543, 11174658189737631113, 18385152961050631924, 9881471501704199804, 9636744945302995714, 12323181865658998064, 14903454669611502952, 1490539036394497080, 11688514875590095153, 16093513520259190726, 7731471377060742735, 5247500963110975116, 5269361527156951110, 13733877647296302634, 11865469401112846356, 7643242142337524006, 15572658687280648106, 9345628789826937825, 3291248301730279223, 16808111015808513609, 16274730253017522022, 12243901590027926887, 6559275936659510680, 17224785255700525855, 1390310476158884261, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [4690506171811599662, 2737440767612572473, 11521696315622895181, 1112809250875085271, 12021362864117640865, 18151871077622688335, 9897941768997576086, 4026157395886157229, 10359334248806725290, 4146117248162417047, 17246235733851217304, 10866279963718241802, 11383920474028743559, 6348426772268882755, 4713833248608103744, 10090565134847963788, 10865777585291872469, 3995119331147317584, 1039809878544438546, 9281899713308431529, 894389675194381154, 14912731377283108791, 2518971765323930332, 14554524254203776994, 14524699810240327783, 2026981110418907406, 12320900210322448034, 6520538036510347086, 6198597980723382916, 7473328648066901490, 1026110231435118088, 4584625016228750380, 0, 140, 8710514240711102938, 3087828367487460915, 8550318671602553781, 4930631020140393563, 1021301660011942544, 3073595205709678428, 2828555514110129215, 4454529496924239314, 4850807088481902893, 8327420331623942113, 5731477673914408028, 9865807300278005609, 453077352291409865, 12820055819705071946, 17847152132518767621, 8150970536507693114, 4592469706020729085, 8591936306357206220, 9734673703119078710, 11269239869586993393, 13212629127542823790, 8294118794714299790, 18005585695632222469, 5850018245424229562, 3823107055299292863, 11302847087529014346, 6890858608219888881, 10680339138669917038, 9892588909603237147, 14743087584632180635, 9365253138981608257, 9113412038486870528, 12891440258701617795, 10322300200196682981, 17715988767376665360, 12529577197437921705, 6552591582707442459, 4758921283651545108, 2473371596923514175, 4508995650639757747, 8913958469585669066, 3583695132258196536, 12251718655020006238, 17851199719794441593, 8176730118494162678, 9396959786745583185, 3556146813643685764, 10220987366360269577, 875353240064010198, 3230914141298165225, 12763806424191572386, 13303243524843396217, 6289147021348404787, 12692366118122891151, 8285789034090944076, 14023237997722359599, 17743718519616976296, 14731468822320978999, 2543793480285047170, 17021793130360212806, 11915740833798992018, 13282343245327117747, 0, 136, 16864340361327671903, 2636070061904000825, 1539270658943308645, 8663103496298937284, 797155414931197277, 7929222985705309752, 5418421295167202847, 16520350781038259800, 11697635461652845634, 10326065236143981873, 4672452207442160023, 9236109584144478544, 2355139499180822246, 7782053902926446231, 2620978815438101291, 3668923621194401622, 246363526423127035, 10353083146864436335, 3430895131654614161, 12564495361718767183, 4982750975383300564, 14559648290526166949, 6242143746593499460, 11140632426269699329, 3028234720115016827, 6653412960111738263, 17564919688262005304, 284282844772359316, 7938696543505248162, 17100537000217132265, 0, 32, 10452764368937945515, 6969997263492352670, 15570786589164252178, 16136993048454358354, 16378352067056606124, 11747573379431147483, 12296464969648251345, 8155132212936940581, 2470200969414032680, 18126939303114916528, 16736276280592238734, 15549342782445497049, 9033882039108268313, 5121596298161079296, 14336897502470956191, 6301009824137139871, 16614860627935231068, 10383378433371415142, 10330363517752279308, 10937466001850040595, 16305844076412050396, 7189713532379018536, 7568236447715590536, 10805187342082326609, 7424874700566577356, 13861219118264849665, 7052270251739242825, 17586339544079318164, 14071176523136369481, 12282546735285148319, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [7471531250255239926, 957106104872100553, 8426354436255247671, 14696972132215546141, 16692922442306646447, 8874979589420119367, 875297058086066175, 17626443192502070146, 10085921208436197132, 7288928467232887868, 17085775336106720298, 2718833903563323199, 7078253443595954934, 13309456694532316914, 5975284652827254996, 4866716465241707365, 9487238857935659569, 17181552195820469706, 8127338887120154462, 11933049108483241248, 179996691661177615, 3374573212837962242, 4025363669025839136, 8885320358009245035, 7362303317308040642, 10721260413929615658, 11637817792474845578, 13461475369693849006, 10395653141429564317, 12120812098909026742, 14623333492544617469, 7448701979965755247, 0, 35, 13745802786964652170, 10807941376803729065, 11967821891194701924, 2468953284439066013, 14003176497724809129, 4195286142867428231, 16235476345222743147, 16311400958482462738, 1275416753317277649, 7827742839669371295, 15144275993610658984, 17059326124115937407, 1609065912712094319, 1953375973007785317, 4662315141802736133, 2648588484571064605, 10314135606564051297, 17798108062832293769, 17976467869316326526, 10521545375054979384, 5478438738361095924, 4079016485765258670, 6409557376003924138, 9751499496869829327, 17630322765550216924, 17889552338200421323, 13578840114630190185, 2119568863265536467, 8158174533637128652, 804908825530740834, 4243893038989355703, 8922317147540258088, 7976296880270099068, 279851189829800217, 1629791578136936575, 9250281207577685312, 16325213226883592903, 14233424972710589898, 1150752289248225959, 13420723953151700222, 13103867886586495168, 10246367578585743447, 9749713722270402553, 17275110341684860619, 6783090395235209659, 17969645096023124419, 4121935965911645088, 4288337514646499477, 7084144568226748800, 6029442255508906403, 10924085850925815890, 8369007777733896382, 8232780781393445755, 9118931780992437842, 3679317166559661163, 5036788400317364302, 4470738656604083779, 8115411932938273702, 6422638912707970220, 16012433424607683700, 6326608805282345628, 16657610054734022844, 0, 34, 6567391571487826395, 5204289601743072522, 3431536436519013066, 18098398151169262506, 7669185665212226764, 5455708142000104069, 9902960937688969164, 16439153306838678161, 9116909952501731628, 259487815978835763, 11207509487307725092, 13598970521047669184, 13294225392413433281, 17974846784869714720, 1531979193630020279, 8742633689618768661, 12951219828222672250, 1272063647175062154, 1015593294205135440, 1601391529726059156, 6891640398393941397, 9120291006888379304, 10474372360890458437, 5584077426972546342, 6680864214558642932, 2419346771478639592, 9600963709893327666, 7733975108380115257, 3435995547523177385, 10362535235958450122, 0, 8, 9114363797835460134, 5446076396314160376, 12863008906537145423, 10008421878335836436, 9952321233871043669, 12872379155893703237, 7266552182027361169, 1266036355585216796, 2621902104176569009, 8791105532651972211, 6351975813451610601, 11821139808280113179, 11281913023757770338, 3277134497757048289, 13219080767636598429, 10181825490691565485, 2766637533497216499, 5527857141123489970, 8463471033597650592, 16863468430858262436, 4521466714741486225, 2112404415880305855, 6776665887355979100, 4283028800297139078, 17448147405455891940, 2672696094870261596, 654959311657763753, 15404879372302137522, 458610335793450516, 11708893791522292939, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [16928201695930024468, 13316048579382449360, 2713831240363482992, 17933860786448377030, 12140276230850597158, 1606372307127613897, 3188770991194636906, 14438001176756564964, 16448487398099419345, 9918214746375746352, 18110219924373985313, 7493603045769629260, 745957266720787386, 208949971747081929, 17140128915513269672, 10592811345979549626, 17407028959895176066, 8512417397041248917, 7287596669447050848, 9095813259348077504, 12193512270869861572, 13556169973586801756, 14690878971952130243, 3851130964131028937, 5140683189548028765, 4356298339163646871, 3363935513258073239, 6101475308358905031, 15929576060773374367, 9238706649514600628, 6772806779673451094, 12849137552501188796, 0, 35, 6548375970637655697, 12966884757436832352, 8617173377985249829, 14369692677316723198, 7988737883003214917, 199454479220437296, 16488861457711574881, 7336046662918934307, 15030081564191678849, 2458019052558535305, 3971043898284956979, 169011925839529283, 247484960726213991, 11098826393785027594, 6337173918784738400, 11606973446973456199, 1842388487495083111, 3843434841734991971, 17692030742991723124, 11518912608009699621, 12820002738657995668, 7568893198878892067, 7859209399338136233, 14455157706277846466, 4973217863350539721, 16132832657712782617, 18189457662137520245, 17447468029829501860, 5366612376176920228, 15978537433270792071, 2372900269115514267, 7638869850317184912, 9869196225863171361, 6918765821995287137, 1369739146488483681, 1289422996858358477, 3642389184556912711, 3891108637149977246, 15140294830527696728, 5009228872137272209, 7715172072574760928, 1421290680685617214, 14403164863632503479, 10265245098090210711, 7174788237318142123, 6381427654975252574, 7602994898079563251, 15302356383007635999, 15586805931977175637, 18437766594761332377, 11240603387110570141, 15093603048951386807, 7035853470370737247, 1835696655621331722, 8169021299801629244, 14781376510855187932, 9409022898528060781, 10695296899698374978, 17063170837522968299, 3702512996340883595, 2628586313169132635, 10245076951199455280, 0, 34, 13313027311321423572, 9192034959170904294, 14701500658652215925, 3854356596578551734, 5718692378574184090, 17501390179378757090, 8526809416150489728, 6507550884061463423, 7814960517829781662, 2939637999200097803, 780950602796552578, 4118107554308446430, 8555475415255527439, 14714307830357033751, 15614510648083677054, 17171454789201612359, 15897739400545916002, 5578273266312075011, 10191353484336583572, 2940473809902205523, 14962502826274181007, 2115641271859045975, 7064236544478437245, 10824702985925635247, 12931918488324919856, 8429882718924461151, 11244752067809188397, 2111913529644288504, 6112640616610282754, 6599190416745833044, 0, 8, 6104172690014223231, 3119855977255645286, 2700229040680838768, 4228220371303630837, 12976691418076017877, 15391527008624099592, 15522155400452634037, 17655908650961725957, 5157987610310047621, 13664486701019622043, 12908699189677656287, 14840926611057477527, 6092037682822283700, 15181448373122947619, 2083722204849270202, 1893419523737526751, 11329911669537538562, 12331432886354737271, 9636585409664050258, 5131588463040403759, 10248116973079783912, 2136665268102207704, 17448444978654544666, 11945433761064128885, 4462464721020457233, 17579935132869425842, 7098417589530391109, 15343623253038912080, 7762335122892638892, 10310226363807226654, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 6419744430976403982, 3447697248540225808, 10044864192452182412, 7058340312231756422, 11424300291678555912, 15031231631039778878, 2669622821021436503, 14911345319478414189, 5914533097243323078, 8371470863620210867, 2533220603754125879, 14376937495131853153, 8539659581227571270, 10662827764253743390, 17166726581641984506, 11280387487817815677, 15742094452256624479, 8912948444301774054, 14703675557715690630, 7196421200244503747, 2515843481723679483, 9280041324473036738, 9451078778045131871, 18129703980105207203, 16085683684539047157, 7181119043238227738, 17090649967623261857, 7951988307407900542, 13025686387588160039, 10950281275289859162, 677561570464011141, 0, 175, 14697063750404833549, 5887611756450648665, 4390455106880745190, 12605921110673978057, 3909247147397492340, 9689010753727301488, 9581721436999738864, 16354053311311796732, 7989095941327388146, 15260860572373553109, 9500012181060025316, 18019646022591970627, 9649122197052954943, 2900327270128075, 14086650041861556859, 3689293233291605771, 13498186418617526222, 15088669255793884845, 8596529378407272747, 16168113363552219541, 15854163065073538636, 9399437128660150397, 7202708241142113012, 14757940169676147698, 6949143047896273946, 15186394770637938057, 3979322074577621357, 5317810489943751161, 13663234493876910991, 12876040067831025585, 0, 1061325914286080806, 16723391107514202352, 9754566926160679801, 12819365845000407643, 9991664912056245947, 9847657839340877601, 9218945951971409528, 17937489760159731410, 6898590972078729604, 8642762389205548177, 5286310130352931456, 3192683419970405684, 7291895670920337828, 9471733465477014135, 5916843872480033571, 15161469576939421414, 10084364066798723299, 8948842015142234828, 11061922567205483533, 4596163035992380964, 16524077373781301709, 3948990276587207306, 17492638446874188318, 14193096602587779175, 7319641733964937743, 8739778943225234768, 5782681438096211376, 11891715600478694595, 5580010029452924235, 1761218265234642115, 11605105809497505058, 0, 170, 946461078672821334, 16281780351388912901, 2935418863412242354, 14713353090133347394, 1791207195906381248, 1092415958346704160, 8319785044806982194, 11182822967626325795, 16809587424157045315, 2244733962249620937, 16303706249485479712, 845878992383212753, 5921002467687226204, 4434027484725189444, 15967620315457307754, 17386925554974145101, 13158427748622481094, 6196246176234489731, 8582026933349467190, 611778401982756412, 16288180016347524015, 16434619985909351985, 1145514137751095479, 5160952971387430527, 8451565207539691282, 5967893180517848182, 7714774968702541161, 14978023560208702638, 18014742166879778909, 5450578834500306709, 0, 40, 1560947813056021755, 6935064976442414148, 9999441144135002932, 10354700837586583171, 6040781227937012106, 4698117391978117444, 4735711626023545756, 11217844833019453026, 3130590714605394722, 2809204122464618686, 10935232469327759448, 18335893537613898174, 10868401885487323501, 15799177281014635734, 17187052562019754838, 4027411046406207040, 11879721967266924677, 3613659344771632047, 1846469577394958972, 14668357323201408029, 14939045883642543835, 2885718226990976376, 4969257074069595075, 10824274197210729467, 13212275138420405274, 10563919532671437398, 12234598862193668129, 14653607410806008848, 2498958194485300229, 3512215170452429648, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [87, 7416632953558849265, 17594999963544064287, 12743397052876062010, 16793498368204377302, 11520998711037823747, 7102906674716336449, 5413886510672963560, 1869688954383701255, 2779549538868222645, 2240230247124034957, 1133217540165824186, 15083342046854437444, 16448963681750067902, 1360814798563974092, 10806646336881251745, 7783394201341070849, 3435210620583322514, 6672417563265002316, 8185266593862172618, 11336008056438129603, 11885558902631228328, 2880459223621017435, 5581858847773628805, 5641110601962994164, 11691200044195449244, 18247981403702122132, 5440276046356043250, 17479206923733922587, 8202861560648587401, 6069495537705640, 6253001344519856608, 0, 140, 11345515238018223131, 2946171615755015016, 10503353101665672276, 15589073729373314001, 13718116689255862703, 4274061922998936105, 6661690865570834646, 2350105156607890338, 11848223112496568240, 575220748088635860, 14463381670682493434, 6239522938056088373, 5225807468457901577, 5430077683379130363, 2608178208619376380, 17198482303941924567, 3796686867992995838, 13906033972215271083, 16841535128816011006, 3862251867639640526, 2035529259540079632, 9756998763275612257, 1710277459229142915, 16231968704214022931, 11354865285620231158, 2004972393153402371, 12504370868862613699, 7450671729747196018, 11869180945716319347, 10995045216798627929, 87, 6657939908049969746, 18076794411180476280, 205142327694293412, 16544719539062425474, 2678151302770396230, 4629674588184701527, 4756922096433783348, 6601966437239502772, 11244080601096335225, 6649199742327408095, 1784797448120793789, 14231596045603977911, 4619347748135638900, 670946413872621524, 9168306336221214796, 2712598845436515249, 4708938355998137236, 12719783652674704119, 17571986815953822221, 10053747442208350154, 9541903258826307302, 16365489308483642755, 9446845463763503898, 12491857199480659906, 8850778807446174241, 10733909952514206486, 15234998934151879467, 9571493212894702614, 4393284534245665333, 7926227231583287531, 15430453444364458588, 0, 136, 10841411014448826746, 10924324070009278511, 4390811061445162297, 10665404042695900090, 11148796663006115025, 16584177158338467512, 15369021590994653978, 13860609558593370204, 3837193053542887320, 7652640894347806080, 683219561750944695, 4006536353767232614, 4047796662675347846, 1149920536684206111, 1698301089048909092, 6224704259817574157, 4439284651749775339, 16476516570230330168, 10834199646006576067, 16282481854654492091, 6659294847490221927, 12242894720083399562, 7156478509869523727, 9996508607909856718, 17045153176928915002, 4097937233975335255, 13892339685592049122, 3881709886225480466, 10446442293007407525, 1539493896147927159, 0, 32, 9302012295643728416, 424328237663665361, 17748121622218558811, 6681769685034042719, 10907932526941371789, 14996603190997478665, 13982878080104642188, 3336783822228111865, 7403528606603453519, 7309352233404946366, 11509327586943808925, 6803943428138467537, 12870260590513220077, 3798257798625653324, 15652192157997003684, 8260391000410661595, 9099897743400681933, 16067207775248165408, 7640841583197908852, 16739199083410292994, 1998275509994500625, 10688417071827877337, 16160081185811655577, 2725954513011781037, 3040692668058239811, 15097072321276989567, 7813293313258815644, 15261763399945716285, 2258772319189190202, 6756061023037720295, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 11356706632132474470, 2358849405739495388, 8252049255686697090, 1550389821256969487, 6750324157015485381, 604741251465830172, 17676294546444101345, 1421326959851451806, 16490161619089770695, 7767675836373196892, 2198451335895548750, 14472480345778371117, 4528209626244081470, 18204665069024529476, 11966881683411871471, 15889763672746314463, 4160946893194356300, 15047282824503396386, 16648027271626045172, 17326536692088196432, 13311336675659068295, 10920522191757572329, 6554220297842488502, 5028468445182081313, 10053567802826673403, 9039178885558385498, 8545236135635685226, 10069135081496908116, 4751010459333335795, 15084214110056267454, 1607381721595724854, 0, 35, 809326793687057962, 13043350793597586415, 3445826420292422918, 15832983954926147440, 13006453459232495210, 6690439008924914176, 14925506152061129229, 7686554446337042304, 1386567235067272296, 18336554683084823555, 13461715534861002386, 6450595223101539903, 16347954830762298502, 15583422763378897975, 5985288376766257087, 9084874200639035992, 17711582701900015634, 865108223448999540, 16640836306313302925, 2841702098020816448, 10239653893689953177, 16135446855619161594, 14211710812292436619, 4482236293883987028, 7541264006304433571, 12592463296509852982, 9966350562627740919, 10317133817946706776, 2674823044861603020, 8201489714833429310, 0, 13425232862973212709, 7318735608001207147, 2870457579998112786, 8435616415860238896, 196396598284240198, 15030346739460637318, 11783104108423427368, 6893308270453759366, 1186051241082879855, 5410658890137048512, 10911572374110245694, 3704568930318998699, 15085014690020902180, 10285804549311169869, 9214751878561195125, 10949533612894576728, 4512217941150685160, 3355391310977906543, 2378656381642692957, 1495035938694254211, 1628981830846711491, 1657549910326762005, 2033490153416681362, 15310508516972009936, 9202695474221693202, 2288182338723422425, 1229088437375601266, 2390601416181918661, 7303237900174645421, 2453521579710367516, 11406074192870264875, 0, 34, 8422262931452347509, 13885570107923725144, 235244799151795110, 17975760300270072840, 21645088928215528, 13378438338434245321, 11260622121353286786, 13136688320626048612, 17881560939567828117, 16601834208041636644, 2350599886583381643, 3676641047171560447, 2612703737764640459, 6165448709088710825, 9702561415374819789, 14396227383672448392, 2871975363154349452, 13084396173640101372, 15953404371899770169, 14377272925308367884, 5291380804534138171, 576711179775643850, 11287382459948400014, 9324129603955102500, 10503620158827014837, 6130889055094603538, 5442709211693844142, 2968563472347562608, 10528964699829495885, 358459342719025633, 0, 8, 7519454690376123692, 7627104070861575574, 17604686071836489236, 14277148259130460564, 8312218486680706135, 8395439642754559152, 17307771294890409643, 9298206908486537717, 3027629924013931359, 2933551330348935458, 1450485994192951386, 8585052201707081835, 10624425952582111111, 16773523322999621677, 13337622149287916761, 17874287708894504070, 14164897610403484003, 11216401648549709020, 911970190394256131, 3202853507803349037, 14616902435260689479, 14924823153427050614, 4881022900440414264, 9723366934152472594, 16335725686098559697, 8087897843744270993, 11437013713086863200, 7627258546495067733, 18044191572661655945, 16490279521751489469, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 2156162188207533858, 1652445317709542069, 9710174156710538584, 3687395741963426550, 18198216273587752711, 1838753262326158154, 17157485573110166020, 15957089851173678739, 18249894041959305436, 4865827667628828701, 13002397426121818840, 2056311725258650732, 10926587116602338049, 5861292583325103670, 7147743639536563769, 17793738412709433040, 7010314501210327907, 14741490826925726048, 11016711855241315519, 2381487671462803904, 2201441872551078055, 12296957712116650503, 10199495361398762521, 17597473646777692775, 8352767355705497400, 6369472266524549650, 3523683736119512174, 16946656379378628774, 5583968744804760129, 12827986113643603592, 11319208922614274152, 0, 35, 8353595870573531205, 2540346347559199959, 15905617593867500462, 15206447585345432360, 9587574406720228419, 13962042635878587483, 12647708209366536631, 5660351957917038651, 2686094179381860856, 6724344971643611017, 7730484900119681480, 17496531794766962548, 9582673736768413052, 5090730089788327507, 16316669523444224399, 15180713067843619854, 3366467649642622206, 3781233238795801028, 5780865724855930643, 4603482683901152330, 6284610136599748777, 5490240700537832368, 3009248399805477246, 6182266765615504635, 10157260196426992044, 11702418701530435943, 16215780421699068990, 12595602375369553246, 14007226435224111078, 13655239822733173662, 0, 595597012989057201, 17139781905758323226, 3995355680811906625, 8414041561969840147, 6056580584982795553, 2275917558381110739, 1213850852525589804, 12621557274381914353, 8183226668403108743, 3186362008740620984, 13198139370097152194, 2958463820434100861, 6175120933459995736, 605479756900086202, 9130478176053651155, 5046313161028350213, 6401077792884902899, 6554586936759661283, 17551059730726512380, 4149682069832499543, 18155642743356144121, 7818664772328532886, 10601663807010949823, 13981378283476746869, 8981534628391844134, 12415014162240143946, 12267765271876857143, 16738431774071597762, 639602489095149029, 13916262071165774844, 6409620289494267476, 0, 34, 9168769012195838974, 8757246072351383525, 15819587373362991575, 6330331124468459419, 17594449485955496857, 5094615699180819390, 10468588157075103568, 17500241837984025274, 12590769989805218521, 10257339134394161483, 6020533408585278677, 9887559600989616103, 17174772404727048357, 8260989830322406645, 15331894718426588199, 13817494132369433237, 7270842089806116389, 14464987003178196376, 12856235623981550070, 6446968933011398838, 4625298604721424009, 7537989708572581312, 8773062848621227780, 7997392847552644982, 12295542285792207282, 2236820296563710856, 6411496154095679628, 96618257160083950, 2708395562256972928, 13820925760592258770, 0, 8, 17781582622500481192, 12847902632736061277, 12021499907877242591, 16751519355106661703, 9062087890172095618, 3834953580385337540, 2969703856153678454, 11604562295556139307, 10447912046373566534, 12987934619706800857, 12352596220492768030, 14816150974992525275, 2172600571554701126, 18086375044546604023, 16313093185369681775, 14997664071320688070, 347950016295486690, 9206182676441692601, 3566552483989599402, 4925983231752336365, 1728701557101400581, 7087476601458867917, 9759961360999781392, 12569092891286895547, 14206292953735333262, 16422952955631166803, 6294107725304445883, 9537940691512987143, 15535806100011306333, 7080716573279759555, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] }, last_program_row: RowIndex(13) }, program_info: ProgramInfo { program_hash: Word([6116677274871151273, 10392133002436897113, 10134148635057625602, 12864813595450034552]), kernel: Kernel([]) }, stack_outputs: StackOutputs { elements: [0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, merkle_store_nodes: {Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571]): (Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350]), Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350])), Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484]): (Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693]), Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693])), Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781]): (Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874]), Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874])), Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171]): (Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361]), Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361])), Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815]): (Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305]), Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305])), Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689]): (Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195]), Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195])), Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362]): (Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063]), Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063])), Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848]): (Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661]), Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661])), Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352]): (Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829]), Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829])), Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444]): (Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223]), Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223])), Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386]): (Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388]), Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388])), Word([13190842942618341421, 17548956981569849952, 15418963848144418856, 730733050713174879]): (Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144]), Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144])), Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874]): (Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675]), Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675])), Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594]): (Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115]), Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115])), Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809]): (Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257]), Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257])), Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777]): (Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555]), Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555])), Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509]): (Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882]), Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882])), Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725]): (Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979]), Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979])), Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134]): (Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987]), Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987])), Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828]): (Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910]), Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910])), Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830]): (Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054]), Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054])), Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228]): (Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742]), Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742])), Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443]): (Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928]), Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928])), Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643]): (Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979]), Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979])), Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758]): (Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106]), Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106])), Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580]): (Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594]), Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594])), Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765]): (Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045]), Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045])), Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766]): (Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281]), Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281])), Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385]): (Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828]), Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828])), Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579]): (Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171]), Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171])), Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212]): (Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992]), Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992])), Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463]): (Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004]), Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004])), Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502]): (Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023]), Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023])), Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539]): (Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537]), Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537])), Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865]): (Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225]), Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225])), Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690]): (Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947]), Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947])), Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202]): (Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552]), Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552])), Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079]): (Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444]), Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444])), Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850]): (Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548]), Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548])), Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448]): (Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987]), Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987])), Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041]): (Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035]), Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035])), Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301]): (Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414]), Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414])), Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414]): (Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212]), Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212])), Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703]): (Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439]), Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439])), Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271]): (Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955]), Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955])), Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882]): (Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802]), Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802])), Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152]): (Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887]), Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887])), Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028]): (Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948]), Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948])), Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331]): (Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093]), Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093])), Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394]): (Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134]), Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134])), Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546]): (Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228]), Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228])), Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620]): (Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414]), Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414])), Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800]): (Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703]), Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703])), Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671]): (Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205]), Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205])), Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537]): (Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011]), Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011])), Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516]): (Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301]), Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301])), Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831]): (Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986]), Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986])), Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415]): (Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057]), Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057])), Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722]): (Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689]), Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689])), Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144]): (Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682]), Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682])), Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295]): (Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268]), Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268])), Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818]): (Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513]), Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513])), Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241]): (Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565]), Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565])), Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439]): (Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012]), Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012])), Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512]): (Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850]), Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850])), Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986]): (Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865]), Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865])), Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982]): (Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777]), Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777])), Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808]): (Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394]), Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394])), Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979]): (Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690]), Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690])), Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093]): (Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620]), Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620])), Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902]): (Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789]), Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789])), Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542]): (Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094]), Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094])), Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057]): (Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362]), Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362])), Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205]): (Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961]), Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961])), Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401]): (Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580]), Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580])), Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553]): (Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960]), Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960])), Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169]): (Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031]), Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031])), Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682]): (Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053]), Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053])), Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118]): (Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562]), Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562])), Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725]): (Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666]), Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666])), Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661]): (Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897]), Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897])), Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981]): (Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447]), Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447])), Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072]): (Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646]), Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646])), Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140]): (Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404]), Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404])), Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515]): (Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152]), Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152])), Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709]): (Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664]), Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664])), Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800]): (Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103]), Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103])), Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741]): (Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169]), Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169])), Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005]): (Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758]), Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758])), Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802]): (Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070]), Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070])), Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159]): (Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005]), Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005])), Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350]): (Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443]), Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443])), Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697]): (Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573]), Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573])), Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928]): (Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331]), Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331])), Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320]): (Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166]), Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166])), Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814]): (Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079]), Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079])), Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447]): (Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820]), Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820])), Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284]): (Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057]), Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057])), Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697]): (Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131]), Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131])), Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955]): (Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290]), Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290])), Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910]): (Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202]), Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202])), Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910]): (Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822]), Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822])), Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106]): (Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847]), Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847])), Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404]): (Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441]), Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441])), Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796]): (Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186]), Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186])), Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053]): (Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516]), Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516])), Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992]): (Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818]), Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818])), Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957]): (Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315]), Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315])), Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709]): (Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794]), Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794])), Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091]): (Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539]), Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539])), Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664]): (Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558]), Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558])), Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294]): (Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579]), Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579])), Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947]): (Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502]), Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502])), Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829]): (Word([0, 0, 0, 0]), Word([0, 0, 0, 0])), Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045]): (Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137]), Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137])), Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914]): (Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041]), Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041])), Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573]): (Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378]), Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378])), Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699]): (Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873]), Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873])), Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225]): (Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262]), Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262])), Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057]): (Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692]), Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692])), Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131]): (Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997]), Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997])), Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555]): (Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385]), Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385])), Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195]): (Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709]), Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709])), Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166]): (Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542]), Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542])), Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027]): (Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373]), Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373])), Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378]): (Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509]), Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509])), Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097]): (Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553]), Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553])), Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217]): (Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815]), Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815])), Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873]): (Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864]), Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864])), Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997]): (Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722]), Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722])), Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887]): (Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766]), Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766])), Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589]): (Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757]), Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757])), Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539]): (Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665]), Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665])), Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129]): (Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229]), Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229])), Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137]): (Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312]), Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312])), Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019]): (Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378]), Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378])), Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331]): (Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713]), Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713])), Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]): (Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980]), Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980])), Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325]): (Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546]), Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546])), Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170]): (Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822]), Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822])), Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054]): (Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295]), Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295])), Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925]): (Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848]), Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848])), Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909]): (Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796]), Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796])), Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540]): (Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170]), Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170])), Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214]): (Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448]), Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448])), Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317]): (Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294]), Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294])), Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757]): (Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416]), Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416])), Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378]): (Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091]), Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091])), Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263]): (Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463]), Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463])), Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666]): (Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361]), Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361])), Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174]): (Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992]), Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992])), Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470]): (Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401]), Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401])), Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665]): (Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957]), Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957])), Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262]): (Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144]), Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144])), Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229]): (Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284]), Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284])), Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134]): (Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325]), Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325])), Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855]): (Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765]), Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765])), Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115]): (Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814]), Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814])), Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441]): (Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831]), Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831])), Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977]): (Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446]), Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446])), Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880]): (Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005]), Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005])), Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789]): (Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995]), Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995])), Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000]): (Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267]), Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267])), Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998]): (Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982]), Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982])), Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995]): (Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539]), Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539])), Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507]): (Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512]), Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512])), Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305]): (Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118]), Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118])), Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219]): (Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009]), Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009])), Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416]): (Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089]), Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089])), Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980]): (Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445]), Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445])), Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063]): (Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140]), Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140])), Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713]): (Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159]), Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159])), Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031]): (Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809]), Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809])), Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932]): (Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037]), Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037])), Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094]): (Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925]), Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925])), Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315]): (Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386]), Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386])), Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446]): (Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721]), Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721])), Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742]): (Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981]), Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981])), Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661]): (Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072]), Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072])), Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979]): (Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671]), Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671])), Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361]): (Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269]), Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269])), Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558]): (Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571]), Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571])), Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290]): (Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902]), Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902])), Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987]): (Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741]), Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741])), Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902]): (Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515]), Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515])), Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497]): (Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028]), Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028])), Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948]): (Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709]), Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709])), Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009]): (Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725]), Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725])), Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387]): (Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317]), Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317])), Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159]): (Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808]), Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808])), Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394]): (Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699]), Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699])), Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312]): (Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000]), Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000])), Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987]): (Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821]), Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821])), Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046]): (Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909]), Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909])), Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565]): (Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028]), Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028])), Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269]): (Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352]), Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352])), Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847]): (Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271]), Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271])), Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513]): (Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800]), Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800])), Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054]): (Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394]), Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394])), Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004]): (Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977]), Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977])), Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675]): (Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800]), Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800])), Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692]): (Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159]), Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159])), Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909]): (Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932]), Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932])), Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814]): (Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697]), Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697])), Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186]): (Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387]), Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387])), Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445]): (Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470]), Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470])), Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966]): (Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507]), Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507])), Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548]): (Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253]), Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253])), Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897]): (Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783]), Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783])), Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208]): (Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054]), Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054])), Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268]): (Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661]), Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661])), Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388]): (Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643]), Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643])), Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257]): (Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174]), Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174])), Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960]): (Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241]), Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241])), Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721]): (Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046]), Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046])), Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822]): (Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217]), Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217])), Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253]): (Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697]), Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697])), Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054]): (Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019]), Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019])), Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821]): (Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432]), Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432])), Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864]): (Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105]), Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105])), Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373]): (Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855]), Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855])), Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646]): (Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830]), Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830])), Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460]): (Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208]), Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208])), Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033]): (Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214]), Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214])), Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105]): (Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129]), Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129])), Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281]): (Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909]), Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909])), Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028]): (Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027]), Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027])), Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012]): (Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054]), Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054])), Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562]): (Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589]), Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589])), Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037]): (Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097]), Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097])), Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355]): (Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460]), Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460])), Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223]): (Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355]), Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355])), Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089]): (Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306]), Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306])), Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035]): (Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219]), Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219])), Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432]): (Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297]), Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297])), Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693]): (Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263]), Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263])), Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794]): (Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484]), Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484])), Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552]): (Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941]), Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941])), Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267]): (Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814]), Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814])), Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992]): (Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415]), Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415])), Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941]): (Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966]), Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966])), Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822]): (Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320]), Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320])), Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306]): (Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902]), Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902])), Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820]): (Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880]), Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880])), Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361]): (Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725]), Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725])), Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005]): (Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914]), Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914])), Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783]): (Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781]), Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781])), Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011]): (Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033]), Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033])), Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297]): (Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910]), Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910])), Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070]): (Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134]), Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134])), Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144]): (Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331]), Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331])), Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023]): (Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497]), Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497])), Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103]): (Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540]), Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540])), Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961]): (Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998]), Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998])), Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414]): (Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]), Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]))}, trace_len_summary: TraceLenSummary { main_trace_len: 14, range_trace_len: 39, chiplets_trace_len: ChipletsLengths { hash_chiplet_len: 160, bitwise_chiplet_len: 0, memory_chiplet_len: 0, kernel_rom_len: 0 } } } +ExecutionTrace { main_trace: MainTrace { storage: Parts { core_rm: [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 14618787401296499486, 12175440663040620259, 17580394656599216612, 9332791485604804823, 11950369617180951798, 9444935041463352282, 8315531457715846029, 9889393354952375157, 0, 0, 0, 0, 0, 0, 1, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 35, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 2, 0, 0, 0, 0, 0, 3, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 3, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 1, 1, 1, 14618787401296499486, 12175440663040620259, 17580394656599216612, 9332791485604804823, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 4, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1942941126776981551, 9461460041610899538, 7600020670677266955, 3257731577738044347, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 0, 0, 0, 0, 0, 0, 1, 0, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 5, 0, 0, 0, 0, 0, 5, 0, 1, 1, 0, 1, 0, 1, 34, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 6, 0, 0, 0, 0, 0, 7, 0, 1, 0, 0, 0, 1, 0, 0, 5, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 7, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 1, 1, 1, 1942941126776981551, 9461460041610899538, 7600020670677266955, 3257731577738044347, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 8, 0, 0, 0, 0, 0, 5, 0, 1, 1, 0, 1, 0, 1, 8, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 9, 0, 0, 0, 0, 0, 9, 0, 0, 0, 1, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 10, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 1, 1, 1, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 11, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 1, 1, 1, 11950369617180951798, 9444935041463352282, 8315531457715846029, 9889393354952375157, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 12, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 31, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 33, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 39, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 43, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 47, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 50, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 51, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 53, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 54, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 55, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 59, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 60, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 61, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 67, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 69, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 70, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 71, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 72, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 73, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 74, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 75, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 76, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 77, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 78, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 79, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 81, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 82, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 83, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 86, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 87, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 88, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 89, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 90, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 91, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 92, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 93, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 94, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 97, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 98, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 99, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 101, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 102, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 103, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 104, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 105, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 106, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 107, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 108, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 109, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 110, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 111, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 112, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 113, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 114, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 115, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 116, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 117, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 118, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 119, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 120, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 121, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 122, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 123, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 124, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 125, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 126, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 127, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0], chiplets_rm: [1, 1, 0, 0, 14618787401296499486, 12175440663040620259, 17580394656599216612, 9332791485604804823, 11950369617180951798, 9444935041463352282, 8315531457715846029, 9889393354952375157, 0, 87, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 12230109559590207045, 16524836159467994993, 15355865270174544634, 1391859963977339721, 12022620756870035528, 14989772180267129899, 13982693476036346567, 4019135314604422332, 0, 0, 1, 0, 0, 1, 1, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 14618787401296499486, 12175440663040620259, 17580394656599216612, 9332791485604804823, 7798791211572712091, 16041868217785231203, 6640187881380078347, 235747346370324341, 13046105914206547188, 17104930832431035898, 3750541143739447161, 16424211063756942915, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1942941126776981551, 9461460041610899538, 7600020670677266955, 3257731577738044347, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 0, 87, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 11950369617180951798, 9444935041463352282, 8315531457715846029, 9889393354952375157, 5389779285479201372, 17553508332489815141, 15087772099628732551, 5347478766541373443, 10896571887744929962, 11129997511013985752, 8670230788026367137, 9164328147053886136, 0, 0, 1, 0, 0, 1, 1, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1942941126776981551, 9461460041610899538, 7600020670677266955, 3257731577738044347, 15558099059781162807, 12870793504304295307, 12385397219736869043, 13164551900610862841, 279187929191844389, 3949603689257433549, 17380497166734391477, 5117931133682798382, 0, 0, 1, 0, 0, 1, 1, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 1244837894821529086, 14023738310468542470, 9319458442815716445, 5220020845190256514, 18381067342435073896, 15418184987737128626, 17753079332212842976, 12382717352847060954, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1532070872953744281, 11675978725956395507, 8258108365434236190, 8977540451988253054, 8832291907404336605, 16801197610032323372, 8498902414702613411, 2217861947967210820, 14648106445605106304, 5194857384255130698, 4543357020291533691, 1677011855369223059, 1, 0, 0, 0, 1, 0, 0, 0, 0, 18164368745351378969, 665130184182531292, 14548211377038648988, 9026463808500414994, 12372059324693434695, 8512906579977137276, 10951940384741553765, 2990681100436043903, 15463650459774420968, 6115025020360005524, 13619612156045325099, 9915559200666512746, 1, 0, 0, 0, 1, 0, 0, 0, 0, 73542357038484620, 16275608702285065538, 15615370514429573107, 11554047591217380375, 9626234372118459069, 14043139718664795091, 7172345985251039651, 13714446996516992992, 14079807935308074442, 17175342044195045043, 16936021968982853164, 3883665509408281322, 1, 0, 0, 0, 1, 0, 8133824218287649370, 1205363866316521559, 7923953289074004648, 1611370566290075655, 12516876786630134052, 16156412840636435500, 16066365782016562356, 12209717470970729826, 648151295134950813, 8424608506935970051, 941071657155810425, 12476535243066524999, 13046835168670418046, 13563090428318398174, 10213204276953300366, 1, 0, 0, 0, 1, 0, 11656233811569695541, 16780366708706866018, 10469348806910132738, 12317597613336433996, 16800450568443907772, 7958196127911254005, 5580405360121542127, 17991322909541306091, 9587008055009063413, 917862094456531518, 17636182943787095305, 5347924966817937746, 15791860137463552476, 5352122275530338033, 8207615265206228485, 1, 0, 0, 0, 1, 0, 13280747180546192023, 13818056542207317059, 12768869371961439487, 2029833730308772760, 3067168931363951888, 630426464913806566, 13807710542081112496, 10340529818978391824, 8301137772228612306, 18032943025979156234, 5571856761516233924, 15102755171792177729, 1386022355796901548, 10780164990569095481, 14005839963275167003, 1, 0, 0, 0, 1, 0, 8161514060541966002, 5430054846479849757, 855673369941768792, 8583346124368767357, 7152703336258374657, 4793816855328822248, 1475819744300266017, 5162097063446717296, 9158417383194264473, 17323069022182310843, 17309666448184518221, 16540233824244985004, 13271685073550397851, 3683818685539825395, 12883632168742702763, 1, 0, 0, 0, 1, 0, 14889661894667616899, 13319328534492736282, 511216470843933116, 5414088302741599345, 16030190225904238830, 6111859869108706126, 4321093113239299552, 4706826096768711507, 11021679444547674749, 15678561454143187205, 15168765916033556420, 7046395423559884948, 3431032212531228618, 9443306432483343000, 6291224588853575811, 1, 0, 0, 0, 1, 0, 11384512740043719026, 17996531901144166752, 4183594834611630116, 17695445402585642319, 15258305803668890228, 17106752205417894410, 13259786553689259064, 15859967842550332610, 5138368225191856866, 8345451659183769670, 4299979085769618674, 10058172520180004407, 16132576493934338934, 312707111584502977, 8025187035739711204, 1, 0, 0, 0, 1, 0, 17152042124522816142, 9826569971726481595, 8959076337043698126, 1987260706895490300, 17423289859865292784, 12258188545233319580, 4291864820252135891, 2950910453815263271, 852440029525711434, 1223549137263517018, 605327998629874385, 3009980753663636725, 8722464778364467857, 17216818427461180092, 13380853612843880678, 1, 0, 0, 0, 1, 0, 7979264206910945674, 0, 0, 7448791324579059841, 1050285053399784347, 16767087000176263535, 14849165193424062452, 2498996933077132011, 13658177069616805094, 495936213960522537, 13576872019913404781, 7640966386182958606, 4271515987309482058, 13463445006653778819, 12292225704634605892, 1, 0, 0, 0, 1, 0, 0, 0, 0, 6053040396430810733, 2172892474788961636, 18161859984545851402, 13488248907260320483, 8430623432188198915, 3055646124754645267, 4245215712607391946, 2243958878529225177, 14990440908620774864, 3080921390696878855, 595284666932255390, 6192940699035995377, 1, 0, 0, 0, 1, 0, 0, 0, 0, 14921496778760644502, 16662036864627516510, 6434377642684009725, 1840544361770929313, 15074823591915634941, 5258982948465254673, 2683768063818053258, 238295676214993337, 17552036469726894364, 15877921873938893194, 14734786106453693759, 1371624439541100057, 1, 0, 0, 0, 1, 0, 0, 0, 0, 516742705862090749, 5947805230277704319, 5952541516123965670, 9026915957393505056, 5986317686192419732, 75717367401824328, 8923961895635206791, 17106810061565988432, 7157463081631406163, 150940732863733992, 15657864298531798718, 12227344478922314236, 1, 0, 0, 0, 1, 0, 0, 0, 0, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 1244837894821529086, 14023738310468542470, 9319458442815716445, 5220020845190256514, 18381067342435073896, 15418184987737128626, 17753079332212842976, 12382717352847060954, 1, 0, 0, 0, 1, 0, 0, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 10338918064798200754, 15286122942437340674, 6004213370540561229, 11077881500896133090, 15185046381229794929, 4025060549564442513, 16691190932080263388, 17911971684749301267, 1792647895939561414, 11040149027552020115, 16788268171496683395, 6690778673349798915, 1, 0, 0, 0, 1, 0, 0, 0, 0, 18207620435178905496, 4478894291978491061, 8126565228616187566, 14565598150868720008, 486704718504877876, 5092068149414351847, 4895519870785798161, 18320934558859357026, 4783600071858140824, 7590991738963063833, 15020058681279762757, 8502154501231846969, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1790253480113930875, 11472368064126754753, 16140937904922483949, 12784262958320173457, 8992534124131108063, 17197330755228127793, 17888648586033704362, 3783608546885852925, 11488181860237317371, 6520363121033018355, 5666192756396478125, 14698764588926429548, 1, 0, 0, 0, 1, 0, 4775960838571449442, 12355201513767393906, 16893169864929129892, 3067820580898613927, 4037642048582652770, 6463406968300557513, 1334655449937755180, 16454962669178338822, 3423416796618681452, 15635204112556936010, 11367217176161227780, 15846919749025709683, 8739705468185832455, 1695606868833824155, 14902201197695023622, 1, 0, 0, 0, 1, 0, 7270109453425771694, 6393439473671243944, 5763178267509538253, 87155278506862768, 17182682045085641378, 13669966515951696363, 6730246632471569917, 11015850215265080242, 5781848723365073595, 14722218108828704340, 12249120524157518956, 15530817548594619752, 2571721876460128542, 1124203808167418458, 4658355789422303197, 1, 0, 0, 0, 1, 0, 619730554607827397, 2707784357837694055, 10389429507854625814, 412437114519718435, 17010823019251866220, 8496853728750345058, 3962235926057627964, 7293691342607609411, 4966485821032368622, 17523850342152507329, 16165780461118504337, 6833077136448453098, 18408644517259086000, 13790345385092960681, 1118981994890433291, 1, 0, 0, 0, 1, 0, 2870832816007467384, 2873570063945483268, 5260498635996294368, 10072735002004767449, 7363233941642473793, 10401385213219539176, 9719773007613995950, 10216717372939649307, 13022711033487370480, 9232213967333586262, 3354429439844650126, 13306058477265011029, 3840400538830937486, 15100916108359921929, 12686728912814672715, 1, 0, 0, 0, 1, 0, 10126186915863966894, 13849382609137246799, 14871056570003924152, 4577474152973240700, 10319035267502935180, 1107109480596608884, 910001863439660317, 17323775771861278671, 11990539141370178689, 1895237968841058140, 3069611939766785355, 13990132518689115799, 9158955820349235201, 3334355584256728822, 6532229842765454575, 1, 0, 0, 0, 1, 0, 8418794997351000750, 1324633730077053524, 7680826640634201152, 6943155698572158851, 4119721600018041835, 10160115415927000034, 13670021867743170174, 10426040451143237205, 12527054859506162043, 693011963436135866, 15847427063003354492, 1193915807921269299, 5530767236037587666, 4498758928312101948, 1668396433795256171, 1, 0, 0, 0, 1, 0, 12474497430381571234, 3486558176421926303, 176934443909317952, 8642603494321417085, 13568047686929876305, 13873699071648888616, 5469909543377435991, 1153721650762048262, 6332701647560212482, 14750767280279403533, 3863562993110808460, 10010469643426778773, 13610145136323473859, 13803405503382348517, 10066622964560025039, 1, 0, 0, 0, 1, 0, 6502239097904837007, 0, 0, 11596242931973405682, 7569447524345075040, 11402732351667273497, 17726124048449719654, 2143489115939838335, 2291345291252627066, 13774221459002946228, 5704848367751370496, 14844994802213729480, 13325648093707576188, 655937328333223270, 12601714085039449766, 1, 0, 0, 0, 1, 0, 0, 0, 0, 10080683606039484932, 557142253253508029, 11861574744773262883, 17479297133692971328, 13431343265670357832, 5107644268576628652, 5672451077690842648, 10697999158618521351, 13783189127611294708, 6370270522833708976, 16602411989536803847, 17535824353652041621, 1, 0, 0, 0, 1, 0, 0, 0, 0, 18221718971044951820, 11123331110225556773, 17884963006522019435, 13581862227015801716, 3539406162482662008, 12779267696302831166, 17568889654867020374, 14043625177809463809, 10953842550742243459, 17624483884859046607, 16829866994010956924, 10383254959407238075, 1, 0, 0, 0, 1, 0, 0, 0, 0, 7704989128662250393, 7731722432250559639, 1104300072480693820, 12966826694165085383, 5898355191387204970, 418343475844287535, 17504741557362850364, 11212567254567942759, 4585972511305465500, 831671821010246741, 1347174724805777450, 9978241385511108600, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1942941126776981551, 9461460041610899538, 7600020670677266955, 3257731577738044347, 15558099059781162807, 12870793504304295307, 12385397219736869043, 13164551900610862841, 279187929191844389, 3949603689257433549, 17380497166734391477, 5117931133682798382, 1, 0, 0, 0, 1, 0, 0, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 2844174837506797768, 14770415536338085095, 8053473190425314497, 12810585393750772644, 12517162067313615795, 6708309406641442601, 9752285986344000829, 14839297145466054073, 8534874634076336098, 14795338728791802759, 16467940132402131085, 13518949717672180282, 1, 0, 0, 0, 1, 0, 0, 0, 0, 197345143463752877, 11590552548391007208, 8513135180731923185, 4789498072246113352, 11303926357913784691, 11723443921595997802, 14952876297128645088, 4864312901193078229, 6947659381816817219, 1746178727761685368, 12918373769842417551, 8684596229708270516, 1, 0, 0, 0, 1, 0, 0, 0, 0, 3198805477847978589, 13930889360803740657, 15057872115125399602, 10921141672562986793, 5789960870644177461, 15608139912666005512, 12683155364689979788, 18346811491373252273, 10487394721802866951, 11974532682130534845, 1519861526503586143, 1098638899502132867, 1, 0, 0, 0, 1, 0, 17128804603859274179, 15425440231805738567, 2171332404261207924, 12061940714814445323, 16550302237377331826, 12740022639409649481, 4788619492523060974, 12101496647901663530, 12627924597542725825, 4538464495267088575, 7655969430543094352, 17740697538393183772, 1276333715732019707, 14173930302505429451, 13814834917482380980, 1, 0, 0, 0, 1, 0, 13522108978497478647, 15326000623266678192, 3937153401353680192, 5391465844431065097, 18248340349342647871, 15368790604451050198, 14035485820573370176, 16386022069680258207, 9349013130282144239, 1551611900277525346, 9934003659359682927, 4355136691411596250, 6906369583230328082, 6194111766557181711, 7090430103975125421, 1, 0, 0, 0, 1, 0, 6858104153104953844, 2783142950383804293, 8584815630276621541, 13736751627541767595, 14322019951421583643, 7328081675331405521, 2919878666094336280, 18265421608060798137, 847119850511152679, 6488028398833527134, 14030107144688032001, 16464054037947062503, 11306313446221145933, 2618902231753980169, 7111715274719427805, 1, 0, 0, 0, 1, 0, 14207818010411458005, 10702031730649360848, 1427799141318779075, 587927478659780999, 15271511291908440421, 1631153249982564447, 14860375384915403614, 5053574427925446505, 16185831982250091643, 5313306335957257312, 14408389614090560738, 3446934167305825216, 6924078255851134462, 1944495675792485669, 9381181653175935358, 1, 0, 0, 0, 1, 0, 1514501911734050528, 2103447129935109946, 15243544860712411446, 15662501863724208746, 13145679926921004363, 4622578459096655813, 15178320922885462585, 6934952687117461169, 6429901021776189429, 8190297765436449986, 17289740015790507499, 5474448770498973057, 14426481937239015119, 15225288135317750243, 9334877092232131090, 1, 0, 0, 0, 1, 0, 17039418869353369367, 5045115566370760009, 4671027510138840984, 7061837181192953446, 12931235775561067332, 13176020926551886014, 2651979372862304957, 6448209114888282956, 14113477446789099358, 14604918207559224688, 8862983295294549605, 16863262536586421908, 9999167437358985507, 9478876837144190569, 5194157795194187382, 1, 0, 0, 0, 1, 0, 10651133333257123943, 11101110287260233241, 650894676042466653, 15832539727497904498, 16656333065661736860, 18369789225665462210, 2693003614851431067, 772790696866677272, 2480179799990567291, 17304358978184667075, 6187736184647340944, 17237712361917640397, 14072736642225359273, 10623410937495095553, 3019557709101931446, 1, 0, 0, 0, 1, 0, 3558792632055854276, 0, 0, 18279620994548222363, 7537712095633077660, 17235753368900772495, 10138479632844764387, 10676334012313161836, 10151433255181272788, 4221944602571779671, 14378476772841555006, 12143502102929103640, 11730678005747995442, 5601143081558686791, 9280411157191944580, 1, 0, 0, 0, 1, 0, 0, 0, 0, 16884818255031608393, 13045713162430805835, 3600896491691629579, 2370161244647043179, 661552320621341973, 5193471677143062225, 4344568064600414577, 6287012165400024744, 16771346841353293653, 11496244803188049682, 13192283114216253262, 1468753321492310312, 1, 0, 0, 0, 1, 0, 0, 0, 0, 10180755850695837534, 6978965227021412920, 3137528352086851557, 4639410328460555037, 12740940713361972140, 6139739720960649901, 6992560805366421671, 5664952048525874594, 15115584234380815111, 6423836987080682296, 16291666223467597742, 9479232376233529718, 1, 0, 0, 0, 1, 0, 0, 0, 0, 10733409993326982567, 1953734515310810079, 14379372350324944355, 1719086499025241451, 3695292032734759229, 13442410518056192242, 5600036575840165991, 16476082167990762462, 13437881851625150616, 9220830330798622848, 10959186559397338078, 3278679000955332681, 1, 0, 0, 0, 1, 0, 0, 0, 0, 14618787401296499486, 12175440663040620259, 17580394656599216612, 9332791485604804823, 7798791211572712091, 16041868217785231203, 6640187881380078347, 235747346370324341, 13046105914206547188, 17104930832431035898, 3750541143739447161, 16424211063756942915, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1942941126776981551, 9461460041610899538, 7600020670677266955, 3257731577738044347, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 0, 87, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 3140855868878816939, 13853610777244465556, 7305682856568545034, 17768394568131058378, 4102628019324006119, 4284053222036732600, 702918224602433827, 10375695918533438253, 11152995795829941880, 5169004732887479405, 15116124983681184313, 11068900437831795240, 1, 0, 0, 0, 1, 0, 0, 0, 0, 14674311818750931642, 15727102992101643424, 10209637917493742085, 14433760483016802213, 15023858318134776079, 13617465913120919705, 11153310337321385356, 12991360735056054606, 3550460033083965293, 13918925059933519570, 14012164523634193404, 9616156815711922050, 1, 0, 0, 0, 1, 0, 0, 0, 0, 10332893761271738825, 4468346375378916401, 9749151272711495276, 8699061724169347090, 9834940708477034873, 5947156991246950325, 14409035433392705531, 628920525634910939, 11788382252656375499, 4818566561319754770, 14056028560156009139, 14939415572295847861, 1, 0, 0, 0, 1, 0, 5517847790939712612, 17084191072185647983, 4373790465892097554, 4225331220542153300, 2130235836373540041, 11014336955587517267, 13261921604701925672, 13681942946271658553, 12034991783627364558, 1627804654564744257, 2932739946223714750, 6512410412877608540, 6097164629377042547, 13231886920322033342, 11051251506011467161, 1, 0, 0, 0, 1, 0, 6837868493616672931, 3932850543815016562, 5993352762837579443, 17042968652914390951, 10638038987314268392, 827661294420902564, 12480026891102399910, 15584776283300553616, 16018818694656253476, 174727052104985970, 6997609737938415989, 18257746455231651762, 2120214735299642538, 343151165640891818, 10759684562283919705, 1, 0, 0, 0, 1, 0, 9492867381892087299, 16262800480453112023, 17322872276971640738, 14643806196666560377, 15595136242254344950, 7518181154580928497, 1317098796508350392, 10963738407742121793, 909342354741125081, 11768528957432122607, 8394540270261060467, 6404191905775366043, 9794215422759310631, 3090225984746935786, 14584417906224674271, 1, 0, 0, 0, 1, 0, 13612281739545428458, 14760519749949005735, 11059096111732277153, 8127477948862304659, 2899450088585457524, 7178383302195079413, 4080342379963224440, 15065835405932063604, 7174159973314940261, 7866236788120069085, 18372302221082695790, 6755863915990177867, 16393276955272037238, 6508850325341530182, 485362918438249523, 1, 0, 0, 0, 1, 0, 4372640031216207607, 5629259567684105503, 4719933692909427189, 12089107207026598168, 12364521740255563281, 15126929415582004941, 9583199887191732065, 8988068388491896607, 10885812525421994040, 3179713771850761109, 3646259631192899507, 2420177325979175775, 10058704817135704897, 328248192680369153, 1212206002969597043, 1, 0, 0, 0, 1, 0, 16719971632373437139, 8913437407619212875, 12445715620888469070, 14590495590496016249, 12591982458207239898, 3518540272376153691, 13537778478631670985, 5768862501974313259, 6641802290415749520, 2619647825741307367, 5310404789838069255, 2813523707389681640, 6001123487053466814, 13283119919073385632, 3027180794999366288, 1, 0, 0, 0, 1, 0, 16985432419746479334, 1732148218874634898, 10732456770751424600, 6298968617386740411, 5222599433923214178, 18313080032108507945, 16008519283195378358, 13531413419888790066, 2081323533358520207, 15255353550768211576, 17138176985304544396, 15815114409447852656, 390133022963677303, 9368984280090759390, 4226326679630301281, 1, 0, 0, 0, 1, 0, 10878179176838766787, 0, 0, 15143079744491591624, 122684593814478623, 17881594072631522907, 7229419957503946158, 12940017521193772991, 10151817482573032909, 8733418387703005516, 1319594737760624758, 14880293583396293735, 5898942779435783768, 16811128745251295765, 1109240219058196190, 1, 0, 0, 0, 1, 0, 0, 0, 0, 17097058137364766519, 12170170828128327789, 8827354137729360970, 14939098920471879539, 17594240265564849285, 12594120096976711335, 11639588720238971595, 2961214099077550944, 2199574547323924831, 11634736545140098063, 16804232943677874803, 715700715650088406, 1, 0, 0, 0, 1, 0, 0, 0, 0, 8947505233582573905, 6678598843273392764, 3725073892233240125, 7720092071903033897, 5255970636116417070, 12681977177382299121, 9779623946328742809, 268997569335911479, 13033985248158052224, 7447389216002042151, 7736891773241144274, 1940240082052736870, 1, 0, 0, 0, 1, 0, 0, 0, 0, 6118821869453917786, 2608197264550826766, 9411170196077201442, 6661421389020413469, 14375230321868528117, 3141438207172205564, 6958632034797014787, 17400815499287696997, 9312329466912734898, 5143036856532903190, 7161333884680390469, 8058403803683718142, 1, 0, 0, 0, 1, 0, 0, 0, 0, 11950369617180951798, 9444935041463352282, 8315531457715846029, 9889393354952375157, 5389779285479201372, 17553508332489815141, 15087772099628732551, 5347478766541373443, 10896571887744929962, 11129997511013985752, 8670230788026367137, 9164328147053886136, 1, 0, 0, 0, 1, 0, 0, 0, 0, 14618787401296499486, 12175440663040620259, 17580394656599216612, 9332791485604804823, 11950369617180951798, 9444935041463352282, 8315531457715846029, 9889393354952375157, 0, 87, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 12075365935646826911, 12555112468856587408, 11785226375886997917, 4824245574712348149, 6698272548511662058, 7437332431719550829, 8805294974760200296, 13665174347101618099, 6738391298770517604, 7192645425446594991, 9388817984500446763, 5794113475247796131, 1, 0, 0, 0, 1, 0, 0, 0, 0, 12970026081624744192, 12744187783136811240, 2410348887864631027, 12978945726327275454, 1554921798601148240, 11229913696364167708, 8973022178183201081, 139928186177466980, 13649876187837155162, 10757898852954163787, 1183567474340415150, 18328332676029395445, 1, 0, 0, 0, 1, 0, 0, 0, 0, 13115145854204970892, 17983425541226801902, 503096672456724597, 17391026586069653618, 11975412188970431284, 12728070322904945002, 12583843770217265045, 5648611480833313028, 5270318028794710036, 9198234540668451702, 15227185125669186823, 13442379348215607242, 1, 0, 0, 0, 1, 0, 7938014903722142143, 4026985013879105156, 15433899134283001186, 5518543654937541191, 7811482114300450425, 18246857844067051489, 5066330555278535354, 12777013593391110699, 12191575961919955189, 17344099196019282708, 13114270510039317151, 14016355395255073114, 6427069658768868190, 2211726190322481583, 4862466322566539257, 1, 0, 0, 0, 1, 0, 6295390960602027128, 1672635780379469502, 5514393169316646408, 15268698329081358799, 6358521007699847181, 8905575183526941079, 6308301555581432298, 2713628301395331598, 15644594447494294958, 2471335144483071788, 7634628028118476493, 8705396367530590759, 510439172729197823, 5910464539270739337, 11313308155928141, 1, 0, 0, 0, 1, 0, 16526896907746924406, 3520066619418494561, 5902635986331447140, 4398972274698089981, 12631024732346185051, 8386841573792151210, 12218015928704154046, 10432140379698280314, 11468177025236775618, 13346741951457031181, 11864092150902575386, 1957967507142109539, 1187524630546802447, 6811974332530919582, 1674557656829922128, 1, 0, 0, 0, 1, 0, 1584868061124279887, 9442704715127069304, 1641023224966192349, 6329396367180888266, 404888665587209724, 1712028768453542123, 9636831554872487700, 11205546840421184087, 14264854432675592118, 4651572474102722880, 2600150713028016700, 7671260856915471824, 13564816252723126852, 12833222284634831992, 3051460357884001758, 1, 0, 0, 0, 1, 0, 428341091691738800, 18339284103630472679, 7870616161402447553, 15334351080828855345, 1972261447295035604, 17003628149811009423, 13559543871756207414, 12791588703509816612, 16874590433396658583, 10546926997829974134, 1613237926847090038, 5103230212642319031, 1275403119419295716, 12931787129843438351, 9482922846676968945, 1, 0, 0, 0, 1, 0, 3664885029783550679, 11363752911665810183, 9134704894151526337, 13215878359575686624, 18224453919930723109, 14701830073355456188, 7627101113505064542, 16932075092084463114, 13716504142013330150, 998335944076440638, 12137387735186731363, 17058369724013530208, 1767224174321722467, 602199799565625282, 4204601874695641395, 1, 0, 0, 0, 1, 0, 7106463660950754017, 7750176763733153254, 7574864206138859398, 4526848524085695537, 12851507948139845134, 12194522465304354477, 203045723268582723, 13800072724692742244, 6219761752233525772, 578458477173417489, 12409381620398170328, 3611444773280584194, 8973301930488357361, 6492541737016997329, 7829849934035424392, 1, 0, 0, 0, 1, 0, 4777343346630271661, 0, 0, 15040112894884950263, 12254503491494638924, 10905362093557669084, 12506798032013022761, 15503156871268737834, 10398894083161474515, 15562472066553605377, 9297592479728714122, 15171127217706380424, 9656102210084357377, 6955904167393062211, 12517713541538021270, 1, 0, 0, 0, 1, 0, 0, 0, 0, 16222821967647715914, 18236388426739201624, 10359860344541184143, 1153281584568447720, 11215911684698899438, 1590480596834601729, 5406804875063937073, 902825103749099378, 4476247383648377898, 6603681318758243995, 7979346268508668223, 9081216985780183305, 1, 0, 0, 0, 1, 0, 0, 0, 0, 7115759549889295004, 17795973162642491077, 3118063002769479276, 3375328991910866222, 14829673264916467260, 17032170639409509898, 15296986551515876803, 17801462043040480905, 12194152217648072934, 15515146157726073849, 587062581941150380, 292701116829680586, 1, 0, 0, 0, 1, 0, 0, 0, 0, 571143354463273441, 9666544608273691458, 12872042550989601583, 10652410992593235579, 11969486770687628423, 5473191134781977608, 6282849523905673255, 17953708178661470530, 9124580738322974913, 3090550876749265149, 6178971316333817527, 17953687842851871221, 1, 0, 0, 0, 1, 0, 0, 0, 0, 10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048, 12230109559590207045, 16524836159467994993, 15355865270174544634, 1391859963977339721, 12022620756870035528, 14989772180267129899, 13982693476036346567, 4019135314604422332, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], range_checker_cols: [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2187, 4374, 6561, 8748, 10935, 13122, 15309, 17496, 19683, 21870, 24057, 26244, 28431, 30618, 32805, 34992, 37179, 39366, 41553, 43740, 45927, 48114, 50301, 52488, 54675, 56862, 59049, 61236, 63423, 64152, 64881, 65124, 65367, 65448, 65529, 65532, 65535, 65535]], num_rows: 128 }, last_program_row: RowIndex(13) }, program_info: ProgramInfo { program_hash: Word([10033257784419832427, 14686140193024196894, 15436783799654791584, 11131623826151749048]), kernel: Kernel([]) }, stack_outputs: StackOutputs { elements: [0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, precompile_requests: [], final_precompile_transcript: PrecompileTranscript { state: Word([0, 0, 0, 0]) }, trace_len_summary: TraceLenSummary { main_trace_len: 14, range_trace_len: 39, chiplets_trace_len: ChipletsLengths { hash_chiplet_len: 96, bitwise_chiplet_len: 0, memory_chiplet_len: 0, ace_chiplet_len: 0, kernel_rom_len: 0 } } } diff --git a/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_03.snap b/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_03.snap index 238daa45df..2b8842f847 100644 --- a/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_03.snap +++ b/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_03.snap @@ -2,4 +2,4 @@ source: processor/src/trace/parallel/tests.rs expression: DeterministicTrace(&trace_from_fragments) --- -ExecutionTrace { main_trace: MainTrace { columns: ColMatrix { columns: [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 33, 33, 33, 1, 65, 97, 97, 65, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [7458506668679174706, 1032, 8, 0, 7458506668679174706, 5598651459581075585, 34, 0, 5598651459581075585, 13620833136975709089, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613], [18375473735916206629, 0, 1, 1, 18375473735916206629, 7804753453550466256, 0, 65, 7804753453550466256, 2256486347761721492, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099], [2105717247508690050, 0, 0, 0, 2105717247508690050, 17777748786253636403, 0, 0, 17777748786253636403, 5193960644663470490, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350], [1679902783560062568, 0, 0, 0, 1679902783560062568, 9435312778805252724, 0, 0, 9435312778805252724, 12344784587178360875, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526], [13620833136975709089, 0, 0, 0, 0, 3358534066525179769, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [2256486347761721492, 0, 0, 0, 0, 9365253138981608257, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [5193960644663470490, 0, 0, 0, 0, 4243893038989355703, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [12344784587178360875, 0, 0, 0, 0, 2372900269115514267, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2187, 4374, 6561, 8748, 10935, 13122, 15309, 17496, 19683, 21870, 24057, 26244, 28431, 30618, 32805, 34992, 37179, 39366, 41553, 43740, 45927, 48114, 50301, 52488, 54675, 56862, 59049, 61236, 63423, 64152, 64881, 65124, 65367, 65448, 65529, 65532, 65535, 65535], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [7458506668679174706, 11091832976040936962, 11629723830403400020, 18085092721393681494, 5334827122981806215, 18131418839636252978, 14614347609195626268, 8910439294593611592, 3843332007587847712, 1023179011544432384, 3804737116729640404, 133391072621725577, 12470388296134501021, 632583774013957871, 4078804678813269002, 4646445037357820970, 12451999842825777859, 10348876437499804673, 4709521304751214351, 3818143376057959690, 13735545676744754358, 5911009352187537543, 11554714135033312948, 9410850814958744902, 11602211351055880832, 12661500893159548834, 9684778724196116231, 18082132319471479459, 5677068088590394277, 13067481717060632118, 17366862825980504064, 12752059346458920613, 1032, 10320, 13024110921086730221, 3587442816163675215, 512402747638547729, 9217956011885162917, 3925750957223009950, 8674177413178223320, 12846799727083908462, 9116601283268739756, 2958792353189815054, 1720195204565087693, 7696852080146622077, 2890877729556257606, 16676527939404087356, 223754558788184593, 4767414622778376421, 14072300156908432530, 16856861612825314654, 11910434229443384600, 15658716527747040980, 14322127566252286435, 4770460127206402609, 10805338145914832851, 1391598300875421210, 18211456042978337510, 11866022853402812888, 6438324596032750504, 13328288515202849800, 17331158106613184460, 18344276842462151560, 7458506668679174706, 5598651459581075585, 644336023812026221, 13247747688876077858, 18204236545845216971, 16083593158731167399, 4357419437649084221, 5464680208294216350, 2779149829283345558, 7975999984217399211, 3799311940445025695, 12287115722151291956, 7889055060352596454, 3871221682982067508, 16266218633314388061, 10296105519823441978, 6482329477820286957, 2184206139900597012, 13275897735411980967, 3045004919428473516, 16702736287849627035, 4028816571826363002, 15011221569533006108, 2864985628223798368, 15475498524455915389, 5364573001665328907, 10397611698676440611, 8883008337890476036, 17315153826736218240, 14581052801302714514, 17999554639252319772, 18022889162320300611, 13620833136975709089, 34, 340, 14059267169109730234, 15746924929585133009, 471985631500087772, 16946433723443173275, 4595135147820207091, 2053997855496151567, 18402496786565368100, 387609426153233273, 8469665991798416914, 7881354678273462636, 11816560343993810599, 9054561158700241520, 7881520773741268125, 1631726701000003728, 9048332065221759951, 11440521690988525934, 11399562976973524004, 5295775600298609171, 16854936978988550164, 4555566089436281371, 8045874719633055695, 11420674364099598202, 11942861833844189240, 15820096964950298640, 4263756598719013378, 7647209523022736387, 13465875315346524402, 17464705757459592393, 14751425303934963720, 5598651459581075585, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [18375473735916206629, 4371092720588693207, 7555819500301263096, 7871576915936585054, 7738161198426062879, 4439752770537371709, 3239157867226066300, 13695428956813660853, 8114913103795360695, 3271513559100018830, 1227622944719103238, 17840970837055628605, 967816437372899090, 1525132029610696618, 8930953641447820548, 1991652128187274521, 1878310895470329371, 1537331530871119668, 17179845365129498366, 6628846356810584866, 18158002788694963974, 8030209565693857269, 16465976624819029473, 15848213422225602213, 16693748147017299005, 15158850031902933967, 18144229372703820177, 8111553228231189401, 420461259745383997, 17094012225747072853, 16556024871956851478, 18135096529078946099, 0, 8256, 1131208899036558480, 1667157010810320250, 2053960715201569301, 1526213270499333709, 69813565043892453, 14925652377538846871, 1380252317064967448, 9902934070223067140, 3786794161520721521, 664031068804619792, 8470323998416702977, 4965297830526000942, 9404280000999464502, 8244737495337250711, 4784363486033662704, 4680481291290566437, 15373555507761845373, 8780119261264514018, 729009684537575982, 18306419558979237700, 15407410920890065538, 2509966126115291236, 12709897403480972846, 11498596868429821859, 6606875518512322314, 13880694912200059110, 6972406840307481976, 14148490408465275064, 2917966740410115114, 18375473735916206629, 7804753453550466256, 10860407685663036604, 1563629168745730928, 4862512017968946683, 1035294938480129016, 17121277837906333314, 7566123129055455762, 801761918673301233, 8221980324343257318, 8971289227653573810, 14503443403830829887, 4403991158284421772, 3539411744559999519, 17877470569230350231, 13052305487168984918, 11988250928057152362, 7990654922366982189, 8123717249091864283, 273044411934894184, 12617346169478402785, 2083501518846346052, 1182260721753268305, 16655426125402668777, 18315976927222050841, 13684207927534177805, 15562831278015850283, 7777530579170086866, 17762371058211819624, 4106083518382761605, 3917672276375751396, 667054191578263747, 2256486347761721492, 0, 272, 15833028045737259664, 379315838026506093, 8581974592770288933, 17442451301272882541, 16579750051606898066, 5674487159031204202, 1541891846645406613, 8209041782659254452, 11966225502153548517, 9096730616149686024, 15618906860941665577, 14146738543483816160, 1119526938685078607, 8710432271010401746, 13282504786121257878, 1858131981777548381, 12223656597910297554, 11826686549344788050, 4472804247539583969, 7599118004690938513, 8277718642341650597, 8460103377465445883, 4568736565087160671, 4933680726900799861, 16645964836945405904, 3680609073412509534, 16176623117443515258, 15081244610133230814, 6410948793715747581, 7804753453550466256, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [2105717247508690050, 7371349600976768903, 1908428216714745226, 2226486931669462500, 16096322966046779578, 5448090446075942959, 10098429045835473018, 4809915777199041455, 18236464326626014645, 2690803580142520255, 1917959726470568181, 7355089244606367886, 9988016662047687018, 6075081950126577031, 782991345573128788, 17727121868432118686, 616586521336426688, 5444667365009856158, 3285592017878659318, 7931583655659423496, 6385821061540880880, 8735792590442216465, 11893401421408965, 8831024347202442032, 4451634306410080384, 8173507753862756681, 15267089652751109873, 10164019920559079526, 5461641667913740527, 4977882380646661156, 5148753722704728721, 13200399719329805350, 0, 2064, 18136552782870868471, 952274539956745973, 15933282259815262093, 9924516287334785738, 18064603646801610993, 5114527609957824263, 11816233963570869158, 17699527003452380450, 14533708946479200173, 17484213571014188868, 832814531422633701, 1508169308733590908, 8423043379628164525, 12595277727969636921, 14226276023010866965, 10485112285448962747, 1783527593060720204, 10145484005384627580, 7463752398658534839, 17345550819494003223, 4432309123412733588, 7086318781105575433, 8830891075082588619, 310185093236608634, 16683125300631590273, 7786799186167080425, 29465347809991832, 8090161351836983773, 8665315444141111469, 2105717247508690050, 17777748786253636403, 12906637371964794665, 9477262435683869924, 9199231093019338048, 7358751435793575899, 12569972625839259527, 5847320563034378965, 7599987891632365696, 10432134440683583258, 16242679258308055777, 13780789328607365793, 1153491566876700606, 13641042641136958279, 5969854971149325760, 6340590356564925801, 9771444654514086827, 15776260062082886705, 8278469467176979574, 16237604982476195391, 7423750977119185664, 6710003146178124596, 376186270665682407, 15539788083889931684, 11273188656572444234, 5199551304380116153, 11734010025122035435, 3764388601356982695, 11644487560172946408, 15563655808705061071, 5533608926617884295, 14514898346462505299, 5193960644663470490, 0, 68, 4457596741936238930, 12529581077675993243, 303974201734355881, 13345903392866909652, 9586267930884889862, 5178817950472007665, 6608322246477847509, 4070515537963445793, 9312477480709452614, 8889792067304111866, 11078425489498232713, 636055309231688517, 8580323529307502020, 12246954824275240956, 13948398243979685168, 14683551372837095812, 4744943918536266830, 10091391594533925883, 11270159100715194202, 16104697287955959682, 2983615207234436698, 10804815118997327370, 139420663301414639, 11145521977996788455, 1535579717520953536, 14470422183799365804, 208588932528011586, 11685358340804306780, 2822178276157738566, 17777748786253636403, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1679902783560062568, 14926961084296668554, 18296820143542754124, 5759648439566973806, 7690180744863199464, 6255055536007924620, 9967438444965419122, 6053822608871655533, 3970724348518176437, 6498891217103059128, 10341231834356228091, 8497160540604180804, 5144558705352378414, 5437844264442299443, 8712431777609915948, 3915629295644008966, 1353567482375898210, 16603575236790899764, 17009424079525297171, 3253699369098499458, 10648493462065257860, 10940203220400825059, 7261956826490066834, 5730064365163707705, 8826144244207679463, 11688897202604808409, 4559302720015817859, 4402707951554525697, 12375228725744876260, 13367890413392736054, 15438373163420410642, 905179285088193526, 0, 2064, 9594118340025725004, 16218246678075491818, 11582919835122342747, 5661452934218108707, 3714647928422746674, 13689184893219719187, 1899963197709801965, 8313716591368695784, 17822645741084942000, 18354595702287703799, 12620512717427217848, 10145637708639089787, 1735222492513760332, 14681927838838900060, 9262747238997471758, 11498487923782501751, 8924101344488972446, 2592517964915386184, 4276681409258176044, 3764365715267793208, 3120204268813370353, 6019260256544801113, 2801984351776029768, 16979166255722313516, 2813750347113564525, 16588139065369475399, 12012198471360912693, 2492059183640657261, 16968938268466755316, 1679902783560062568, 9435312778805252724, 12594665258064570661, 1586451078180607598, 9325815886784366656, 13163107377789060321, 5998117226166788975, 7008390784506277276, 7362390315901265787, 5188984820381727203, 5842708215320867131, 13553650342229414448, 5955476415838559193, 8725164908673674579, 15174091024100472501, 13637649140457772157, 16186415272190469176, 4473737633571089105, 2032050757569801828, 16070334483916823186, 7382925316452200710, 7820237015849984079, 13711104951459639694, 15277864807184951074, 7746677489393361812, 10897962020578390602, 2459478953251166639, 6142067256785271224, 1469990404519833898, 14737929225229310854, 17685816709290022661, 5568614684720127113, 12344784587178360875, 0, 68, 8186419089203192999, 15318603549361168513, 7911471416782656233, 14239435248344205979, 2133634484310994464, 8097913535946941412, 113263425049039362, 248987352426060274, 10939256691674299939, 17358468187481791647, 12423884741952977957, 56617284060232395, 1868806426895026968, 222259776750343599, 15059516987340721081, 8741184015917561905, 2066403566980848459, 3696239822839219697, 15367181090448289261, 8349149003644261348, 10280553347796952088, 7301079719327054003, 6885778115777578237, 12504375544103392076, 9288443086735636960, 4503182154932177101, 17461402434481489861, 10152174670869705735, 6117144343302310887, 9435312778805252724, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [13620833136975709089, 1046930547281056921, 5022880593775506902, 7356080910092118039, 16589884839242022257, 8919754405551141869, 782951559730000700, 4320210530167177353, 1189869440416317038, 11509478421996896286, 14131663596834904750, 3063592889799439815, 8310309385140170305, 9794866582382956591, 815213714413043438, 14909022885730690459, 1965134134848901020, 8569284627647542389, 11756365299450742783, 17765218832065923306, 17214386397833253270, 8857548797279425296, 9589793731564825353, 5744303806832189345, 9245523889540971217, 17743277714115543370, 75478605149737153, 16642733757618334231, 10408597074326334289, 1854469405851562328, 5120877191992423544, 6125088443291536169, 0, 5160, 1190658701913535022, 9371121588404883743, 7133056533056999470, 7380100170229652082, 14719783382686670107, 4693530971176924881, 11125714198188567552, 2434816259070577714, 17927785478103501878, 834873962620943786, 1091858408197145201, 9293176204765248193, 11318806736621162148, 979530496520387452, 8328113718786640843, 15870139479256453021, 7754853849459016697, 2742936430580983415, 6806060556807781604, 5089080673677611112, 16430235900965466453, 309743103212430298, 15664803780047891222, 3113571524475220627, 17862871362988443440, 1231393200801541530, 15779352999894925288, 6026600320279882336, 6970552753544824994, 4949154992619464010, 3358534066525179769, 2539641719046213719, 10199880931320172189, 6982964906206022277, 18160468829511284938, 13459748022261389691, 8540403463779371619, 298971077135778992, 9448428205117043728, 7211550496031219820, 5534997352008564058, 8961849300614763067, 16471253951712069551, 11996630593586982068, 17666409503469399853, 14743209389502972128, 13621451519455201128, 11693451034972088239, 376126037836000660, 12412096817616379990, 866468160396608077, 16487331493773223294, 15132792027965031247, 12005877568613345660, 5222840910814569167, 9174906967528115515, 12806387721803954058, 12420516276683200334, 8854457266879028181, 9558115804602486754, 6487880825188915613, 2384716068805359876, 0, 170, 13502722698945446624, 10582364865337924932, 8264438684589566467, 7775924941916048886, 7506941477585260226, 13559643900430805558, 14624701183045087851, 16810498729905278091, 3617722030424605287, 12209401598010007429, 14622001497128700788, 7124074456411373593, 11046353624103181594, 16506916834573600874, 2763493011778369288, 4381652925229768341, 9935322272824673857, 864619558035150967, 1868429356172715569, 6908757966622831414, 14123318794287563052, 4877497612363750655, 2105400693641679480, 8941132592749341698, 12124737918817624189, 15847492668873519030, 7578220797847929864, 9410406960468072857, 4811333449307081983, 5256913258227871425, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [2256486347761721492, 1399831673864751627, 12438672130810751909, 10240118010240816453, 12454995736750842450, 12272610174663972685, 16716772686788009039, 17679411248915786729, 9344021820453066790, 15548275238570617018, 12554227251830406338, 7982818396816137943, 8298623838207759766, 9667670442404470529, 14730751205912092663, 17475545646146195192, 7561186990159804961, 3352703426322824443, 11124655848983105243, 7361271662241444721, 1785076194951656280, 13323648175345935378, 15598576959546342188, 12701095265259304800, 3219799610745612107, 1555585114147558761, 10397456717804752138, 2319272066426069991, 17926066510128935923, 1264814027228690376, 15123699931666188121, 2665390174743669239, 0, 4128, 1352424102745866255, 13301242752201603536, 5420135027930584396, 17078794493496835379, 4779811836607866048, 3650219859599657886, 13618468821889769363, 11429589192023659923, 8853101337885331080, 9650238821992519861, 14401087967309285252, 12035560952634921032, 15407186837043713393, 15711028160746246110, 5396976350889627712, 15903424027416555998, 11304777107657759509, 9857843669692965578, 12605480788735099613, 14618970056708743810, 8493993205782554647, 6059068631740368787, 18316971448227884023, 12499808993385025318, 4210674244211222629, 18405965507148502967, 173097048437312502, 15568437290332308327, 11532601739151124629, 10000279862191744493, 9365253138981608257, 9113412038486870510, 12237115836192970750, 13532373892635206986, 11668565565569624948, 2114739335810906841, 16845938989106496862, 18053472495070906903, 9578952411771586845, 2253954535466549551, 11957330595594263589, 4327169169737696049, 8097241277176222682, 17499521208876685046, 10474171567958477310, 2884885063912824473, 9389176041985146128, 2067286230266639471, 3365016398014065199, 738171567486888734, 6622135657383660119, 4978858449337102663, 1252098561428724852, 813491835360077960, 3026073706021528936, 1157174472277816506, 8848575890036236601, 4801870550462804365, 7028466390812097322, 8403721226663073636, 8970732296705167988, 12459739889109502988, 0, 136, 16864340361327671903, 2636070061904000825, 1539270658943308645, 8663103496298937284, 797155414931197277, 7929222985705309752, 5418421295167202847, 16520350781038259800, 11697635461652845634, 10326065236143981873, 4672452207442160023, 9236109584144478544, 2355139499180822246, 7782053902926446231, 2620978815438101291, 3668923621194401622, 246363526423127035, 10353083146864436335, 3430895131654614161, 12564495361718767183, 4982750975383300564, 14559648290526166949, 6242143746593499460, 11140632426269699329, 3028234720115016827, 6653412960111738263, 17564919688262005304, 284282844772359316, 7938696543505248162, 17100537000217132265, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [5193960644663470490, 18378615377082669582, 9942094792989095510, 18239658104155677632, 3247221802734244696, 8138145110381489386, 8305898108846284300, 4495835739545312127, 13363880742094688735, 409501507955448067, 9615046049029083973, 9226283480795415930, 6188039948757326954, 1925348622523205808, 16932487676782686187, 6461440512631901369, 6379521145060545439, 1135364094435597517, 6898694641523826133, 881111998832614715, 7852757539889945333, 8831210118957475983, 15508177777761403707, 1274251095252206369, 6462015026972174497, 14758961666322366163, 12911489632740586743, 10573355084806673526, 11042755251558401992, 1655214279385078584, 17558359767143120899, 18009389558374812227, 0, 1032, 4798141223555508282, 12962488577647927717, 10133257770726709126, 332864556927106185, 12116126881643349994, 6604148216925166409, 101015634312276042, 15934992137290074922, 6112274855072540816, 17762248064501548615, 13166189948742588777, 270100349969833402, 13485211244653928073, 3502306881032295169, 13607663468974078519, 8883940618995723208, 10623667092532612652, 12293715092576816840, 10386976621364522928, 9128135834925108269, 15731443845270647366, 13373704167654916087, 13746187061551926812, 11684868053863796759, 3258729720361659960, 10434904637843727165, 7034851303745741351, 16133345873308301364, 5426492436527662130, 2980140658145787783, 4243893038989355703, 8922317147540258079, 15524901873579080579, 14961355291644520251, 8912131487655833337, 845467818172067610, 6513419642881984303, 15821388348544564061, 918209442918452849, 1771868273093277971, 11088759444000251587, 15710903694873023395, 7739199555620722590, 403122127909161589, 16794196935209020317, 420049465494673582, 3241180689003955516, 6815831073966054431, 13165955590245083084, 3933813014659210303, 7891509834730356602, 14572658037405460796, 18097121197159342726, 15303933786232509118, 6355852571927224576, 5965705308661034968, 3878821330615144039, 17609259256248013285, 15839551803056895538, 2863101478933748100, 6867483661888889167, 11007533278239168078, 0, 34, 6567391571487826395, 5204289601743072522, 3431536436519013066, 18098398151169262506, 7669185665212226764, 5455708142000104069, 9902960937688969164, 16439153306838678161, 9116909952501731628, 259487815978835763, 11207509487307725092, 13598970521047669184, 13294225392413433281, 17974846784869714720, 1531979193630020279, 8742633689618768661, 12951219828222672250, 1272063647175062154, 1015593294205135440, 1601391529726059156, 6891640398393941397, 9120291006888379304, 10474372360890458437, 5584077426972546342, 6680864214558642932, 2419346771478639592, 9600963709893327666, 7733975108380115257, 3435995547523177385, 10362535235958450122, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [12344784587178360875, 7525588297109292118, 10242077034078069399, 6920809802339641674, 17643499204383222535, 16688592460292823795, 3252667668159125426, 6639040797936707465, 1827636079652666195, 2462138615393893213, 7273091941301037907, 7777539981955361461, 17791722127119122070, 13941030348836860953, 2461265848652382458, 17178103242399629259, 12982591110459702249, 4311636691398707716, 11830890166127089072, 7160199109027716330, 14107503556614837834, 6316368550299988901, 12988322271117575851, 12500666959478542023, 4763644307980385379, 17502332825869685988, 9045450374393109306, 7379498771612731567, 16568845003086625163, 4695178656129701184, 1678315832465296045, 15789153556893733830, 0, 1032, 11702782905971311743, 8115486282645452027, 16425371230714077552, 10333496212804492507, 1572943607289284437, 13244361396034453954, 12880029163967100393, 14716450796809578181, 2618965885956593171, 1606019581379521796, 12562170441304287563, 4599116799417823473, 4257071131168813417, 10446583017549019711, 3570388907037362614, 11170081717188072664, 17238997244398394333, 17231192964516960933, 8123337005847551087, 7060091366977384949, 5719725530909274667, 5057603743378325948, 13848013489728729143, 17729739340387068117, 367186060507240673, 1411195984452924204, 11088333491201093194, 16575090776691519559, 16147396598096989679, 14525300817521856881, 2372900269115514267, 7638869850317184909, 18112581651832813996, 7934301823485851614, 13134589595174512908, 5143267856379088965, 1385332020236631836, 4877336193186145990, 18193547062192211825, 4615765459892113834, 3381950137508436504, 17429784608409914678, 14977580224084415767, 6849317271519196447, 5437598344549503419, 1906047363049945529, 5004054537041877249, 14661239785476454049, 10553785792947774039, 2119915982392644589, 8985292275604857439, 9726386267280827154, 4505582310884934806, 12912789541737329022, 7115507662283435621, 2051190405167774802, 1232238311229055715, 220176432091768973, 5422499495491255741, 8009273299237215820, 13359803287975487032, 5187224287159924757, 0, 34, 13313027311321423572, 9192034959170904294, 14701500658652215925, 3854356596578551734, 5718692378574184090, 17501390179378757090, 8526809416150489728, 6507550884061463423, 7814960517829781662, 2939637999200097803, 780950602796552578, 4118107554308446430, 8555475415255527439, 14714307830357033751, 15614510648083677054, 17171454789201612359, 15897739400545916002, 5578273266312075011, 10191353484336583572, 2940473809902205523, 14962502826274181007, 2115641271859045975, 7064236544478437245, 10824702985925635247, 12931918488324919856, 8429882718924461151, 11244752067809188397, 2111913529644288504, 6112640616610282754, 6599190416745833044, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 4046254507773998773, 6534480484041428863, 3251048018398498863, 14672293546278713057, 16728924149188845306, 128728647106458681, 14226927580887823496, 8277248794545234814, 4354566838645069185, 16178613916401188944, 5304102959326456112, 9791457517463513797, 10245170831782510809, 11611317382660466625, 13569694221132024345, 16005837490233273516, 2791259658093074998, 13441513594234320689, 4241376053954359578, 3545073666350874448, 15186107276182512091, 10698815982870498162, 10971920968668641865, 9145865124167298835, 405811361541120846, 9884965742324813117, 2876689281462596902, 16445466086575260512, 14688957924306712254, 16306354913676224825, 16604794485775028126, 0, 5160, 18346837778669738664, 15130142357101091527, 6726588340010678615, 8394319278312203283, 15942424551308612685, 7629500615465222065, 14939877513325106589, 17048523965011794048, 2306293645521445312, 823113708878672797, 14981348226783328932, 7432878333905782051, 3482639998457803800, 632277917380007036, 18266437030920184246, 3366715262389109205, 5280275432441977334, 5379329043314533811, 13912213856326486056, 17217059915921675075, 15634373017412823086, 14981257187297131103, 16697350900700022325, 5239234081629986555, 3229291246709926782, 18373224696258292584, 6771862800272250893, 7666370275789511263, 12942227631865082960, 15190222347874856922, 0, 1061325914286080764, 9554433906850032874, 4012321235764609039, 14967212595115142793, 5983394632166978443, 5809835498849113816, 6561933873120105870, 2140629501848088776, 6712525834006528890, 5760623808290856282, 10552757613235067722, 1939309373056894313, 14427320366022536141, 8538471352201975220, 14188752564290255096, 7981877957758397164, 1148470236137421383, 11019464818805406210, 7769960423081990191, 14632278337044440617, 849771658931440922, 5632784009618830911, 5696241881348246065, 1879984915784172244, 16312530632323862580, 13300309889942581843, 15448409017348426344, 1639569934817636487, 17233518173045382262, 14413924905126977169, 9045462722956532208, 0, 170, 946461078672821334, 16281780351388912901, 2935418863412242354, 14713353090133347394, 1791207195906381248, 1092415958346704160, 8319785044806982194, 11182822967626325795, 16809587424157045315, 2244733962249620937, 16303706249485479712, 845878992383212753, 5921002467687226204, 4434027484725189444, 15967620315457307754, 17386925554974145101, 13158427748622481094, 6196246176234489731, 8582026933349467190, 611778401982756412, 16288180016347524015, 16434619985909351985, 1145514137751095479, 5160952971387430527, 8451565207539691282, 5967893180517848182, 7714774968702541161, 14978023560208702638, 18014742166879778909, 5450578834500306709, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [87, 8072556154622677081, 1267311017976162806, 171317623411600853, 14846028244624432327, 5697605161887258162, 6090204166740560590, 11791493563989406548, 17428436932452366793, 5676009947455004918, 18345317182680976060, 18287702590376570538, 4985574569677261947, 15947076302058294771, 15533043966546096492, 13147369042643698626, 13830067522797295398, 9812515853737376613, 1153576568012481332, 6976086965219136352, 9332017051661502953, 11709096929003024091, 4784660881537662841, 4083552985517123622, 9895527598631437834, 3406650305555277621, 13871430865741604308, 2950941648901088194, 3993419962022258191, 6722743736070459606, 1297747773924291443, 15433589206667095645, 0, 4128, 6496253015800789210, 18063315295058131399, 14099326864720264780, 16744359797696928029, 11669954633423859445, 10923938539628559259, 10579480970462933513, 17315553376669597828, 12114095292572219189, 16129781670858537825, 67936491912723144, 6285840300661422802, 14359460599290704174, 7597471307904508314, 8469569990667894210, 9117246600999250277, 14614928058075190380, 13738364908865630160, 1806905237893315697, 261412144627674040, 8380596589382515797, 3809925330596605534, 1983199361335541287, 6337901890572878101, 17063257729896061936, 12690697575318882146, 3846044480011221270, 10729939698274680623, 5297971463863936522, 8671284646676347574, 84, 6657939908049969710, 5132111129018882891, 8232522030470930177, 2748555984042091513, 15852736438270791360, 3031910609778633238, 10165962755900271710, 16659854091479845434, 17343121214427119893, 854734865188827599, 16332742745573253042, 719106832906440841, 5187730385273117170, 5680967626748162975, 12443929595174060051, 6984107838208124669, 8017806737059891905, 3253255241682497310, 17244932564674349345, 1765857304688336746, 6104054101040517608, 16644020687030024364, 595269491299106953, 16831646467700047759, 6176340855571448766, 18004816485425051763, 4101389897636298429, 17541610204110287382, 7370145379849234412, 11764023996857035803, 3516218181999416212, 0, 136, 10841411014448826746, 10924324070009278511, 4390811061445162297, 10665404042695900090, 11148796663006115025, 16584177158338467512, 15369021590994653978, 13860609558593370204, 3837193053542887320, 7652640894347806080, 683219561750944695, 4006536353767232614, 4047796662675347846, 1149920536684206111, 1698301089048909092, 6224704259817574157, 4439284651749775339, 16476516570230330168, 10834199646006576067, 16282481854654492091, 6659294847490221927, 12242894720083399562, 7156478509869523727, 9996508607909856718, 17045153176928915002, 4097937233975335255, 13892339685592049122, 3881709886225480466, 10446442293007407525, 1539493896147927159, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 14732236349158007950, 7398379382324753631, 16529615322051348437, 17750754114621262532, 3376246851343252040, 16812742874230723382, 5497427090926806167, 10370890449220293026, 12072808913033091146, 3773065747435304139, 1433120707818296652, 12602993390877629622, 11873715535213483733, 13503968807830695383, 1548449854272693349, 2164072014511735918, 2051419284241394287, 7675966884444101274, 7631305566403533669, 9974196014981023153, 16049335883858064137, 2471757314515864029, 247517241416190936, 17714417256089308015, 11671008027458954016, 581610329922371147, 16154960330167538938, 5798502399718959312, 5346182502077854664, 14220066076326577834, 1379414419793409060, 0, 1032, 13084260837127404333, 4018109146681745349, 14498381569327145056, 3778421823029569719, 1344624249217908323, 3634653398484528177, 1428985706412758663, 11382569756632997337, 13894906302086601399, 3911680161282028629, 11467762927868003365, 10098326072301516020, 16073214466625742345, 16150512194511843089, 11525294274796193451, 15902507139806774023, 13926886722650908730, 2974304378722638293, 5274544965980948277, 9984170014312577610, 639485734140932316, 15088403650698955530, 17189134684458608982, 6515320870350778492, 7902492290152572474, 17310456195349246143, 4070136787975548901, 6345872167795009033, 3095930865537762353, 4232664728858134772, 0, 13425232862973212691, 18017734206314589878, 4362746362325529522, 5580595613883635850, 14186966130004258435, 12558944767443104505, 9400104492160547353, 10540307613825778005, 16337971251965072535, 10106057436125976033, 9544366711268571215, 5728567960549491041, 13778603290469351967, 16022817295707876509, 11816634839594428392, 1619816382417214775, 332425507059551196, 5638968861636104000, 13036766990591622942, 5135102707173364321, 10242389681667623919, 5777720311941164202, 426018854260317513, 11718167143057109482, 13648951505177506250, 14542650836653761124, 18018546562218872798, 4457636384061007994, 2416704573314226662, 914323423605581375, 6601699247185721889, 0, 34, 8422262931452347509, 13885570107923725144, 235244799151795110, 17975760300270072840, 21645088928215528, 13378438338434245321, 11260622121353286786, 13136688320626048612, 17881560939567828117, 16601834208041636644, 2350599886583381643, 3676641047171560447, 2612703737764640459, 6165448709088710825, 9702561415374819789, 14396227383672448392, 2871975363154349452, 13084396173640101372, 15953404371899770169, 14377272925308367884, 5291380804534138171, 576711179775643850, 11287382459948400014, 9324129603955102500, 10503620158827014837, 6130889055094603538, 5442709211693844142, 2968563472347562608, 10528964699829495885, 358459342719025633, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 7484183127135320340, 13467318737723490903, 18417997150771375303, 7719389523268106465, 2784882046013758615, 12479320332521777529, 17052932344949276269, 10938440435726947483, 3905086412998728873, 15634495878209337408, 16923840111614250132, 16397885158502248985, 1407236965451031446, 7800595096011710855, 9403004147208138835, 9997729556720517342, 8534668514381008137, 9227268528750758459, 13403671598326027744, 4715851494578741692, 2189528202978614673, 8567186243928218861, 9297942977636733700, 12120305129322824184, 16911451126764050505, 8250812173422443178, 10259824399772380043, 14694981892968238671, 485814636516518185, 14546030952858743710, 17545164675990066495, 0, 1032, 15909096041365347974, 18432189660917429733, 2798890989547891271, 10768372030970716894, 5935807051329113911, 1259182408195029650, 16024750973514577255, 6103595041913569283, 914770550723164908, 5067028895751058275, 5242612139537538536, 13359135899043031769, 4430959127423856282, 16317056360529517539, 2634255659160911215, 15590656855559575839, 6832335878067392309, 6045109056629836176, 18146646330136390606, 6482705684632040588, 2770791364887326735, 7707774010999656594, 3401430074469265273, 3500862351024377705, 5135727797169111985, 14940852959892477883, 9633218853985087472, 16966092255533854383, 3065488485208441055, 15703076512693482766, 0, 595597012989057195, 2376871353626003378, 17667748366842763551, 1405929090442079600, 18135181650619726914, 7403637996862883832, 5964686311110162804, 203041400479358567, 3387955851036204878, 2169976152805477386, 15733337581560247916, 7104142523828512918, 11829327565897640936, 816639760928622921, 11238339345191818453, 11391625709863387987, 6031165808075129231, 10104077332067730329, 6839520087480516521, 14155312441647748702, 4167237297971124611, 4042518115334572170, 7632437875765360091, 10425826042851550943, 10797236500243700589, 17846423932362838045, 11994705126716395168, 1154262141907751651, 15744039038114735423, 13449385390195333360, 16051125308748956016, 0, 34, 9168769012195838974, 8757246072351383525, 15819587373362991575, 6330331124468459419, 17594449485955496857, 5094615699180819390, 10468588157075103568, 17500241837984025274, 12590769989805218521, 10257339134394161483, 6020533408585278677, 9887559600989616103, 17174772404727048357, 8260989830322406645, 15331894718426588199, 13817494132369433237, 7270842089806116389, 14464987003178196376, 12856235623981550070, 6446968933011398838, 4625298604721424009, 7537989708572581312, 8773062848621227780, 7997392847552644982, 12295542285792207282, 2236820296563710856, 6411496154095679628, 96618257160083950, 2708395562256972928, 13820925760592258770, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] }, last_program_row: RowIndex(11) }, program_info: ProgramInfo { program_hash: Word([12752059346458920613, 18135096529078946099, 13200399719329805350, 905179285088193526]), kernel: Kernel([]) }, stack_outputs: StackOutputs { elements: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, merkle_store_nodes: {Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571]): (Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350]), Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350])), Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484]): (Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693]), Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693])), Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781]): (Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874]), Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874])), Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171]): (Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361]), Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361])), Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815]): (Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305]), Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305])), Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689]): (Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195]), Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195])), Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362]): (Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063]), Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063])), Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848]): (Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661]), Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661])), Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352]): (Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829]), Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829])), Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444]): (Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223]), Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223])), Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386]): (Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388]), Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388])), Word([13190842942618341421, 17548956981569849952, 15418963848144418856, 730733050713174879]): (Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144]), Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144])), Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874]): (Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675]), Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675])), Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594]): (Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115]), Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115])), Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809]): (Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257]), Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257])), Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777]): (Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555]), Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555])), Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509]): (Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882]), Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882])), Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725]): (Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979]), Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979])), Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134]): (Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987]), Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987])), Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828]): (Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910]), Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910])), Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830]): (Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054]), Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054])), Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228]): (Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742]), Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742])), Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443]): (Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928]), Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928])), Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643]): (Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979]), Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979])), Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758]): (Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106]), Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106])), Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580]): (Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594]), Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594])), Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765]): (Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045]), Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045])), Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766]): (Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281]), Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281])), Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385]): (Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828]), Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828])), Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579]): (Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171]), Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171])), Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212]): (Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992]), Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992])), Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463]): (Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004]), Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004])), Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502]): (Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023]), Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023])), Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539]): (Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537]), Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537])), Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865]): (Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225]), Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225])), Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690]): (Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947]), Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947])), Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202]): (Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552]), Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552])), Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079]): (Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444]), Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444])), Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850]): (Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548]), Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548])), Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448]): (Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987]), Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987])), Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041]): (Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035]), Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035])), Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301]): (Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414]), Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414])), Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414]): (Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212]), Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212])), Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703]): (Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439]), Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439])), Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271]): (Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955]), Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955])), Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882]): (Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802]), Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802])), Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152]): (Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887]), Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887])), Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028]): (Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948]), Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948])), Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331]): (Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093]), Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093])), Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394]): (Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134]), Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134])), Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546]): (Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228]), Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228])), Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620]): (Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414]), Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414])), Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800]): (Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703]), Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703])), Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671]): (Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205]), Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205])), Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537]): (Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011]), Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011])), Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516]): (Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301]), Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301])), Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831]): (Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986]), Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986])), Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415]): (Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057]), Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057])), Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722]): (Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689]), Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689])), Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144]): (Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682]), Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682])), Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295]): (Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268]), Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268])), Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818]): (Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513]), Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513])), Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241]): (Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565]), Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565])), Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439]): (Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012]), Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012])), Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512]): (Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850]), Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850])), Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986]): (Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865]), Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865])), Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982]): (Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777]), Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777])), Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808]): (Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394]), Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394])), Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979]): (Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690]), Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690])), Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093]): (Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620]), Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620])), Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902]): (Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789]), Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789])), Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542]): (Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094]), Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094])), Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057]): (Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362]), Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362])), Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205]): (Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961]), Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961])), Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401]): (Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580]), Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580])), Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553]): (Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960]), Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960])), Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169]): (Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031]), Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031])), Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682]): (Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053]), Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053])), Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118]): (Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562]), Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562])), Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725]): (Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666]), Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666])), Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661]): (Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897]), Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897])), Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981]): (Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447]), Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447])), Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072]): (Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646]), Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646])), Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140]): (Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404]), Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404])), Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515]): (Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152]), Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152])), Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709]): (Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664]), Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664])), Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800]): (Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103]), Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103])), Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741]): (Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169]), Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169])), Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005]): (Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758]), Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758])), Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802]): (Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070]), Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070])), Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159]): (Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005]), Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005])), Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350]): (Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443]), Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443])), Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697]): (Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573]), Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573])), Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928]): (Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331]), Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331])), Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320]): (Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166]), Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166])), Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814]): (Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079]), Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079])), Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447]): (Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820]), Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820])), Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284]): (Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057]), Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057])), Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697]): (Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131]), Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131])), Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955]): (Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290]), Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290])), Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910]): (Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202]), Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202])), Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910]): (Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822]), Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822])), Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106]): (Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847]), Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847])), Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404]): (Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441]), Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441])), Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796]): (Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186]), Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186])), Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053]): (Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516]), Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516])), Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992]): (Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818]), Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818])), Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957]): (Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315]), Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315])), Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709]): (Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794]), Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794])), Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091]): (Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539]), Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539])), Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664]): (Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558]), Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558])), Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294]): (Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579]), Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579])), Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947]): (Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502]), Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502])), Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829]): (Word([0, 0, 0, 0]), Word([0, 0, 0, 0])), Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045]): (Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137]), Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137])), Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914]): (Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041]), Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041])), Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573]): (Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378]), Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378])), Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699]): (Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873]), Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873])), Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225]): (Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262]), Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262])), Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057]): (Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692]), Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692])), Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131]): (Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997]), Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997])), Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555]): (Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385]), Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385])), Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195]): (Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709]), Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709])), Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166]): (Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542]), Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542])), Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027]): (Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373]), Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373])), Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378]): (Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509]), Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509])), Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097]): (Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553]), Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553])), Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217]): (Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815]), Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815])), Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873]): (Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864]), Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864])), Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997]): (Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722]), Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722])), Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887]): (Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766]), Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766])), Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589]): (Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757]), Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757])), Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539]): (Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665]), Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665])), Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129]): (Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229]), Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229])), Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137]): (Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312]), Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312])), Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019]): (Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378]), Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378])), Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331]): (Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713]), Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713])), Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]): (Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980]), Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980])), Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325]): (Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546]), Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546])), Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170]): (Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822]), Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822])), Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054]): (Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295]), Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295])), Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925]): (Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848]), Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848])), Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909]): (Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796]), Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796])), Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540]): (Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170]), Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170])), Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214]): (Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448]), Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448])), Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317]): (Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294]), Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294])), Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757]): (Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416]), Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416])), Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378]): (Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091]), Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091])), Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263]): (Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463]), Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463])), Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666]): (Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361]), Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361])), Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174]): (Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992]), Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992])), Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470]): (Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401]), Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401])), Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665]): (Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957]), Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957])), Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262]): (Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144]), Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144])), Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229]): (Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284]), Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284])), Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134]): (Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325]), Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325])), Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855]): (Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765]), Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765])), Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115]): (Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814]), Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814])), Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441]): (Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831]), Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831])), Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977]): (Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446]), Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446])), Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880]): (Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005]), Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005])), Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789]): (Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995]), Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995])), Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000]): (Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267]), Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267])), Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998]): (Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982]), Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982])), Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995]): (Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539]), Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539])), Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507]): (Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512]), Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512])), Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305]): (Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118]), Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118])), Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219]): (Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009]), Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009])), Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416]): (Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089]), Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089])), Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980]): (Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445]), Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445])), Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063]): (Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140]), Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140])), Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713]): (Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159]), Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159])), Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031]): (Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809]), Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809])), Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932]): (Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037]), Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037])), Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094]): (Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925]), Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925])), Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315]): (Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386]), Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386])), Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446]): (Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721]), Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721])), Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742]): (Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981]), Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981])), Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661]): (Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072]), Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072])), Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979]): (Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671]), Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671])), Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361]): (Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269]), Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269])), Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558]): (Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571]), Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571])), Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290]): (Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902]), Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902])), Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987]): (Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741]), Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741])), Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902]): (Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515]), Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515])), Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497]): (Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028]), Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028])), Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948]): (Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709]), Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709])), Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009]): (Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725]), Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725])), Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387]): (Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317]), Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317])), Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159]): (Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808]), Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808])), Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394]): (Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699]), Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699])), Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312]): (Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000]), Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000])), Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987]): (Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821]), Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821])), Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046]): (Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909]), Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909])), Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565]): (Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028]), Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028])), Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269]): (Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352]), Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352])), Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847]): (Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271]), Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271])), Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513]): (Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800]), Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800])), Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054]): (Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394]), Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394])), Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004]): (Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977]), Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977])), Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675]): (Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800]), Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800])), Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692]): (Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159]), Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159])), Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909]): (Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932]), Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932])), Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814]): (Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697]), Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697])), Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186]): (Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387]), Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387])), Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445]): (Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470]), Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470])), Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966]): (Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507]), Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507])), Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548]): (Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253]), Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253])), Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897]): (Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783]), Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783])), Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208]): (Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054]), Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054])), Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268]): (Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661]), Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661])), Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388]): (Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643]), Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643])), Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257]): (Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174]), Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174])), Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960]): (Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241]), Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241])), Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721]): (Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046]), Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046])), Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822]): (Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217]), Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217])), Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253]): (Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697]), Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697])), Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054]): (Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019]), Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019])), Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821]): (Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432]), Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432])), Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864]): (Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105]), Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105])), Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373]): (Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855]), Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855])), Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646]): (Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830]), Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830])), Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460]): (Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208]), Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208])), Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033]): (Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214]), Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214])), Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105]): (Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129]), Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129])), Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281]): (Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909]), Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909])), Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028]): (Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027]), Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027])), Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012]): (Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054]), Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054])), Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562]): (Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589]), Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589])), Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037]): (Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097]), Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097])), Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355]): (Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460]), Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460])), Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223]): (Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355]), Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355])), Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089]): (Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306]), Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306])), Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035]): (Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219]), Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219])), Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432]): (Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297]), Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297])), Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693]): (Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263]), Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263])), Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794]): (Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484]), Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484])), Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552]): (Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941]), Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941])), Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267]): (Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814]), Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814])), Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992]): (Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415]), Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415])), Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941]): (Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966]), Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966])), Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822]): (Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320]), Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320])), Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306]): (Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902]), Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902])), Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820]): (Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880]), Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880])), Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361]): (Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725]), Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725])), Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005]): (Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914]), Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914])), Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783]): (Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781]), Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781])), Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011]): (Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033]), Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033])), Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297]): (Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910]), Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910])), Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070]): (Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134]), Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134])), Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144]): (Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331]), Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331])), Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023]): (Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497]), Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497])), Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103]): (Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540]), Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540])), Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961]): (Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998]), Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998])), Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414]): (Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]), Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]))}, trace_len_summary: TraceLenSummary { main_trace_len: 12, range_trace_len: 39, chiplets_trace_len: ChipletsLengths { hash_chiplet_len: 128, bitwise_chiplet_len: 0, memory_chiplet_len: 0, kernel_rom_len: 0 } } } +ExecutionTrace { main_trace: MainTrace { storage: Parts { core_rm: [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 10403713768525900847, 2139411523427040457, 8515917035379853351, 856023126862020256, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1032, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 2, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 8, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 3, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 4, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 1, 1, 1, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 5, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1942941126776981551, 9461460041610899538, 7600020670677266955, 3257731577738044347, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 6, 0, 0, 0, 0, 0, 5, 0, 1, 1, 0, 1, 0, 1, 34, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 7, 0, 0, 0, 0, 0, 7, 0, 1, 0, 0, 0, 1, 0, 0, 5, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 8, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 1, 1, 1, 1942941126776981551, 9461460041610899538, 7600020670677266955, 3257731577738044347, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 9, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 1, 1, 1, 10403713768525900847, 2139411523427040457, 8515917035379853351, 856023126862020256, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 10, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 31, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 33, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 39, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 43, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 47, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 50, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 51, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 53, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 54, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 55, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 59, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 60, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 61, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 67, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 69, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 70, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 71, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 72, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 73, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 74, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 75, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 76, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 77, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 78, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 79, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 81, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 82, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 83, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 86, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 87, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 88, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 89, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 90, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 91, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 92, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 93, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 94, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 97, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 98, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 99, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 101, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 102, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 103, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 104, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 105, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 106, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 107, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 108, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 109, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 110, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 111, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 112, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 113, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 114, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 115, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 116, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 117, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 118, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 119, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 120, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 121, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 122, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 123, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 124, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 125, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 126, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 127, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0], chiplets_rm: [1, 1, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 10403713768525900847, 2139411523427040457, 8515917035379853351, 856023126862020256, 0, 87, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 484349804684265665, 6880098633847640351, 846980218218532239, 17903889365796795298, 5550459936565271753, 9107753202341829570, 15324484398676964645, 9257266254418654737, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1032, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 11116382020814057190, 14732796941305378371, 13074361791711182490, 6715193688317415490, 1571558009365433839, 13285275197432594374, 15905141483335727027, 2507840277166973476, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1942941126776981551, 9461460041610899538, 7600020670677266955, 3257731577738044347, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 0, 84, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 10403713768525900847, 2139411523427040457, 8515917035379853351, 856023126862020256, 5748739229791737666, 3971489439724797398, 10156667480279311531, 10471841795831116097, 4161518306931659446, 14664557596733629071, 10457686661281861787, 5372530612210116852, 0, 0, 1, 0, 0, 1, 1, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1942941126776981551, 9461460041610899538, 7600020670677266955, 3257731577738044347, 15558099059781162807, 12870793504304295307, 12385397219736869043, 13164551900610862841, 279187929191844389, 3949603689257433549, 17380497166734391477, 5117931133682798382, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 10338918064798200754, 15286122942437340674, 6004213370540561229, 11077881500896133090, 15185046381229794929, 4025060549564442513, 16691190932080263388, 17911971684749301267, 1792647895939561414, 11040149027552020115, 16788268171496683395, 6690778673349798915, 1, 0, 0, 0, 1, 0, 0, 0, 0, 18207620435178905496, 4478894291978491061, 8126565228616187566, 14565598150868720008, 486704718504877876, 5092068149414351847, 4895519870785798161, 18320934558859357026, 4783600071858140824, 7590991738963063833, 15020058681279762757, 8502154501231846969, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1790253480113930875, 11472368064126754753, 16140937904922483949, 12784262958320173457, 8992534124131108063, 17197330755228127793, 17888648586033704362, 3783608546885852925, 11488181860237317371, 6520363121033018355, 5666192756396478125, 14698764588926429548, 1, 0, 0, 0, 1, 0, 4775960838571449442, 12355201513767393906, 16893169864929129892, 3067820580898613927, 4037642048582652770, 6463406968300557513, 1334655449937755180, 16454962669178338822, 3423416796618681452, 15635204112556936010, 11367217176161227780, 15846919749025709683, 8739705468185832455, 1695606868833824155, 14902201197695023622, 1, 0, 0, 0, 1, 0, 7270109453425771694, 6393439473671243944, 5763178267509538253, 87155278506862768, 17182682045085641378, 13669966515951696363, 6730246632471569917, 11015850215265080242, 5781848723365073595, 14722218108828704340, 12249120524157518956, 15530817548594619752, 2571721876460128542, 1124203808167418458, 4658355789422303197, 1, 0, 0, 0, 1, 0, 619730554607827397, 2707784357837694055, 10389429507854625814, 412437114519718435, 17010823019251866220, 8496853728750345058, 3962235926057627964, 7293691342607609411, 4966485821032368622, 17523850342152507329, 16165780461118504337, 6833077136448453098, 18408644517259086000, 13790345385092960681, 1118981994890433291, 1, 0, 0, 0, 1, 0, 2870832816007467384, 2873570063945483268, 5260498635996294368, 10072735002004767449, 7363233941642473793, 10401385213219539176, 9719773007613995950, 10216717372939649307, 13022711033487370480, 9232213967333586262, 3354429439844650126, 13306058477265011029, 3840400538830937486, 15100916108359921929, 12686728912814672715, 1, 0, 0, 0, 1, 0, 10126186915863966894, 13849382609137246799, 14871056570003924152, 4577474152973240700, 10319035267502935180, 1107109480596608884, 910001863439660317, 17323775771861278671, 11990539141370178689, 1895237968841058140, 3069611939766785355, 13990132518689115799, 9158955820349235201, 3334355584256728822, 6532229842765454575, 1, 0, 0, 0, 1, 0, 8418794997351000750, 1324633730077053524, 7680826640634201152, 6943155698572158851, 4119721600018041835, 10160115415927000034, 13670021867743170174, 10426040451143237205, 12527054859506162043, 693011963436135866, 15847427063003354492, 1193915807921269299, 5530767236037587666, 4498758928312101948, 1668396433795256171, 1, 0, 0, 0, 1, 0, 12474497430381571234, 3486558176421926303, 176934443909317952, 8642603494321417085, 13568047686929876305, 13873699071648888616, 5469909543377435991, 1153721650762048262, 6332701647560212482, 14750767280279403533, 3863562993110808460, 10010469643426778773, 13610145136323473859, 13803405503382348517, 10066622964560025039, 1, 0, 0, 0, 1, 0, 6502239097904837007, 0, 0, 11596242931973405682, 7569447524345075040, 11402732351667273497, 17726124048449719654, 2143489115939838335, 2291345291252627066, 13774221459002946228, 5704848367751370496, 14844994802213729480, 13325648093707576188, 655937328333223270, 12601714085039449766, 1, 0, 0, 0, 1, 0, 0, 0, 0, 10080683606039484932, 557142253253508029, 11861574744773262883, 17479297133692971328, 13431343265670357832, 5107644268576628652, 5672451077690842648, 10697999158618521351, 13783189127611294708, 6370270522833708976, 16602411989536803847, 17535824353652041621, 1, 0, 0, 0, 1, 0, 0, 0, 0, 18221718971044951820, 11123331110225556773, 17884963006522019435, 13581862227015801716, 3539406162482662008, 12779267696302831166, 17568889654867020374, 14043625177809463809, 10953842550742243459, 17624483884859046607, 16829866994010956924, 10383254959407238075, 1, 0, 0, 0, 1, 0, 0, 0, 0, 7704989128662250393, 7731722432250559639, 1104300072480693820, 12966826694165085383, 5898355191387204970, 418343475844287535, 17504741557362850364, 11212567254567942759, 4585972511305465500, 831671821010246741, 1347174724805777450, 9978241385511108600, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1942941126776981551, 9461460041610899538, 7600020670677266955, 3257731577738044347, 15558099059781162807, 12870793504304295307, 12385397219736869043, 13164551900610862841, 279187929191844389, 3949603689257433549, 17380497166734391477, 5117931133682798382, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1032, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 15913981378790993016, 12701179462806902902, 9645342555817022514, 6889850077248808033, 678249829196625442, 8726676798253716750, 14136118088409135949, 1027279235140821190, 8048729929177993405, 2542525775606472849, 3283471062508934848, 18058280687405074483, 1, 0, 0, 0, 1, 0, 0, 0, 0, 11899090779839289087, 1701090513954162998, 6953639183117323837, 11460660778637092812, 8345945186928076892, 11308243255833047975, 5734666540714547293, 1546649737555419076, 14643837757854608147, 7477230882792828789, 2359592855656894189, 12732146754685591216, 1, 0, 0, 0, 1, 0, 0, 0, 0, 16283412161296764998, 17261112905912533997, 1498213616014501531, 7707889409925905689, 16090493533591377617, 525010687572874692, 5228788497345464933, 13051466527897639054, 3560924095387897187, 12551242480725370445, 4038828260160651477, 6132317990703151787, 1, 0, 0, 0, 1, 0, 14261694278902826987, 16097544111075686229, 16632169854204459773, 14265791174051766329, 14732671264513481238, 15642599276989292777, 7593738854072541043, 11440582168151819564, 18258483622390056257, 6851601084855956341, 10463349537167637967, 10032876585525342603, 825669147467031185, 16271217766495541082, 9021089524754424392, 1, 0, 0, 0, 1, 0, 16780109665356203593, 16025948514351396737, 4256182047405196535, 4919013996388780384, 6974015548720770018, 10189882052640604940, 12288632186238773648, 7055558833039165669, 9820743264545515107, 7353106531603230851, 5612808106478211181, 362487531847990854, 10259224130335842891, 2374318293393776907, 16208179153232019183, 1, 0, 0, 0, 1, 0, 9496969110446094198, 10424961628901078909, 7587726188775237019, 13423955604028434301, 12288543613568774022, 4068762405627465026, 7288480650179820504, 1035430088689333582, 2651098721515326755, 4524440782000877024, 3013038852551457145, 12536534023666437466, 6560028330562582937, 9090521726813489969, 17634755409309861791, 1, 0, 0, 0, 1, 0, 15761194215082968049, 15796684185970405493, 1294179585337070936, 5701860167148115542, 17707247215386403887, 18419960639673587986, 14570347312565937582, 8634142387233894354, 11938075017385927203, 8060480374868324599, 16699922976999064541, 14234489074154948378, 17210389744085299852, 17331527780947314617, 16356838976302290254, 1, 0, 0, 0, 1, 0, 6184336662619539433, 7106147576739595100, 18237994300618329820, 9768155666925548219, 226714884885574576, 11169479382209254075, 5756676929838789145, 29803495366482069, 13128905441940840949, 18304516631519674746, 3177693875357946498, 10624850715031233718, 16956738608020324589, 10558540052020438814, 7826502712354673600, 1, 0, 0, 0, 1, 0, 1980308537464408089, 6810023246846442283, 9400257804338494201, 11246932855318952856, 7504545710540897051, 5823677062954428984, 9151299935574592196, 15905322272715446259, 18174748553199601666, 9877077233183640995, 2431998410719122545, 3541292002384422941, 5416588529930333172, 15788517205879313917, 2490575598934209003, 1, 0, 0, 0, 1, 0, 17950140321155419078, 9014768943295123367, 10707122777228105884, 10701204914974985643, 15060806908759160804, 7011191650405807117, 13598159658926423040, 3947314552577424057, 12985682730462769834, 18264715466581442035, 7667189540353817157, 7685483800933651249, 16085167604591833455, 16105855167414075111, 16215395602017884846, 1, 0, 0, 0, 1, 0, 8676227747932036802, 0, 0, 11504729673400082663, 3659553513673892306, 10374352082945691939, 15819529278889203623, 18107940902385670152, 8889798095480337831, 12737345777792032790, 456604824069734238, 2859376131275373721, 8758251935142908528, 2364536875264708997, 2435873391009301907, 1, 0, 0, 0, 1, 0, 0, 0, 0, 16797630026773069829, 16954579754978210547, 4393671449525183699, 6245909065255485436, 8311309349844601638, 3305827896314343556, 1615477551160071258, 3897903986825909618, 13015230208471866351, 13839070994009764281, 2415598337053791919, 5526300544248852335, 1, 0, 0, 0, 1, 0, 0, 0, 0, 12827873667465929582, 15892701250663610383, 549489834728826775, 9425334953627649153, 15402634395731091512, 11814416271399500934, 14597718118926923662, 4726679541432826422, 342915941842538663, 11221492717904369823, 17188959961041335276, 13559932473868727168, 1, 0, 0, 0, 1, 0, 0, 0, 0, 8689096602925893779, 4096531352684607500, 8424481237826564505, 15238165026175259240, 10985176737527635898, 2672540837788784952, 6649439643634522762, 7581835251244605715, 17671970641549389116, 18069913154458602790, 749417941228438762, 6150863900366154379, 1, 0, 0, 0, 1, 0, 0, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 11116382020814057190, 14732796941305378371, 13074361791711182490, 6715193688317415490, 1571558009365433839, 13285275197432594374, 15905141483335727027, 2507840277166973476, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1942941126776981551, 9461460041610899538, 7600020670677266955, 3257731577738044347, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 0, 84, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 17300126657859479093, 11313920102849673527, 6346627796045519057, 7389299619274629431, 9262647006463201494, 12900235463952244627, 7852421498196750068, 1141784430625393243, 12150004112779528077, 146728085155958051, 1479007214074296519, 5326692900453573033, 1, 0, 0, 0, 1, 0, 0, 0, 0, 13417131057632658648, 13887354800197146837, 8609784525483513948, 16453892850627486456, 976357452201521805, 14650998861370095747, 15798952093464371291, 14383483119098647176, 18419038023611574318, 3683052509510392753, 12831965507313403291, 11464211275629339672, 1, 0, 0, 0, 1, 0, 0, 0, 0, 4507099831440932953, 6830877239439284265, 9097811782723336829, 18355313083727954627, 7779515141290159182, 15839592087462215756, 13604506694568008603, 14024127302218670748, 5952493440729260050, 4068297222526233952, 1979966764305086565, 9333200475194576798, 1, 0, 0, 0, 1, 0, 8357924686780715814, 6636884447613425583, 9624380725568248686, 2880287348195737852, 885106567500324074, 6448875554992341703, 9855604354502581698, 9375523715508471459, 12339746387209375629, 10455158341094955823, 15902189126849452967, 12030315950055306153, 12641257084941861137, 15957996139063952329, 15783553274882271383, 1, 0, 0, 0, 1, 0, 5347236343958253894, 4025896570838415692, 14804406762588016934, 182667766089555833, 8746225101260903407, 12800409546363710287, 816655693375320760, 3488220768045884341, 17449960788520479876, 13060006746047445404, 4590648600733170196, 14869579734892957539, 137356745712127171, 13422659882759208113, 2676688078772673635, 1, 0, 0, 0, 1, 0, 2921699901762625847, 2649189506073489962, 9913373798344930711, 7755498383134197376, 17631069913300146763, 918789106343442195, 12710306366297056980, 3352461179293085611, 13949166093507073033, 16957002236887535634, 5578100969514402869, 4043905565383364858, 7659576686417292817, 2367890233987709775, 8348028103004129201, 1, 0, 0, 0, 1, 0, 10172794879368016270, 6345331429530820033, 5837950612071262866, 16650183950518877881, 761183529886498658, 882392762205142966, 10341241875528441727, 10625329717419136765, 9971095066673234358, 4232004013780299993, 4126250918613430195, 1352790980003480299, 15265846796546163655, 16214598491416624701, 6270582476047461808, 1, 0, 0, 0, 1, 0, 3029040881537747494, 16192268821146642419, 1429264540499601619, 723722855549182307, 9275648404607992275, 7653230088222442503, 5336572895513434476, 17267978825783635674, 2055211161196684150, 5382467524735065973, 17562229302921943767, 11689925804137528317, 12333395168151976785, 13928209897558581843, 6382294855606512139, 1, 0, 0, 0, 1, 0, 7880496552213312201, 15122758161943386192, 7696912976710769683, 16684832919913645113, 1325781221503242261, 9767481056214686264, 15383255957179010771, 4765175578813598212, 352612095018961168, 8164700351999240448, 11366624484197321797, 14418389432583501516, 5429053278517118996, 2079377923041037634, 9248817126035377137, 1, 0, 0, 0, 1, 0, 7798482983966084054, 9698350464160947514, 2622165840457703741, 3191144700364674222, 13840521809458223850, 6693472114669876018, 1844850377219340954, 6041824929233084189, 10694505064011226265, 9837159640677247471, 421241411507411802, 1387064907365996610, 7160690172588878117, 6170204562255862519, 11691591530451877345, 1, 0, 0, 0, 1, 0, 12784330368443191752, 0, 0, 1511701347894443705, 3195625100455147555, 8197728783207379545, 449202167972758168, 10429619634413714415, 1266474106654512299, 10043612818557622726, 17546950285193103331, 17459565798841957386, 1545883776729609444, 4559076489231806387, 2919974393045314777, 1, 0, 0, 0, 1, 0, 0, 0, 0, 14541231479059008872, 2573517030855683796, 3524292720580177308, 13855152767270114589, 3006044390476483944, 594411982442348353, 2707135781132813285, 7980470443732427589, 10692471325161091019, 16152944287821214660, 16000995173627170117, 3599288644418559718, 1, 0, 0, 0, 1, 0, 0, 0, 0, 16401658505261312282, 14340768500784081639, 9157399410194868857, 9102901647434269728, 17796618941315046862, 6870559696376279126, 14430288544136295714, 11256415914434052793, 13509056984869078243, 16212533703602772012, 10731537818920783986, 9244614718938709708, 1, 0, 0, 0, 1, 0, 0, 0, 0, 10956055287997745079, 17622456621764780147, 5455165430251125445, 6727955785885619519, 14753857082920611668, 13906110808313848802, 8347093488770218639, 8918883692704710750, 15290172371351697411, 10523129087658444171, 15727241650811717280, 10475089196439845505, 1, 0, 0, 0, 1, 0, 0, 0, 0, 10403713768525900847, 2139411523427040457, 8515917035379853351, 856023126862020256, 5748739229791737666, 3971489439724797398, 10156667480279311531, 10471841795831116097, 4161518306931659446, 14664557596733629071, 10457686661281861787, 5372530612210116852, 1, 0, 0, 0, 1, 0, 0, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 10403713768525900847, 2139411523427040457, 8515917035379853351, 856023126862020256, 0, 87, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 14973522761191262497, 4230519249120879894, 2629183259646768977, 10141819052260397061, 13407203767006087071, 12300175896314074402, 2702373535953719449, 14066933458796711308, 2220020800002954405, 1153376321238519426, 9501912115787530137, 11467779250790108687, 1, 0, 0, 0, 1, 0, 0, 0, 0, 17579142101067141791, 16331511478156948621, 2536845301555017815, 4655744751626348560, 1315476336364332532, 12758262197074716778, 17888512728802654414, 5454338212767341777, 14616265448064819190, 4049834289657867128, 2177315978307888394, 2010382289454711711, 1, 0, 0, 0, 1, 0, 0, 0, 0, 12664267918550820934, 8493562230894032491, 10885506335001351491, 10623508799881057302, 10765360003981902673, 4842275562010620878, 8656573021603208590, 2450260130765540973, 17667697651318069254, 3544163002330957814, 9007165683524157049, 4518865977780754525, 1, 0, 0, 0, 1, 0, 12821199281659850615, 12524526780064226282, 8688367803817133517, 7111709976940449855, 6042875499671257036, 10602803306945095136, 18053244771098668210, 15869901507286010642, 15765124758947684257, 909769595464630286, 9984901127103118556, 16104234613185942963, 1596997669664652458, 3285629071226892513, 5254177489666731166, 1, 0, 0, 0, 1, 0, 1319022057496410037, 6723956385664361856, 362758946504872978, 17945942309272171171, 7547510637898886664, 8389575157731885000, 5432655503035172224, 8636630472484196539, 17112531070480946597, 5597227622497427759, 8296183404013335152, 8448226142379838282, 9123809571274586481, 4262155088312829534, 6352753764020113838, 1, 0, 0, 0, 1, 0, 15817353186600079517, 11896741780081321151, 8120557738706811421, 1514840266710990643, 2518758362364209964, 14494370701341234363, 18160488913248834173, 415225714783614736, 14762958776895421659, 1582837024273971615, 826388124734417268, 9723851761924399417, 2904897680946636379, 572660879606393944, 5062575418735094728, 1, 0, 0, 0, 1, 0, 11887745873838856200, 11056257118819520017, 8546453177127819509, 3906777862244807614, 15967237477862396017, 1240858482343082944, 8886870748754950786, 15806110295452780709, 6486381282415609829, 16950387463813522784, 8577643233130284288, 17768236078519772738, 217872450018257683, 6293942954387886585, 10974892067682463496, 1, 0, 0, 0, 1, 0, 2581007320496406744, 7054105961444862624, 15347768076097298693, 8125727413083423821, 10805393644723323985, 13586718478006757236, 17768197347468566879, 17280093366403031105, 635835674863826303, 4568185472217893804, 9296267175044089272, 10337709963460435554, 4440112583501734927, 9729481707513785664, 4743006626934706100, 1, 0, 0, 0, 1, 0, 17610297678684695918, 16364115285854473865, 11595150248116497643, 7035439775474110251, 11847308316956964837, 7889458920902982286, 11305368688963866992, 14287445400250554900, 1893961912880033900, 10317967923286478317, 3918181922279376301, 15000492392148830533, 7931144489554367364, 9476759250402767950, 18270644106765218282, 1, 0, 0, 0, 1, 0, 11532830003582511953, 460321325058925628, 12709513064174486630, 6478715440156951267, 14089413401266079358, 2281022494971066801, 3378217915115563837, 4838851040494198977, 11743317019648187379, 3359761112394096597, 13620706797177850518, 3438335644910777353, 2067033555957484299, 11784176479463653422, 9418905686906839178, 1, 0, 0, 0, 1, 0, 17359699556169412381, 0, 0, 17848865035999698302, 9363353806961732906, 1059359355271114718, 3722579262469999737, 7401377741210733980, 4394776823738550294, 17911331326024175702, 14231054337850845953, 1567229020978754366, 10965059646087563007, 4717306534304214129, 6160606101751839399, 1, 0, 0, 0, 1, 0, 0, 0, 0, 5210262791539000682, 3231850662476970044, 12242203768226360021, 16352185264854542792, 15126409509795103366, 17462025488896312666, 10962575762908536311, 16737021171185522127, 6692618053949882379, 17172828881706643966, 14646740046786928565, 1663831101883973254, 1, 0, 0, 0, 1, 0, 0, 0, 0, 4908282038977879385, 2701244722093391429, 15021286664224332416, 10534803976436280037, 15876667595247308635, 16333738989139894331, 1581145115862775994, 18250779698217077450, 7155162361709676048, 10303228755363253440, 4300281072628271246, 16497484699945471993, 1, 0, 0, 0, 1, 0, 0, 0, 0, 4313772916158122500, 2902278358899028132, 254766801126374444, 5671561640468956184, 4347645646061943576, 1998087227139787801, 12798150249100419438, 647551028640823116, 15480041353865470488, 13024601617472109101, 16248647525361276326, 18146087632373782831, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 484349804684265665, 6880098633847640351, 846980218218532239, 17903889365796795298, 5550459936565271753, 9107753202341829570, 15324484398676964645, 9257266254418654737, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], range_checker_cols: [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2187, 4374, 6561, 8748, 10935, 13122, 15309, 17496, 19683, 21870, 24057, 26244, 28431, 30618, 32805, 34992, 37179, 39366, 41553, 43740, 45927, 48114, 50301, 52488, 54675, 56862, 59049, 61236, 63423, 64152, 64881, 65124, 65367, 65448, 65529, 65532, 65535, 65535]], num_rows: 128 }, last_program_row: RowIndex(11) }, program_info: ProgramInfo { program_hash: Word([1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209]), kernel: Kernel([]) }, stack_outputs: StackOutputs { elements: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, precompile_requests: [], final_precompile_transcript: PrecompileTranscript { state: Word([0, 0, 0, 0]) }, trace_len_summary: TraceLenSummary { main_trace_len: 12, range_trace_len: 39, chiplets_trace_len: ChipletsLengths { hash_chiplet_len: 80, bitwise_chiplet_len: 0, memory_chiplet_len: 0, ace_chiplet_len: 0, kernel_rom_len: 0 } } } diff --git a/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_04.snap b/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_04.snap index 31dced8cf9..4a91b413ab 100644 --- a/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_04.snap +++ b/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_04.snap @@ -2,4 +2,4 @@ source: processor/src/trace/parallel/tests.rs expression: DeterministicTrace(&trace_from_fragments) --- -ExecutionTrace { main_trace: MainTrace { columns: ColMatrix { columns: [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 33, 33, 33, 1, 65, 97, 97, 65, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [7458506668679174706, 1032, 8, 0, 7458506668679174706, 5598651459581075585, 8, 0, 3358534066525179769, 13620833136975709089, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613], [18375473735916206629, 0, 1, 1, 18375473735916206629, 7804753453550466256, 0, 65, 9365253138981608257, 2256486347761721492, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099], [2105717247508690050, 0, 0, 0, 2105717247508690050, 17777748786253636403, 0, 0, 4243893038989355703, 5193960644663470490, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350], [1679902783560062568, 0, 0, 0, 1679902783560062568, 9435312778805252724, 0, 0, 2372900269115514267, 12344784587178360875, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526], [13620833136975709089, 0, 0, 0, 0, 3358534066525179769, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [2256486347761721492, 0, 0, 0, 0, 9365253138981608257, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [5193960644663470490, 0, 0, 0, 0, 4243893038989355703, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [12344784587178360875, 0, 0, 0, 0, 2372900269115514267, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 9999, 0, 0, 9999, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [9999, 9999, 9999, 0, 9999, 9999, 0, 0, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2187, 4374, 6561, 8748, 10935, 13122, 15309, 17496, 19683, 21870, 24057, 26244, 28431, 30618, 32805, 34992, 37179, 39366, 41553, 43740, 45927, 48114, 50301, 52488, 54675, 56862, 59049, 61236, 63423, 64152, 64881, 65124, 65367, 65448, 65529, 65532, 65535, 65535], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [7458506668679174706, 11091832976040936962, 11629723830403400020, 18085092721393681494, 5334827122981806215, 18131418839636252978, 14614347609195626268, 8910439294593611592, 3843332007587847712, 1023179011544432384, 3804737116729640404, 133391072621725577, 12470388296134501021, 632583774013957871, 4078804678813269002, 4646445037357820970, 12451999842825777859, 10348876437499804673, 4709521304751214351, 3818143376057959690, 13735545676744754358, 5911009352187537543, 11554714135033312948, 9410850814958744902, 11602211351055880832, 12661500893159548834, 9684778724196116231, 18082132319471479459, 5677068088590394277, 13067481717060632118, 17366862825980504064, 12752059346458920613, 1032, 10320, 13024110921086730221, 3587442816163675215, 512402747638547729, 9217956011885162917, 3925750957223009950, 8674177413178223320, 12846799727083908462, 9116601283268739756, 2958792353189815054, 1720195204565087693, 7696852080146622077, 2890877729556257606, 16676527939404087356, 223754558788184593, 4767414622778376421, 14072300156908432530, 16856861612825314654, 11910434229443384600, 15658716527747040980, 14322127566252286435, 4770460127206402609, 10805338145914832851, 1391598300875421210, 18211456042978337510, 11866022853402812888, 6438324596032750504, 13328288515202849800, 17331158106613184460, 18344276842462151560, 7458506668679174706, 5598651459581075585, 644336023812026221, 13247747688876077858, 18204236545845216971, 16083593158731167399, 4357419437649084221, 5464680208294216350, 2779149829283345558, 7975999984217399211, 3799311940445025695, 12287115722151291956, 7889055060352596454, 3871221682982067508, 16266218633314388061, 10296105519823441978, 6482329477820286957, 2184206139900597012, 13275897735411980967, 3045004919428473516, 16702736287849627035, 4028816571826363002, 15011221569533006108, 2864985628223798368, 15475498524455915389, 5364573001665328907, 10397611698676440611, 8883008337890476036, 17315153826736218240, 14581052801302714514, 17999554639252319772, 18022889162320300611, 13620833136975709089, 8, 80, 16253482711025978099, 16690839578921925157, 11755424915479552417, 17934377671577204140, 15509754874715907467, 6426721221030580337, 11049594146888643723, 14912334368661229147, 17657273147290084056, 9105126057127804171, 13430225876739607206, 3614830725909060912, 14569284676797348998, 4705513459362295944, 424917224365117418, 2835737623710330612, 1964100172858915134, 14896843043547784767, 15482419984058848245, 18437547705335910066, 3162257106529980441, 5297995970636059087, 9661978795293871188, 10128143329575104151, 770728251595531533, 9782965673735423214, 1347942901513492691, 12086966446141742548, 10239457018222882008, 3358534066525179769, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [18375473735916206629, 4371092720588693207, 7555819500301263096, 7871576915936585054, 7738161198426062879, 4439752770537371709, 3239157867226066300, 13695428956813660853, 8114913103795360695, 3271513559100018830, 1227622944719103238, 17840970837055628605, 967816437372899090, 1525132029610696618, 8930953641447820548, 1991652128187274521, 1878310895470329371, 1537331530871119668, 17179845365129498366, 6628846356810584866, 18158002788694963974, 8030209565693857269, 16465976624819029473, 15848213422225602213, 16693748147017299005, 15158850031902933967, 18144229372703820177, 8111553228231189401, 420461259745383997, 17094012225747072853, 16556024871956851478, 18135096529078946099, 0, 8256, 1131208899036558480, 1667157010810320250, 2053960715201569301, 1526213270499333709, 69813565043892453, 14925652377538846871, 1380252317064967448, 9902934070223067140, 3786794161520721521, 664031068804619792, 8470323998416702977, 4965297830526000942, 9404280000999464502, 8244737495337250711, 4784363486033662704, 4680481291290566437, 15373555507761845373, 8780119261264514018, 729009684537575982, 18306419558979237700, 15407410920890065538, 2509966126115291236, 12709897403480972846, 11498596868429821859, 6606875518512322314, 13880694912200059110, 6972406840307481976, 14148490408465275064, 2917966740410115114, 18375473735916206629, 7804753453550466256, 10860407685663036604, 1563629168745730928, 4862512017968946683, 1035294938480129016, 17121277837906333314, 7566123129055455762, 801761918673301233, 8221980324343257318, 8971289227653573810, 14503443403830829887, 4403991158284421772, 3539411744559999519, 17877470569230350231, 13052305487168984918, 11988250928057152362, 7990654922366982189, 8123717249091864283, 273044411934894184, 12617346169478402785, 2083501518846346052, 1182260721753268305, 16655426125402668777, 18315976927222050841, 13684207927534177805, 15562831278015850283, 7777530579170086866, 17762371058211819624, 4106083518382761605, 3917672276375751396, 667054191578263747, 2256486347761721492, 0, 64, 5751576643258238090, 7830268710878889486, 4868320831660690795, 7042762868047858013, 1028615964620729689, 12270587957620579653, 7267371538363991280, 16125626865182516658, 16950134439933558852, 13427183447069512151, 16117382505273595827, 2222792985740553749, 6517696895688418945, 15516128650333221731, 6357034143715229949, 12960707821770488929, 12451444460344609421, 8786747128188560390, 7634329044629047826, 7741107824034642016, 10975559322169081956, 6007758954686348362, 13971256108093330407, 16868860295450858142, 434120282701603474, 11571634562637977474, 5581285869985960561, 6581368197537384623, 17661012293298952642, 9365253138981608257, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [2105717247508690050, 7371349600976768903, 1908428216714745226, 2226486931669462500, 16096322966046779578, 5448090446075942959, 10098429045835473018, 4809915777199041455, 18236464326626014645, 2690803580142520255, 1917959726470568181, 7355089244606367886, 9988016662047687018, 6075081950126577031, 782991345573128788, 17727121868432118686, 616586521336426688, 5444667365009856158, 3285592017878659318, 7931583655659423496, 6385821061540880880, 8735792590442216465, 11893401421408965, 8831024347202442032, 4451634306410080384, 8173507753862756681, 15267089652751109873, 10164019920559079526, 5461641667913740527, 4977882380646661156, 5148753722704728721, 13200399719329805350, 0, 2064, 18136552782870868471, 952274539956745973, 15933282259815262093, 9924516287334785738, 18064603646801610993, 5114527609957824263, 11816233963570869158, 17699527003452380450, 14533708946479200173, 17484213571014188868, 832814531422633701, 1508169308733590908, 8423043379628164525, 12595277727969636921, 14226276023010866965, 10485112285448962747, 1783527593060720204, 10145484005384627580, 7463752398658534839, 17345550819494003223, 4432309123412733588, 7086318781105575433, 8830891075082588619, 310185093236608634, 16683125300631590273, 7786799186167080425, 29465347809991832, 8090161351836983773, 8665315444141111469, 2105717247508690050, 17777748786253636403, 12906637371964794665, 9477262435683869924, 9199231093019338048, 7358751435793575899, 12569972625839259527, 5847320563034378965, 7599987891632365696, 10432134440683583258, 16242679258308055777, 13780789328607365793, 1153491566876700606, 13641042641136958279, 5969854971149325760, 6340590356564925801, 9771444654514086827, 15776260062082886705, 8278469467176979574, 16237604982476195391, 7423750977119185664, 6710003146178124596, 376186270665682407, 15539788083889931684, 11273188656572444234, 5199551304380116153, 11734010025122035435, 3764388601356982695, 11644487560172946408, 15563655808705061071, 5533608926617884295, 14514898346462505299, 5193960644663470490, 0, 16, 7110029021941723513, 10115409991715085575, 11428668827299215140, 4015039023438705588, 3732466887400149035, 5870841944205588609, 8421627027326523148, 8231214549142439222, 10318470559229280016, 15171283498151438808, 12477430934852872037, 3853779543897991795, 14662750186533371679, 7423988381383082226, 13549468426633458145, 11079168775731474830, 12471207782095033761, 17595325414333663547, 7042468264080735391, 17650115337646869205, 14946074228061446423, 4655654314239637986, 11187552516160183253, 18115881480442018545, 899748567092010447, 14020868337400209874, 15417366235984526759, 3331301994171189600, 15814677761660135474, 4243893038989355703, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1679902783560062568, 14926961084296668554, 18296820143542754124, 5759648439566973806, 7690180744863199464, 6255055536007924620, 9967438444965419122, 6053822608871655533, 3970724348518176437, 6498891217103059128, 10341231834356228091, 8497160540604180804, 5144558705352378414, 5437844264442299443, 8712431777609915948, 3915629295644008966, 1353567482375898210, 16603575236790899764, 17009424079525297171, 3253699369098499458, 10648493462065257860, 10940203220400825059, 7261956826490066834, 5730064365163707705, 8826144244207679463, 11688897202604808409, 4559302720015817859, 4402707951554525697, 12375228725744876260, 13367890413392736054, 15438373163420410642, 905179285088193526, 0, 2064, 9594118340025725004, 16218246678075491818, 11582919835122342747, 5661452934218108707, 3714647928422746674, 13689184893219719187, 1899963197709801965, 8313716591368695784, 17822645741084942000, 18354595702287703799, 12620512717427217848, 10145637708639089787, 1735222492513760332, 14681927838838900060, 9262747238997471758, 11498487923782501751, 8924101344488972446, 2592517964915386184, 4276681409258176044, 3764365715267793208, 3120204268813370353, 6019260256544801113, 2801984351776029768, 16979166255722313516, 2813750347113564525, 16588139065369475399, 12012198471360912693, 2492059183640657261, 16968938268466755316, 1679902783560062568, 9435312778805252724, 12594665258064570661, 1586451078180607598, 9325815886784366656, 13163107377789060321, 5998117226166788975, 7008390784506277276, 7362390315901265787, 5188984820381727203, 5842708215320867131, 13553650342229414448, 5955476415838559193, 8725164908673674579, 15174091024100472501, 13637649140457772157, 16186415272190469176, 4473737633571089105, 2032050757569801828, 16070334483916823186, 7382925316452200710, 7820237015849984079, 13711104951459639694, 15277864807184951074, 7746677489393361812, 10897962020578390602, 2459478953251166639, 6142067256785271224, 1469990404519833898, 14737929225229310854, 17685816709290022661, 5568614684720127113, 12344784587178360875, 0, 16, 3208043314804619251, 6920597847411412414, 17985619796195836408, 11907191178709112742, 16377455862733420451, 15572876043608056600, 9466912758182965715, 17480763791598773801, 15029113851915312964, 1953587265841775225, 7175742902791404624, 6820764940134875350, 16069841829669607101, 15548451706938320654, 11760680638795846495, 1560700914733041660, 762367990279432470, 2603436428456411224, 6200990949184863170, 11673627333152839295, 7804486006334068097, 1006207264024395366, 11193609705356653459, 5704515878100803393, 14918729158665343812, 10658508130485449873, 380737719356524599, 12870561906904032245, 6984680585936259437, 2372900269115514267, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [13620833136975709089, 1046930547281056921, 5022880593775506902, 7356080910092118039, 16589884839242022257, 8919754405551141869, 782951559730000700, 4320210530167177353, 1189869440416317038, 11509478421996896286, 14131663596834904750, 3063592889799439815, 8310309385140170305, 9794866582382956591, 815213714413043438, 14909022885730690459, 1965134134848901020, 8569284627647542389, 11756365299450742783, 17765218832065923306, 17214386397833253270, 8857548797279425296, 9589793731564825353, 5744303806832189345, 9245523889540971217, 17743277714115543370, 75478605149737153, 16642733757618334231, 10408597074326334289, 1854469405851562328, 5120877191992423544, 6125088443291536169, 0, 5160, 1190658701913535022, 9371121588404883743, 7133056533056999470, 7380100170229652082, 14719783382686670107, 4693530971176924881, 11125714198188567552, 2434816259070577714, 17927785478103501878, 834873962620943786, 1091858408197145201, 9293176204765248193, 11318806736621162148, 979530496520387452, 8328113718786640843, 15870139479256453021, 7754853849459016697, 2742936430580983415, 6806060556807781604, 5089080673677611112, 16430235900965466453, 309743103212430298, 15664803780047891222, 3113571524475220627, 17862871362988443440, 1231393200801541530, 15779352999894925288, 6026600320279882336, 6970552753544824994, 4949154992619464010, 3358534066525179769, 2539641719046213719, 10199880931320172189, 6982964906206022277, 18160468829511284938, 13459748022261389691, 8540403463779371619, 298971077135778992, 9448428205117043728, 7211550496031219820, 5534997352008564058, 8961849300614763067, 16471253951712069551, 11996630593586982068, 17666409503469399853, 14743209389502972128, 13621451519455201128, 11693451034972088239, 376126037836000660, 12412096817616379990, 866468160396608077, 16487331493773223294, 15132792027965031247, 12005877568613345660, 5222840910814569167, 9174906967528115515, 12806387721803954058, 12420516276683200334, 8854457266879028181, 9558115804602486754, 6487880825188915613, 2384716068805359876, 0, 40, 18130890293586930078, 18252951749527557342, 4460903658820341507, 859505755654562117, 5961685480015386121, 12134776249586726543, 11174658189737631113, 18385152961050631924, 9881471501704199804, 9636744945302995714, 12323181865658998064, 14903454669611502952, 1490539036394497080, 11688514875590095153, 16093513520259190726, 7731471377060742735, 5247500963110975116, 5269361527156951110, 13733877647296302634, 11865469401112846356, 7643242142337524006, 15572658687280648106, 9345628789826937825, 3291248301730279223, 16808111015808513609, 16274730253017522022, 12243901590027926887, 6559275936659510680, 17224785255700525855, 1390310476158884261, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [2256486347761721492, 1399831673864751627, 12438672130810751909, 10240118010240816453, 12454995736750842450, 12272610174663972685, 16716772686788009039, 17679411248915786729, 9344021820453066790, 15548275238570617018, 12554227251830406338, 7982818396816137943, 8298623838207759766, 9667670442404470529, 14730751205912092663, 17475545646146195192, 7561186990159804961, 3352703426322824443, 11124655848983105243, 7361271662241444721, 1785076194951656280, 13323648175345935378, 15598576959546342188, 12701095265259304800, 3219799610745612107, 1555585114147558761, 10397456717804752138, 2319272066426069991, 17926066510128935923, 1264814027228690376, 15123699931666188121, 2665390174743669239, 0, 4128, 1352424102745866255, 13301242752201603536, 5420135027930584396, 17078794493496835379, 4779811836607866048, 3650219859599657886, 13618468821889769363, 11429589192023659923, 8853101337885331080, 9650238821992519861, 14401087967309285252, 12035560952634921032, 15407186837043713393, 15711028160746246110, 5396976350889627712, 15903424027416555998, 11304777107657759509, 9857843669692965578, 12605480788735099613, 14618970056708743810, 8493993205782554647, 6059068631740368787, 18316971448227884023, 12499808993385025318, 4210674244211222629, 18405965507148502967, 173097048437312502, 15568437290332308327, 11532601739151124629, 10000279862191744493, 9365253138981608257, 9113412038486870510, 12237115836192970750, 13532373892635206986, 11668565565569624948, 2114739335810906841, 16845938989106496862, 18053472495070906903, 9578952411771586845, 2253954535466549551, 11957330595594263589, 4327169169737696049, 8097241277176222682, 17499521208876685046, 10474171567958477310, 2884885063912824473, 9389176041985146128, 2067286230266639471, 3365016398014065199, 738171567486888734, 6622135657383660119, 4978858449337102663, 1252098561428724852, 813491835360077960, 3026073706021528936, 1157174472277816506, 8848575890036236601, 4801870550462804365, 7028466390812097322, 8403721226663073636, 8970732296705167988, 12459739889109502988, 0, 32, 10452764368937945515, 6969997263492352670, 15570786589164252178, 16136993048454358354, 16378352067056606124, 11747573379431147483, 12296464969648251345, 8155132212936940581, 2470200969414032680, 18126939303114916528, 16736276280592238734, 15549342782445497049, 9033882039108268313, 5121596298161079296, 14336897502470956191, 6301009824137139871, 16614860627935231068, 10383378433371415142, 10330363517752279308, 10937466001850040595, 16305844076412050396, 7189713532379018536, 7568236447715590536, 10805187342082326609, 7424874700566577356, 13861219118264849665, 7052270251739242825, 17586339544079318164, 14071176523136369481, 12282546735285148319, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [5193960644663470490, 18378615377082669582, 9942094792989095510, 18239658104155677632, 3247221802734244696, 8138145110381489386, 8305898108846284300, 4495835739545312127, 13363880742094688735, 409501507955448067, 9615046049029083973, 9226283480795415930, 6188039948757326954, 1925348622523205808, 16932487676782686187, 6461440512631901369, 6379521145060545439, 1135364094435597517, 6898694641523826133, 881111998832614715, 7852757539889945333, 8831210118957475983, 15508177777761403707, 1274251095252206369, 6462015026972174497, 14758961666322366163, 12911489632740586743, 10573355084806673526, 11042755251558401992, 1655214279385078584, 17558359767143120899, 18009389558374812227, 0, 1032, 4798141223555508282, 12962488577647927717, 10133257770726709126, 332864556927106185, 12116126881643349994, 6604148216925166409, 101015634312276042, 15934992137290074922, 6112274855072540816, 17762248064501548615, 13166189948742588777, 270100349969833402, 13485211244653928073, 3502306881032295169, 13607663468974078519, 8883940618995723208, 10623667092532612652, 12293715092576816840, 10386976621364522928, 9128135834925108269, 15731443845270647366, 13373704167654916087, 13746187061551926812, 11684868053863796759, 3258729720361659960, 10434904637843727165, 7034851303745741351, 16133345873308301364, 5426492436527662130, 2980140658145787783, 4243893038989355703, 8922317147540258079, 15524901873579080579, 14961355291644520251, 8912131487655833337, 845467818172067610, 6513419642881984303, 15821388348544564061, 918209442918452849, 1771868273093277971, 11088759444000251587, 15710903694873023395, 7739199555620722590, 403122127909161589, 16794196935209020317, 420049465494673582, 3241180689003955516, 6815831073966054431, 13165955590245083084, 3933813014659210303, 7891509834730356602, 14572658037405460796, 18097121197159342726, 15303933786232509118, 6355852571927224576, 5965705308661034968, 3878821330615144039, 17609259256248013285, 15839551803056895538, 2863101478933748100, 6867483661888889167, 11007533278239168078, 0, 8, 9114363797835460134, 5446076396314160376, 12863008906537145423, 10008421878335836436, 9952321233871043669, 12872379155893703237, 7266552182027361169, 1266036355585216796, 2621902104176569009, 8791105532651972211, 6351975813451610601, 11821139808280113179, 11281913023757770338, 3277134497757048289, 13219080767636598429, 10181825490691565485, 2766637533497216499, 5527857141123489970, 8463471033597650592, 16863468430858262436, 4521466714741486225, 2112404415880305855, 6776665887355979100, 4283028800297139078, 17448147405455891940, 2672696094870261596, 654959311657763753, 15404879372302137522, 458610335793450516, 11708893791522292939, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [12344784587178360875, 7525588297109292118, 10242077034078069399, 6920809802339641674, 17643499204383222535, 16688592460292823795, 3252667668159125426, 6639040797936707465, 1827636079652666195, 2462138615393893213, 7273091941301037907, 7777539981955361461, 17791722127119122070, 13941030348836860953, 2461265848652382458, 17178103242399629259, 12982591110459702249, 4311636691398707716, 11830890166127089072, 7160199109027716330, 14107503556614837834, 6316368550299988901, 12988322271117575851, 12500666959478542023, 4763644307980385379, 17502332825869685988, 9045450374393109306, 7379498771612731567, 16568845003086625163, 4695178656129701184, 1678315832465296045, 15789153556893733830, 0, 1032, 11702782905971311743, 8115486282645452027, 16425371230714077552, 10333496212804492507, 1572943607289284437, 13244361396034453954, 12880029163967100393, 14716450796809578181, 2618965885956593171, 1606019581379521796, 12562170441304287563, 4599116799417823473, 4257071131168813417, 10446583017549019711, 3570388907037362614, 11170081717188072664, 17238997244398394333, 17231192964516960933, 8123337005847551087, 7060091366977384949, 5719725530909274667, 5057603743378325948, 13848013489728729143, 17729739340387068117, 367186060507240673, 1411195984452924204, 11088333491201093194, 16575090776691519559, 16147396598096989679, 14525300817521856881, 2372900269115514267, 7638869850317184909, 18112581651832813996, 7934301823485851614, 13134589595174512908, 5143267856379088965, 1385332020236631836, 4877336193186145990, 18193547062192211825, 4615765459892113834, 3381950137508436504, 17429784608409914678, 14977580224084415767, 6849317271519196447, 5437598344549503419, 1906047363049945529, 5004054537041877249, 14661239785476454049, 10553785792947774039, 2119915982392644589, 8985292275604857439, 9726386267280827154, 4505582310884934806, 12912789541737329022, 7115507662283435621, 2051190405167774802, 1232238311229055715, 220176432091768973, 5422499495491255741, 8009273299237215820, 13359803287975487032, 5187224287159924757, 0, 8, 6104172690014223231, 3119855977255645286, 2700229040680838768, 4228220371303630837, 12976691418076017877, 15391527008624099592, 15522155400452634037, 17655908650961725957, 5157987610310047621, 13664486701019622043, 12908699189677656287, 14840926611057477527, 6092037682822283700, 15181448373122947619, 2083722204849270202, 1893419523737526751, 11329911669537538562, 12331432886354737271, 9636585409664050258, 5131588463040403759, 10248116973079783912, 2136665268102207704, 17448444978654544666, 11945433761064128885, 4462464721020457233, 17579935132869425842, 7098417589530391109, 15343623253038912080, 7762335122892638892, 10310226363807226654, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 4046254507773998773, 6534480484041428863, 3251048018398498863, 14672293546278713057, 16728924149188845306, 128728647106458681, 14226927580887823496, 8277248794545234814, 4354566838645069185, 16178613916401188944, 5304102959326456112, 9791457517463513797, 10245170831782510809, 11611317382660466625, 13569694221132024345, 16005837490233273516, 2791259658093074998, 13441513594234320689, 4241376053954359578, 3545073666350874448, 15186107276182512091, 10698815982870498162, 10971920968668641865, 9145865124167298835, 405811361541120846, 9884965742324813117, 2876689281462596902, 16445466086575260512, 14688957924306712254, 16306354913676224825, 16604794485775028126, 0, 5160, 18346837778669738664, 15130142357101091527, 6726588340010678615, 8394319278312203283, 15942424551308612685, 7629500615465222065, 14939877513325106589, 17048523965011794048, 2306293645521445312, 823113708878672797, 14981348226783328932, 7432878333905782051, 3482639998457803800, 632277917380007036, 18266437030920184246, 3366715262389109205, 5280275432441977334, 5379329043314533811, 13912213856326486056, 17217059915921675075, 15634373017412823086, 14981257187297131103, 16697350900700022325, 5239234081629986555, 3229291246709926782, 18373224696258292584, 6771862800272250893, 7666370275789511263, 12942227631865082960, 15190222347874856922, 0, 1061325914286080764, 9554433906850032874, 4012321235764609039, 14967212595115142793, 5983394632166978443, 5809835498849113816, 6561933873120105870, 2140629501848088776, 6712525834006528890, 5760623808290856282, 10552757613235067722, 1939309373056894313, 14427320366022536141, 8538471352201975220, 14188752564290255096, 7981877957758397164, 1148470236137421383, 11019464818805406210, 7769960423081990191, 14632278337044440617, 849771658931440922, 5632784009618830911, 5696241881348246065, 1879984915784172244, 16312530632323862580, 13300309889942581843, 15448409017348426344, 1639569934817636487, 17233518173045382262, 14413924905126977169, 9045462722956532208, 0, 40, 1560947813056021755, 6935064976442414148, 9999441144135002932, 10354700837586583171, 6040781227937012106, 4698117391978117444, 4735711626023545756, 11217844833019453026, 3130590714605394722, 2809204122464618686, 10935232469327759448, 18335893537613898174, 10868401885487323501, 15799177281014635734, 17187052562019754838, 4027411046406207040, 11879721967266924677, 3613659344771632047, 1846469577394958972, 14668357323201408029, 14939045883642543835, 2885718226990976376, 4969257074069595075, 10824274197210729467, 13212275138420405274, 10563919532671437398, 12234598862193668129, 14653607410806008848, 2498958194485300229, 3512215170452429648, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [87, 8072556154622677081, 1267311017976162806, 171317623411600853, 14846028244624432327, 5697605161887258162, 6090204166740560590, 11791493563989406548, 17428436932452366793, 5676009947455004918, 18345317182680976060, 18287702590376570538, 4985574569677261947, 15947076302058294771, 15533043966546096492, 13147369042643698626, 13830067522797295398, 9812515853737376613, 1153576568012481332, 6976086965219136352, 9332017051661502953, 11709096929003024091, 4784660881537662841, 4083552985517123622, 9895527598631437834, 3406650305555277621, 13871430865741604308, 2950941648901088194, 3993419962022258191, 6722743736070459606, 1297747773924291443, 15433589206667095645, 0, 4128, 6496253015800789210, 18063315295058131399, 14099326864720264780, 16744359797696928029, 11669954633423859445, 10923938539628559259, 10579480970462933513, 17315553376669597828, 12114095292572219189, 16129781670858537825, 67936491912723144, 6285840300661422802, 14359460599290704174, 7597471307904508314, 8469569990667894210, 9117246600999250277, 14614928058075190380, 13738364908865630160, 1806905237893315697, 261412144627674040, 8380596589382515797, 3809925330596605534, 1983199361335541287, 6337901890572878101, 17063257729896061936, 12690697575318882146, 3846044480011221270, 10729939698274680623, 5297971463863936522, 8671284646676347574, 84, 6657939908049969710, 5132111129018882891, 8232522030470930177, 2748555984042091513, 15852736438270791360, 3031910609778633238, 10165962755900271710, 16659854091479845434, 17343121214427119893, 854734865188827599, 16332742745573253042, 719106832906440841, 5187730385273117170, 5680967626748162975, 12443929595174060051, 6984107838208124669, 8017806737059891905, 3253255241682497310, 17244932564674349345, 1765857304688336746, 6104054101040517608, 16644020687030024364, 595269491299106953, 16831646467700047759, 6176340855571448766, 18004816485425051763, 4101389897636298429, 17541610204110287382, 7370145379849234412, 11764023996857035803, 3516218181999416212, 0, 32, 9302012295643728416, 424328237663665361, 17748121622218558811, 6681769685034042719, 10907932526941371789, 14996603190997478665, 13982878080104642188, 3336783822228111865, 7403528606603453519, 7309352233404946366, 11509327586943808925, 6803943428138467537, 12870260590513220077, 3798257798625653324, 15652192157997003684, 8260391000410661595, 9099897743400681933, 16067207775248165408, 7640841583197908852, 16739199083410292994, 1998275509994500625, 10688417071827877337, 16160081185811655577, 2725954513011781037, 3040692668058239811, 15097072321276989567, 7813293313258815644, 15261763399945716285, 2258772319189190202, 6756061023037720295, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 14732236349158007950, 7398379382324753631, 16529615322051348437, 17750754114621262532, 3376246851343252040, 16812742874230723382, 5497427090926806167, 10370890449220293026, 12072808913033091146, 3773065747435304139, 1433120707818296652, 12602993390877629622, 11873715535213483733, 13503968807830695383, 1548449854272693349, 2164072014511735918, 2051419284241394287, 7675966884444101274, 7631305566403533669, 9974196014981023153, 16049335883858064137, 2471757314515864029, 247517241416190936, 17714417256089308015, 11671008027458954016, 581610329922371147, 16154960330167538938, 5798502399718959312, 5346182502077854664, 14220066076326577834, 1379414419793409060, 0, 1032, 13084260837127404333, 4018109146681745349, 14498381569327145056, 3778421823029569719, 1344624249217908323, 3634653398484528177, 1428985706412758663, 11382569756632997337, 13894906302086601399, 3911680161282028629, 11467762927868003365, 10098326072301516020, 16073214466625742345, 16150512194511843089, 11525294274796193451, 15902507139806774023, 13926886722650908730, 2974304378722638293, 5274544965980948277, 9984170014312577610, 639485734140932316, 15088403650698955530, 17189134684458608982, 6515320870350778492, 7902492290152572474, 17310456195349246143, 4070136787975548901, 6345872167795009033, 3095930865537762353, 4232664728858134772, 0, 13425232862973212691, 18017734206314589878, 4362746362325529522, 5580595613883635850, 14186966130004258435, 12558944767443104505, 9400104492160547353, 10540307613825778005, 16337971251965072535, 10106057436125976033, 9544366711268571215, 5728567960549491041, 13778603290469351967, 16022817295707876509, 11816634839594428392, 1619816382417214775, 332425507059551196, 5638968861636104000, 13036766990591622942, 5135102707173364321, 10242389681667623919, 5777720311941164202, 426018854260317513, 11718167143057109482, 13648951505177506250, 14542650836653761124, 18018546562218872798, 4457636384061007994, 2416704573314226662, 914323423605581375, 6601699247185721889, 0, 8, 7519454690376123692, 7627104070861575574, 17604686071836489236, 14277148259130460564, 8312218486680706135, 8395439642754559152, 17307771294890409643, 9298206908486537717, 3027629924013931359, 2933551330348935458, 1450485994192951386, 8585052201707081835, 10624425952582111111, 16773523322999621677, 13337622149287916761, 17874287708894504070, 14164897610403484003, 11216401648549709020, 911970190394256131, 3202853507803349037, 14616902435260689479, 14924823153427050614, 4881022900440414264, 9723366934152472594, 16335725686098559697, 8087897843744270993, 11437013713086863200, 7627258546495067733, 18044191572661655945, 16490279521751489469, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 7484183127135320340, 13467318737723490903, 18417997150771375303, 7719389523268106465, 2784882046013758615, 12479320332521777529, 17052932344949276269, 10938440435726947483, 3905086412998728873, 15634495878209337408, 16923840111614250132, 16397885158502248985, 1407236965451031446, 7800595096011710855, 9403004147208138835, 9997729556720517342, 8534668514381008137, 9227268528750758459, 13403671598326027744, 4715851494578741692, 2189528202978614673, 8567186243928218861, 9297942977636733700, 12120305129322824184, 16911451126764050505, 8250812173422443178, 10259824399772380043, 14694981892968238671, 485814636516518185, 14546030952858743710, 17545164675990066495, 0, 1032, 15909096041365347974, 18432189660917429733, 2798890989547891271, 10768372030970716894, 5935807051329113911, 1259182408195029650, 16024750973514577255, 6103595041913569283, 914770550723164908, 5067028895751058275, 5242612139537538536, 13359135899043031769, 4430959127423856282, 16317056360529517539, 2634255659160911215, 15590656855559575839, 6832335878067392309, 6045109056629836176, 18146646330136390606, 6482705684632040588, 2770791364887326735, 7707774010999656594, 3401430074469265273, 3500862351024377705, 5135727797169111985, 14940852959892477883, 9633218853985087472, 16966092255533854383, 3065488485208441055, 15703076512693482766, 0, 595597012989057195, 2376871353626003378, 17667748366842763551, 1405929090442079600, 18135181650619726914, 7403637996862883832, 5964686311110162804, 203041400479358567, 3387955851036204878, 2169976152805477386, 15733337581560247916, 7104142523828512918, 11829327565897640936, 816639760928622921, 11238339345191818453, 11391625709863387987, 6031165808075129231, 10104077332067730329, 6839520087480516521, 14155312441647748702, 4167237297971124611, 4042518115334572170, 7632437875765360091, 10425826042851550943, 10797236500243700589, 17846423932362838045, 11994705126716395168, 1154262141907751651, 15744039038114735423, 13449385390195333360, 16051125308748956016, 0, 8, 17781582622500481192, 12847902632736061277, 12021499907877242591, 16751519355106661703, 9062087890172095618, 3834953580385337540, 2969703856153678454, 11604562295556139307, 10447912046373566534, 12987934619706800857, 12352596220492768030, 14816150974992525275, 2172600571554701126, 18086375044546604023, 16313093185369681775, 14997664071320688070, 347950016295486690, 9206182676441692601, 3566552483989599402, 4925983231752336365, 1728701557101400581, 7087476601458867917, 9759961360999781392, 12569092891286895547, 14206292953735333262, 16422952955631166803, 6294107725304445883, 9537940691512987143, 15535806100011306333, 7080716573279759555, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] }, last_program_row: RowIndex(11) }, program_info: ProgramInfo { program_hash: Word([12752059346458920613, 18135096529078946099, 13200399719329805350, 905179285088193526]), kernel: Kernel([]) }, stack_outputs: StackOutputs { elements: [0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, merkle_store_nodes: {Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571]): (Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350]), Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350])), Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484]): (Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693]), Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693])), Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781]): (Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874]), Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874])), Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171]): (Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361]), Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361])), Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815]): (Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305]), Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305])), Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689]): (Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195]), Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195])), Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362]): (Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063]), Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063])), Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848]): (Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661]), Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661])), Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352]): (Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829]), Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829])), Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444]): (Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223]), Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223])), Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386]): (Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388]), Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388])), Word([13190842942618341421, 17548956981569849952, 15418963848144418856, 730733050713174879]): (Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144]), Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144])), Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874]): (Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675]), Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675])), Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594]): (Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115]), Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115])), Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809]): (Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257]), Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257])), Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777]): (Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555]), Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555])), Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509]): (Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882]), Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882])), Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725]): (Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979]), Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979])), Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134]): (Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987]), Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987])), Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828]): (Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910]), Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910])), Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830]): (Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054]), Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054])), Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228]): (Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742]), Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742])), Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443]): (Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928]), Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928])), Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643]): (Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979]), Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979])), Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758]): (Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106]), Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106])), Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580]): (Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594]), Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594])), Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765]): (Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045]), Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045])), Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766]): (Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281]), Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281])), Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385]): (Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828]), Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828])), Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579]): (Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171]), Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171])), Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212]): (Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992]), Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992])), Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463]): (Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004]), Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004])), Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502]): (Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023]), Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023])), Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539]): (Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537]), Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537])), Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865]): (Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225]), Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225])), Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690]): (Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947]), Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947])), Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202]): (Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552]), Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552])), Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079]): (Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444]), Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444])), Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850]): (Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548]), Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548])), Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448]): (Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987]), Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987])), Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041]): (Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035]), Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035])), Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301]): (Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414]), Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414])), Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414]): (Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212]), Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212])), Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703]): (Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439]), Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439])), Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271]): (Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955]), Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955])), Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882]): (Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802]), Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802])), Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152]): (Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887]), Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887])), Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028]): (Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948]), Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948])), Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331]): (Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093]), Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093])), Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394]): (Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134]), Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134])), Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546]): (Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228]), Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228])), Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620]): (Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414]), Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414])), Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800]): (Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703]), Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703])), Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671]): (Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205]), Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205])), Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537]): (Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011]), Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011])), Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516]): (Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301]), Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301])), Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831]): (Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986]), Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986])), Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415]): (Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057]), Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057])), Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722]): (Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689]), Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689])), Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144]): (Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682]), Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682])), Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295]): (Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268]), Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268])), Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818]): (Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513]), Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513])), Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241]): (Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565]), Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565])), Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439]): (Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012]), Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012])), Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512]): (Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850]), Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850])), Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986]): (Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865]), Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865])), Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982]): (Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777]), Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777])), Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808]): (Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394]), Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394])), Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979]): (Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690]), Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690])), Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093]): (Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620]), Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620])), Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902]): (Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789]), Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789])), Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542]): (Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094]), Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094])), Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057]): (Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362]), Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362])), Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205]): (Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961]), Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961])), Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401]): (Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580]), Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580])), Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553]): (Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960]), Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960])), Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169]): (Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031]), Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031])), Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682]): (Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053]), Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053])), Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118]): (Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562]), Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562])), Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725]): (Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666]), Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666])), Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661]): (Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897]), Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897])), Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981]): (Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447]), Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447])), Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072]): (Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646]), Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646])), Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140]): (Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404]), Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404])), Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515]): (Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152]), Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152])), Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709]): (Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664]), Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664])), Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800]): (Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103]), Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103])), Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741]): (Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169]), Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169])), Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005]): (Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758]), Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758])), Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802]): (Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070]), Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070])), Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159]): (Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005]), Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005])), Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350]): (Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443]), Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443])), Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697]): (Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573]), Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573])), Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928]): (Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331]), Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331])), Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320]): (Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166]), Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166])), Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814]): (Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079]), Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079])), Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447]): (Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820]), Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820])), Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284]): (Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057]), Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057])), Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697]): (Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131]), Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131])), Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955]): (Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290]), Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290])), Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910]): (Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202]), Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202])), Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910]): (Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822]), Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822])), Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106]): (Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847]), Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847])), Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404]): (Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441]), Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441])), Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796]): (Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186]), Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186])), Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053]): (Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516]), Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516])), Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992]): (Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818]), Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818])), Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957]): (Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315]), Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315])), Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709]): (Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794]), Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794])), Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091]): (Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539]), Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539])), Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664]): (Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558]), Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558])), Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294]): (Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579]), Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579])), Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947]): (Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502]), Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502])), Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829]): (Word([0, 0, 0, 0]), Word([0, 0, 0, 0])), Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045]): (Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137]), Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137])), Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914]): (Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041]), Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041])), Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573]): (Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378]), Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378])), Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699]): (Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873]), Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873])), Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225]): (Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262]), Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262])), Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057]): (Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692]), Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692])), Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131]): (Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997]), Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997])), Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555]): (Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385]), Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385])), Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195]): (Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709]), Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709])), Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166]): (Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542]), Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542])), Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027]): (Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373]), Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373])), Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378]): (Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509]), Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509])), Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097]): (Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553]), Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553])), Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217]): (Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815]), Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815])), Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873]): (Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864]), Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864])), Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997]): (Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722]), Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722])), Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887]): (Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766]), Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766])), Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589]): (Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757]), Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757])), Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539]): (Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665]), Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665])), Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129]): (Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229]), Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229])), Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137]): (Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312]), Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312])), Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019]): (Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378]), Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378])), Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331]): (Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713]), Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713])), Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]): (Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980]), Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980])), Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325]): (Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546]), Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546])), Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170]): (Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822]), Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822])), Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054]): (Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295]), Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295])), Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925]): (Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848]), Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848])), Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909]): (Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796]), Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796])), Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540]): (Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170]), Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170])), Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214]): (Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448]), Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448])), Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317]): (Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294]), Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294])), Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757]): (Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416]), Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416])), Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378]): (Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091]), Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091])), Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263]): (Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463]), Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463])), Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666]): (Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361]), Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361])), Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174]): (Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992]), Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992])), Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470]): (Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401]), Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401])), Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665]): (Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957]), Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957])), Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262]): (Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144]), Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144])), Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229]): (Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284]), Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284])), Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134]): (Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325]), Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325])), Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855]): (Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765]), Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765])), Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115]): (Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814]), Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814])), Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441]): (Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831]), Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831])), Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977]): (Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446]), Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446])), Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880]): (Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005]), Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005])), Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789]): (Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995]), Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995])), Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000]): (Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267]), Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267])), Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998]): (Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982]), Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982])), Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995]): (Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539]), Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539])), Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507]): (Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512]), Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512])), Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305]): (Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118]), Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118])), Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219]): (Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009]), Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009])), Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416]): (Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089]), Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089])), Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980]): (Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445]), Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445])), Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063]): (Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140]), Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140])), Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713]): (Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159]), Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159])), Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031]): (Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809]), Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809])), Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932]): (Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037]), Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037])), Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094]): (Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925]), Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925])), Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315]): (Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386]), Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386])), Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446]): (Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721]), Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721])), Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742]): (Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981]), Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981])), Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661]): (Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072]), Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072])), Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979]): (Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671]), Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671])), Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361]): (Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269]), Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269])), Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558]): (Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571]), Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571])), Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290]): (Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902]), Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902])), Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987]): (Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741]), Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741])), Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902]): (Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515]), Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515])), Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497]): (Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028]), Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028])), Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948]): (Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709]), Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709])), Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009]): (Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725]), Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725])), Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387]): (Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317]), Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317])), Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159]): (Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808]), Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808])), Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394]): (Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699]), Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699])), Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312]): (Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000]), Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000])), Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987]): (Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821]), Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821])), Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046]): (Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909]), Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909])), Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565]): (Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028]), Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028])), Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269]): (Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352]), Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352])), Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847]): (Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271]), Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271])), Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513]): (Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800]), Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800])), Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054]): (Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394]), Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394])), Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004]): (Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977]), Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977])), Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675]): (Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800]), Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800])), Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692]): (Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159]), Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159])), Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909]): (Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932]), Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932])), Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814]): (Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697]), Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697])), Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186]): (Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387]), Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387])), Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445]): (Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470]), Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470])), Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966]): (Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507]), Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507])), Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548]): (Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253]), Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253])), Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897]): (Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783]), Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783])), Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208]): (Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054]), Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054])), Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268]): (Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661]), Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661])), Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388]): (Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643]), Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643])), Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257]): (Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174]), Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174])), Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960]): (Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241]), Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241])), Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721]): (Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046]), Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046])), Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822]): (Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217]), Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217])), Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253]): (Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697]), Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697])), Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054]): (Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019]), Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019])), Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821]): (Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432]), Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432])), Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864]): (Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105]), Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105])), Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373]): (Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855]), Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855])), Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646]): (Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830]), Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830])), Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460]): (Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208]), Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208])), Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033]): (Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214]), Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214])), Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105]): (Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129]), Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129])), Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281]): (Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909]), Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909])), Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028]): (Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027]), Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027])), Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012]): (Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054]), Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054])), Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562]): (Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589]), Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589])), Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037]): (Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097]), Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097])), Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355]): (Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460]), Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460])), Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223]): (Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355]), Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355])), Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089]): (Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306]), Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306])), Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035]): (Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219]), Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219])), Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432]): (Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297]), Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297])), Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693]): (Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263]), Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263])), Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794]): (Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484]), Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484])), Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552]): (Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941]), Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941])), Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267]): (Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814]), Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814])), Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992]): (Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415]), Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415])), Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941]): (Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966]), Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966])), Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822]): (Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320]), Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320])), Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306]): (Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902]), Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902])), Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820]): (Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880]), Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880])), Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361]): (Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725]), Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725])), Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005]): (Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914]), Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914])), Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783]): (Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781]), Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781])), Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011]): (Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033]), Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033])), Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297]): (Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910]), Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910])), Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070]): (Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134]), Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134])), Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144]): (Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331]), Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331])), Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023]): (Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497]), Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497])), Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103]): (Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540]), Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540])), Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961]): (Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998]), Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998])), Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414]): (Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]), Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]))}, trace_len_summary: TraceLenSummary { main_trace_len: 12, range_trace_len: 39, chiplets_trace_len: ChipletsLengths { hash_chiplet_len: 128, bitwise_chiplet_len: 0, memory_chiplet_len: 0, kernel_rom_len: 0 } } } +ExecutionTrace { main_trace: MainTrace { storage: Parts { core_rm: [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 10403713768525900847, 2139411523427040457, 8515917035379853351, 856023126862020256, 0, 0, 0, 0, 0, 0, 1, 0, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1032, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 2, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 8, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 3, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 4, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 1, 1, 1, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 5, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1942941126776981551, 9461460041610899538, 7600020670677266955, 3257731577738044347, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 0, 0, 0, 0, 0, 0, 1, 0, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 6, 0, 0, 0, 0, 0, 5, 0, 1, 1, 0, 1, 0, 1, 8, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 7, 0, 0, 0, 0, 0, 7, 0, 0, 0, 1, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 8, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 1, 1, 1, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 9, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 1, 1, 1, 10403713768525900847, 2139411523427040457, 8515917035379853351, 856023126862020256, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 10, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 31, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 33, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 39, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 43, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 47, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 50, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 51, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 53, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 54, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 55, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 59, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 60, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 61, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 67, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 69, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 70, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 71, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 72, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 73, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 74, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 75, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 76, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 77, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 78, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 79, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 81, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 82, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 83, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 86, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 87, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 88, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 89, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 90, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 91, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 92, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 93, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 94, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 97, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 98, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 99, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 101, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 102, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 103, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 104, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 105, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 106, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 107, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 108, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 109, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 110, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 111, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 112, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 113, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 114, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 115, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 116, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 117, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 118, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 119, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 120, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 121, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 122, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 123, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 124, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 125, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 126, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 127, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0], chiplets_rm: [1, 1, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 10403713768525900847, 2139411523427040457, 8515917035379853351, 856023126862020256, 0, 87, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 484349804684265665, 6880098633847640351, 846980218218532239, 17903889365796795298, 5550459936565271753, 9107753202341829570, 15324484398676964645, 9257266254418654737, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1032, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 11116382020814057190, 14732796941305378371, 13074361791711182490, 6715193688317415490, 1571558009365433839, 13285275197432594374, 15905141483335727027, 2507840277166973476, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1942941126776981551, 9461460041610899538, 7600020670677266955, 3257731577738044347, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 0, 84, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 10403713768525900847, 2139411523427040457, 8515917035379853351, 856023126862020256, 5748739229791737666, 3971489439724797398, 10156667480279311531, 10471841795831116097, 4161518306931659446, 14664557596733629071, 10457686661281861787, 5372530612210116852, 0, 0, 1, 0, 0, 1, 1, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 1244837894821529086, 14023738310468542470, 9319458442815716445, 5220020845190256514, 18381067342435073896, 15418184987737128626, 17753079332212842976, 12382717352847060954, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1532070872953744281, 11675978725956395507, 8258108365434236190, 8977540451988253054, 8832291907404336605, 16801197610032323372, 8498902414702613411, 2217861947967210820, 14648106445605106304, 5194857384255130698, 4543357020291533691, 1677011855369223059, 1, 0, 0, 0, 1, 0, 0, 0, 0, 18164368745351378969, 665130184182531292, 14548211377038648988, 9026463808500414994, 12372059324693434695, 8512906579977137276, 10951940384741553765, 2990681100436043903, 15463650459774420968, 6115025020360005524, 13619612156045325099, 9915559200666512746, 1, 0, 0, 0, 1, 0, 0, 0, 0, 73542357038484620, 16275608702285065538, 15615370514429573107, 11554047591217380375, 9626234372118459069, 14043139718664795091, 7172345985251039651, 13714446996516992992, 14079807935308074442, 17175342044195045043, 16936021968982853164, 3883665509408281322, 1, 0, 0, 0, 1, 0, 8133824218287649370, 1205363866316521559, 7923953289074004648, 1611370566290075655, 12516876786630134052, 16156412840636435500, 16066365782016562356, 12209717470970729826, 648151295134950813, 8424608506935970051, 941071657155810425, 12476535243066524999, 13046835168670418046, 13563090428318398174, 10213204276953300366, 1, 0, 0, 0, 1, 0, 11656233811569695541, 16780366708706866018, 10469348806910132738, 12317597613336433996, 16800450568443907772, 7958196127911254005, 5580405360121542127, 17991322909541306091, 9587008055009063413, 917862094456531518, 17636182943787095305, 5347924966817937746, 15791860137463552476, 5352122275530338033, 8207615265206228485, 1, 0, 0, 0, 1, 0, 13280747180546192023, 13818056542207317059, 12768869371961439487, 2029833730308772760, 3067168931363951888, 630426464913806566, 13807710542081112496, 10340529818978391824, 8301137772228612306, 18032943025979156234, 5571856761516233924, 15102755171792177729, 1386022355796901548, 10780164990569095481, 14005839963275167003, 1, 0, 0, 0, 1, 0, 8161514060541966002, 5430054846479849757, 855673369941768792, 8583346124368767357, 7152703336258374657, 4793816855328822248, 1475819744300266017, 5162097063446717296, 9158417383194264473, 17323069022182310843, 17309666448184518221, 16540233824244985004, 13271685073550397851, 3683818685539825395, 12883632168742702763, 1, 0, 0, 0, 1, 0, 14889661894667616899, 13319328534492736282, 511216470843933116, 5414088302741599345, 16030190225904238830, 6111859869108706126, 4321093113239299552, 4706826096768711507, 11021679444547674749, 15678561454143187205, 15168765916033556420, 7046395423559884948, 3431032212531228618, 9443306432483343000, 6291224588853575811, 1, 0, 0, 0, 1, 0, 11384512740043719026, 17996531901144166752, 4183594834611630116, 17695445402585642319, 15258305803668890228, 17106752205417894410, 13259786553689259064, 15859967842550332610, 5138368225191856866, 8345451659183769670, 4299979085769618674, 10058172520180004407, 16132576493934338934, 312707111584502977, 8025187035739711204, 1, 0, 0, 0, 1, 0, 17152042124522816142, 9826569971726481595, 8959076337043698126, 1987260706895490300, 17423289859865292784, 12258188545233319580, 4291864820252135891, 2950910453815263271, 852440029525711434, 1223549137263517018, 605327998629874385, 3009980753663636725, 8722464778364467857, 17216818427461180092, 13380853612843880678, 1, 0, 0, 0, 1, 0, 7979264206910945674, 0, 0, 7448791324579059841, 1050285053399784347, 16767087000176263535, 14849165193424062452, 2498996933077132011, 13658177069616805094, 495936213960522537, 13576872019913404781, 7640966386182958606, 4271515987309482058, 13463445006653778819, 12292225704634605892, 1, 0, 0, 0, 1, 0, 0, 0, 0, 6053040396430810733, 2172892474788961636, 18161859984545851402, 13488248907260320483, 8430623432188198915, 3055646124754645267, 4245215712607391946, 2243958878529225177, 14990440908620774864, 3080921390696878855, 595284666932255390, 6192940699035995377, 1, 0, 0, 0, 1, 0, 0, 0, 0, 14921496778760644502, 16662036864627516510, 6434377642684009725, 1840544361770929313, 15074823591915634941, 5258982948465254673, 2683768063818053258, 238295676214993337, 17552036469726894364, 15877921873938893194, 14734786106453693759, 1371624439541100057, 1, 0, 0, 0, 1, 0, 0, 0, 0, 516742705862090749, 5947805230277704319, 5952541516123965670, 9026915957393505056, 5986317686192419732, 75717367401824328, 8923961895635206791, 17106810061565988432, 7157463081631406163, 150940732863733992, 15657864298531798718, 12227344478922314236, 1, 0, 0, 0, 1, 0, 0, 0, 0, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 1244837894821529086, 14023738310468542470, 9319458442815716445, 5220020845190256514, 18381067342435073896, 15418184987737128626, 17753079332212842976, 12382717352847060954, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1032, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 15913981378790993016, 12701179462806902902, 9645342555817022514, 6889850077248808033, 678249829196625442, 8726676798253716750, 14136118088409135949, 1027279235140821190, 8048729929177993405, 2542525775606472849, 3283471062508934848, 18058280687405074483, 1, 0, 0, 0, 1, 0, 0, 0, 0, 11899090779839289087, 1701090513954162998, 6953639183117323837, 11460660778637092812, 8345945186928076892, 11308243255833047975, 5734666540714547293, 1546649737555419076, 14643837757854608147, 7477230882792828789, 2359592855656894189, 12732146754685591216, 1, 0, 0, 0, 1, 0, 0, 0, 0, 16283412161296764998, 17261112905912533997, 1498213616014501531, 7707889409925905689, 16090493533591377617, 525010687572874692, 5228788497345464933, 13051466527897639054, 3560924095387897187, 12551242480725370445, 4038828260160651477, 6132317990703151787, 1, 0, 0, 0, 1, 0, 14261694278902826987, 16097544111075686229, 16632169854204459773, 14265791174051766329, 14732671264513481238, 15642599276989292777, 7593738854072541043, 11440582168151819564, 18258483622390056257, 6851601084855956341, 10463349537167637967, 10032876585525342603, 825669147467031185, 16271217766495541082, 9021089524754424392, 1, 0, 0, 0, 1, 0, 16780109665356203593, 16025948514351396737, 4256182047405196535, 4919013996388780384, 6974015548720770018, 10189882052640604940, 12288632186238773648, 7055558833039165669, 9820743264545515107, 7353106531603230851, 5612808106478211181, 362487531847990854, 10259224130335842891, 2374318293393776907, 16208179153232019183, 1, 0, 0, 0, 1, 0, 9496969110446094198, 10424961628901078909, 7587726188775237019, 13423955604028434301, 12288543613568774022, 4068762405627465026, 7288480650179820504, 1035430088689333582, 2651098721515326755, 4524440782000877024, 3013038852551457145, 12536534023666437466, 6560028330562582937, 9090521726813489969, 17634755409309861791, 1, 0, 0, 0, 1, 0, 15761194215082968049, 15796684185970405493, 1294179585337070936, 5701860167148115542, 17707247215386403887, 18419960639673587986, 14570347312565937582, 8634142387233894354, 11938075017385927203, 8060480374868324599, 16699922976999064541, 14234489074154948378, 17210389744085299852, 17331527780947314617, 16356838976302290254, 1, 0, 0, 0, 1, 0, 6184336662619539433, 7106147576739595100, 18237994300618329820, 9768155666925548219, 226714884885574576, 11169479382209254075, 5756676929838789145, 29803495366482069, 13128905441940840949, 18304516631519674746, 3177693875357946498, 10624850715031233718, 16956738608020324589, 10558540052020438814, 7826502712354673600, 1, 0, 0, 0, 1, 0, 1980308537464408089, 6810023246846442283, 9400257804338494201, 11246932855318952856, 7504545710540897051, 5823677062954428984, 9151299935574592196, 15905322272715446259, 18174748553199601666, 9877077233183640995, 2431998410719122545, 3541292002384422941, 5416588529930333172, 15788517205879313917, 2490575598934209003, 1, 0, 0, 0, 1, 0, 17950140321155419078, 9014768943295123367, 10707122777228105884, 10701204914974985643, 15060806908759160804, 7011191650405807117, 13598159658926423040, 3947314552577424057, 12985682730462769834, 18264715466581442035, 7667189540353817157, 7685483800933651249, 16085167604591833455, 16105855167414075111, 16215395602017884846, 1, 0, 0, 0, 1, 0, 8676227747932036802, 0, 0, 11504729673400082663, 3659553513673892306, 10374352082945691939, 15819529278889203623, 18107940902385670152, 8889798095480337831, 12737345777792032790, 456604824069734238, 2859376131275373721, 8758251935142908528, 2364536875264708997, 2435873391009301907, 1, 0, 0, 0, 1, 0, 0, 0, 0, 16797630026773069829, 16954579754978210547, 4393671449525183699, 6245909065255485436, 8311309349844601638, 3305827896314343556, 1615477551160071258, 3897903986825909618, 13015230208471866351, 13839070994009764281, 2415598337053791919, 5526300544248852335, 1, 0, 0, 0, 1, 0, 0, 0, 0, 12827873667465929582, 15892701250663610383, 549489834728826775, 9425334953627649153, 15402634395731091512, 11814416271399500934, 14597718118926923662, 4726679541432826422, 342915941842538663, 11221492717904369823, 17188959961041335276, 13559932473868727168, 1, 0, 0, 0, 1, 0, 0, 0, 0, 8689096602925893779, 4096531352684607500, 8424481237826564505, 15238165026175259240, 10985176737527635898, 2672540837788784952, 6649439643634522762, 7581835251244605715, 17671970641549389116, 18069913154458602790, 749417941228438762, 6150863900366154379, 1, 0, 0, 0, 1, 0, 0, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 11116382020814057190, 14732796941305378371, 13074361791711182490, 6715193688317415490, 1571558009365433839, 13285275197432594374, 15905141483335727027, 2507840277166973476, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1942941126776981551, 9461460041610899538, 7600020670677266955, 3257731577738044347, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 0, 84, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 17300126657859479093, 11313920102849673527, 6346627796045519057, 7389299619274629431, 9262647006463201494, 12900235463952244627, 7852421498196750068, 1141784430625393243, 12150004112779528077, 146728085155958051, 1479007214074296519, 5326692900453573033, 1, 0, 0, 0, 1, 0, 0, 0, 0, 13417131057632658648, 13887354800197146837, 8609784525483513948, 16453892850627486456, 976357452201521805, 14650998861370095747, 15798952093464371291, 14383483119098647176, 18419038023611574318, 3683052509510392753, 12831965507313403291, 11464211275629339672, 1, 0, 0, 0, 1, 0, 0, 0, 0, 4507099831440932953, 6830877239439284265, 9097811782723336829, 18355313083727954627, 7779515141290159182, 15839592087462215756, 13604506694568008603, 14024127302218670748, 5952493440729260050, 4068297222526233952, 1979966764305086565, 9333200475194576798, 1, 0, 0, 0, 1, 0, 8357924686780715814, 6636884447613425583, 9624380725568248686, 2880287348195737852, 885106567500324074, 6448875554992341703, 9855604354502581698, 9375523715508471459, 12339746387209375629, 10455158341094955823, 15902189126849452967, 12030315950055306153, 12641257084941861137, 15957996139063952329, 15783553274882271383, 1, 0, 0, 0, 1, 0, 5347236343958253894, 4025896570838415692, 14804406762588016934, 182667766089555833, 8746225101260903407, 12800409546363710287, 816655693375320760, 3488220768045884341, 17449960788520479876, 13060006746047445404, 4590648600733170196, 14869579734892957539, 137356745712127171, 13422659882759208113, 2676688078772673635, 1, 0, 0, 0, 1, 0, 2921699901762625847, 2649189506073489962, 9913373798344930711, 7755498383134197376, 17631069913300146763, 918789106343442195, 12710306366297056980, 3352461179293085611, 13949166093507073033, 16957002236887535634, 5578100969514402869, 4043905565383364858, 7659576686417292817, 2367890233987709775, 8348028103004129201, 1, 0, 0, 0, 1, 0, 10172794879368016270, 6345331429530820033, 5837950612071262866, 16650183950518877881, 761183529886498658, 882392762205142966, 10341241875528441727, 10625329717419136765, 9971095066673234358, 4232004013780299993, 4126250918613430195, 1352790980003480299, 15265846796546163655, 16214598491416624701, 6270582476047461808, 1, 0, 0, 0, 1, 0, 3029040881537747494, 16192268821146642419, 1429264540499601619, 723722855549182307, 9275648404607992275, 7653230088222442503, 5336572895513434476, 17267978825783635674, 2055211161196684150, 5382467524735065973, 17562229302921943767, 11689925804137528317, 12333395168151976785, 13928209897558581843, 6382294855606512139, 1, 0, 0, 0, 1, 0, 7880496552213312201, 15122758161943386192, 7696912976710769683, 16684832919913645113, 1325781221503242261, 9767481056214686264, 15383255957179010771, 4765175578813598212, 352612095018961168, 8164700351999240448, 11366624484197321797, 14418389432583501516, 5429053278517118996, 2079377923041037634, 9248817126035377137, 1, 0, 0, 0, 1, 0, 7798482983966084054, 9698350464160947514, 2622165840457703741, 3191144700364674222, 13840521809458223850, 6693472114669876018, 1844850377219340954, 6041824929233084189, 10694505064011226265, 9837159640677247471, 421241411507411802, 1387064907365996610, 7160690172588878117, 6170204562255862519, 11691591530451877345, 1, 0, 0, 0, 1, 0, 12784330368443191752, 0, 0, 1511701347894443705, 3195625100455147555, 8197728783207379545, 449202167972758168, 10429619634413714415, 1266474106654512299, 10043612818557622726, 17546950285193103331, 17459565798841957386, 1545883776729609444, 4559076489231806387, 2919974393045314777, 1, 0, 0, 0, 1, 0, 0, 0, 0, 14541231479059008872, 2573517030855683796, 3524292720580177308, 13855152767270114589, 3006044390476483944, 594411982442348353, 2707135781132813285, 7980470443732427589, 10692471325161091019, 16152944287821214660, 16000995173627170117, 3599288644418559718, 1, 0, 0, 0, 1, 0, 0, 0, 0, 16401658505261312282, 14340768500784081639, 9157399410194868857, 9102901647434269728, 17796618941315046862, 6870559696376279126, 14430288544136295714, 11256415914434052793, 13509056984869078243, 16212533703602772012, 10731537818920783986, 9244614718938709708, 1, 0, 0, 0, 1, 0, 0, 0, 0, 10956055287997745079, 17622456621764780147, 5455165430251125445, 6727955785885619519, 14753857082920611668, 13906110808313848802, 8347093488770218639, 8918883692704710750, 15290172371351697411, 10523129087658444171, 15727241650811717280, 10475089196439845505, 1, 0, 0, 0, 1, 0, 0, 0, 0, 10403713768525900847, 2139411523427040457, 8515917035379853351, 856023126862020256, 5748739229791737666, 3971489439724797398, 10156667480279311531, 10471841795831116097, 4161518306931659446, 14664557596733629071, 10457686661281861787, 5372530612210116852, 1, 0, 0, 0, 1, 0, 0, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 10403713768525900847, 2139411523427040457, 8515917035379853351, 856023126862020256, 0, 87, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 14973522761191262497, 4230519249120879894, 2629183259646768977, 10141819052260397061, 13407203767006087071, 12300175896314074402, 2702373535953719449, 14066933458796711308, 2220020800002954405, 1153376321238519426, 9501912115787530137, 11467779250790108687, 1, 0, 0, 0, 1, 0, 0, 0, 0, 17579142101067141791, 16331511478156948621, 2536845301555017815, 4655744751626348560, 1315476336364332532, 12758262197074716778, 17888512728802654414, 5454338212767341777, 14616265448064819190, 4049834289657867128, 2177315978307888394, 2010382289454711711, 1, 0, 0, 0, 1, 0, 0, 0, 0, 12664267918550820934, 8493562230894032491, 10885506335001351491, 10623508799881057302, 10765360003981902673, 4842275562010620878, 8656573021603208590, 2450260130765540973, 17667697651318069254, 3544163002330957814, 9007165683524157049, 4518865977780754525, 1, 0, 0, 0, 1, 0, 12821199281659850615, 12524526780064226282, 8688367803817133517, 7111709976940449855, 6042875499671257036, 10602803306945095136, 18053244771098668210, 15869901507286010642, 15765124758947684257, 909769595464630286, 9984901127103118556, 16104234613185942963, 1596997669664652458, 3285629071226892513, 5254177489666731166, 1, 0, 0, 0, 1, 0, 1319022057496410037, 6723956385664361856, 362758946504872978, 17945942309272171171, 7547510637898886664, 8389575157731885000, 5432655503035172224, 8636630472484196539, 17112531070480946597, 5597227622497427759, 8296183404013335152, 8448226142379838282, 9123809571274586481, 4262155088312829534, 6352753764020113838, 1, 0, 0, 0, 1, 0, 15817353186600079517, 11896741780081321151, 8120557738706811421, 1514840266710990643, 2518758362364209964, 14494370701341234363, 18160488913248834173, 415225714783614736, 14762958776895421659, 1582837024273971615, 826388124734417268, 9723851761924399417, 2904897680946636379, 572660879606393944, 5062575418735094728, 1, 0, 0, 0, 1, 0, 11887745873838856200, 11056257118819520017, 8546453177127819509, 3906777862244807614, 15967237477862396017, 1240858482343082944, 8886870748754950786, 15806110295452780709, 6486381282415609829, 16950387463813522784, 8577643233130284288, 17768236078519772738, 217872450018257683, 6293942954387886585, 10974892067682463496, 1, 0, 0, 0, 1, 0, 2581007320496406744, 7054105961444862624, 15347768076097298693, 8125727413083423821, 10805393644723323985, 13586718478006757236, 17768197347468566879, 17280093366403031105, 635835674863826303, 4568185472217893804, 9296267175044089272, 10337709963460435554, 4440112583501734927, 9729481707513785664, 4743006626934706100, 1, 0, 0, 0, 1, 0, 17610297678684695918, 16364115285854473865, 11595150248116497643, 7035439775474110251, 11847308316956964837, 7889458920902982286, 11305368688963866992, 14287445400250554900, 1893961912880033900, 10317967923286478317, 3918181922279376301, 15000492392148830533, 7931144489554367364, 9476759250402767950, 18270644106765218282, 1, 0, 0, 0, 1, 0, 11532830003582511953, 460321325058925628, 12709513064174486630, 6478715440156951267, 14089413401266079358, 2281022494971066801, 3378217915115563837, 4838851040494198977, 11743317019648187379, 3359761112394096597, 13620706797177850518, 3438335644910777353, 2067033555957484299, 11784176479463653422, 9418905686906839178, 1, 0, 0, 0, 1, 0, 17359699556169412381, 0, 0, 17848865035999698302, 9363353806961732906, 1059359355271114718, 3722579262469999737, 7401377741210733980, 4394776823738550294, 17911331326024175702, 14231054337850845953, 1567229020978754366, 10965059646087563007, 4717306534304214129, 6160606101751839399, 1, 0, 0, 0, 1, 0, 0, 0, 0, 5210262791539000682, 3231850662476970044, 12242203768226360021, 16352185264854542792, 15126409509795103366, 17462025488896312666, 10962575762908536311, 16737021171185522127, 6692618053949882379, 17172828881706643966, 14646740046786928565, 1663831101883973254, 1, 0, 0, 0, 1, 0, 0, 0, 0, 4908282038977879385, 2701244722093391429, 15021286664224332416, 10534803976436280037, 15876667595247308635, 16333738989139894331, 1581145115862775994, 18250779698217077450, 7155162361709676048, 10303228755363253440, 4300281072628271246, 16497484699945471993, 1, 0, 0, 0, 1, 0, 0, 0, 0, 4313772916158122500, 2902278358899028132, 254766801126374444, 5671561640468956184, 4347645646061943576, 1998087227139787801, 12798150249100419438, 647551028640823116, 15480041353865470488, 13024601617472109101, 16248647525361276326, 18146087632373782831, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 484349804684265665, 6880098633847640351, 846980218218532239, 17903889365796795298, 5550459936565271753, 9107753202341829570, 15324484398676964645, 9257266254418654737, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], range_checker_cols: [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2187, 4374, 6561, 8748, 10935, 13122, 15309, 17496, 19683, 21870, 24057, 26244, 28431, 30618, 32805, 34992, 37179, 39366, 41553, 43740, 45927, 48114, 50301, 52488, 54675, 56862, 59049, 61236, 63423, 64152, 64881, 65124, 65367, 65448, 65529, 65532, 65535, 65535]], num_rows: 128 }, last_program_row: RowIndex(11) }, program_info: ProgramInfo { program_hash: Word([1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209]), kernel: Kernel([]) }, stack_outputs: StackOutputs { elements: [0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, precompile_requests: [], final_precompile_transcript: PrecompileTranscript { state: Word([0, 0, 0, 0]) }, trace_len_summary: TraceLenSummary { main_trace_len: 12, range_trace_len: 39, chiplets_trace_len: ChipletsLengths { hash_chiplet_len: 80, bitwise_chiplet_len: 0, memory_chiplet_len: 0, ace_chiplet_len: 0, kernel_rom_len: 0 } } } diff --git a/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_05.snap b/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_05.snap index 238daa45df..2b8842f847 100644 --- a/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_05.snap +++ b/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_05.snap @@ -2,4 +2,4 @@ source: processor/src/trace/parallel/tests.rs expression: DeterministicTrace(&trace_from_fragments) --- -ExecutionTrace { main_trace: MainTrace { columns: ColMatrix { columns: [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 33, 33, 33, 1, 65, 97, 97, 65, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [7458506668679174706, 1032, 8, 0, 7458506668679174706, 5598651459581075585, 34, 0, 5598651459581075585, 13620833136975709089, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613], [18375473735916206629, 0, 1, 1, 18375473735916206629, 7804753453550466256, 0, 65, 7804753453550466256, 2256486347761721492, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099], [2105717247508690050, 0, 0, 0, 2105717247508690050, 17777748786253636403, 0, 0, 17777748786253636403, 5193960644663470490, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350], [1679902783560062568, 0, 0, 0, 1679902783560062568, 9435312778805252724, 0, 0, 9435312778805252724, 12344784587178360875, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526], [13620833136975709089, 0, 0, 0, 0, 3358534066525179769, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [2256486347761721492, 0, 0, 0, 0, 9365253138981608257, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [5193960644663470490, 0, 0, 0, 0, 4243893038989355703, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [12344784587178360875, 0, 0, 0, 0, 2372900269115514267, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2187, 4374, 6561, 8748, 10935, 13122, 15309, 17496, 19683, 21870, 24057, 26244, 28431, 30618, 32805, 34992, 37179, 39366, 41553, 43740, 45927, 48114, 50301, 52488, 54675, 56862, 59049, 61236, 63423, 64152, 64881, 65124, 65367, 65448, 65529, 65532, 65535, 65535], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [7458506668679174706, 11091832976040936962, 11629723830403400020, 18085092721393681494, 5334827122981806215, 18131418839636252978, 14614347609195626268, 8910439294593611592, 3843332007587847712, 1023179011544432384, 3804737116729640404, 133391072621725577, 12470388296134501021, 632583774013957871, 4078804678813269002, 4646445037357820970, 12451999842825777859, 10348876437499804673, 4709521304751214351, 3818143376057959690, 13735545676744754358, 5911009352187537543, 11554714135033312948, 9410850814958744902, 11602211351055880832, 12661500893159548834, 9684778724196116231, 18082132319471479459, 5677068088590394277, 13067481717060632118, 17366862825980504064, 12752059346458920613, 1032, 10320, 13024110921086730221, 3587442816163675215, 512402747638547729, 9217956011885162917, 3925750957223009950, 8674177413178223320, 12846799727083908462, 9116601283268739756, 2958792353189815054, 1720195204565087693, 7696852080146622077, 2890877729556257606, 16676527939404087356, 223754558788184593, 4767414622778376421, 14072300156908432530, 16856861612825314654, 11910434229443384600, 15658716527747040980, 14322127566252286435, 4770460127206402609, 10805338145914832851, 1391598300875421210, 18211456042978337510, 11866022853402812888, 6438324596032750504, 13328288515202849800, 17331158106613184460, 18344276842462151560, 7458506668679174706, 5598651459581075585, 644336023812026221, 13247747688876077858, 18204236545845216971, 16083593158731167399, 4357419437649084221, 5464680208294216350, 2779149829283345558, 7975999984217399211, 3799311940445025695, 12287115722151291956, 7889055060352596454, 3871221682982067508, 16266218633314388061, 10296105519823441978, 6482329477820286957, 2184206139900597012, 13275897735411980967, 3045004919428473516, 16702736287849627035, 4028816571826363002, 15011221569533006108, 2864985628223798368, 15475498524455915389, 5364573001665328907, 10397611698676440611, 8883008337890476036, 17315153826736218240, 14581052801302714514, 17999554639252319772, 18022889162320300611, 13620833136975709089, 34, 340, 14059267169109730234, 15746924929585133009, 471985631500087772, 16946433723443173275, 4595135147820207091, 2053997855496151567, 18402496786565368100, 387609426153233273, 8469665991798416914, 7881354678273462636, 11816560343993810599, 9054561158700241520, 7881520773741268125, 1631726701000003728, 9048332065221759951, 11440521690988525934, 11399562976973524004, 5295775600298609171, 16854936978988550164, 4555566089436281371, 8045874719633055695, 11420674364099598202, 11942861833844189240, 15820096964950298640, 4263756598719013378, 7647209523022736387, 13465875315346524402, 17464705757459592393, 14751425303934963720, 5598651459581075585, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [18375473735916206629, 4371092720588693207, 7555819500301263096, 7871576915936585054, 7738161198426062879, 4439752770537371709, 3239157867226066300, 13695428956813660853, 8114913103795360695, 3271513559100018830, 1227622944719103238, 17840970837055628605, 967816437372899090, 1525132029610696618, 8930953641447820548, 1991652128187274521, 1878310895470329371, 1537331530871119668, 17179845365129498366, 6628846356810584866, 18158002788694963974, 8030209565693857269, 16465976624819029473, 15848213422225602213, 16693748147017299005, 15158850031902933967, 18144229372703820177, 8111553228231189401, 420461259745383997, 17094012225747072853, 16556024871956851478, 18135096529078946099, 0, 8256, 1131208899036558480, 1667157010810320250, 2053960715201569301, 1526213270499333709, 69813565043892453, 14925652377538846871, 1380252317064967448, 9902934070223067140, 3786794161520721521, 664031068804619792, 8470323998416702977, 4965297830526000942, 9404280000999464502, 8244737495337250711, 4784363486033662704, 4680481291290566437, 15373555507761845373, 8780119261264514018, 729009684537575982, 18306419558979237700, 15407410920890065538, 2509966126115291236, 12709897403480972846, 11498596868429821859, 6606875518512322314, 13880694912200059110, 6972406840307481976, 14148490408465275064, 2917966740410115114, 18375473735916206629, 7804753453550466256, 10860407685663036604, 1563629168745730928, 4862512017968946683, 1035294938480129016, 17121277837906333314, 7566123129055455762, 801761918673301233, 8221980324343257318, 8971289227653573810, 14503443403830829887, 4403991158284421772, 3539411744559999519, 17877470569230350231, 13052305487168984918, 11988250928057152362, 7990654922366982189, 8123717249091864283, 273044411934894184, 12617346169478402785, 2083501518846346052, 1182260721753268305, 16655426125402668777, 18315976927222050841, 13684207927534177805, 15562831278015850283, 7777530579170086866, 17762371058211819624, 4106083518382761605, 3917672276375751396, 667054191578263747, 2256486347761721492, 0, 272, 15833028045737259664, 379315838026506093, 8581974592770288933, 17442451301272882541, 16579750051606898066, 5674487159031204202, 1541891846645406613, 8209041782659254452, 11966225502153548517, 9096730616149686024, 15618906860941665577, 14146738543483816160, 1119526938685078607, 8710432271010401746, 13282504786121257878, 1858131981777548381, 12223656597910297554, 11826686549344788050, 4472804247539583969, 7599118004690938513, 8277718642341650597, 8460103377465445883, 4568736565087160671, 4933680726900799861, 16645964836945405904, 3680609073412509534, 16176623117443515258, 15081244610133230814, 6410948793715747581, 7804753453550466256, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [2105717247508690050, 7371349600976768903, 1908428216714745226, 2226486931669462500, 16096322966046779578, 5448090446075942959, 10098429045835473018, 4809915777199041455, 18236464326626014645, 2690803580142520255, 1917959726470568181, 7355089244606367886, 9988016662047687018, 6075081950126577031, 782991345573128788, 17727121868432118686, 616586521336426688, 5444667365009856158, 3285592017878659318, 7931583655659423496, 6385821061540880880, 8735792590442216465, 11893401421408965, 8831024347202442032, 4451634306410080384, 8173507753862756681, 15267089652751109873, 10164019920559079526, 5461641667913740527, 4977882380646661156, 5148753722704728721, 13200399719329805350, 0, 2064, 18136552782870868471, 952274539956745973, 15933282259815262093, 9924516287334785738, 18064603646801610993, 5114527609957824263, 11816233963570869158, 17699527003452380450, 14533708946479200173, 17484213571014188868, 832814531422633701, 1508169308733590908, 8423043379628164525, 12595277727969636921, 14226276023010866965, 10485112285448962747, 1783527593060720204, 10145484005384627580, 7463752398658534839, 17345550819494003223, 4432309123412733588, 7086318781105575433, 8830891075082588619, 310185093236608634, 16683125300631590273, 7786799186167080425, 29465347809991832, 8090161351836983773, 8665315444141111469, 2105717247508690050, 17777748786253636403, 12906637371964794665, 9477262435683869924, 9199231093019338048, 7358751435793575899, 12569972625839259527, 5847320563034378965, 7599987891632365696, 10432134440683583258, 16242679258308055777, 13780789328607365793, 1153491566876700606, 13641042641136958279, 5969854971149325760, 6340590356564925801, 9771444654514086827, 15776260062082886705, 8278469467176979574, 16237604982476195391, 7423750977119185664, 6710003146178124596, 376186270665682407, 15539788083889931684, 11273188656572444234, 5199551304380116153, 11734010025122035435, 3764388601356982695, 11644487560172946408, 15563655808705061071, 5533608926617884295, 14514898346462505299, 5193960644663470490, 0, 68, 4457596741936238930, 12529581077675993243, 303974201734355881, 13345903392866909652, 9586267930884889862, 5178817950472007665, 6608322246477847509, 4070515537963445793, 9312477480709452614, 8889792067304111866, 11078425489498232713, 636055309231688517, 8580323529307502020, 12246954824275240956, 13948398243979685168, 14683551372837095812, 4744943918536266830, 10091391594533925883, 11270159100715194202, 16104697287955959682, 2983615207234436698, 10804815118997327370, 139420663301414639, 11145521977996788455, 1535579717520953536, 14470422183799365804, 208588932528011586, 11685358340804306780, 2822178276157738566, 17777748786253636403, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1679902783560062568, 14926961084296668554, 18296820143542754124, 5759648439566973806, 7690180744863199464, 6255055536007924620, 9967438444965419122, 6053822608871655533, 3970724348518176437, 6498891217103059128, 10341231834356228091, 8497160540604180804, 5144558705352378414, 5437844264442299443, 8712431777609915948, 3915629295644008966, 1353567482375898210, 16603575236790899764, 17009424079525297171, 3253699369098499458, 10648493462065257860, 10940203220400825059, 7261956826490066834, 5730064365163707705, 8826144244207679463, 11688897202604808409, 4559302720015817859, 4402707951554525697, 12375228725744876260, 13367890413392736054, 15438373163420410642, 905179285088193526, 0, 2064, 9594118340025725004, 16218246678075491818, 11582919835122342747, 5661452934218108707, 3714647928422746674, 13689184893219719187, 1899963197709801965, 8313716591368695784, 17822645741084942000, 18354595702287703799, 12620512717427217848, 10145637708639089787, 1735222492513760332, 14681927838838900060, 9262747238997471758, 11498487923782501751, 8924101344488972446, 2592517964915386184, 4276681409258176044, 3764365715267793208, 3120204268813370353, 6019260256544801113, 2801984351776029768, 16979166255722313516, 2813750347113564525, 16588139065369475399, 12012198471360912693, 2492059183640657261, 16968938268466755316, 1679902783560062568, 9435312778805252724, 12594665258064570661, 1586451078180607598, 9325815886784366656, 13163107377789060321, 5998117226166788975, 7008390784506277276, 7362390315901265787, 5188984820381727203, 5842708215320867131, 13553650342229414448, 5955476415838559193, 8725164908673674579, 15174091024100472501, 13637649140457772157, 16186415272190469176, 4473737633571089105, 2032050757569801828, 16070334483916823186, 7382925316452200710, 7820237015849984079, 13711104951459639694, 15277864807184951074, 7746677489393361812, 10897962020578390602, 2459478953251166639, 6142067256785271224, 1469990404519833898, 14737929225229310854, 17685816709290022661, 5568614684720127113, 12344784587178360875, 0, 68, 8186419089203192999, 15318603549361168513, 7911471416782656233, 14239435248344205979, 2133634484310994464, 8097913535946941412, 113263425049039362, 248987352426060274, 10939256691674299939, 17358468187481791647, 12423884741952977957, 56617284060232395, 1868806426895026968, 222259776750343599, 15059516987340721081, 8741184015917561905, 2066403566980848459, 3696239822839219697, 15367181090448289261, 8349149003644261348, 10280553347796952088, 7301079719327054003, 6885778115777578237, 12504375544103392076, 9288443086735636960, 4503182154932177101, 17461402434481489861, 10152174670869705735, 6117144343302310887, 9435312778805252724, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [13620833136975709089, 1046930547281056921, 5022880593775506902, 7356080910092118039, 16589884839242022257, 8919754405551141869, 782951559730000700, 4320210530167177353, 1189869440416317038, 11509478421996896286, 14131663596834904750, 3063592889799439815, 8310309385140170305, 9794866582382956591, 815213714413043438, 14909022885730690459, 1965134134848901020, 8569284627647542389, 11756365299450742783, 17765218832065923306, 17214386397833253270, 8857548797279425296, 9589793731564825353, 5744303806832189345, 9245523889540971217, 17743277714115543370, 75478605149737153, 16642733757618334231, 10408597074326334289, 1854469405851562328, 5120877191992423544, 6125088443291536169, 0, 5160, 1190658701913535022, 9371121588404883743, 7133056533056999470, 7380100170229652082, 14719783382686670107, 4693530971176924881, 11125714198188567552, 2434816259070577714, 17927785478103501878, 834873962620943786, 1091858408197145201, 9293176204765248193, 11318806736621162148, 979530496520387452, 8328113718786640843, 15870139479256453021, 7754853849459016697, 2742936430580983415, 6806060556807781604, 5089080673677611112, 16430235900965466453, 309743103212430298, 15664803780047891222, 3113571524475220627, 17862871362988443440, 1231393200801541530, 15779352999894925288, 6026600320279882336, 6970552753544824994, 4949154992619464010, 3358534066525179769, 2539641719046213719, 10199880931320172189, 6982964906206022277, 18160468829511284938, 13459748022261389691, 8540403463779371619, 298971077135778992, 9448428205117043728, 7211550496031219820, 5534997352008564058, 8961849300614763067, 16471253951712069551, 11996630593586982068, 17666409503469399853, 14743209389502972128, 13621451519455201128, 11693451034972088239, 376126037836000660, 12412096817616379990, 866468160396608077, 16487331493773223294, 15132792027965031247, 12005877568613345660, 5222840910814569167, 9174906967528115515, 12806387721803954058, 12420516276683200334, 8854457266879028181, 9558115804602486754, 6487880825188915613, 2384716068805359876, 0, 170, 13502722698945446624, 10582364865337924932, 8264438684589566467, 7775924941916048886, 7506941477585260226, 13559643900430805558, 14624701183045087851, 16810498729905278091, 3617722030424605287, 12209401598010007429, 14622001497128700788, 7124074456411373593, 11046353624103181594, 16506916834573600874, 2763493011778369288, 4381652925229768341, 9935322272824673857, 864619558035150967, 1868429356172715569, 6908757966622831414, 14123318794287563052, 4877497612363750655, 2105400693641679480, 8941132592749341698, 12124737918817624189, 15847492668873519030, 7578220797847929864, 9410406960468072857, 4811333449307081983, 5256913258227871425, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [2256486347761721492, 1399831673864751627, 12438672130810751909, 10240118010240816453, 12454995736750842450, 12272610174663972685, 16716772686788009039, 17679411248915786729, 9344021820453066790, 15548275238570617018, 12554227251830406338, 7982818396816137943, 8298623838207759766, 9667670442404470529, 14730751205912092663, 17475545646146195192, 7561186990159804961, 3352703426322824443, 11124655848983105243, 7361271662241444721, 1785076194951656280, 13323648175345935378, 15598576959546342188, 12701095265259304800, 3219799610745612107, 1555585114147558761, 10397456717804752138, 2319272066426069991, 17926066510128935923, 1264814027228690376, 15123699931666188121, 2665390174743669239, 0, 4128, 1352424102745866255, 13301242752201603536, 5420135027930584396, 17078794493496835379, 4779811836607866048, 3650219859599657886, 13618468821889769363, 11429589192023659923, 8853101337885331080, 9650238821992519861, 14401087967309285252, 12035560952634921032, 15407186837043713393, 15711028160746246110, 5396976350889627712, 15903424027416555998, 11304777107657759509, 9857843669692965578, 12605480788735099613, 14618970056708743810, 8493993205782554647, 6059068631740368787, 18316971448227884023, 12499808993385025318, 4210674244211222629, 18405965507148502967, 173097048437312502, 15568437290332308327, 11532601739151124629, 10000279862191744493, 9365253138981608257, 9113412038486870510, 12237115836192970750, 13532373892635206986, 11668565565569624948, 2114739335810906841, 16845938989106496862, 18053472495070906903, 9578952411771586845, 2253954535466549551, 11957330595594263589, 4327169169737696049, 8097241277176222682, 17499521208876685046, 10474171567958477310, 2884885063912824473, 9389176041985146128, 2067286230266639471, 3365016398014065199, 738171567486888734, 6622135657383660119, 4978858449337102663, 1252098561428724852, 813491835360077960, 3026073706021528936, 1157174472277816506, 8848575890036236601, 4801870550462804365, 7028466390812097322, 8403721226663073636, 8970732296705167988, 12459739889109502988, 0, 136, 16864340361327671903, 2636070061904000825, 1539270658943308645, 8663103496298937284, 797155414931197277, 7929222985705309752, 5418421295167202847, 16520350781038259800, 11697635461652845634, 10326065236143981873, 4672452207442160023, 9236109584144478544, 2355139499180822246, 7782053902926446231, 2620978815438101291, 3668923621194401622, 246363526423127035, 10353083146864436335, 3430895131654614161, 12564495361718767183, 4982750975383300564, 14559648290526166949, 6242143746593499460, 11140632426269699329, 3028234720115016827, 6653412960111738263, 17564919688262005304, 284282844772359316, 7938696543505248162, 17100537000217132265, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [5193960644663470490, 18378615377082669582, 9942094792989095510, 18239658104155677632, 3247221802734244696, 8138145110381489386, 8305898108846284300, 4495835739545312127, 13363880742094688735, 409501507955448067, 9615046049029083973, 9226283480795415930, 6188039948757326954, 1925348622523205808, 16932487676782686187, 6461440512631901369, 6379521145060545439, 1135364094435597517, 6898694641523826133, 881111998832614715, 7852757539889945333, 8831210118957475983, 15508177777761403707, 1274251095252206369, 6462015026972174497, 14758961666322366163, 12911489632740586743, 10573355084806673526, 11042755251558401992, 1655214279385078584, 17558359767143120899, 18009389558374812227, 0, 1032, 4798141223555508282, 12962488577647927717, 10133257770726709126, 332864556927106185, 12116126881643349994, 6604148216925166409, 101015634312276042, 15934992137290074922, 6112274855072540816, 17762248064501548615, 13166189948742588777, 270100349969833402, 13485211244653928073, 3502306881032295169, 13607663468974078519, 8883940618995723208, 10623667092532612652, 12293715092576816840, 10386976621364522928, 9128135834925108269, 15731443845270647366, 13373704167654916087, 13746187061551926812, 11684868053863796759, 3258729720361659960, 10434904637843727165, 7034851303745741351, 16133345873308301364, 5426492436527662130, 2980140658145787783, 4243893038989355703, 8922317147540258079, 15524901873579080579, 14961355291644520251, 8912131487655833337, 845467818172067610, 6513419642881984303, 15821388348544564061, 918209442918452849, 1771868273093277971, 11088759444000251587, 15710903694873023395, 7739199555620722590, 403122127909161589, 16794196935209020317, 420049465494673582, 3241180689003955516, 6815831073966054431, 13165955590245083084, 3933813014659210303, 7891509834730356602, 14572658037405460796, 18097121197159342726, 15303933786232509118, 6355852571927224576, 5965705308661034968, 3878821330615144039, 17609259256248013285, 15839551803056895538, 2863101478933748100, 6867483661888889167, 11007533278239168078, 0, 34, 6567391571487826395, 5204289601743072522, 3431536436519013066, 18098398151169262506, 7669185665212226764, 5455708142000104069, 9902960937688969164, 16439153306838678161, 9116909952501731628, 259487815978835763, 11207509487307725092, 13598970521047669184, 13294225392413433281, 17974846784869714720, 1531979193630020279, 8742633689618768661, 12951219828222672250, 1272063647175062154, 1015593294205135440, 1601391529726059156, 6891640398393941397, 9120291006888379304, 10474372360890458437, 5584077426972546342, 6680864214558642932, 2419346771478639592, 9600963709893327666, 7733975108380115257, 3435995547523177385, 10362535235958450122, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [12344784587178360875, 7525588297109292118, 10242077034078069399, 6920809802339641674, 17643499204383222535, 16688592460292823795, 3252667668159125426, 6639040797936707465, 1827636079652666195, 2462138615393893213, 7273091941301037907, 7777539981955361461, 17791722127119122070, 13941030348836860953, 2461265848652382458, 17178103242399629259, 12982591110459702249, 4311636691398707716, 11830890166127089072, 7160199109027716330, 14107503556614837834, 6316368550299988901, 12988322271117575851, 12500666959478542023, 4763644307980385379, 17502332825869685988, 9045450374393109306, 7379498771612731567, 16568845003086625163, 4695178656129701184, 1678315832465296045, 15789153556893733830, 0, 1032, 11702782905971311743, 8115486282645452027, 16425371230714077552, 10333496212804492507, 1572943607289284437, 13244361396034453954, 12880029163967100393, 14716450796809578181, 2618965885956593171, 1606019581379521796, 12562170441304287563, 4599116799417823473, 4257071131168813417, 10446583017549019711, 3570388907037362614, 11170081717188072664, 17238997244398394333, 17231192964516960933, 8123337005847551087, 7060091366977384949, 5719725530909274667, 5057603743378325948, 13848013489728729143, 17729739340387068117, 367186060507240673, 1411195984452924204, 11088333491201093194, 16575090776691519559, 16147396598096989679, 14525300817521856881, 2372900269115514267, 7638869850317184909, 18112581651832813996, 7934301823485851614, 13134589595174512908, 5143267856379088965, 1385332020236631836, 4877336193186145990, 18193547062192211825, 4615765459892113834, 3381950137508436504, 17429784608409914678, 14977580224084415767, 6849317271519196447, 5437598344549503419, 1906047363049945529, 5004054537041877249, 14661239785476454049, 10553785792947774039, 2119915982392644589, 8985292275604857439, 9726386267280827154, 4505582310884934806, 12912789541737329022, 7115507662283435621, 2051190405167774802, 1232238311229055715, 220176432091768973, 5422499495491255741, 8009273299237215820, 13359803287975487032, 5187224287159924757, 0, 34, 13313027311321423572, 9192034959170904294, 14701500658652215925, 3854356596578551734, 5718692378574184090, 17501390179378757090, 8526809416150489728, 6507550884061463423, 7814960517829781662, 2939637999200097803, 780950602796552578, 4118107554308446430, 8555475415255527439, 14714307830357033751, 15614510648083677054, 17171454789201612359, 15897739400545916002, 5578273266312075011, 10191353484336583572, 2940473809902205523, 14962502826274181007, 2115641271859045975, 7064236544478437245, 10824702985925635247, 12931918488324919856, 8429882718924461151, 11244752067809188397, 2111913529644288504, 6112640616610282754, 6599190416745833044, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 4046254507773998773, 6534480484041428863, 3251048018398498863, 14672293546278713057, 16728924149188845306, 128728647106458681, 14226927580887823496, 8277248794545234814, 4354566838645069185, 16178613916401188944, 5304102959326456112, 9791457517463513797, 10245170831782510809, 11611317382660466625, 13569694221132024345, 16005837490233273516, 2791259658093074998, 13441513594234320689, 4241376053954359578, 3545073666350874448, 15186107276182512091, 10698815982870498162, 10971920968668641865, 9145865124167298835, 405811361541120846, 9884965742324813117, 2876689281462596902, 16445466086575260512, 14688957924306712254, 16306354913676224825, 16604794485775028126, 0, 5160, 18346837778669738664, 15130142357101091527, 6726588340010678615, 8394319278312203283, 15942424551308612685, 7629500615465222065, 14939877513325106589, 17048523965011794048, 2306293645521445312, 823113708878672797, 14981348226783328932, 7432878333905782051, 3482639998457803800, 632277917380007036, 18266437030920184246, 3366715262389109205, 5280275432441977334, 5379329043314533811, 13912213856326486056, 17217059915921675075, 15634373017412823086, 14981257187297131103, 16697350900700022325, 5239234081629986555, 3229291246709926782, 18373224696258292584, 6771862800272250893, 7666370275789511263, 12942227631865082960, 15190222347874856922, 0, 1061325914286080764, 9554433906850032874, 4012321235764609039, 14967212595115142793, 5983394632166978443, 5809835498849113816, 6561933873120105870, 2140629501848088776, 6712525834006528890, 5760623808290856282, 10552757613235067722, 1939309373056894313, 14427320366022536141, 8538471352201975220, 14188752564290255096, 7981877957758397164, 1148470236137421383, 11019464818805406210, 7769960423081990191, 14632278337044440617, 849771658931440922, 5632784009618830911, 5696241881348246065, 1879984915784172244, 16312530632323862580, 13300309889942581843, 15448409017348426344, 1639569934817636487, 17233518173045382262, 14413924905126977169, 9045462722956532208, 0, 170, 946461078672821334, 16281780351388912901, 2935418863412242354, 14713353090133347394, 1791207195906381248, 1092415958346704160, 8319785044806982194, 11182822967626325795, 16809587424157045315, 2244733962249620937, 16303706249485479712, 845878992383212753, 5921002467687226204, 4434027484725189444, 15967620315457307754, 17386925554974145101, 13158427748622481094, 6196246176234489731, 8582026933349467190, 611778401982756412, 16288180016347524015, 16434619985909351985, 1145514137751095479, 5160952971387430527, 8451565207539691282, 5967893180517848182, 7714774968702541161, 14978023560208702638, 18014742166879778909, 5450578834500306709, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [87, 8072556154622677081, 1267311017976162806, 171317623411600853, 14846028244624432327, 5697605161887258162, 6090204166740560590, 11791493563989406548, 17428436932452366793, 5676009947455004918, 18345317182680976060, 18287702590376570538, 4985574569677261947, 15947076302058294771, 15533043966546096492, 13147369042643698626, 13830067522797295398, 9812515853737376613, 1153576568012481332, 6976086965219136352, 9332017051661502953, 11709096929003024091, 4784660881537662841, 4083552985517123622, 9895527598631437834, 3406650305555277621, 13871430865741604308, 2950941648901088194, 3993419962022258191, 6722743736070459606, 1297747773924291443, 15433589206667095645, 0, 4128, 6496253015800789210, 18063315295058131399, 14099326864720264780, 16744359797696928029, 11669954633423859445, 10923938539628559259, 10579480970462933513, 17315553376669597828, 12114095292572219189, 16129781670858537825, 67936491912723144, 6285840300661422802, 14359460599290704174, 7597471307904508314, 8469569990667894210, 9117246600999250277, 14614928058075190380, 13738364908865630160, 1806905237893315697, 261412144627674040, 8380596589382515797, 3809925330596605534, 1983199361335541287, 6337901890572878101, 17063257729896061936, 12690697575318882146, 3846044480011221270, 10729939698274680623, 5297971463863936522, 8671284646676347574, 84, 6657939908049969710, 5132111129018882891, 8232522030470930177, 2748555984042091513, 15852736438270791360, 3031910609778633238, 10165962755900271710, 16659854091479845434, 17343121214427119893, 854734865188827599, 16332742745573253042, 719106832906440841, 5187730385273117170, 5680967626748162975, 12443929595174060051, 6984107838208124669, 8017806737059891905, 3253255241682497310, 17244932564674349345, 1765857304688336746, 6104054101040517608, 16644020687030024364, 595269491299106953, 16831646467700047759, 6176340855571448766, 18004816485425051763, 4101389897636298429, 17541610204110287382, 7370145379849234412, 11764023996857035803, 3516218181999416212, 0, 136, 10841411014448826746, 10924324070009278511, 4390811061445162297, 10665404042695900090, 11148796663006115025, 16584177158338467512, 15369021590994653978, 13860609558593370204, 3837193053542887320, 7652640894347806080, 683219561750944695, 4006536353767232614, 4047796662675347846, 1149920536684206111, 1698301089048909092, 6224704259817574157, 4439284651749775339, 16476516570230330168, 10834199646006576067, 16282481854654492091, 6659294847490221927, 12242894720083399562, 7156478509869523727, 9996508607909856718, 17045153176928915002, 4097937233975335255, 13892339685592049122, 3881709886225480466, 10446442293007407525, 1539493896147927159, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 14732236349158007950, 7398379382324753631, 16529615322051348437, 17750754114621262532, 3376246851343252040, 16812742874230723382, 5497427090926806167, 10370890449220293026, 12072808913033091146, 3773065747435304139, 1433120707818296652, 12602993390877629622, 11873715535213483733, 13503968807830695383, 1548449854272693349, 2164072014511735918, 2051419284241394287, 7675966884444101274, 7631305566403533669, 9974196014981023153, 16049335883858064137, 2471757314515864029, 247517241416190936, 17714417256089308015, 11671008027458954016, 581610329922371147, 16154960330167538938, 5798502399718959312, 5346182502077854664, 14220066076326577834, 1379414419793409060, 0, 1032, 13084260837127404333, 4018109146681745349, 14498381569327145056, 3778421823029569719, 1344624249217908323, 3634653398484528177, 1428985706412758663, 11382569756632997337, 13894906302086601399, 3911680161282028629, 11467762927868003365, 10098326072301516020, 16073214466625742345, 16150512194511843089, 11525294274796193451, 15902507139806774023, 13926886722650908730, 2974304378722638293, 5274544965980948277, 9984170014312577610, 639485734140932316, 15088403650698955530, 17189134684458608982, 6515320870350778492, 7902492290152572474, 17310456195349246143, 4070136787975548901, 6345872167795009033, 3095930865537762353, 4232664728858134772, 0, 13425232862973212691, 18017734206314589878, 4362746362325529522, 5580595613883635850, 14186966130004258435, 12558944767443104505, 9400104492160547353, 10540307613825778005, 16337971251965072535, 10106057436125976033, 9544366711268571215, 5728567960549491041, 13778603290469351967, 16022817295707876509, 11816634839594428392, 1619816382417214775, 332425507059551196, 5638968861636104000, 13036766990591622942, 5135102707173364321, 10242389681667623919, 5777720311941164202, 426018854260317513, 11718167143057109482, 13648951505177506250, 14542650836653761124, 18018546562218872798, 4457636384061007994, 2416704573314226662, 914323423605581375, 6601699247185721889, 0, 34, 8422262931452347509, 13885570107923725144, 235244799151795110, 17975760300270072840, 21645088928215528, 13378438338434245321, 11260622121353286786, 13136688320626048612, 17881560939567828117, 16601834208041636644, 2350599886583381643, 3676641047171560447, 2612703737764640459, 6165448709088710825, 9702561415374819789, 14396227383672448392, 2871975363154349452, 13084396173640101372, 15953404371899770169, 14377272925308367884, 5291380804534138171, 576711179775643850, 11287382459948400014, 9324129603955102500, 10503620158827014837, 6130889055094603538, 5442709211693844142, 2968563472347562608, 10528964699829495885, 358459342719025633, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 7484183127135320340, 13467318737723490903, 18417997150771375303, 7719389523268106465, 2784882046013758615, 12479320332521777529, 17052932344949276269, 10938440435726947483, 3905086412998728873, 15634495878209337408, 16923840111614250132, 16397885158502248985, 1407236965451031446, 7800595096011710855, 9403004147208138835, 9997729556720517342, 8534668514381008137, 9227268528750758459, 13403671598326027744, 4715851494578741692, 2189528202978614673, 8567186243928218861, 9297942977636733700, 12120305129322824184, 16911451126764050505, 8250812173422443178, 10259824399772380043, 14694981892968238671, 485814636516518185, 14546030952858743710, 17545164675990066495, 0, 1032, 15909096041365347974, 18432189660917429733, 2798890989547891271, 10768372030970716894, 5935807051329113911, 1259182408195029650, 16024750973514577255, 6103595041913569283, 914770550723164908, 5067028895751058275, 5242612139537538536, 13359135899043031769, 4430959127423856282, 16317056360529517539, 2634255659160911215, 15590656855559575839, 6832335878067392309, 6045109056629836176, 18146646330136390606, 6482705684632040588, 2770791364887326735, 7707774010999656594, 3401430074469265273, 3500862351024377705, 5135727797169111985, 14940852959892477883, 9633218853985087472, 16966092255533854383, 3065488485208441055, 15703076512693482766, 0, 595597012989057195, 2376871353626003378, 17667748366842763551, 1405929090442079600, 18135181650619726914, 7403637996862883832, 5964686311110162804, 203041400479358567, 3387955851036204878, 2169976152805477386, 15733337581560247916, 7104142523828512918, 11829327565897640936, 816639760928622921, 11238339345191818453, 11391625709863387987, 6031165808075129231, 10104077332067730329, 6839520087480516521, 14155312441647748702, 4167237297971124611, 4042518115334572170, 7632437875765360091, 10425826042851550943, 10797236500243700589, 17846423932362838045, 11994705126716395168, 1154262141907751651, 15744039038114735423, 13449385390195333360, 16051125308748956016, 0, 34, 9168769012195838974, 8757246072351383525, 15819587373362991575, 6330331124468459419, 17594449485955496857, 5094615699180819390, 10468588157075103568, 17500241837984025274, 12590769989805218521, 10257339134394161483, 6020533408585278677, 9887559600989616103, 17174772404727048357, 8260989830322406645, 15331894718426588199, 13817494132369433237, 7270842089806116389, 14464987003178196376, 12856235623981550070, 6446968933011398838, 4625298604721424009, 7537989708572581312, 8773062848621227780, 7997392847552644982, 12295542285792207282, 2236820296563710856, 6411496154095679628, 96618257160083950, 2708395562256972928, 13820925760592258770, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] }, last_program_row: RowIndex(11) }, program_info: ProgramInfo { program_hash: Word([12752059346458920613, 18135096529078946099, 13200399719329805350, 905179285088193526]), kernel: Kernel([]) }, stack_outputs: StackOutputs { elements: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, merkle_store_nodes: {Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571]): (Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350]), Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350])), Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484]): (Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693]), Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693])), Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781]): (Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874]), Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874])), Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171]): (Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361]), Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361])), Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815]): (Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305]), Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305])), Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689]): (Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195]), Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195])), Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362]): (Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063]), Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063])), Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848]): (Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661]), Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661])), Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352]): (Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829]), Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829])), Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444]): (Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223]), Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223])), Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386]): (Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388]), Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388])), Word([13190842942618341421, 17548956981569849952, 15418963848144418856, 730733050713174879]): (Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144]), Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144])), Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874]): (Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675]), Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675])), Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594]): (Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115]), Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115])), Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809]): (Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257]), Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257])), Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777]): (Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555]), Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555])), Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509]): (Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882]), Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882])), Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725]): (Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979]), Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979])), Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134]): (Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987]), Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987])), Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828]): (Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910]), Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910])), Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830]): (Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054]), Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054])), Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228]): (Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742]), Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742])), Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443]): (Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928]), Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928])), Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643]): (Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979]), Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979])), Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758]): (Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106]), Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106])), Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580]): (Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594]), Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594])), Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765]): (Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045]), Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045])), Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766]): (Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281]), Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281])), Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385]): (Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828]), Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828])), Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579]): (Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171]), Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171])), Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212]): (Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992]), Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992])), Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463]): (Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004]), Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004])), Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502]): (Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023]), Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023])), Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539]): (Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537]), Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537])), Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865]): (Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225]), Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225])), Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690]): (Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947]), Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947])), Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202]): (Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552]), Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552])), Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079]): (Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444]), Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444])), Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850]): (Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548]), Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548])), Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448]): (Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987]), Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987])), Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041]): (Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035]), Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035])), Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301]): (Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414]), Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414])), Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414]): (Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212]), Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212])), Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703]): (Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439]), Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439])), Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271]): (Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955]), Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955])), Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882]): (Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802]), Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802])), Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152]): (Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887]), Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887])), Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028]): (Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948]), Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948])), Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331]): (Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093]), Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093])), Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394]): (Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134]), Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134])), Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546]): (Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228]), Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228])), Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620]): (Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414]), Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414])), Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800]): (Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703]), Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703])), Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671]): (Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205]), Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205])), Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537]): (Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011]), Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011])), Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516]): (Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301]), Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301])), Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831]): (Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986]), Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986])), Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415]): (Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057]), Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057])), Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722]): (Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689]), Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689])), Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144]): (Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682]), Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682])), Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295]): (Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268]), Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268])), Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818]): (Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513]), Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513])), Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241]): (Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565]), Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565])), Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439]): (Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012]), Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012])), Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512]): (Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850]), Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850])), Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986]): (Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865]), Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865])), Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982]): (Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777]), Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777])), Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808]): (Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394]), Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394])), Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979]): (Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690]), Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690])), Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093]): (Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620]), Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620])), Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902]): (Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789]), Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789])), Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542]): (Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094]), Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094])), Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057]): (Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362]), Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362])), Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205]): (Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961]), Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961])), Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401]): (Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580]), Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580])), Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553]): (Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960]), Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960])), Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169]): (Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031]), Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031])), Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682]): (Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053]), Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053])), Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118]): (Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562]), Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562])), Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725]): (Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666]), Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666])), Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661]): (Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897]), Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897])), Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981]): (Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447]), Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447])), Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072]): (Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646]), Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646])), Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140]): (Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404]), Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404])), Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515]): (Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152]), Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152])), Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709]): (Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664]), Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664])), Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800]): (Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103]), Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103])), Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741]): (Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169]), Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169])), Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005]): (Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758]), Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758])), Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802]): (Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070]), Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070])), Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159]): (Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005]), Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005])), Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350]): (Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443]), Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443])), Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697]): (Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573]), Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573])), Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928]): (Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331]), Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331])), Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320]): (Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166]), Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166])), Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814]): (Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079]), Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079])), Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447]): (Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820]), Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820])), Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284]): (Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057]), Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057])), Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697]): (Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131]), Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131])), Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955]): (Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290]), Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290])), Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910]): (Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202]), Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202])), Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910]): (Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822]), Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822])), Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106]): (Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847]), Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847])), Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404]): (Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441]), Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441])), Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796]): (Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186]), Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186])), Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053]): (Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516]), Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516])), Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992]): (Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818]), Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818])), Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957]): (Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315]), Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315])), Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709]): (Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794]), Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794])), Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091]): (Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539]), Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539])), Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664]): (Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558]), Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558])), Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294]): (Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579]), Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579])), Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947]): (Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502]), Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502])), Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829]): (Word([0, 0, 0, 0]), Word([0, 0, 0, 0])), Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045]): (Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137]), Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137])), Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914]): (Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041]), Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041])), Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573]): (Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378]), Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378])), Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699]): (Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873]), Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873])), Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225]): (Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262]), Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262])), Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057]): (Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692]), Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692])), Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131]): (Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997]), Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997])), Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555]): (Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385]), Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385])), Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195]): (Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709]), Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709])), Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166]): (Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542]), Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542])), Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027]): (Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373]), Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373])), Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378]): (Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509]), Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509])), Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097]): (Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553]), Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553])), Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217]): (Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815]), Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815])), Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873]): (Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864]), Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864])), Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997]): (Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722]), Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722])), Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887]): (Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766]), Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766])), Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589]): (Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757]), Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757])), Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539]): (Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665]), Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665])), Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129]): (Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229]), Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229])), Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137]): (Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312]), Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312])), Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019]): (Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378]), Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378])), Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331]): (Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713]), Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713])), Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]): (Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980]), Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980])), Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325]): (Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546]), Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546])), Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170]): (Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822]), Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822])), Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054]): (Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295]), Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295])), Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925]): (Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848]), Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848])), Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909]): (Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796]), Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796])), Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540]): (Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170]), Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170])), Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214]): (Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448]), Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448])), Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317]): (Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294]), Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294])), Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757]): (Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416]), Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416])), Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378]): (Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091]), Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091])), Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263]): (Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463]), Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463])), Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666]): (Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361]), Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361])), Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174]): (Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992]), Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992])), Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470]): (Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401]), Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401])), Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665]): (Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957]), Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957])), Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262]): (Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144]), Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144])), Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229]): (Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284]), Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284])), Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134]): (Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325]), Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325])), Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855]): (Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765]), Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765])), Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115]): (Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814]), Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814])), Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441]): (Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831]), Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831])), Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977]): (Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446]), Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446])), Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880]): (Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005]), Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005])), Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789]): (Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995]), Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995])), Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000]): (Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267]), Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267])), Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998]): (Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982]), Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982])), Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995]): (Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539]), Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539])), Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507]): (Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512]), Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512])), Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305]): (Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118]), Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118])), Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219]): (Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009]), Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009])), Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416]): (Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089]), Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089])), Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980]): (Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445]), Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445])), Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063]): (Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140]), Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140])), Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713]): (Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159]), Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159])), Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031]): (Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809]), Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809])), Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932]): (Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037]), Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037])), Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094]): (Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925]), Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925])), Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315]): (Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386]), Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386])), Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446]): (Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721]), Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721])), Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742]): (Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981]), Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981])), Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661]): (Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072]), Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072])), Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979]): (Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671]), Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671])), Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361]): (Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269]), Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269])), Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558]): (Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571]), Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571])), Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290]): (Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902]), Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902])), Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987]): (Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741]), Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741])), Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902]): (Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515]), Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515])), Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497]): (Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028]), Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028])), Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948]): (Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709]), Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709])), Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009]): (Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725]), Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725])), Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387]): (Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317]), Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317])), Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159]): (Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808]), Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808])), Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394]): (Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699]), Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699])), Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312]): (Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000]), Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000])), Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987]): (Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821]), Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821])), Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046]): (Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909]), Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909])), Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565]): (Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028]), Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028])), Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269]): (Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352]), Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352])), Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847]): (Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271]), Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271])), Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513]): (Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800]), Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800])), Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054]): (Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394]), Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394])), Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004]): (Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977]), Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977])), Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675]): (Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800]), Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800])), Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692]): (Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159]), Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159])), Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909]): (Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932]), Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932])), Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814]): (Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697]), Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697])), Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186]): (Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387]), Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387])), Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445]): (Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470]), Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470])), Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966]): (Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507]), Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507])), Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548]): (Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253]), Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253])), Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897]): (Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783]), Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783])), Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208]): (Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054]), Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054])), Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268]): (Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661]), Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661])), Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388]): (Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643]), Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643])), Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257]): (Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174]), Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174])), Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960]): (Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241]), Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241])), Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721]): (Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046]), Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046])), Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822]): (Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217]), Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217])), Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253]): (Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697]), Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697])), Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054]): (Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019]), Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019])), Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821]): (Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432]), Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432])), Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864]): (Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105]), Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105])), Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373]): (Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855]), Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855])), Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646]): (Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830]), Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830])), Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460]): (Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208]), Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208])), Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033]): (Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214]), Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214])), Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105]): (Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129]), Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129])), Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281]): (Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909]), Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909])), Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028]): (Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027]), Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027])), Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012]): (Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054]), Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054])), Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562]): (Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589]), Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589])), Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037]): (Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097]), Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097])), Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355]): (Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460]), Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460])), Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223]): (Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355]), Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355])), Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089]): (Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306]), Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306])), Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035]): (Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219]), Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219])), Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432]): (Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297]), Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297])), Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693]): (Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263]), Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263])), Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794]): (Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484]), Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484])), Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552]): (Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941]), Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941])), Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267]): (Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814]), Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814])), Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992]): (Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415]), Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415])), Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941]): (Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966]), Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966])), Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822]): (Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320]), Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320])), Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306]): (Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902]), Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902])), Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820]): (Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880]), Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880])), Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361]): (Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725]), Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725])), Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005]): (Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914]), Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914])), Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783]): (Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781]), Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781])), Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011]): (Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033]), Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033])), Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297]): (Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910]), Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910])), Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070]): (Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134]), Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134])), Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144]): (Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331]), Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331])), Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023]): (Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497]), Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497])), Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103]): (Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540]), Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540])), Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961]): (Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998]), Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998])), Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414]): (Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]), Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]))}, trace_len_summary: TraceLenSummary { main_trace_len: 12, range_trace_len: 39, chiplets_trace_len: ChipletsLengths { hash_chiplet_len: 128, bitwise_chiplet_len: 0, memory_chiplet_len: 0, kernel_rom_len: 0 } } } +ExecutionTrace { main_trace: MainTrace { storage: Parts { core_rm: [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 10403713768525900847, 2139411523427040457, 8515917035379853351, 856023126862020256, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1032, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 2, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 8, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 3, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 4, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 1, 1, 1, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 5, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1942941126776981551, 9461460041610899538, 7600020670677266955, 3257731577738044347, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 6, 0, 0, 0, 0, 0, 5, 0, 1, 1, 0, 1, 0, 1, 34, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 7, 0, 0, 0, 0, 0, 7, 0, 1, 0, 0, 0, 1, 0, 0, 5, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 8, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 1, 1, 1, 1942941126776981551, 9461460041610899538, 7600020670677266955, 3257731577738044347, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 9, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 1, 1, 1, 10403713768525900847, 2139411523427040457, 8515917035379853351, 856023126862020256, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 10, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 31, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 33, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 39, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 43, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 47, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 50, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 51, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 53, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 54, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 55, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 59, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 60, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 61, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 67, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 69, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 70, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 71, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 72, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 73, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 74, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 75, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 76, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 77, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 78, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 79, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 81, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 82, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 83, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 86, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 87, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 88, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 89, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 90, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 91, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 92, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 93, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 94, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 97, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 98, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 99, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 101, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 102, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 103, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 104, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 105, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 106, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 107, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 108, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 109, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 110, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 111, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 112, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 113, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 114, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 115, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 116, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 117, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 118, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 119, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 120, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 121, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 122, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 123, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 124, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 125, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 126, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 127, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0], chiplets_rm: [1, 1, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 10403713768525900847, 2139411523427040457, 8515917035379853351, 856023126862020256, 0, 87, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 484349804684265665, 6880098633847640351, 846980218218532239, 17903889365796795298, 5550459936565271753, 9107753202341829570, 15324484398676964645, 9257266254418654737, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1032, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 11116382020814057190, 14732796941305378371, 13074361791711182490, 6715193688317415490, 1571558009365433839, 13285275197432594374, 15905141483335727027, 2507840277166973476, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1942941126776981551, 9461460041610899538, 7600020670677266955, 3257731577738044347, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 0, 84, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 10403713768525900847, 2139411523427040457, 8515917035379853351, 856023126862020256, 5748739229791737666, 3971489439724797398, 10156667480279311531, 10471841795831116097, 4161518306931659446, 14664557596733629071, 10457686661281861787, 5372530612210116852, 0, 0, 1, 0, 0, 1, 1, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1942941126776981551, 9461460041610899538, 7600020670677266955, 3257731577738044347, 15558099059781162807, 12870793504304295307, 12385397219736869043, 13164551900610862841, 279187929191844389, 3949603689257433549, 17380497166734391477, 5117931133682798382, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 10338918064798200754, 15286122942437340674, 6004213370540561229, 11077881500896133090, 15185046381229794929, 4025060549564442513, 16691190932080263388, 17911971684749301267, 1792647895939561414, 11040149027552020115, 16788268171496683395, 6690778673349798915, 1, 0, 0, 0, 1, 0, 0, 0, 0, 18207620435178905496, 4478894291978491061, 8126565228616187566, 14565598150868720008, 486704718504877876, 5092068149414351847, 4895519870785798161, 18320934558859357026, 4783600071858140824, 7590991738963063833, 15020058681279762757, 8502154501231846969, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1790253480113930875, 11472368064126754753, 16140937904922483949, 12784262958320173457, 8992534124131108063, 17197330755228127793, 17888648586033704362, 3783608546885852925, 11488181860237317371, 6520363121033018355, 5666192756396478125, 14698764588926429548, 1, 0, 0, 0, 1, 0, 4775960838571449442, 12355201513767393906, 16893169864929129892, 3067820580898613927, 4037642048582652770, 6463406968300557513, 1334655449937755180, 16454962669178338822, 3423416796618681452, 15635204112556936010, 11367217176161227780, 15846919749025709683, 8739705468185832455, 1695606868833824155, 14902201197695023622, 1, 0, 0, 0, 1, 0, 7270109453425771694, 6393439473671243944, 5763178267509538253, 87155278506862768, 17182682045085641378, 13669966515951696363, 6730246632471569917, 11015850215265080242, 5781848723365073595, 14722218108828704340, 12249120524157518956, 15530817548594619752, 2571721876460128542, 1124203808167418458, 4658355789422303197, 1, 0, 0, 0, 1, 0, 619730554607827397, 2707784357837694055, 10389429507854625814, 412437114519718435, 17010823019251866220, 8496853728750345058, 3962235926057627964, 7293691342607609411, 4966485821032368622, 17523850342152507329, 16165780461118504337, 6833077136448453098, 18408644517259086000, 13790345385092960681, 1118981994890433291, 1, 0, 0, 0, 1, 0, 2870832816007467384, 2873570063945483268, 5260498635996294368, 10072735002004767449, 7363233941642473793, 10401385213219539176, 9719773007613995950, 10216717372939649307, 13022711033487370480, 9232213967333586262, 3354429439844650126, 13306058477265011029, 3840400538830937486, 15100916108359921929, 12686728912814672715, 1, 0, 0, 0, 1, 0, 10126186915863966894, 13849382609137246799, 14871056570003924152, 4577474152973240700, 10319035267502935180, 1107109480596608884, 910001863439660317, 17323775771861278671, 11990539141370178689, 1895237968841058140, 3069611939766785355, 13990132518689115799, 9158955820349235201, 3334355584256728822, 6532229842765454575, 1, 0, 0, 0, 1, 0, 8418794997351000750, 1324633730077053524, 7680826640634201152, 6943155698572158851, 4119721600018041835, 10160115415927000034, 13670021867743170174, 10426040451143237205, 12527054859506162043, 693011963436135866, 15847427063003354492, 1193915807921269299, 5530767236037587666, 4498758928312101948, 1668396433795256171, 1, 0, 0, 0, 1, 0, 12474497430381571234, 3486558176421926303, 176934443909317952, 8642603494321417085, 13568047686929876305, 13873699071648888616, 5469909543377435991, 1153721650762048262, 6332701647560212482, 14750767280279403533, 3863562993110808460, 10010469643426778773, 13610145136323473859, 13803405503382348517, 10066622964560025039, 1, 0, 0, 0, 1, 0, 6502239097904837007, 0, 0, 11596242931973405682, 7569447524345075040, 11402732351667273497, 17726124048449719654, 2143489115939838335, 2291345291252627066, 13774221459002946228, 5704848367751370496, 14844994802213729480, 13325648093707576188, 655937328333223270, 12601714085039449766, 1, 0, 0, 0, 1, 0, 0, 0, 0, 10080683606039484932, 557142253253508029, 11861574744773262883, 17479297133692971328, 13431343265670357832, 5107644268576628652, 5672451077690842648, 10697999158618521351, 13783189127611294708, 6370270522833708976, 16602411989536803847, 17535824353652041621, 1, 0, 0, 0, 1, 0, 0, 0, 0, 18221718971044951820, 11123331110225556773, 17884963006522019435, 13581862227015801716, 3539406162482662008, 12779267696302831166, 17568889654867020374, 14043625177809463809, 10953842550742243459, 17624483884859046607, 16829866994010956924, 10383254959407238075, 1, 0, 0, 0, 1, 0, 0, 0, 0, 7704989128662250393, 7731722432250559639, 1104300072480693820, 12966826694165085383, 5898355191387204970, 418343475844287535, 17504741557362850364, 11212567254567942759, 4585972511305465500, 831671821010246741, 1347174724805777450, 9978241385511108600, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1942941126776981551, 9461460041610899538, 7600020670677266955, 3257731577738044347, 15558099059781162807, 12870793504304295307, 12385397219736869043, 13164551900610862841, 279187929191844389, 3949603689257433549, 17380497166734391477, 5117931133682798382, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1032, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 15913981378790993016, 12701179462806902902, 9645342555817022514, 6889850077248808033, 678249829196625442, 8726676798253716750, 14136118088409135949, 1027279235140821190, 8048729929177993405, 2542525775606472849, 3283471062508934848, 18058280687405074483, 1, 0, 0, 0, 1, 0, 0, 0, 0, 11899090779839289087, 1701090513954162998, 6953639183117323837, 11460660778637092812, 8345945186928076892, 11308243255833047975, 5734666540714547293, 1546649737555419076, 14643837757854608147, 7477230882792828789, 2359592855656894189, 12732146754685591216, 1, 0, 0, 0, 1, 0, 0, 0, 0, 16283412161296764998, 17261112905912533997, 1498213616014501531, 7707889409925905689, 16090493533591377617, 525010687572874692, 5228788497345464933, 13051466527897639054, 3560924095387897187, 12551242480725370445, 4038828260160651477, 6132317990703151787, 1, 0, 0, 0, 1, 0, 14261694278902826987, 16097544111075686229, 16632169854204459773, 14265791174051766329, 14732671264513481238, 15642599276989292777, 7593738854072541043, 11440582168151819564, 18258483622390056257, 6851601084855956341, 10463349537167637967, 10032876585525342603, 825669147467031185, 16271217766495541082, 9021089524754424392, 1, 0, 0, 0, 1, 0, 16780109665356203593, 16025948514351396737, 4256182047405196535, 4919013996388780384, 6974015548720770018, 10189882052640604940, 12288632186238773648, 7055558833039165669, 9820743264545515107, 7353106531603230851, 5612808106478211181, 362487531847990854, 10259224130335842891, 2374318293393776907, 16208179153232019183, 1, 0, 0, 0, 1, 0, 9496969110446094198, 10424961628901078909, 7587726188775237019, 13423955604028434301, 12288543613568774022, 4068762405627465026, 7288480650179820504, 1035430088689333582, 2651098721515326755, 4524440782000877024, 3013038852551457145, 12536534023666437466, 6560028330562582937, 9090521726813489969, 17634755409309861791, 1, 0, 0, 0, 1, 0, 15761194215082968049, 15796684185970405493, 1294179585337070936, 5701860167148115542, 17707247215386403887, 18419960639673587986, 14570347312565937582, 8634142387233894354, 11938075017385927203, 8060480374868324599, 16699922976999064541, 14234489074154948378, 17210389744085299852, 17331527780947314617, 16356838976302290254, 1, 0, 0, 0, 1, 0, 6184336662619539433, 7106147576739595100, 18237994300618329820, 9768155666925548219, 226714884885574576, 11169479382209254075, 5756676929838789145, 29803495366482069, 13128905441940840949, 18304516631519674746, 3177693875357946498, 10624850715031233718, 16956738608020324589, 10558540052020438814, 7826502712354673600, 1, 0, 0, 0, 1, 0, 1980308537464408089, 6810023246846442283, 9400257804338494201, 11246932855318952856, 7504545710540897051, 5823677062954428984, 9151299935574592196, 15905322272715446259, 18174748553199601666, 9877077233183640995, 2431998410719122545, 3541292002384422941, 5416588529930333172, 15788517205879313917, 2490575598934209003, 1, 0, 0, 0, 1, 0, 17950140321155419078, 9014768943295123367, 10707122777228105884, 10701204914974985643, 15060806908759160804, 7011191650405807117, 13598159658926423040, 3947314552577424057, 12985682730462769834, 18264715466581442035, 7667189540353817157, 7685483800933651249, 16085167604591833455, 16105855167414075111, 16215395602017884846, 1, 0, 0, 0, 1, 0, 8676227747932036802, 0, 0, 11504729673400082663, 3659553513673892306, 10374352082945691939, 15819529278889203623, 18107940902385670152, 8889798095480337831, 12737345777792032790, 456604824069734238, 2859376131275373721, 8758251935142908528, 2364536875264708997, 2435873391009301907, 1, 0, 0, 0, 1, 0, 0, 0, 0, 16797630026773069829, 16954579754978210547, 4393671449525183699, 6245909065255485436, 8311309349844601638, 3305827896314343556, 1615477551160071258, 3897903986825909618, 13015230208471866351, 13839070994009764281, 2415598337053791919, 5526300544248852335, 1, 0, 0, 0, 1, 0, 0, 0, 0, 12827873667465929582, 15892701250663610383, 549489834728826775, 9425334953627649153, 15402634395731091512, 11814416271399500934, 14597718118926923662, 4726679541432826422, 342915941842538663, 11221492717904369823, 17188959961041335276, 13559932473868727168, 1, 0, 0, 0, 1, 0, 0, 0, 0, 8689096602925893779, 4096531352684607500, 8424481237826564505, 15238165026175259240, 10985176737527635898, 2672540837788784952, 6649439643634522762, 7581835251244605715, 17671970641549389116, 18069913154458602790, 749417941228438762, 6150863900366154379, 1, 0, 0, 0, 1, 0, 0, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 11116382020814057190, 14732796941305378371, 13074361791711182490, 6715193688317415490, 1571558009365433839, 13285275197432594374, 15905141483335727027, 2507840277166973476, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1942941126776981551, 9461460041610899538, 7600020670677266955, 3257731577738044347, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 0, 84, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 17300126657859479093, 11313920102849673527, 6346627796045519057, 7389299619274629431, 9262647006463201494, 12900235463952244627, 7852421498196750068, 1141784430625393243, 12150004112779528077, 146728085155958051, 1479007214074296519, 5326692900453573033, 1, 0, 0, 0, 1, 0, 0, 0, 0, 13417131057632658648, 13887354800197146837, 8609784525483513948, 16453892850627486456, 976357452201521805, 14650998861370095747, 15798952093464371291, 14383483119098647176, 18419038023611574318, 3683052509510392753, 12831965507313403291, 11464211275629339672, 1, 0, 0, 0, 1, 0, 0, 0, 0, 4507099831440932953, 6830877239439284265, 9097811782723336829, 18355313083727954627, 7779515141290159182, 15839592087462215756, 13604506694568008603, 14024127302218670748, 5952493440729260050, 4068297222526233952, 1979966764305086565, 9333200475194576798, 1, 0, 0, 0, 1, 0, 8357924686780715814, 6636884447613425583, 9624380725568248686, 2880287348195737852, 885106567500324074, 6448875554992341703, 9855604354502581698, 9375523715508471459, 12339746387209375629, 10455158341094955823, 15902189126849452967, 12030315950055306153, 12641257084941861137, 15957996139063952329, 15783553274882271383, 1, 0, 0, 0, 1, 0, 5347236343958253894, 4025896570838415692, 14804406762588016934, 182667766089555833, 8746225101260903407, 12800409546363710287, 816655693375320760, 3488220768045884341, 17449960788520479876, 13060006746047445404, 4590648600733170196, 14869579734892957539, 137356745712127171, 13422659882759208113, 2676688078772673635, 1, 0, 0, 0, 1, 0, 2921699901762625847, 2649189506073489962, 9913373798344930711, 7755498383134197376, 17631069913300146763, 918789106343442195, 12710306366297056980, 3352461179293085611, 13949166093507073033, 16957002236887535634, 5578100969514402869, 4043905565383364858, 7659576686417292817, 2367890233987709775, 8348028103004129201, 1, 0, 0, 0, 1, 0, 10172794879368016270, 6345331429530820033, 5837950612071262866, 16650183950518877881, 761183529886498658, 882392762205142966, 10341241875528441727, 10625329717419136765, 9971095066673234358, 4232004013780299993, 4126250918613430195, 1352790980003480299, 15265846796546163655, 16214598491416624701, 6270582476047461808, 1, 0, 0, 0, 1, 0, 3029040881537747494, 16192268821146642419, 1429264540499601619, 723722855549182307, 9275648404607992275, 7653230088222442503, 5336572895513434476, 17267978825783635674, 2055211161196684150, 5382467524735065973, 17562229302921943767, 11689925804137528317, 12333395168151976785, 13928209897558581843, 6382294855606512139, 1, 0, 0, 0, 1, 0, 7880496552213312201, 15122758161943386192, 7696912976710769683, 16684832919913645113, 1325781221503242261, 9767481056214686264, 15383255957179010771, 4765175578813598212, 352612095018961168, 8164700351999240448, 11366624484197321797, 14418389432583501516, 5429053278517118996, 2079377923041037634, 9248817126035377137, 1, 0, 0, 0, 1, 0, 7798482983966084054, 9698350464160947514, 2622165840457703741, 3191144700364674222, 13840521809458223850, 6693472114669876018, 1844850377219340954, 6041824929233084189, 10694505064011226265, 9837159640677247471, 421241411507411802, 1387064907365996610, 7160690172588878117, 6170204562255862519, 11691591530451877345, 1, 0, 0, 0, 1, 0, 12784330368443191752, 0, 0, 1511701347894443705, 3195625100455147555, 8197728783207379545, 449202167972758168, 10429619634413714415, 1266474106654512299, 10043612818557622726, 17546950285193103331, 17459565798841957386, 1545883776729609444, 4559076489231806387, 2919974393045314777, 1, 0, 0, 0, 1, 0, 0, 0, 0, 14541231479059008872, 2573517030855683796, 3524292720580177308, 13855152767270114589, 3006044390476483944, 594411982442348353, 2707135781132813285, 7980470443732427589, 10692471325161091019, 16152944287821214660, 16000995173627170117, 3599288644418559718, 1, 0, 0, 0, 1, 0, 0, 0, 0, 16401658505261312282, 14340768500784081639, 9157399410194868857, 9102901647434269728, 17796618941315046862, 6870559696376279126, 14430288544136295714, 11256415914434052793, 13509056984869078243, 16212533703602772012, 10731537818920783986, 9244614718938709708, 1, 0, 0, 0, 1, 0, 0, 0, 0, 10956055287997745079, 17622456621764780147, 5455165430251125445, 6727955785885619519, 14753857082920611668, 13906110808313848802, 8347093488770218639, 8918883692704710750, 15290172371351697411, 10523129087658444171, 15727241650811717280, 10475089196439845505, 1, 0, 0, 0, 1, 0, 0, 0, 0, 10403713768525900847, 2139411523427040457, 8515917035379853351, 856023126862020256, 5748739229791737666, 3971489439724797398, 10156667480279311531, 10471841795831116097, 4161518306931659446, 14664557596733629071, 10457686661281861787, 5372530612210116852, 1, 0, 0, 0, 1, 0, 0, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 10403713768525900847, 2139411523427040457, 8515917035379853351, 856023126862020256, 0, 87, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 14973522761191262497, 4230519249120879894, 2629183259646768977, 10141819052260397061, 13407203767006087071, 12300175896314074402, 2702373535953719449, 14066933458796711308, 2220020800002954405, 1153376321238519426, 9501912115787530137, 11467779250790108687, 1, 0, 0, 0, 1, 0, 0, 0, 0, 17579142101067141791, 16331511478156948621, 2536845301555017815, 4655744751626348560, 1315476336364332532, 12758262197074716778, 17888512728802654414, 5454338212767341777, 14616265448064819190, 4049834289657867128, 2177315978307888394, 2010382289454711711, 1, 0, 0, 0, 1, 0, 0, 0, 0, 12664267918550820934, 8493562230894032491, 10885506335001351491, 10623508799881057302, 10765360003981902673, 4842275562010620878, 8656573021603208590, 2450260130765540973, 17667697651318069254, 3544163002330957814, 9007165683524157049, 4518865977780754525, 1, 0, 0, 0, 1, 0, 12821199281659850615, 12524526780064226282, 8688367803817133517, 7111709976940449855, 6042875499671257036, 10602803306945095136, 18053244771098668210, 15869901507286010642, 15765124758947684257, 909769595464630286, 9984901127103118556, 16104234613185942963, 1596997669664652458, 3285629071226892513, 5254177489666731166, 1, 0, 0, 0, 1, 0, 1319022057496410037, 6723956385664361856, 362758946504872978, 17945942309272171171, 7547510637898886664, 8389575157731885000, 5432655503035172224, 8636630472484196539, 17112531070480946597, 5597227622497427759, 8296183404013335152, 8448226142379838282, 9123809571274586481, 4262155088312829534, 6352753764020113838, 1, 0, 0, 0, 1, 0, 15817353186600079517, 11896741780081321151, 8120557738706811421, 1514840266710990643, 2518758362364209964, 14494370701341234363, 18160488913248834173, 415225714783614736, 14762958776895421659, 1582837024273971615, 826388124734417268, 9723851761924399417, 2904897680946636379, 572660879606393944, 5062575418735094728, 1, 0, 0, 0, 1, 0, 11887745873838856200, 11056257118819520017, 8546453177127819509, 3906777862244807614, 15967237477862396017, 1240858482343082944, 8886870748754950786, 15806110295452780709, 6486381282415609829, 16950387463813522784, 8577643233130284288, 17768236078519772738, 217872450018257683, 6293942954387886585, 10974892067682463496, 1, 0, 0, 0, 1, 0, 2581007320496406744, 7054105961444862624, 15347768076097298693, 8125727413083423821, 10805393644723323985, 13586718478006757236, 17768197347468566879, 17280093366403031105, 635835674863826303, 4568185472217893804, 9296267175044089272, 10337709963460435554, 4440112583501734927, 9729481707513785664, 4743006626934706100, 1, 0, 0, 0, 1, 0, 17610297678684695918, 16364115285854473865, 11595150248116497643, 7035439775474110251, 11847308316956964837, 7889458920902982286, 11305368688963866992, 14287445400250554900, 1893961912880033900, 10317967923286478317, 3918181922279376301, 15000492392148830533, 7931144489554367364, 9476759250402767950, 18270644106765218282, 1, 0, 0, 0, 1, 0, 11532830003582511953, 460321325058925628, 12709513064174486630, 6478715440156951267, 14089413401266079358, 2281022494971066801, 3378217915115563837, 4838851040494198977, 11743317019648187379, 3359761112394096597, 13620706797177850518, 3438335644910777353, 2067033555957484299, 11784176479463653422, 9418905686906839178, 1, 0, 0, 0, 1, 0, 17359699556169412381, 0, 0, 17848865035999698302, 9363353806961732906, 1059359355271114718, 3722579262469999737, 7401377741210733980, 4394776823738550294, 17911331326024175702, 14231054337850845953, 1567229020978754366, 10965059646087563007, 4717306534304214129, 6160606101751839399, 1, 0, 0, 0, 1, 0, 0, 0, 0, 5210262791539000682, 3231850662476970044, 12242203768226360021, 16352185264854542792, 15126409509795103366, 17462025488896312666, 10962575762908536311, 16737021171185522127, 6692618053949882379, 17172828881706643966, 14646740046786928565, 1663831101883973254, 1, 0, 0, 0, 1, 0, 0, 0, 0, 4908282038977879385, 2701244722093391429, 15021286664224332416, 10534803976436280037, 15876667595247308635, 16333738989139894331, 1581145115862775994, 18250779698217077450, 7155162361709676048, 10303228755363253440, 4300281072628271246, 16497484699945471993, 1, 0, 0, 0, 1, 0, 0, 0, 0, 4313772916158122500, 2902278358899028132, 254766801126374444, 5671561640468956184, 4347645646061943576, 1998087227139787801, 12798150249100419438, 647551028640823116, 15480041353865470488, 13024601617472109101, 16248647525361276326, 18146087632373782831, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 484349804684265665, 6880098633847640351, 846980218218532239, 17903889365796795298, 5550459936565271753, 9107753202341829570, 15324484398676964645, 9257266254418654737, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], range_checker_cols: [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2187, 4374, 6561, 8748, 10935, 13122, 15309, 17496, 19683, 21870, 24057, 26244, 28431, 30618, 32805, 34992, 37179, 39366, 41553, 43740, 45927, 48114, 50301, 52488, 54675, 56862, 59049, 61236, 63423, 64152, 64881, 65124, 65367, 65448, 65529, 65532, 65535, 65535]], num_rows: 128 }, last_program_row: RowIndex(11) }, program_info: ProgramInfo { program_hash: Word([1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209]), kernel: Kernel([]) }, stack_outputs: StackOutputs { elements: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, precompile_requests: [], final_precompile_transcript: PrecompileTranscript { state: Word([0, 0, 0, 0]) }, trace_len_summary: TraceLenSummary { main_trace_len: 12, range_trace_len: 39, chiplets_trace_len: ChipletsLengths { hash_chiplet_len: 80, bitwise_chiplet_len: 0, memory_chiplet_len: 0, ace_chiplet_len: 0, kernel_rom_len: 0 } } } diff --git a/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_06.snap b/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_06.snap index 31dced8cf9..4a91b413ab 100644 --- a/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_06.snap +++ b/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_06.snap @@ -2,4 +2,4 @@ source: processor/src/trace/parallel/tests.rs expression: DeterministicTrace(&trace_from_fragments) --- -ExecutionTrace { main_trace: MainTrace { columns: ColMatrix { columns: [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 33, 33, 33, 1, 65, 97, 97, 65, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [7458506668679174706, 1032, 8, 0, 7458506668679174706, 5598651459581075585, 8, 0, 3358534066525179769, 13620833136975709089, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613, 12752059346458920613], [18375473735916206629, 0, 1, 1, 18375473735916206629, 7804753453550466256, 0, 65, 9365253138981608257, 2256486347761721492, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099, 18135096529078946099], [2105717247508690050, 0, 0, 0, 2105717247508690050, 17777748786253636403, 0, 0, 4243893038989355703, 5193960644663470490, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350, 13200399719329805350], [1679902783560062568, 0, 0, 0, 1679902783560062568, 9435312778805252724, 0, 0, 2372900269115514267, 12344784587178360875, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526, 905179285088193526], [13620833136975709089, 0, 0, 0, 0, 3358534066525179769, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [2256486347761721492, 0, 0, 0, 0, 9365253138981608257, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [5193960644663470490, 0, 0, 0, 0, 4243893038989355703, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [12344784587178360875, 0, 0, 0, 0, 2372900269115514267, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 9999, 0, 0, 9999, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [9999, 9999, 9999, 0, 9999, 9999, 0, 0, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2187, 4374, 6561, 8748, 10935, 13122, 15309, 17496, 19683, 21870, 24057, 26244, 28431, 30618, 32805, 34992, 37179, 39366, 41553, 43740, 45927, 48114, 50301, 52488, 54675, 56862, 59049, 61236, 63423, 64152, 64881, 65124, 65367, 65448, 65529, 65532, 65535, 65535], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [7458506668679174706, 11091832976040936962, 11629723830403400020, 18085092721393681494, 5334827122981806215, 18131418839636252978, 14614347609195626268, 8910439294593611592, 3843332007587847712, 1023179011544432384, 3804737116729640404, 133391072621725577, 12470388296134501021, 632583774013957871, 4078804678813269002, 4646445037357820970, 12451999842825777859, 10348876437499804673, 4709521304751214351, 3818143376057959690, 13735545676744754358, 5911009352187537543, 11554714135033312948, 9410850814958744902, 11602211351055880832, 12661500893159548834, 9684778724196116231, 18082132319471479459, 5677068088590394277, 13067481717060632118, 17366862825980504064, 12752059346458920613, 1032, 10320, 13024110921086730221, 3587442816163675215, 512402747638547729, 9217956011885162917, 3925750957223009950, 8674177413178223320, 12846799727083908462, 9116601283268739756, 2958792353189815054, 1720195204565087693, 7696852080146622077, 2890877729556257606, 16676527939404087356, 223754558788184593, 4767414622778376421, 14072300156908432530, 16856861612825314654, 11910434229443384600, 15658716527747040980, 14322127566252286435, 4770460127206402609, 10805338145914832851, 1391598300875421210, 18211456042978337510, 11866022853402812888, 6438324596032750504, 13328288515202849800, 17331158106613184460, 18344276842462151560, 7458506668679174706, 5598651459581075585, 644336023812026221, 13247747688876077858, 18204236545845216971, 16083593158731167399, 4357419437649084221, 5464680208294216350, 2779149829283345558, 7975999984217399211, 3799311940445025695, 12287115722151291956, 7889055060352596454, 3871221682982067508, 16266218633314388061, 10296105519823441978, 6482329477820286957, 2184206139900597012, 13275897735411980967, 3045004919428473516, 16702736287849627035, 4028816571826363002, 15011221569533006108, 2864985628223798368, 15475498524455915389, 5364573001665328907, 10397611698676440611, 8883008337890476036, 17315153826736218240, 14581052801302714514, 17999554639252319772, 18022889162320300611, 13620833136975709089, 8, 80, 16253482711025978099, 16690839578921925157, 11755424915479552417, 17934377671577204140, 15509754874715907467, 6426721221030580337, 11049594146888643723, 14912334368661229147, 17657273147290084056, 9105126057127804171, 13430225876739607206, 3614830725909060912, 14569284676797348998, 4705513459362295944, 424917224365117418, 2835737623710330612, 1964100172858915134, 14896843043547784767, 15482419984058848245, 18437547705335910066, 3162257106529980441, 5297995970636059087, 9661978795293871188, 10128143329575104151, 770728251595531533, 9782965673735423214, 1347942901513492691, 12086966446141742548, 10239457018222882008, 3358534066525179769, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [18375473735916206629, 4371092720588693207, 7555819500301263096, 7871576915936585054, 7738161198426062879, 4439752770537371709, 3239157867226066300, 13695428956813660853, 8114913103795360695, 3271513559100018830, 1227622944719103238, 17840970837055628605, 967816437372899090, 1525132029610696618, 8930953641447820548, 1991652128187274521, 1878310895470329371, 1537331530871119668, 17179845365129498366, 6628846356810584866, 18158002788694963974, 8030209565693857269, 16465976624819029473, 15848213422225602213, 16693748147017299005, 15158850031902933967, 18144229372703820177, 8111553228231189401, 420461259745383997, 17094012225747072853, 16556024871956851478, 18135096529078946099, 0, 8256, 1131208899036558480, 1667157010810320250, 2053960715201569301, 1526213270499333709, 69813565043892453, 14925652377538846871, 1380252317064967448, 9902934070223067140, 3786794161520721521, 664031068804619792, 8470323998416702977, 4965297830526000942, 9404280000999464502, 8244737495337250711, 4784363486033662704, 4680481291290566437, 15373555507761845373, 8780119261264514018, 729009684537575982, 18306419558979237700, 15407410920890065538, 2509966126115291236, 12709897403480972846, 11498596868429821859, 6606875518512322314, 13880694912200059110, 6972406840307481976, 14148490408465275064, 2917966740410115114, 18375473735916206629, 7804753453550466256, 10860407685663036604, 1563629168745730928, 4862512017968946683, 1035294938480129016, 17121277837906333314, 7566123129055455762, 801761918673301233, 8221980324343257318, 8971289227653573810, 14503443403830829887, 4403991158284421772, 3539411744559999519, 17877470569230350231, 13052305487168984918, 11988250928057152362, 7990654922366982189, 8123717249091864283, 273044411934894184, 12617346169478402785, 2083501518846346052, 1182260721753268305, 16655426125402668777, 18315976927222050841, 13684207927534177805, 15562831278015850283, 7777530579170086866, 17762371058211819624, 4106083518382761605, 3917672276375751396, 667054191578263747, 2256486347761721492, 0, 64, 5751576643258238090, 7830268710878889486, 4868320831660690795, 7042762868047858013, 1028615964620729689, 12270587957620579653, 7267371538363991280, 16125626865182516658, 16950134439933558852, 13427183447069512151, 16117382505273595827, 2222792985740553749, 6517696895688418945, 15516128650333221731, 6357034143715229949, 12960707821770488929, 12451444460344609421, 8786747128188560390, 7634329044629047826, 7741107824034642016, 10975559322169081956, 6007758954686348362, 13971256108093330407, 16868860295450858142, 434120282701603474, 11571634562637977474, 5581285869985960561, 6581368197537384623, 17661012293298952642, 9365253138981608257, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [2105717247508690050, 7371349600976768903, 1908428216714745226, 2226486931669462500, 16096322966046779578, 5448090446075942959, 10098429045835473018, 4809915777199041455, 18236464326626014645, 2690803580142520255, 1917959726470568181, 7355089244606367886, 9988016662047687018, 6075081950126577031, 782991345573128788, 17727121868432118686, 616586521336426688, 5444667365009856158, 3285592017878659318, 7931583655659423496, 6385821061540880880, 8735792590442216465, 11893401421408965, 8831024347202442032, 4451634306410080384, 8173507753862756681, 15267089652751109873, 10164019920559079526, 5461641667913740527, 4977882380646661156, 5148753722704728721, 13200399719329805350, 0, 2064, 18136552782870868471, 952274539956745973, 15933282259815262093, 9924516287334785738, 18064603646801610993, 5114527609957824263, 11816233963570869158, 17699527003452380450, 14533708946479200173, 17484213571014188868, 832814531422633701, 1508169308733590908, 8423043379628164525, 12595277727969636921, 14226276023010866965, 10485112285448962747, 1783527593060720204, 10145484005384627580, 7463752398658534839, 17345550819494003223, 4432309123412733588, 7086318781105575433, 8830891075082588619, 310185093236608634, 16683125300631590273, 7786799186167080425, 29465347809991832, 8090161351836983773, 8665315444141111469, 2105717247508690050, 17777748786253636403, 12906637371964794665, 9477262435683869924, 9199231093019338048, 7358751435793575899, 12569972625839259527, 5847320563034378965, 7599987891632365696, 10432134440683583258, 16242679258308055777, 13780789328607365793, 1153491566876700606, 13641042641136958279, 5969854971149325760, 6340590356564925801, 9771444654514086827, 15776260062082886705, 8278469467176979574, 16237604982476195391, 7423750977119185664, 6710003146178124596, 376186270665682407, 15539788083889931684, 11273188656572444234, 5199551304380116153, 11734010025122035435, 3764388601356982695, 11644487560172946408, 15563655808705061071, 5533608926617884295, 14514898346462505299, 5193960644663470490, 0, 16, 7110029021941723513, 10115409991715085575, 11428668827299215140, 4015039023438705588, 3732466887400149035, 5870841944205588609, 8421627027326523148, 8231214549142439222, 10318470559229280016, 15171283498151438808, 12477430934852872037, 3853779543897991795, 14662750186533371679, 7423988381383082226, 13549468426633458145, 11079168775731474830, 12471207782095033761, 17595325414333663547, 7042468264080735391, 17650115337646869205, 14946074228061446423, 4655654314239637986, 11187552516160183253, 18115881480442018545, 899748567092010447, 14020868337400209874, 15417366235984526759, 3331301994171189600, 15814677761660135474, 4243893038989355703, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1679902783560062568, 14926961084296668554, 18296820143542754124, 5759648439566973806, 7690180744863199464, 6255055536007924620, 9967438444965419122, 6053822608871655533, 3970724348518176437, 6498891217103059128, 10341231834356228091, 8497160540604180804, 5144558705352378414, 5437844264442299443, 8712431777609915948, 3915629295644008966, 1353567482375898210, 16603575236790899764, 17009424079525297171, 3253699369098499458, 10648493462065257860, 10940203220400825059, 7261956826490066834, 5730064365163707705, 8826144244207679463, 11688897202604808409, 4559302720015817859, 4402707951554525697, 12375228725744876260, 13367890413392736054, 15438373163420410642, 905179285088193526, 0, 2064, 9594118340025725004, 16218246678075491818, 11582919835122342747, 5661452934218108707, 3714647928422746674, 13689184893219719187, 1899963197709801965, 8313716591368695784, 17822645741084942000, 18354595702287703799, 12620512717427217848, 10145637708639089787, 1735222492513760332, 14681927838838900060, 9262747238997471758, 11498487923782501751, 8924101344488972446, 2592517964915386184, 4276681409258176044, 3764365715267793208, 3120204268813370353, 6019260256544801113, 2801984351776029768, 16979166255722313516, 2813750347113564525, 16588139065369475399, 12012198471360912693, 2492059183640657261, 16968938268466755316, 1679902783560062568, 9435312778805252724, 12594665258064570661, 1586451078180607598, 9325815886784366656, 13163107377789060321, 5998117226166788975, 7008390784506277276, 7362390315901265787, 5188984820381727203, 5842708215320867131, 13553650342229414448, 5955476415838559193, 8725164908673674579, 15174091024100472501, 13637649140457772157, 16186415272190469176, 4473737633571089105, 2032050757569801828, 16070334483916823186, 7382925316452200710, 7820237015849984079, 13711104951459639694, 15277864807184951074, 7746677489393361812, 10897962020578390602, 2459478953251166639, 6142067256785271224, 1469990404519833898, 14737929225229310854, 17685816709290022661, 5568614684720127113, 12344784587178360875, 0, 16, 3208043314804619251, 6920597847411412414, 17985619796195836408, 11907191178709112742, 16377455862733420451, 15572876043608056600, 9466912758182965715, 17480763791598773801, 15029113851915312964, 1953587265841775225, 7175742902791404624, 6820764940134875350, 16069841829669607101, 15548451706938320654, 11760680638795846495, 1560700914733041660, 762367990279432470, 2603436428456411224, 6200990949184863170, 11673627333152839295, 7804486006334068097, 1006207264024395366, 11193609705356653459, 5704515878100803393, 14918729158665343812, 10658508130485449873, 380737719356524599, 12870561906904032245, 6984680585936259437, 2372900269115514267, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [13620833136975709089, 1046930547281056921, 5022880593775506902, 7356080910092118039, 16589884839242022257, 8919754405551141869, 782951559730000700, 4320210530167177353, 1189869440416317038, 11509478421996896286, 14131663596834904750, 3063592889799439815, 8310309385140170305, 9794866582382956591, 815213714413043438, 14909022885730690459, 1965134134848901020, 8569284627647542389, 11756365299450742783, 17765218832065923306, 17214386397833253270, 8857548797279425296, 9589793731564825353, 5744303806832189345, 9245523889540971217, 17743277714115543370, 75478605149737153, 16642733757618334231, 10408597074326334289, 1854469405851562328, 5120877191992423544, 6125088443291536169, 0, 5160, 1190658701913535022, 9371121588404883743, 7133056533056999470, 7380100170229652082, 14719783382686670107, 4693530971176924881, 11125714198188567552, 2434816259070577714, 17927785478103501878, 834873962620943786, 1091858408197145201, 9293176204765248193, 11318806736621162148, 979530496520387452, 8328113718786640843, 15870139479256453021, 7754853849459016697, 2742936430580983415, 6806060556807781604, 5089080673677611112, 16430235900965466453, 309743103212430298, 15664803780047891222, 3113571524475220627, 17862871362988443440, 1231393200801541530, 15779352999894925288, 6026600320279882336, 6970552753544824994, 4949154992619464010, 3358534066525179769, 2539641719046213719, 10199880931320172189, 6982964906206022277, 18160468829511284938, 13459748022261389691, 8540403463779371619, 298971077135778992, 9448428205117043728, 7211550496031219820, 5534997352008564058, 8961849300614763067, 16471253951712069551, 11996630593586982068, 17666409503469399853, 14743209389502972128, 13621451519455201128, 11693451034972088239, 376126037836000660, 12412096817616379990, 866468160396608077, 16487331493773223294, 15132792027965031247, 12005877568613345660, 5222840910814569167, 9174906967528115515, 12806387721803954058, 12420516276683200334, 8854457266879028181, 9558115804602486754, 6487880825188915613, 2384716068805359876, 0, 40, 18130890293586930078, 18252951749527557342, 4460903658820341507, 859505755654562117, 5961685480015386121, 12134776249586726543, 11174658189737631113, 18385152961050631924, 9881471501704199804, 9636744945302995714, 12323181865658998064, 14903454669611502952, 1490539036394497080, 11688514875590095153, 16093513520259190726, 7731471377060742735, 5247500963110975116, 5269361527156951110, 13733877647296302634, 11865469401112846356, 7643242142337524006, 15572658687280648106, 9345628789826937825, 3291248301730279223, 16808111015808513609, 16274730253017522022, 12243901590027926887, 6559275936659510680, 17224785255700525855, 1390310476158884261, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [2256486347761721492, 1399831673864751627, 12438672130810751909, 10240118010240816453, 12454995736750842450, 12272610174663972685, 16716772686788009039, 17679411248915786729, 9344021820453066790, 15548275238570617018, 12554227251830406338, 7982818396816137943, 8298623838207759766, 9667670442404470529, 14730751205912092663, 17475545646146195192, 7561186990159804961, 3352703426322824443, 11124655848983105243, 7361271662241444721, 1785076194951656280, 13323648175345935378, 15598576959546342188, 12701095265259304800, 3219799610745612107, 1555585114147558761, 10397456717804752138, 2319272066426069991, 17926066510128935923, 1264814027228690376, 15123699931666188121, 2665390174743669239, 0, 4128, 1352424102745866255, 13301242752201603536, 5420135027930584396, 17078794493496835379, 4779811836607866048, 3650219859599657886, 13618468821889769363, 11429589192023659923, 8853101337885331080, 9650238821992519861, 14401087967309285252, 12035560952634921032, 15407186837043713393, 15711028160746246110, 5396976350889627712, 15903424027416555998, 11304777107657759509, 9857843669692965578, 12605480788735099613, 14618970056708743810, 8493993205782554647, 6059068631740368787, 18316971448227884023, 12499808993385025318, 4210674244211222629, 18405965507148502967, 173097048437312502, 15568437290332308327, 11532601739151124629, 10000279862191744493, 9365253138981608257, 9113412038486870510, 12237115836192970750, 13532373892635206986, 11668565565569624948, 2114739335810906841, 16845938989106496862, 18053472495070906903, 9578952411771586845, 2253954535466549551, 11957330595594263589, 4327169169737696049, 8097241277176222682, 17499521208876685046, 10474171567958477310, 2884885063912824473, 9389176041985146128, 2067286230266639471, 3365016398014065199, 738171567486888734, 6622135657383660119, 4978858449337102663, 1252098561428724852, 813491835360077960, 3026073706021528936, 1157174472277816506, 8848575890036236601, 4801870550462804365, 7028466390812097322, 8403721226663073636, 8970732296705167988, 12459739889109502988, 0, 32, 10452764368937945515, 6969997263492352670, 15570786589164252178, 16136993048454358354, 16378352067056606124, 11747573379431147483, 12296464969648251345, 8155132212936940581, 2470200969414032680, 18126939303114916528, 16736276280592238734, 15549342782445497049, 9033882039108268313, 5121596298161079296, 14336897502470956191, 6301009824137139871, 16614860627935231068, 10383378433371415142, 10330363517752279308, 10937466001850040595, 16305844076412050396, 7189713532379018536, 7568236447715590536, 10805187342082326609, 7424874700566577356, 13861219118264849665, 7052270251739242825, 17586339544079318164, 14071176523136369481, 12282546735285148319, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [5193960644663470490, 18378615377082669582, 9942094792989095510, 18239658104155677632, 3247221802734244696, 8138145110381489386, 8305898108846284300, 4495835739545312127, 13363880742094688735, 409501507955448067, 9615046049029083973, 9226283480795415930, 6188039948757326954, 1925348622523205808, 16932487676782686187, 6461440512631901369, 6379521145060545439, 1135364094435597517, 6898694641523826133, 881111998832614715, 7852757539889945333, 8831210118957475983, 15508177777761403707, 1274251095252206369, 6462015026972174497, 14758961666322366163, 12911489632740586743, 10573355084806673526, 11042755251558401992, 1655214279385078584, 17558359767143120899, 18009389558374812227, 0, 1032, 4798141223555508282, 12962488577647927717, 10133257770726709126, 332864556927106185, 12116126881643349994, 6604148216925166409, 101015634312276042, 15934992137290074922, 6112274855072540816, 17762248064501548615, 13166189948742588777, 270100349969833402, 13485211244653928073, 3502306881032295169, 13607663468974078519, 8883940618995723208, 10623667092532612652, 12293715092576816840, 10386976621364522928, 9128135834925108269, 15731443845270647366, 13373704167654916087, 13746187061551926812, 11684868053863796759, 3258729720361659960, 10434904637843727165, 7034851303745741351, 16133345873308301364, 5426492436527662130, 2980140658145787783, 4243893038989355703, 8922317147540258079, 15524901873579080579, 14961355291644520251, 8912131487655833337, 845467818172067610, 6513419642881984303, 15821388348544564061, 918209442918452849, 1771868273093277971, 11088759444000251587, 15710903694873023395, 7739199555620722590, 403122127909161589, 16794196935209020317, 420049465494673582, 3241180689003955516, 6815831073966054431, 13165955590245083084, 3933813014659210303, 7891509834730356602, 14572658037405460796, 18097121197159342726, 15303933786232509118, 6355852571927224576, 5965705308661034968, 3878821330615144039, 17609259256248013285, 15839551803056895538, 2863101478933748100, 6867483661888889167, 11007533278239168078, 0, 8, 9114363797835460134, 5446076396314160376, 12863008906537145423, 10008421878335836436, 9952321233871043669, 12872379155893703237, 7266552182027361169, 1266036355585216796, 2621902104176569009, 8791105532651972211, 6351975813451610601, 11821139808280113179, 11281913023757770338, 3277134497757048289, 13219080767636598429, 10181825490691565485, 2766637533497216499, 5527857141123489970, 8463471033597650592, 16863468430858262436, 4521466714741486225, 2112404415880305855, 6776665887355979100, 4283028800297139078, 17448147405455891940, 2672696094870261596, 654959311657763753, 15404879372302137522, 458610335793450516, 11708893791522292939, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [12344784587178360875, 7525588297109292118, 10242077034078069399, 6920809802339641674, 17643499204383222535, 16688592460292823795, 3252667668159125426, 6639040797936707465, 1827636079652666195, 2462138615393893213, 7273091941301037907, 7777539981955361461, 17791722127119122070, 13941030348836860953, 2461265848652382458, 17178103242399629259, 12982591110459702249, 4311636691398707716, 11830890166127089072, 7160199109027716330, 14107503556614837834, 6316368550299988901, 12988322271117575851, 12500666959478542023, 4763644307980385379, 17502332825869685988, 9045450374393109306, 7379498771612731567, 16568845003086625163, 4695178656129701184, 1678315832465296045, 15789153556893733830, 0, 1032, 11702782905971311743, 8115486282645452027, 16425371230714077552, 10333496212804492507, 1572943607289284437, 13244361396034453954, 12880029163967100393, 14716450796809578181, 2618965885956593171, 1606019581379521796, 12562170441304287563, 4599116799417823473, 4257071131168813417, 10446583017549019711, 3570388907037362614, 11170081717188072664, 17238997244398394333, 17231192964516960933, 8123337005847551087, 7060091366977384949, 5719725530909274667, 5057603743378325948, 13848013489728729143, 17729739340387068117, 367186060507240673, 1411195984452924204, 11088333491201093194, 16575090776691519559, 16147396598096989679, 14525300817521856881, 2372900269115514267, 7638869850317184909, 18112581651832813996, 7934301823485851614, 13134589595174512908, 5143267856379088965, 1385332020236631836, 4877336193186145990, 18193547062192211825, 4615765459892113834, 3381950137508436504, 17429784608409914678, 14977580224084415767, 6849317271519196447, 5437598344549503419, 1906047363049945529, 5004054537041877249, 14661239785476454049, 10553785792947774039, 2119915982392644589, 8985292275604857439, 9726386267280827154, 4505582310884934806, 12912789541737329022, 7115507662283435621, 2051190405167774802, 1232238311229055715, 220176432091768973, 5422499495491255741, 8009273299237215820, 13359803287975487032, 5187224287159924757, 0, 8, 6104172690014223231, 3119855977255645286, 2700229040680838768, 4228220371303630837, 12976691418076017877, 15391527008624099592, 15522155400452634037, 17655908650961725957, 5157987610310047621, 13664486701019622043, 12908699189677656287, 14840926611057477527, 6092037682822283700, 15181448373122947619, 2083722204849270202, 1893419523737526751, 11329911669537538562, 12331432886354737271, 9636585409664050258, 5131588463040403759, 10248116973079783912, 2136665268102207704, 17448444978654544666, 11945433761064128885, 4462464721020457233, 17579935132869425842, 7098417589530391109, 15343623253038912080, 7762335122892638892, 10310226363807226654, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 4046254507773998773, 6534480484041428863, 3251048018398498863, 14672293546278713057, 16728924149188845306, 128728647106458681, 14226927580887823496, 8277248794545234814, 4354566838645069185, 16178613916401188944, 5304102959326456112, 9791457517463513797, 10245170831782510809, 11611317382660466625, 13569694221132024345, 16005837490233273516, 2791259658093074998, 13441513594234320689, 4241376053954359578, 3545073666350874448, 15186107276182512091, 10698815982870498162, 10971920968668641865, 9145865124167298835, 405811361541120846, 9884965742324813117, 2876689281462596902, 16445466086575260512, 14688957924306712254, 16306354913676224825, 16604794485775028126, 0, 5160, 18346837778669738664, 15130142357101091527, 6726588340010678615, 8394319278312203283, 15942424551308612685, 7629500615465222065, 14939877513325106589, 17048523965011794048, 2306293645521445312, 823113708878672797, 14981348226783328932, 7432878333905782051, 3482639998457803800, 632277917380007036, 18266437030920184246, 3366715262389109205, 5280275432441977334, 5379329043314533811, 13912213856326486056, 17217059915921675075, 15634373017412823086, 14981257187297131103, 16697350900700022325, 5239234081629986555, 3229291246709926782, 18373224696258292584, 6771862800272250893, 7666370275789511263, 12942227631865082960, 15190222347874856922, 0, 1061325914286080764, 9554433906850032874, 4012321235764609039, 14967212595115142793, 5983394632166978443, 5809835498849113816, 6561933873120105870, 2140629501848088776, 6712525834006528890, 5760623808290856282, 10552757613235067722, 1939309373056894313, 14427320366022536141, 8538471352201975220, 14188752564290255096, 7981877957758397164, 1148470236137421383, 11019464818805406210, 7769960423081990191, 14632278337044440617, 849771658931440922, 5632784009618830911, 5696241881348246065, 1879984915784172244, 16312530632323862580, 13300309889942581843, 15448409017348426344, 1639569934817636487, 17233518173045382262, 14413924905126977169, 9045462722956532208, 0, 40, 1560947813056021755, 6935064976442414148, 9999441144135002932, 10354700837586583171, 6040781227937012106, 4698117391978117444, 4735711626023545756, 11217844833019453026, 3130590714605394722, 2809204122464618686, 10935232469327759448, 18335893537613898174, 10868401885487323501, 15799177281014635734, 17187052562019754838, 4027411046406207040, 11879721967266924677, 3613659344771632047, 1846469577394958972, 14668357323201408029, 14939045883642543835, 2885718226990976376, 4969257074069595075, 10824274197210729467, 13212275138420405274, 10563919532671437398, 12234598862193668129, 14653607410806008848, 2498958194485300229, 3512215170452429648, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [87, 8072556154622677081, 1267311017976162806, 171317623411600853, 14846028244624432327, 5697605161887258162, 6090204166740560590, 11791493563989406548, 17428436932452366793, 5676009947455004918, 18345317182680976060, 18287702590376570538, 4985574569677261947, 15947076302058294771, 15533043966546096492, 13147369042643698626, 13830067522797295398, 9812515853737376613, 1153576568012481332, 6976086965219136352, 9332017051661502953, 11709096929003024091, 4784660881537662841, 4083552985517123622, 9895527598631437834, 3406650305555277621, 13871430865741604308, 2950941648901088194, 3993419962022258191, 6722743736070459606, 1297747773924291443, 15433589206667095645, 0, 4128, 6496253015800789210, 18063315295058131399, 14099326864720264780, 16744359797696928029, 11669954633423859445, 10923938539628559259, 10579480970462933513, 17315553376669597828, 12114095292572219189, 16129781670858537825, 67936491912723144, 6285840300661422802, 14359460599290704174, 7597471307904508314, 8469569990667894210, 9117246600999250277, 14614928058075190380, 13738364908865630160, 1806905237893315697, 261412144627674040, 8380596589382515797, 3809925330596605534, 1983199361335541287, 6337901890572878101, 17063257729896061936, 12690697575318882146, 3846044480011221270, 10729939698274680623, 5297971463863936522, 8671284646676347574, 84, 6657939908049969710, 5132111129018882891, 8232522030470930177, 2748555984042091513, 15852736438270791360, 3031910609778633238, 10165962755900271710, 16659854091479845434, 17343121214427119893, 854734865188827599, 16332742745573253042, 719106832906440841, 5187730385273117170, 5680967626748162975, 12443929595174060051, 6984107838208124669, 8017806737059891905, 3253255241682497310, 17244932564674349345, 1765857304688336746, 6104054101040517608, 16644020687030024364, 595269491299106953, 16831646467700047759, 6176340855571448766, 18004816485425051763, 4101389897636298429, 17541610204110287382, 7370145379849234412, 11764023996857035803, 3516218181999416212, 0, 32, 9302012295643728416, 424328237663665361, 17748121622218558811, 6681769685034042719, 10907932526941371789, 14996603190997478665, 13982878080104642188, 3336783822228111865, 7403528606603453519, 7309352233404946366, 11509327586943808925, 6803943428138467537, 12870260590513220077, 3798257798625653324, 15652192157997003684, 8260391000410661595, 9099897743400681933, 16067207775248165408, 7640841583197908852, 16739199083410292994, 1998275509994500625, 10688417071827877337, 16160081185811655577, 2725954513011781037, 3040692668058239811, 15097072321276989567, 7813293313258815644, 15261763399945716285, 2258772319189190202, 6756061023037720295, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 14732236349158007950, 7398379382324753631, 16529615322051348437, 17750754114621262532, 3376246851343252040, 16812742874230723382, 5497427090926806167, 10370890449220293026, 12072808913033091146, 3773065747435304139, 1433120707818296652, 12602993390877629622, 11873715535213483733, 13503968807830695383, 1548449854272693349, 2164072014511735918, 2051419284241394287, 7675966884444101274, 7631305566403533669, 9974196014981023153, 16049335883858064137, 2471757314515864029, 247517241416190936, 17714417256089308015, 11671008027458954016, 581610329922371147, 16154960330167538938, 5798502399718959312, 5346182502077854664, 14220066076326577834, 1379414419793409060, 0, 1032, 13084260837127404333, 4018109146681745349, 14498381569327145056, 3778421823029569719, 1344624249217908323, 3634653398484528177, 1428985706412758663, 11382569756632997337, 13894906302086601399, 3911680161282028629, 11467762927868003365, 10098326072301516020, 16073214466625742345, 16150512194511843089, 11525294274796193451, 15902507139806774023, 13926886722650908730, 2974304378722638293, 5274544965980948277, 9984170014312577610, 639485734140932316, 15088403650698955530, 17189134684458608982, 6515320870350778492, 7902492290152572474, 17310456195349246143, 4070136787975548901, 6345872167795009033, 3095930865537762353, 4232664728858134772, 0, 13425232862973212691, 18017734206314589878, 4362746362325529522, 5580595613883635850, 14186966130004258435, 12558944767443104505, 9400104492160547353, 10540307613825778005, 16337971251965072535, 10106057436125976033, 9544366711268571215, 5728567960549491041, 13778603290469351967, 16022817295707876509, 11816634839594428392, 1619816382417214775, 332425507059551196, 5638968861636104000, 13036766990591622942, 5135102707173364321, 10242389681667623919, 5777720311941164202, 426018854260317513, 11718167143057109482, 13648951505177506250, 14542650836653761124, 18018546562218872798, 4457636384061007994, 2416704573314226662, 914323423605581375, 6601699247185721889, 0, 8, 7519454690376123692, 7627104070861575574, 17604686071836489236, 14277148259130460564, 8312218486680706135, 8395439642754559152, 17307771294890409643, 9298206908486537717, 3027629924013931359, 2933551330348935458, 1450485994192951386, 8585052201707081835, 10624425952582111111, 16773523322999621677, 13337622149287916761, 17874287708894504070, 14164897610403484003, 11216401648549709020, 911970190394256131, 3202853507803349037, 14616902435260689479, 14924823153427050614, 4881022900440414264, 9723366934152472594, 16335725686098559697, 8087897843744270993, 11437013713086863200, 7627258546495067733, 18044191572661655945, 16490279521751489469, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 7484183127135320340, 13467318737723490903, 18417997150771375303, 7719389523268106465, 2784882046013758615, 12479320332521777529, 17052932344949276269, 10938440435726947483, 3905086412998728873, 15634495878209337408, 16923840111614250132, 16397885158502248985, 1407236965451031446, 7800595096011710855, 9403004147208138835, 9997729556720517342, 8534668514381008137, 9227268528750758459, 13403671598326027744, 4715851494578741692, 2189528202978614673, 8567186243928218861, 9297942977636733700, 12120305129322824184, 16911451126764050505, 8250812173422443178, 10259824399772380043, 14694981892968238671, 485814636516518185, 14546030952858743710, 17545164675990066495, 0, 1032, 15909096041365347974, 18432189660917429733, 2798890989547891271, 10768372030970716894, 5935807051329113911, 1259182408195029650, 16024750973514577255, 6103595041913569283, 914770550723164908, 5067028895751058275, 5242612139537538536, 13359135899043031769, 4430959127423856282, 16317056360529517539, 2634255659160911215, 15590656855559575839, 6832335878067392309, 6045109056629836176, 18146646330136390606, 6482705684632040588, 2770791364887326735, 7707774010999656594, 3401430074469265273, 3500862351024377705, 5135727797169111985, 14940852959892477883, 9633218853985087472, 16966092255533854383, 3065488485208441055, 15703076512693482766, 0, 595597012989057195, 2376871353626003378, 17667748366842763551, 1405929090442079600, 18135181650619726914, 7403637996862883832, 5964686311110162804, 203041400479358567, 3387955851036204878, 2169976152805477386, 15733337581560247916, 7104142523828512918, 11829327565897640936, 816639760928622921, 11238339345191818453, 11391625709863387987, 6031165808075129231, 10104077332067730329, 6839520087480516521, 14155312441647748702, 4167237297971124611, 4042518115334572170, 7632437875765360091, 10425826042851550943, 10797236500243700589, 17846423932362838045, 11994705126716395168, 1154262141907751651, 15744039038114735423, 13449385390195333360, 16051125308748956016, 0, 8, 17781582622500481192, 12847902632736061277, 12021499907877242591, 16751519355106661703, 9062087890172095618, 3834953580385337540, 2969703856153678454, 11604562295556139307, 10447912046373566534, 12987934619706800857, 12352596220492768030, 14816150974992525275, 2172600571554701126, 18086375044546604023, 16313093185369681775, 14997664071320688070, 347950016295486690, 9206182676441692601, 3566552483989599402, 4925983231752336365, 1728701557101400581, 7087476601458867917, 9759961360999781392, 12569092891286895547, 14206292953735333262, 16422952955631166803, 6294107725304445883, 9537940691512987143, 15535806100011306333, 7080716573279759555, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] }, last_program_row: RowIndex(11) }, program_info: ProgramInfo { program_hash: Word([12752059346458920613, 18135096529078946099, 13200399719329805350, 905179285088193526]), kernel: Kernel([]) }, stack_outputs: StackOutputs { elements: [0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, merkle_store_nodes: {Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571]): (Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350]), Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350])), Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484]): (Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693]), Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693])), Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781]): (Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874]), Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874])), Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171]): (Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361]), Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361])), Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815]): (Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305]), Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305])), Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689]): (Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195]), Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195])), Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362]): (Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063]), Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063])), Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848]): (Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661]), Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661])), Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352]): (Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829]), Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829])), Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444]): (Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223]), Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223])), Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386]): (Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388]), Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388])), Word([13190842942618341421, 17548956981569849952, 15418963848144418856, 730733050713174879]): (Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144]), Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144])), Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874]): (Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675]), Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675])), Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594]): (Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115]), Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115])), Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809]): (Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257]), Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257])), Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777]): (Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555]), Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555])), Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509]): (Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882]), Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882])), Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725]): (Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979]), Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979])), Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134]): (Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987]), Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987])), Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828]): (Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910]), Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910])), Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830]): (Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054]), Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054])), Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228]): (Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742]), Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742])), Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443]): (Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928]), Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928])), Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643]): (Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979]), Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979])), Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758]): (Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106]), Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106])), Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580]): (Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594]), Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594])), Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765]): (Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045]), Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045])), Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766]): (Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281]), Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281])), Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385]): (Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828]), Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828])), Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579]): (Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171]), Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171])), Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212]): (Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992]), Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992])), Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463]): (Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004]), Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004])), Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502]): (Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023]), Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023])), Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539]): (Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537]), Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537])), Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865]): (Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225]), Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225])), Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690]): (Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947]), Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947])), Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202]): (Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552]), Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552])), Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079]): (Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444]), Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444])), Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850]): (Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548]), Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548])), Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448]): (Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987]), Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987])), Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041]): (Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035]), Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035])), Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301]): (Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414]), Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414])), Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414]): (Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212]), Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212])), Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703]): (Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439]), Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439])), Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271]): (Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955]), Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955])), Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882]): (Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802]), Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802])), Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152]): (Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887]), Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887])), Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028]): (Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948]), Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948])), Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331]): (Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093]), Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093])), Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394]): (Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134]), Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134])), Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546]): (Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228]), Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228])), Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620]): (Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414]), Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414])), Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800]): (Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703]), Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703])), Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671]): (Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205]), Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205])), Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537]): (Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011]), Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011])), Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516]): (Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301]), Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301])), Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831]): (Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986]), Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986])), Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415]): (Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057]), Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057])), Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722]): (Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689]), Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689])), Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144]): (Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682]), Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682])), Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295]): (Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268]), Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268])), Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818]): (Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513]), Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513])), Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241]): (Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565]), Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565])), Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439]): (Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012]), Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012])), Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512]): (Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850]), Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850])), Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986]): (Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865]), Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865])), Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982]): (Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777]), Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777])), Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808]): (Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394]), Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394])), Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979]): (Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690]), Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690])), Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093]): (Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620]), Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620])), Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902]): (Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789]), Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789])), Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542]): (Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094]), Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094])), Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057]): (Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362]), Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362])), Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205]): (Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961]), Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961])), Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401]): (Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580]), Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580])), Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553]): (Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960]), Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960])), Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169]): (Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031]), Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031])), Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682]): (Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053]), Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053])), Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118]): (Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562]), Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562])), Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725]): (Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666]), Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666])), Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661]): (Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897]), Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897])), Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981]): (Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447]), Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447])), Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072]): (Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646]), Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646])), Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140]): (Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404]), Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404])), Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515]): (Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152]), Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152])), Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709]): (Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664]), Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664])), Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800]): (Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103]), Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103])), Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741]): (Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169]), Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169])), Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005]): (Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758]), Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758])), Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802]): (Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070]), Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070])), Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159]): (Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005]), Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005])), Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350]): (Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443]), Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443])), Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697]): (Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573]), Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573])), Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928]): (Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331]), Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331])), Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320]): (Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166]), Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166])), Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814]): (Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079]), Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079])), Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447]): (Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820]), Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820])), Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284]): (Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057]), Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057])), Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697]): (Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131]), Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131])), Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955]): (Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290]), Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290])), Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910]): (Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202]), Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202])), Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910]): (Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822]), Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822])), Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106]): (Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847]), Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847])), Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404]): (Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441]), Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441])), Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796]): (Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186]), Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186])), Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053]): (Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516]), Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516])), Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992]): (Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818]), Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818])), Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957]): (Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315]), Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315])), Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709]): (Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794]), Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794])), Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091]): (Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539]), Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539])), Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664]): (Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558]), Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558])), Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294]): (Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579]), Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579])), Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947]): (Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502]), Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502])), Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829]): (Word([0, 0, 0, 0]), Word([0, 0, 0, 0])), Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045]): (Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137]), Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137])), Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914]): (Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041]), Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041])), Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573]): (Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378]), Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378])), Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699]): (Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873]), Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873])), Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225]): (Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262]), Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262])), Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057]): (Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692]), Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692])), Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131]): (Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997]), Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997])), Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555]): (Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385]), Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385])), Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195]): (Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709]), Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709])), Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166]): (Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542]), Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542])), Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027]): (Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373]), Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373])), Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378]): (Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509]), Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509])), Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097]): (Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553]), Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553])), Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217]): (Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815]), Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815])), Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873]): (Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864]), Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864])), Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997]): (Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722]), Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722])), Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887]): (Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766]), Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766])), Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589]): (Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757]), Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757])), Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539]): (Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665]), Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665])), Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129]): (Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229]), Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229])), Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137]): (Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312]), Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312])), Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019]): (Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378]), Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378])), Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331]): (Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713]), Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713])), Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]): (Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980]), Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980])), Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325]): (Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546]), Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546])), Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170]): (Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822]), Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822])), Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054]): (Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295]), Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295])), Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925]): (Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848]), Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848])), Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909]): (Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796]), Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796])), Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540]): (Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170]), Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170])), Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214]): (Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448]), Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448])), Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317]): (Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294]), Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294])), Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757]): (Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416]), Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416])), Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378]): (Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091]), Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091])), Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263]): (Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463]), Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463])), Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666]): (Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361]), Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361])), Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174]): (Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992]), Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992])), Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470]): (Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401]), Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401])), Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665]): (Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957]), Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957])), Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262]): (Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144]), Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144])), Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229]): (Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284]), Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284])), Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134]): (Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325]), Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325])), Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855]): (Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765]), Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765])), Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115]): (Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814]), Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814])), Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441]): (Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831]), Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831])), Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977]): (Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446]), Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446])), Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880]): (Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005]), Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005])), Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789]): (Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995]), Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995])), Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000]): (Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267]), Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267])), Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998]): (Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982]), Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982])), Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995]): (Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539]), Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539])), Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507]): (Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512]), Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512])), Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305]): (Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118]), Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118])), Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219]): (Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009]), Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009])), Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416]): (Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089]), Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089])), Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980]): (Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445]), Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445])), Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063]): (Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140]), Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140])), Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713]): (Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159]), Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159])), Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031]): (Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809]), Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809])), Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932]): (Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037]), Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037])), Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094]): (Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925]), Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925])), Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315]): (Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386]), Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386])), Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446]): (Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721]), Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721])), Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742]): (Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981]), Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981])), Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661]): (Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072]), Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072])), Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979]): (Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671]), Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671])), Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361]): (Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269]), Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269])), Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558]): (Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571]), Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571])), Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290]): (Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902]), Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902])), Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987]): (Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741]), Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741])), Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902]): (Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515]), Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515])), Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497]): (Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028]), Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028])), Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948]): (Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709]), Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709])), Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009]): (Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725]), Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725])), Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387]): (Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317]), Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317])), Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159]): (Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808]), Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808])), Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394]): (Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699]), Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699])), Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312]): (Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000]), Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000])), Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987]): (Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821]), Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821])), Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046]): (Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909]), Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909])), Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565]): (Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028]), Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028])), Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269]): (Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352]), Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352])), Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847]): (Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271]), Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271])), Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513]): (Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800]), Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800])), Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054]): (Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394]), Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394])), Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004]): (Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977]), Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977])), Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675]): (Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800]), Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800])), Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692]): (Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159]), Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159])), Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909]): (Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932]), Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932])), Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814]): (Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697]), Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697])), Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186]): (Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387]), Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387])), Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445]): (Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470]), Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470])), Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966]): (Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507]), Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507])), Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548]): (Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253]), Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253])), Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897]): (Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783]), Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783])), Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208]): (Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054]), Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054])), Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268]): (Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661]), Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661])), Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388]): (Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643]), Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643])), Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257]): (Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174]), Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174])), Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960]): (Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241]), Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241])), Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721]): (Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046]), Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046])), Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822]): (Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217]), Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217])), Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253]): (Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697]), Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697])), Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054]): (Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019]), Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019])), Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821]): (Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432]), Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432])), Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864]): (Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105]), Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105])), Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373]): (Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855]), Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855])), Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646]): (Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830]), Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830])), Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460]): (Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208]), Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208])), Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033]): (Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214]), Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214])), Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105]): (Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129]), Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129])), Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281]): (Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909]), Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909])), Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028]): (Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027]), Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027])), Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012]): (Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054]), Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054])), Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562]): (Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589]), Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589])), Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037]): (Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097]), Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097])), Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355]): (Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460]), Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460])), Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223]): (Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355]), Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355])), Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089]): (Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306]), Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306])), Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035]): (Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219]), Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219])), Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432]): (Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297]), Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297])), Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693]): (Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263]), Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263])), Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794]): (Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484]), Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484])), Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552]): (Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941]), Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941])), Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267]): (Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814]), Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814])), Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992]): (Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415]), Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415])), Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941]): (Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966]), Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966])), Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822]): (Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320]), Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320])), Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306]): (Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902]), Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902])), Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820]): (Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880]), Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880])), Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361]): (Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725]), Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725])), Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005]): (Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914]), Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914])), Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783]): (Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781]), Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781])), Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011]): (Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033]), Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033])), Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297]): (Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910]), Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910])), Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070]): (Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134]), Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134])), Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144]): (Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331]), Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331])), Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023]): (Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497]), Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497])), Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103]): (Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540]), Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540])), Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961]): (Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998]), Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998])), Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414]): (Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]), Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]))}, trace_len_summary: TraceLenSummary { main_trace_len: 12, range_trace_len: 39, chiplets_trace_len: ChipletsLengths { hash_chiplet_len: 128, bitwise_chiplet_len: 0, memory_chiplet_len: 0, kernel_rom_len: 0 } } } +ExecutionTrace { main_trace: MainTrace { storage: Parts { core_rm: [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 10403713768525900847, 2139411523427040457, 8515917035379853351, 856023126862020256, 0, 0, 0, 0, 0, 0, 1, 0, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1032, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 2, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 8, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 3, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 4, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 1, 1, 1, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 5, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1942941126776981551, 9461460041610899538, 7600020670677266955, 3257731577738044347, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 0, 0, 0, 0, 0, 0, 1, 0, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 6, 0, 0, 0, 0, 0, 5, 0, 1, 1, 0, 1, 0, 1, 8, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 7, 0, 0, 0, 0, 0, 7, 0, 0, 0, 1, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 8, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 1, 1, 1, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 9, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 1, 1, 1, 10403713768525900847, 2139411523427040457, 8515917035379853351, 856023126862020256, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 10, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 31, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 33, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 39, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 43, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 47, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 50, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 51, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 53, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 54, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 55, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 59, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 60, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 61, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 67, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 69, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 70, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 71, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 72, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 73, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 74, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 75, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 76, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 77, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 78, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 79, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 81, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 82, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 83, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 86, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 87, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 88, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 89, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 90, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 91, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 92, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 93, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 94, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 97, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 98, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 99, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 101, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 102, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 103, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 104, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 105, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 106, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 107, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 108, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 109, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 110, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 111, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 112, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 113, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 114, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 115, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 116, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 117, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 118, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 119, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 120, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 121, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 122, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 123, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 124, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 125, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 126, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 127, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0], chiplets_rm: [1, 1, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 10403713768525900847, 2139411523427040457, 8515917035379853351, 856023126862020256, 0, 87, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 484349804684265665, 6880098633847640351, 846980218218532239, 17903889365796795298, 5550459936565271753, 9107753202341829570, 15324484398676964645, 9257266254418654737, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1032, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 11116382020814057190, 14732796941305378371, 13074361791711182490, 6715193688317415490, 1571558009365433839, 13285275197432594374, 15905141483335727027, 2507840277166973476, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1942941126776981551, 9461460041610899538, 7600020670677266955, 3257731577738044347, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 0, 84, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 10403713768525900847, 2139411523427040457, 8515917035379853351, 856023126862020256, 5748739229791737666, 3971489439724797398, 10156667480279311531, 10471841795831116097, 4161518306931659446, 14664557596733629071, 10457686661281861787, 5372530612210116852, 0, 0, 1, 0, 0, 1, 1, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 1244837894821529086, 14023738310468542470, 9319458442815716445, 5220020845190256514, 18381067342435073896, 15418184987737128626, 17753079332212842976, 12382717352847060954, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1532070872953744281, 11675978725956395507, 8258108365434236190, 8977540451988253054, 8832291907404336605, 16801197610032323372, 8498902414702613411, 2217861947967210820, 14648106445605106304, 5194857384255130698, 4543357020291533691, 1677011855369223059, 1, 0, 0, 0, 1, 0, 0, 0, 0, 18164368745351378969, 665130184182531292, 14548211377038648988, 9026463808500414994, 12372059324693434695, 8512906579977137276, 10951940384741553765, 2990681100436043903, 15463650459774420968, 6115025020360005524, 13619612156045325099, 9915559200666512746, 1, 0, 0, 0, 1, 0, 0, 0, 0, 73542357038484620, 16275608702285065538, 15615370514429573107, 11554047591217380375, 9626234372118459069, 14043139718664795091, 7172345985251039651, 13714446996516992992, 14079807935308074442, 17175342044195045043, 16936021968982853164, 3883665509408281322, 1, 0, 0, 0, 1, 0, 8133824218287649370, 1205363866316521559, 7923953289074004648, 1611370566290075655, 12516876786630134052, 16156412840636435500, 16066365782016562356, 12209717470970729826, 648151295134950813, 8424608506935970051, 941071657155810425, 12476535243066524999, 13046835168670418046, 13563090428318398174, 10213204276953300366, 1, 0, 0, 0, 1, 0, 11656233811569695541, 16780366708706866018, 10469348806910132738, 12317597613336433996, 16800450568443907772, 7958196127911254005, 5580405360121542127, 17991322909541306091, 9587008055009063413, 917862094456531518, 17636182943787095305, 5347924966817937746, 15791860137463552476, 5352122275530338033, 8207615265206228485, 1, 0, 0, 0, 1, 0, 13280747180546192023, 13818056542207317059, 12768869371961439487, 2029833730308772760, 3067168931363951888, 630426464913806566, 13807710542081112496, 10340529818978391824, 8301137772228612306, 18032943025979156234, 5571856761516233924, 15102755171792177729, 1386022355796901548, 10780164990569095481, 14005839963275167003, 1, 0, 0, 0, 1, 0, 8161514060541966002, 5430054846479849757, 855673369941768792, 8583346124368767357, 7152703336258374657, 4793816855328822248, 1475819744300266017, 5162097063446717296, 9158417383194264473, 17323069022182310843, 17309666448184518221, 16540233824244985004, 13271685073550397851, 3683818685539825395, 12883632168742702763, 1, 0, 0, 0, 1, 0, 14889661894667616899, 13319328534492736282, 511216470843933116, 5414088302741599345, 16030190225904238830, 6111859869108706126, 4321093113239299552, 4706826096768711507, 11021679444547674749, 15678561454143187205, 15168765916033556420, 7046395423559884948, 3431032212531228618, 9443306432483343000, 6291224588853575811, 1, 0, 0, 0, 1, 0, 11384512740043719026, 17996531901144166752, 4183594834611630116, 17695445402585642319, 15258305803668890228, 17106752205417894410, 13259786553689259064, 15859967842550332610, 5138368225191856866, 8345451659183769670, 4299979085769618674, 10058172520180004407, 16132576493934338934, 312707111584502977, 8025187035739711204, 1, 0, 0, 0, 1, 0, 17152042124522816142, 9826569971726481595, 8959076337043698126, 1987260706895490300, 17423289859865292784, 12258188545233319580, 4291864820252135891, 2950910453815263271, 852440029525711434, 1223549137263517018, 605327998629874385, 3009980753663636725, 8722464778364467857, 17216818427461180092, 13380853612843880678, 1, 0, 0, 0, 1, 0, 7979264206910945674, 0, 0, 7448791324579059841, 1050285053399784347, 16767087000176263535, 14849165193424062452, 2498996933077132011, 13658177069616805094, 495936213960522537, 13576872019913404781, 7640966386182958606, 4271515987309482058, 13463445006653778819, 12292225704634605892, 1, 0, 0, 0, 1, 0, 0, 0, 0, 6053040396430810733, 2172892474788961636, 18161859984545851402, 13488248907260320483, 8430623432188198915, 3055646124754645267, 4245215712607391946, 2243958878529225177, 14990440908620774864, 3080921390696878855, 595284666932255390, 6192940699035995377, 1, 0, 0, 0, 1, 0, 0, 0, 0, 14921496778760644502, 16662036864627516510, 6434377642684009725, 1840544361770929313, 15074823591915634941, 5258982948465254673, 2683768063818053258, 238295676214993337, 17552036469726894364, 15877921873938893194, 14734786106453693759, 1371624439541100057, 1, 0, 0, 0, 1, 0, 0, 0, 0, 516742705862090749, 5947805230277704319, 5952541516123965670, 9026915957393505056, 5986317686192419732, 75717367401824328, 8923961895635206791, 17106810061565988432, 7157463081631406163, 150940732863733992, 15657864298531798718, 12227344478922314236, 1, 0, 0, 0, 1, 0, 0, 0, 0, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 1244837894821529086, 14023738310468542470, 9319458442815716445, 5220020845190256514, 18381067342435073896, 15418184987737128626, 17753079332212842976, 12382717352847060954, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1032, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 15913981378790993016, 12701179462806902902, 9645342555817022514, 6889850077248808033, 678249829196625442, 8726676798253716750, 14136118088409135949, 1027279235140821190, 8048729929177993405, 2542525775606472849, 3283471062508934848, 18058280687405074483, 1, 0, 0, 0, 1, 0, 0, 0, 0, 11899090779839289087, 1701090513954162998, 6953639183117323837, 11460660778637092812, 8345945186928076892, 11308243255833047975, 5734666540714547293, 1546649737555419076, 14643837757854608147, 7477230882792828789, 2359592855656894189, 12732146754685591216, 1, 0, 0, 0, 1, 0, 0, 0, 0, 16283412161296764998, 17261112905912533997, 1498213616014501531, 7707889409925905689, 16090493533591377617, 525010687572874692, 5228788497345464933, 13051466527897639054, 3560924095387897187, 12551242480725370445, 4038828260160651477, 6132317990703151787, 1, 0, 0, 0, 1, 0, 14261694278902826987, 16097544111075686229, 16632169854204459773, 14265791174051766329, 14732671264513481238, 15642599276989292777, 7593738854072541043, 11440582168151819564, 18258483622390056257, 6851601084855956341, 10463349537167637967, 10032876585525342603, 825669147467031185, 16271217766495541082, 9021089524754424392, 1, 0, 0, 0, 1, 0, 16780109665356203593, 16025948514351396737, 4256182047405196535, 4919013996388780384, 6974015548720770018, 10189882052640604940, 12288632186238773648, 7055558833039165669, 9820743264545515107, 7353106531603230851, 5612808106478211181, 362487531847990854, 10259224130335842891, 2374318293393776907, 16208179153232019183, 1, 0, 0, 0, 1, 0, 9496969110446094198, 10424961628901078909, 7587726188775237019, 13423955604028434301, 12288543613568774022, 4068762405627465026, 7288480650179820504, 1035430088689333582, 2651098721515326755, 4524440782000877024, 3013038852551457145, 12536534023666437466, 6560028330562582937, 9090521726813489969, 17634755409309861791, 1, 0, 0, 0, 1, 0, 15761194215082968049, 15796684185970405493, 1294179585337070936, 5701860167148115542, 17707247215386403887, 18419960639673587986, 14570347312565937582, 8634142387233894354, 11938075017385927203, 8060480374868324599, 16699922976999064541, 14234489074154948378, 17210389744085299852, 17331527780947314617, 16356838976302290254, 1, 0, 0, 0, 1, 0, 6184336662619539433, 7106147576739595100, 18237994300618329820, 9768155666925548219, 226714884885574576, 11169479382209254075, 5756676929838789145, 29803495366482069, 13128905441940840949, 18304516631519674746, 3177693875357946498, 10624850715031233718, 16956738608020324589, 10558540052020438814, 7826502712354673600, 1, 0, 0, 0, 1, 0, 1980308537464408089, 6810023246846442283, 9400257804338494201, 11246932855318952856, 7504545710540897051, 5823677062954428984, 9151299935574592196, 15905322272715446259, 18174748553199601666, 9877077233183640995, 2431998410719122545, 3541292002384422941, 5416588529930333172, 15788517205879313917, 2490575598934209003, 1, 0, 0, 0, 1, 0, 17950140321155419078, 9014768943295123367, 10707122777228105884, 10701204914974985643, 15060806908759160804, 7011191650405807117, 13598159658926423040, 3947314552577424057, 12985682730462769834, 18264715466581442035, 7667189540353817157, 7685483800933651249, 16085167604591833455, 16105855167414075111, 16215395602017884846, 1, 0, 0, 0, 1, 0, 8676227747932036802, 0, 0, 11504729673400082663, 3659553513673892306, 10374352082945691939, 15819529278889203623, 18107940902385670152, 8889798095480337831, 12737345777792032790, 456604824069734238, 2859376131275373721, 8758251935142908528, 2364536875264708997, 2435873391009301907, 1, 0, 0, 0, 1, 0, 0, 0, 0, 16797630026773069829, 16954579754978210547, 4393671449525183699, 6245909065255485436, 8311309349844601638, 3305827896314343556, 1615477551160071258, 3897903986825909618, 13015230208471866351, 13839070994009764281, 2415598337053791919, 5526300544248852335, 1, 0, 0, 0, 1, 0, 0, 0, 0, 12827873667465929582, 15892701250663610383, 549489834728826775, 9425334953627649153, 15402634395731091512, 11814416271399500934, 14597718118926923662, 4726679541432826422, 342915941842538663, 11221492717904369823, 17188959961041335276, 13559932473868727168, 1, 0, 0, 0, 1, 0, 0, 0, 0, 8689096602925893779, 4096531352684607500, 8424481237826564505, 15238165026175259240, 10985176737527635898, 2672540837788784952, 6649439643634522762, 7581835251244605715, 17671970641549389116, 18069913154458602790, 749417941228438762, 6150863900366154379, 1, 0, 0, 0, 1, 0, 0, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 11116382020814057190, 14732796941305378371, 13074361791711182490, 6715193688317415490, 1571558009365433839, 13285275197432594374, 15905141483335727027, 2507840277166973476, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1942941126776981551, 9461460041610899538, 7600020670677266955, 3257731577738044347, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 0, 84, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 17300126657859479093, 11313920102849673527, 6346627796045519057, 7389299619274629431, 9262647006463201494, 12900235463952244627, 7852421498196750068, 1141784430625393243, 12150004112779528077, 146728085155958051, 1479007214074296519, 5326692900453573033, 1, 0, 0, 0, 1, 0, 0, 0, 0, 13417131057632658648, 13887354800197146837, 8609784525483513948, 16453892850627486456, 976357452201521805, 14650998861370095747, 15798952093464371291, 14383483119098647176, 18419038023611574318, 3683052509510392753, 12831965507313403291, 11464211275629339672, 1, 0, 0, 0, 1, 0, 0, 0, 0, 4507099831440932953, 6830877239439284265, 9097811782723336829, 18355313083727954627, 7779515141290159182, 15839592087462215756, 13604506694568008603, 14024127302218670748, 5952493440729260050, 4068297222526233952, 1979966764305086565, 9333200475194576798, 1, 0, 0, 0, 1, 0, 8357924686780715814, 6636884447613425583, 9624380725568248686, 2880287348195737852, 885106567500324074, 6448875554992341703, 9855604354502581698, 9375523715508471459, 12339746387209375629, 10455158341094955823, 15902189126849452967, 12030315950055306153, 12641257084941861137, 15957996139063952329, 15783553274882271383, 1, 0, 0, 0, 1, 0, 5347236343958253894, 4025896570838415692, 14804406762588016934, 182667766089555833, 8746225101260903407, 12800409546363710287, 816655693375320760, 3488220768045884341, 17449960788520479876, 13060006746047445404, 4590648600733170196, 14869579734892957539, 137356745712127171, 13422659882759208113, 2676688078772673635, 1, 0, 0, 0, 1, 0, 2921699901762625847, 2649189506073489962, 9913373798344930711, 7755498383134197376, 17631069913300146763, 918789106343442195, 12710306366297056980, 3352461179293085611, 13949166093507073033, 16957002236887535634, 5578100969514402869, 4043905565383364858, 7659576686417292817, 2367890233987709775, 8348028103004129201, 1, 0, 0, 0, 1, 0, 10172794879368016270, 6345331429530820033, 5837950612071262866, 16650183950518877881, 761183529886498658, 882392762205142966, 10341241875528441727, 10625329717419136765, 9971095066673234358, 4232004013780299993, 4126250918613430195, 1352790980003480299, 15265846796546163655, 16214598491416624701, 6270582476047461808, 1, 0, 0, 0, 1, 0, 3029040881537747494, 16192268821146642419, 1429264540499601619, 723722855549182307, 9275648404607992275, 7653230088222442503, 5336572895513434476, 17267978825783635674, 2055211161196684150, 5382467524735065973, 17562229302921943767, 11689925804137528317, 12333395168151976785, 13928209897558581843, 6382294855606512139, 1, 0, 0, 0, 1, 0, 7880496552213312201, 15122758161943386192, 7696912976710769683, 16684832919913645113, 1325781221503242261, 9767481056214686264, 15383255957179010771, 4765175578813598212, 352612095018961168, 8164700351999240448, 11366624484197321797, 14418389432583501516, 5429053278517118996, 2079377923041037634, 9248817126035377137, 1, 0, 0, 0, 1, 0, 7798482983966084054, 9698350464160947514, 2622165840457703741, 3191144700364674222, 13840521809458223850, 6693472114669876018, 1844850377219340954, 6041824929233084189, 10694505064011226265, 9837159640677247471, 421241411507411802, 1387064907365996610, 7160690172588878117, 6170204562255862519, 11691591530451877345, 1, 0, 0, 0, 1, 0, 12784330368443191752, 0, 0, 1511701347894443705, 3195625100455147555, 8197728783207379545, 449202167972758168, 10429619634413714415, 1266474106654512299, 10043612818557622726, 17546950285193103331, 17459565798841957386, 1545883776729609444, 4559076489231806387, 2919974393045314777, 1, 0, 0, 0, 1, 0, 0, 0, 0, 14541231479059008872, 2573517030855683796, 3524292720580177308, 13855152767270114589, 3006044390476483944, 594411982442348353, 2707135781132813285, 7980470443732427589, 10692471325161091019, 16152944287821214660, 16000995173627170117, 3599288644418559718, 1, 0, 0, 0, 1, 0, 0, 0, 0, 16401658505261312282, 14340768500784081639, 9157399410194868857, 9102901647434269728, 17796618941315046862, 6870559696376279126, 14430288544136295714, 11256415914434052793, 13509056984869078243, 16212533703602772012, 10731537818920783986, 9244614718938709708, 1, 0, 0, 0, 1, 0, 0, 0, 0, 10956055287997745079, 17622456621764780147, 5455165430251125445, 6727955785885619519, 14753857082920611668, 13906110808313848802, 8347093488770218639, 8918883692704710750, 15290172371351697411, 10523129087658444171, 15727241650811717280, 10475089196439845505, 1, 0, 0, 0, 1, 0, 0, 0, 0, 10403713768525900847, 2139411523427040457, 8515917035379853351, 856023126862020256, 5748739229791737666, 3971489439724797398, 10156667480279311531, 10471841795831116097, 4161518306931659446, 14664557596733629071, 10457686661281861787, 5372530612210116852, 1, 0, 0, 0, 1, 0, 0, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 10403713768525900847, 2139411523427040457, 8515917035379853351, 856023126862020256, 0, 87, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 14973522761191262497, 4230519249120879894, 2629183259646768977, 10141819052260397061, 13407203767006087071, 12300175896314074402, 2702373535953719449, 14066933458796711308, 2220020800002954405, 1153376321238519426, 9501912115787530137, 11467779250790108687, 1, 0, 0, 0, 1, 0, 0, 0, 0, 17579142101067141791, 16331511478156948621, 2536845301555017815, 4655744751626348560, 1315476336364332532, 12758262197074716778, 17888512728802654414, 5454338212767341777, 14616265448064819190, 4049834289657867128, 2177315978307888394, 2010382289454711711, 1, 0, 0, 0, 1, 0, 0, 0, 0, 12664267918550820934, 8493562230894032491, 10885506335001351491, 10623508799881057302, 10765360003981902673, 4842275562010620878, 8656573021603208590, 2450260130765540973, 17667697651318069254, 3544163002330957814, 9007165683524157049, 4518865977780754525, 1, 0, 0, 0, 1, 0, 12821199281659850615, 12524526780064226282, 8688367803817133517, 7111709976940449855, 6042875499671257036, 10602803306945095136, 18053244771098668210, 15869901507286010642, 15765124758947684257, 909769595464630286, 9984901127103118556, 16104234613185942963, 1596997669664652458, 3285629071226892513, 5254177489666731166, 1, 0, 0, 0, 1, 0, 1319022057496410037, 6723956385664361856, 362758946504872978, 17945942309272171171, 7547510637898886664, 8389575157731885000, 5432655503035172224, 8636630472484196539, 17112531070480946597, 5597227622497427759, 8296183404013335152, 8448226142379838282, 9123809571274586481, 4262155088312829534, 6352753764020113838, 1, 0, 0, 0, 1, 0, 15817353186600079517, 11896741780081321151, 8120557738706811421, 1514840266710990643, 2518758362364209964, 14494370701341234363, 18160488913248834173, 415225714783614736, 14762958776895421659, 1582837024273971615, 826388124734417268, 9723851761924399417, 2904897680946636379, 572660879606393944, 5062575418735094728, 1, 0, 0, 0, 1, 0, 11887745873838856200, 11056257118819520017, 8546453177127819509, 3906777862244807614, 15967237477862396017, 1240858482343082944, 8886870748754950786, 15806110295452780709, 6486381282415609829, 16950387463813522784, 8577643233130284288, 17768236078519772738, 217872450018257683, 6293942954387886585, 10974892067682463496, 1, 0, 0, 0, 1, 0, 2581007320496406744, 7054105961444862624, 15347768076097298693, 8125727413083423821, 10805393644723323985, 13586718478006757236, 17768197347468566879, 17280093366403031105, 635835674863826303, 4568185472217893804, 9296267175044089272, 10337709963460435554, 4440112583501734927, 9729481707513785664, 4743006626934706100, 1, 0, 0, 0, 1, 0, 17610297678684695918, 16364115285854473865, 11595150248116497643, 7035439775474110251, 11847308316956964837, 7889458920902982286, 11305368688963866992, 14287445400250554900, 1893961912880033900, 10317967923286478317, 3918181922279376301, 15000492392148830533, 7931144489554367364, 9476759250402767950, 18270644106765218282, 1, 0, 0, 0, 1, 0, 11532830003582511953, 460321325058925628, 12709513064174486630, 6478715440156951267, 14089413401266079358, 2281022494971066801, 3378217915115563837, 4838851040494198977, 11743317019648187379, 3359761112394096597, 13620706797177850518, 3438335644910777353, 2067033555957484299, 11784176479463653422, 9418905686906839178, 1, 0, 0, 0, 1, 0, 17359699556169412381, 0, 0, 17848865035999698302, 9363353806961732906, 1059359355271114718, 3722579262469999737, 7401377741210733980, 4394776823738550294, 17911331326024175702, 14231054337850845953, 1567229020978754366, 10965059646087563007, 4717306534304214129, 6160606101751839399, 1, 0, 0, 0, 1, 0, 0, 0, 0, 5210262791539000682, 3231850662476970044, 12242203768226360021, 16352185264854542792, 15126409509795103366, 17462025488896312666, 10962575762908536311, 16737021171185522127, 6692618053949882379, 17172828881706643966, 14646740046786928565, 1663831101883973254, 1, 0, 0, 0, 1, 0, 0, 0, 0, 4908282038977879385, 2701244722093391429, 15021286664224332416, 10534803976436280037, 15876667595247308635, 16333738989139894331, 1581145115862775994, 18250779698217077450, 7155162361709676048, 10303228755363253440, 4300281072628271246, 16497484699945471993, 1, 0, 0, 0, 1, 0, 0, 0, 0, 4313772916158122500, 2902278358899028132, 254766801126374444, 5671561640468956184, 4347645646061943576, 1998087227139787801, 12798150249100419438, 647551028640823116, 15480041353865470488, 13024601617472109101, 16248647525361276326, 18146087632373782831, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209, 484349804684265665, 6880098633847640351, 846980218218532239, 17903889365796795298, 5550459936565271753, 9107753202341829570, 15324484398676964645, 9257266254418654737, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], range_checker_cols: [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2187, 4374, 6561, 8748, 10935, 13122, 15309, 17496, 19683, 21870, 24057, 26244, 28431, 30618, 32805, 34992, 37179, 39366, 41553, 43740, 45927, 48114, 50301, 52488, 54675, 56862, 59049, 61236, 63423, 64152, 64881, 65124, 65367, 65448, 65529, 65532, 65535, 65535]], num_rows: 128 }, last_program_row: RowIndex(11) }, program_info: ProgramInfo { program_hash: Word([1876701632238060746, 15418340615945340323, 12750157181197398124, 14164386418602606209]), kernel: Kernel([]) }, stack_outputs: StackOutputs { elements: [0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, precompile_requests: [], final_precompile_transcript: PrecompileTranscript { state: Word([0, 0, 0, 0]) }, trace_len_summary: TraceLenSummary { main_trace_len: 12, range_trace_len: 39, chiplets_trace_len: ChipletsLengths { hash_chiplet_len: 80, bitwise_chiplet_len: 0, memory_chiplet_len: 0, ace_chiplet_len: 0, kernel_rom_len: 0 } } } diff --git a/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_07.snap b/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_07.snap index 1d5017e559..dea34ebc3e 100644 --- a/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_07.snap +++ b/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_07.snap @@ -2,4 +2,4 @@ source: processor/src/trace/parallel/tests.rs expression: DeterministicTrace(&trace_from_fragments) --- -ExecutionTrace { main_trace: MainTrace { columns: ColMatrix { columns: [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 33, 33, 33, 1, 65, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [7458506668679174706, 1032, 8, 0, 7458506668679174706, 665741763369239996, 8212736248369912082, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000], [18375473735916206629, 0, 1, 1, 18375473735916206629, 5831108162926480783, 4071281311826053218, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331], [2105717247508690050, 0, 0, 0, 2105717247508690050, 7330889791923421278, 16681111697957494384, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271], [1679902783560062568, 0, 0, 0, 1679902783560062568, 13218130135561237014, 6160598189905115531, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851], [8212736248369912082, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [4071281311826053218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [16681111697957494384, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [6160598189905115531, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 9999, 0, 0, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999], [9999, 9999, 9999, 0, 9999, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2187, 4374, 6561, 8748, 10935, 13122, 15309, 17496, 19683, 21870, 24057, 26244, 28431, 30618, 32805, 34992, 37179, 39366, 41553, 43740, 45927, 48114, 50301, 52488, 54675, 56862, 59049, 61236, 63423, 64152, 64881, 65124, 65367, 65448, 65529, 65532, 65535, 65535], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [7458506668679174706, 8136249212351146192, 10784649219148085459, 128781735205120527, 4547968979093876849, 3546336675446295543, 10817940156349236625, 14189444001012371653, 5493374351233807563, 8311102902317058756, 6249712288789018971, 1614874318552505578, 8181452518454181592, 598477530791288280, 8307036201059139827, 17345949525972330427, 17120430504411685184, 9024048572557701022, 5442249363272202440, 8891889669188699464, 13981710006578989582, 15202252296288325862, 8901049526912687276, 11824695302249715491, 8477037444632037091, 10111259653022775679, 9872576991436394594, 13620574761069749666, 10552500864729979640, 18032794979945654604, 153382829717154572, 8442199976350624000, 1032, 10320, 13024110921086730221, 3587442816163675215, 512402747638547729, 9217956011885162917, 3925750957223009950, 8674177413178223320, 12846799727083908462, 9116601283268739756, 2958792353189815054, 1720195204565087693, 7696852080146622077, 2890877729556257606, 16676527939404087356, 223754558788184593, 4767414622778376421, 14072300156908432530, 16856861612825314654, 11910434229443384600, 15658716527747040980, 14322127566252286435, 4770460127206402609, 10805338145914832851, 1391598300875421210, 18211456042978337510, 11866022853402812888, 6438324596032750504, 13328288515202849800, 17331158106613184460, 18344276842462151560, 7458506668679174706, 665741763369239996, 16242795687146137268, 321461142783715873, 2826379816086788535, 1389982844959459783, 7504428176840094167, 16867052141953300014, 6524645837583534023, 7971642927196132266, 895587693811363643, 14045043160415708545, 17186760898540197468, 11586158328390007250, 12564286920483154715, 14264987096664760063, 13473611649745551608, 3074526273535018608, 8192703318881365638, 11332735769645700919, 16102114657139125593, 17852385312535653754, 2362278605853243291, 7801968558670902550, 8976000347315438733, 13152720785410684086, 15178160026565391559, 16635907827753325426, 2952369032039574593, 2377128724052460864, 4064757387509104114, 5276412771718093926, 8212736248369912082, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [18375473735916206629, 17377183675986858406, 16204388331933209503, 9851558383041711453, 2647731244796610075, 13479103754506160685, 1313884950803363652, 15346175195946058279, 8910192708346993775, 2151299325850503780, 16669085269506854818, 12924378726200437768, 5909277165962634165, 7995732842947875893, 14386798070662103151, 7879022579148049870, 15020611106200374787, 10724238176158470430, 15029834199037822311, 11678935371612262717, 7297009056930466619, 14511898776428524296, 319792799645144231, 13382186579597492216, 2694749223042447691, 13263694931203634375, 6000186529178301892, 16523385558055279056, 7022204645736728964, 5338134468072720249, 15645384100209479912, 9488069924049927331, 0, 8256, 1131208899036558480, 1667157010810320250, 2053960715201569301, 1526213270499333709, 69813565043892453, 14925652377538846871, 1380252317064967448, 9902934070223067140, 3786794161520721521, 664031068804619792, 8470323998416702977, 4965297830526000942, 9404280000999464502, 8244737495337250711, 4784363486033662704, 4680481291290566437, 15373555507761845373, 8780119261264514018, 729009684537575982, 18306419558979237700, 15407410920890065538, 2509966126115291236, 12709897403480972846, 11498596868429821859, 6606875518512322314, 13880694912200059110, 6972406840307481976, 14148490408465275064, 2917966740410115114, 18375473735916206629, 5831108162926480783, 5716807500553500532, 340111207878988785, 18256387944673635196, 10860511098536981986, 8459821732881051520, 6920921369535874813, 16951093806716492481, 13791358524817111974, 5736505110286114902, 6134208873573181149, 9775353746636648794, 10511806043496923148, 16994604820290358508, 8663944065392476082, 7230189013861170101, 5624631671914610235, 6327683047402873297, 4175477208176608783, 954074467059951894, 9430822593953620080, 3254964387338063442, 14616933013502048910, 323829297696706606, 15299582253555179912, 8256585982323809806, 16419251794401517641, 11559790149908051338, 2239581712082993389, 12489932951016483829, 11738733634614750668, 4071281311826053218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [2105717247508690050, 3107344020706784815, 7535295255934147784, 14961534904937133494, 15458110929197782417, 5854257801187918217, 7408528896221680379, 7195773034137126318, 6953015881067099300, 8311075386067189185, 7490596925699016321, 2748780903535738274, 14124675439405907210, 13467811864817035684, 12069265029549314681, 8713544979421645407, 7271740931964389253, 13358005363663908988, 1445604555428043843, 15414631947824553103, 3604233398898996465, 11389542141657004950, 753657943574098354, 16156878489884540028, 1283495432526365661, 15770030010231724104, 4992467617151662209, 9388418952293233141, 12063673466969028652, 6266501778891918617, 17390445613818630245, 3589804369840038271, 0, 2064, 18136552782870868471, 952274539956745973, 15933282259815262093, 9924516287334785738, 18064603646801610993, 5114527609957824263, 11816233963570869158, 17699527003452380450, 14533708946479200173, 17484213571014188868, 832814531422633701, 1508169308733590908, 8423043379628164525, 12595277727969636921, 14226276023010866965, 10485112285448962747, 1783527593060720204, 10145484005384627580, 7463752398658534839, 17345550819494003223, 4432309123412733588, 7086318781105575433, 8830891075082588619, 310185093236608634, 16683125300631590273, 7786799186167080425, 29465347809991832, 8090161351836983773, 8665315444141111469, 2105717247508690050, 7330889791923421278, 17979691280170131106, 16980963677900604856, 15976151213056828438, 92714918004478284, 17365496272474871894, 17001192471520708179, 3321277494654107778, 16893172732645584491, 2027752104829715962, 15452271030076785961, 2501796678284190373, 5676660220829808154, 13123673595423766920, 26738717326360259, 17483757498059224444, 12817208054146358362, 6986963031258272860, 16687757358165325375, 18027249453476092631, 15075850538217806798, 4190259332272306773, 2553182391312160489, 6173756644452043592, 7042376686216238529, 38980987021367719, 12463158039410249198, 7049795244189838947, 7060420962088551737, 9342274029206616333, 1435264878438078251, 16681111697957494384, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1679902783560062568, 1730400919877242464, 8594455900178560628, 5726930420197336139, 13273590888045863622, 8753781667987110661, 12948922070052129184, 6957781166000927195, 11540514940863049397, 3555060714483297014, 9392868496609143397, 1424153760517090352, 9018810402297148417, 2907590405487611226, 16087116659981325603, 6124015441109604199, 15635572367538115795, 2170747068790740224, 3201993911066137312, 11259421084459541380, 9993917348799810609, 17222088454832638116, 15686086798273471220, 12787265931454127207, 607842291318703015, 13403753643599459835, 10689062953812945200, 12619604521626526557, 3744742376692732597, 7474246814889551252, 12416458660228151392, 11846932079106298851, 0, 2064, 9594118340025725004, 16218246678075491818, 11582919835122342747, 5661452934218108707, 3714647928422746674, 13689184893219719187, 1899963197709801965, 8313716591368695784, 17822645741084942000, 18354595702287703799, 12620512717427217848, 10145637708639089787, 1735222492513760332, 14681927838838900060, 9262747238997471758, 11498487923782501751, 8924101344488972446, 2592517964915386184, 4276681409258176044, 3764365715267793208, 3120204268813370353, 6019260256544801113, 2801984351776029768, 16979166255722313516, 2813750347113564525, 16588139065369475399, 12012198471360912693, 2492059183640657261, 16968938268466755316, 1679902783560062568, 13218130135561237014, 8897450981738644183, 8122025352910807675, 14806163515298168591, 5442054526001626765, 3774836954819930057, 7873436160289973996, 1985577549930980807, 379441097109437269, 1582743467085230093, 8777470251655517715, 10400069677678307421, 1177689384604532813, 16561198203506864486, 18413269984357459958, 1623867674755828306, 5071121402113212599, 11851310101017854885, 17866089753923079131, 12853565947951893885, 6966840703169954718, 2619660424044064391, 4642489055874642868, 6457652449305783921, 3582227845111194274, 9002213586940350635, 8120300831241327696, 7598230464484206583, 432418536618916281, 10696618739033813212, 2085147768356017783, 6160598189905115531, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [8212736248369912082, 13582507089316059702, 7058022398850579311, 14448859106484550632, 8488923843888712176, 14387511811111000559, 16343533314104084279, 7144420700209912913, 81438176960127805, 11353579355252691279, 15391029939397732169, 13654856085785737791, 17867630563899600855, 15638494238775280514, 15278759115432814741, 9672833929788573796, 8499991101857103008, 4277878641698006595, 12990966731553386694, 325849556554992531, 16823455732252835952, 10325677389248902106, 17215632082750072073, 5871229270093729693, 1418595653525548799, 1623140794865507125, 3521868013962458536, 7592427336074080103, 8813490692122304227, 15033504818965134746, 671768789535371387, 6002676145170957552, 0, 5160, 1190658701913535022, 9371121588404883743, 7133056533056999470, 7380100170229652082, 14719783382686670107, 4693530971176924881, 11125714198188567552, 2434816259070577714, 17927785478103501878, 834873962620943786, 1091858408197145201, 9293176204765248193, 11318806736621162148, 979530496520387452, 8328113718786640843, 15870139479256453021, 7754853849459016697, 2742936430580983415, 6806060556807781604, 5089080673677611112, 16430235900965466453, 309743103212430298, 15664803780047891222, 3113571524475220627, 17862871362988443440, 1231393200801541530, 15779352999894925288, 6026600320279882336, 6970552753544824994, 4949154992619464010, 0, 17344769878280361092, 2672032990889952726, 10966643852490493990, 2592429945178091576, 8172562148455605634, 14004003701484837955, 12834107981647449396, 9875636580100479976, 12047948199477092131, 8025491038733220165, 491259531166040341, 14832623839190995610, 14697509357953676418, 5789610466730383818, 388263584830521272, 7439414156048078496, 15784515228652197776, 11049955424692728889, 14895470599018577003, 7841617945839187879, 17455550201169057010, 2534236084163066389, 6762591351360230328, 5346858927664762265, 7945321262401027963, 10750885965856570936, 12370887997614982110, 16868606775754956395, 12653757924793616214, 11706271638131904220, 10827276321637451859, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [4071281311826053218, 8965269515246497704, 4610105990937441552, 14871257653827208567, 17566918610707158078, 4662267156400217313, 11925160665074583703, 7006577898090498820, 8933338746704632990, 14704958557312921128, 283685871938470517, 17049945775096584485, 1735922796599632945, 18137828521183364954, 1233454545325180310, 4616679305450045558, 799989113534058041, 9548215660109667029, 17638736186517997026, 12905149264926481878, 9206641926728869527, 11201231447988338022, 6044555324419572909, 4856995795253621298, 5361647435575923081, 6166078860096154852, 6696272579393185401, 1638259147884844478, 10134861521414682067, 17465898446534646298, 2270472397704099161, 5665896864361060199, 0, 4128, 1352424102745866255, 13301242752201603536, 5420135027930584396, 17078794493496835379, 4779811836607866048, 3650219859599657886, 13618468821889769363, 11429589192023659923, 8853101337885331080, 9650238821992519861, 14401087967309285252, 12035560952634921032, 15407186837043713393, 15711028160746246110, 5396976350889627712, 15903424027416555998, 11304777107657759509, 9857843669692965578, 12605480788735099613, 14618970056708743810, 8493993205782554647, 6059068631740368787, 18316971448227884023, 12499808993385025318, 4210674244211222629, 18405965507148502967, 173097048437312502, 15568437290332308327, 11532601739151124629, 10000279862191744493, 0, 2858403750276750521, 18287547865064093386, 16643076982183140204, 17607797632632583753, 4606352897788642339, 16669380908105325740, 6888212917900510506, 9887976024132347018, 15672872160122205909, 10605120439023982124, 17832834191852929098, 11180362325911556985, 1797669589287132096, 18316393283013557997, 17455009848636139677, 4212485662162927177, 2684395608227063909, 10865000669694511781, 13048938138389391460, 13946693875892332716, 300901360739248952, 4186546104164144876, 3265288527569414193, 8781944488148208732, 14923610741876695933, 9614148693204557112, 9347068782470538323, 17518823857230050559, 7139121107914525514, 470824845274439747, 1419643695620305796, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [16681111697957494384, 9850604216542701406, 14292233265078610671, 11560507218468362083, 11435884371355098677, 707619676799722739, 13157092351337171268, 2418773787696448890, 4672379866331806862, 14371817650991869953, 3768839363733198769, 9708763303767628077, 11396390941757961228, 4785785956560501030, 16036499041626449319, 9630510095026498877, 7634220798360289556, 5119649922187981964, 6331607203065781588, 16919596794918736104, 32726321504424883, 10309269913347989302, 14782015448458484884, 14683358530499849942, 7836268277036786901, 15462421617591871273, 12213179217732598594, 14536234064731365163, 3637686875728492502, 2382678006125050452, 14226016292255835291, 589873375673641870, 0, 1032, 4798141223555508282, 12962488577647927717, 10133257770726709126, 332864556927106185, 12116126881643349994, 6604148216925166409, 101015634312276042, 15934992137290074922, 6112274855072540816, 17762248064501548615, 13166189948742588777, 270100349969833402, 13485211244653928073, 3502306881032295169, 13607663468974078519, 8883940618995723208, 10623667092532612652, 12293715092576816840, 10386976621364522928, 9128135834925108269, 15731443845270647366, 13373704167654916087, 13746187061551926812, 11684868053863796759, 3258729720361659960, 10434904637843727165, 7034851303745741351, 16133345873308301364, 5426492436527662130, 2980140658145787783, 0, 18213217674792357841, 6883907187243818989, 10614920431791547888, 13376310260819809150, 970536228322621221, 5786498633534169345, 13904299833493296337, 18182241650367492861, 4671451809489883858, 10519951415050407991, 9409416070961479945, 9277815292140415791, 84450611619755921, 13615028923015526256, 15760906032947657328, 10394291523020808732, 14504653302726904108, 8315708932196998089, 2409075654026148870, 367320422432359503, 6139056775213015570, 6944063758267220406, 4458873320026667405, 12662780608684972080, 15472797447424064358, 4158450525844909688, 2549026714004541517, 3246198533692444934, 3222033110084083257, 5683784147168326312, 7836113917086293276, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [6160598189905115531, 18025956107099608580, 11512968082996599149, 1159818605994823015, 2364926874595277907, 7943063494760571709, 16605271790117727213, 11825547519897455023, 15342799649049057800, 3763048797193456654, 1295787082959371660, 16691905436935888241, 1915507152031483536, 17009264450373861587, 16328475049153986635, 8830519937889782762, 10115241278692937317, 1750096680784451786, 16653566373055583790, 4332235233085094180, 627717841813244731, 4706384122596616028, 219643739348167868, 10259409981493264670, 13239490680913326732, 182727077359841351, 8469105874522435313, 8517021520884886781, 3404810976915461357, 3829882598743334141, 14062283116063151751, 1610809089415408623, 0, 1032, 11702782905971311743, 8115486282645452027, 16425371230714077552, 10333496212804492507, 1572943607289284437, 13244361396034453954, 12880029163967100393, 14716450796809578181, 2618965885956593171, 1606019581379521796, 12562170441304287563, 4599116799417823473, 4257071131168813417, 10446583017549019711, 3570388907037362614, 11170081717188072664, 17238997244398394333, 17231192964516960933, 8123337005847551087, 7060091366977384949, 5719725530909274667, 5057603743378325948, 13848013489728729143, 17729739340387068117, 367186060507240673, 1411195984452924204, 11088333491201093194, 16575090776691519559, 16147396598096989679, 14525300817521856881, 0, 4448725490869322134, 16773782102167370766, 9517551778943323923, 9735157781939056258, 13685677539131842935, 74410881992624137, 16112118280329224188, 16455044890046321010, 3166113086359297763, 4123774883019480954, 8049700212209077372, 9143498805844601837, 1269471574449064045, 17099282884571514622, 17951548125515157165, 15320893071039302787, 16371352256021817139, 17154595820341397772, 5088265715035438397, 12952269508513821163, 2910118210482029454, 1585088611936329987, 16759292612217335519, 9851596960932027140, 8679788143435043297, 7792109010626424915, 3420624790371920563, 7480053259498635867, 3615950593461764641, 16487019928286415392, 10289142213544989468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1090670744084208003, 3080746365611415597, 6133575519759388325, 11695447135684149141, 6615075028106709917, 10277147404869816105, 15962120449122821193, 1254198290967296340, 2925289410746405164, 12104312877316532634, 14739488160024614333, 10743573083299131194, 12707577723315108285, 8945689852522735768, 14566241909712907104, 9028236766089923761, 10185013658812384549, 3941868484557913621, 16462538463092115913, 5673651272129016554, 1223470853173331157, 2788160682175050931, 1502692624900434396, 5566335148331577393, 17762829217961409285, 3389969163810664285, 7437527833076252327, 17084466347038006872, 6606368157240498477, 13093088208853880999, 1276807186500217245, 0, 5160, 18346837778669738664, 15130142357101091527, 6726588340010678615, 8394319278312203283, 15942424551308612685, 7629500615465222065, 14939877513325106589, 17048523965011794048, 2306293645521445312, 823113708878672797, 14981348226783328932, 7432878333905782051, 3482639998457803800, 632277917380007036, 18266437030920184246, 3366715262389109205, 5280275432441977334, 5379329043314533811, 13912213856326486056, 17217059915921675075, 15634373017412823086, 14981257187297131103, 16697350900700022325, 5239234081629986555, 3229291246709926782, 18373224696258292584, 6771862800272250893, 7666370275789511263, 12942227631865082960, 15190222347874856922, 0, 17344769878280361687, 11249881205591563163, 16071218949222383338, 546830354766363539, 7776682728634159270, 11209888800273182957, 14728140374725612977, 8386791303267182172, 9638626268997275972, 822684530408571288, 16951904742993551809, 825915008780272344, 18209952013401698562, 390611853699198814, 11327187383464966515, 12709202232488054070, 11552589705164935867, 12311030232489101343, 5023941437735028493, 16069569499603265432, 18063718751316981145, 4010755700397089888, 10892805137373131994, 9089377676555868962, 1220818432464721625, 13088066304082794059, 8657669536399661454, 419065699932221163, 3886495484944885171, 1240710433266681785, 5374430875291145484, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [87, 2631903040606257959, 11859146482331138479, 12232695746376293294, 995389826954784529, 11949085664163595757, 4404337953750906792, 6908862958628621571, 12608149157887976305, 4754146580783023412, 14308250014803856580, 9454287016901482416, 9789905333959995060, 3771810096516115799, 2150959420327906479, 14538218150241396541, 6425179495446994078, 17565393891424303638, 3667075674391371806, 5731318824387052908, 4241445880929460300, 13107360446062265038, 4176811711023066147, 5250671015911848716, 4722672072326683708, 7171204772415813456, 5618587527864308269, 16458991436693873868, 2626622112813681720, 4599215552676510549, 5363423870755590475, 4352525099414593256, 0, 4128, 6496253015800789210, 18063315295058131399, 14099326864720264780, 16744359797696928029, 11669954633423859445, 10923938539628559259, 10579480970462933513, 17315553376669597828, 12114095292572219189, 16129781670858537825, 67936491912723144, 6285840300661422802, 14359460599290704174, 7597471307904508314, 8469569990667894210, 9117246600999250277, 14614928058075190380, 13738364908865630160, 1806905237893315697, 261412144627674040, 8380596589382515797, 3809925330596605534, 1983199361335541287, 6337901890572878101, 17063257729896061936, 12690697575318882146, 3846044480011221270, 10729939698274680623, 5297971463863936522, 8671284646676347574, 85, 2858403750276751031, 1709210755771630360, 11707086547963657475, 2794745820933624420, 2841923277622193225, 16490991381302584921, 5788783276303277595, 14692549583873964816, 9815954444411995352, 16153761647449809543, 6052645635446937049, 17304693813258262086, 11634259222665431081, 12233143040630128964, 8553846008642101336, 18388379526128378444, 15548258272185388836, 15360138454847963029, 3440439455019208235, 7218244406354738621, 5887183982672949081, 15870877452527488142, 15139518776246125573, 5433537245583001116, 13408133831989321267, 4656955130371010155, 14539571260147117550, 17118765335121629772, 3475198118169682060, 11483695604905597390, 11783370765491737635, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 10468230768888023862, 11664682242720909218, 2500570831459298438, 13004725650794618836, 8624527149940617200, 11524055993362242048, 6182388235200005336, 2589834268393847902, 12931236615531993709, 8584449549244767688, 11899064714918281636, 16246984277558583019, 8772638227416864166, 11946855882944424845, 16440133693312412286, 14737175326378679956, 7842923952979169755, 2398501113047325856, 14599944340506938939, 5936050971291911531, 8286147454062396089, 14343924012975607961, 8190973727913189622, 1134938007864643353, 12054037840221089027, 10050755079785196589, 10469731445849191380, 10906931598039016782, 16150808274840457147, 13280081123993966327, 5571840125263174859, 0, 1032, 13084260837127404333, 4018109146681745349, 14498381569327145056, 3778421823029569719, 1344624249217908323, 3634653398484528177, 1428985706412758663, 11382569756632997337, 13894906302086601399, 3911680161282028629, 11467762927868003365, 10098326072301516020, 16073214466625742345, 16150512194511843089, 11525294274796193451, 15902507139806774023, 13926886722650908730, 2974304378722638293, 5274544965980948277, 9984170014312577610, 639485734140932316, 15088403650698955530, 17189134684458608982, 6515320870350778492, 7902492290152572474, 17310456195349246143, 4070136787975548901, 6345872167795009033, 3095930865537762353, 4232664728858134772, 0, 18213217674792358096, 13599297410359034734, 11548640197966434952, 16397756946501824199, 4509993724149584481, 15279575547763923315, 14387788336990426452, 1679695851270735493, 737550782574904766, 16619718868892680991, 4189079835826917979, 16548334619034420779, 2523584064344323171, 18357860221728901477, 9223263721501613140, 836498427651453899, 11050299770631141961, 1906255442715510922, 16855485989141196504, 12664144355455319157, 17100007635940521879, 307480490272233054, 14791890923980574308, 14809283111081511220, 1272668898289027998, 1746726629032389326, 781443211491376776, 4235062597258109895, 17016381150799971149, 387032599105912823, 13820432364368151262, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 12734367032130478571, 915471480408530766, 18393930191488027312, 13545212286845976163, 18210660875436245579, 1541989510332303929, 5733187932229069792, 8676871105886252208, 15648333801800339703, 12513161021723575557, 9265666514596208448, 10311060571948838328, 15479186567637803235, 9457367929087028434, 10997859361453741844, 4801586725411290698, 8358881080234670725, 14262453638255884367, 3602771739252146288, 6541843013709002421, 3170708104995675453, 10921877432993541182, 10224257779706313529, 15830149545637956450, 13414249448981002451, 11722023958758893627, 18138185027267907899, 13905103948731397841, 9009398081722850699, 16014363687546775515, 10945967283455090973, 0, 1032, 15909096041365347974, 18432189660917429733, 2798890989547891271, 10768372030970716894, 5935807051329113911, 1259182408195029650, 16024750973514577255, 6103595041913569283, 914770550723164908, 5067028895751058275, 5242612139537538536, 13359135899043031769, 4430959127423856282, 16317056360529517539, 2634255659160911215, 15590656855559575839, 6832335878067392309, 6045109056629836176, 18146646330136390606, 6482705684632040588, 2770791364887326735, 7707774010999656594, 3401430074469265273, 3500862351024377705, 5135727797169111985, 14940852959892477883, 9633218853985087472, 16966092255533854383, 3065488485208441055, 15703076512693482766, 0, 4448725490869322219, 4944140066849387506, 2095785635431009262, 12375413327700682072, 11081872751342419742, 18058781214879352230, 17856276381917295190, 6718639559482054424, 668947051234094647, 3868828750372286402, 12122170781554046887, 4343898307694473975, 12690125861105998824, 16799534473726304569, 15934980937477619093, 3969747009451350970, 7686328019139102331, 3785180857099199084, 11986142858341385519, 2506152622879710750, 18430687071203156938, 3054089675267069232, 8760992635981950709, 11143171037695874494, 4733232646684685861, 1219894586292412814, 12600138307490245388, 824784286256764128, 10170016208525526833, 593495485489349093, 11923860796119339735, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] }, last_program_row: RowIndex(8) }, program_info: ProgramInfo { program_hash: Word([8442199976350624000, 9488069924049927331, 3589804369840038271, 11846932079106298851]), kernel: Kernel([]) }, stack_outputs: StackOutputs { elements: [9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, merkle_store_nodes: {Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571]): (Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350]), Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350])), Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484]): (Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693]), Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693])), Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781]): (Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874]), Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874])), Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171]): (Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361]), Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361])), Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815]): (Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305]), Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305])), Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689]): (Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195]), Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195])), Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362]): (Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063]), Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063])), Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848]): (Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661]), Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661])), Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352]): (Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829]), Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829])), Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444]): (Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223]), Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223])), Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386]): (Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388]), Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388])), Word([13190842942618341421, 17548956981569849952, 15418963848144418856, 730733050713174879]): (Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144]), Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144])), Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874]): (Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675]), Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675])), Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594]): (Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115]), Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115])), Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809]): (Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257]), Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257])), Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777]): (Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555]), Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555])), Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509]): (Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882]), Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882])), Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725]): (Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979]), Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979])), Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134]): (Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987]), Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987])), Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828]): (Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910]), Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910])), Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830]): (Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054]), Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054])), Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228]): (Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742]), Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742])), Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443]): (Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928]), Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928])), Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643]): (Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979]), Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979])), Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758]): (Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106]), Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106])), Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580]): (Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594]), Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594])), Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765]): (Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045]), Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045])), Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766]): (Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281]), Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281])), Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385]): (Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828]), Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828])), Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579]): (Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171]), Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171])), Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212]): (Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992]), Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992])), Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463]): (Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004]), Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004])), Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502]): (Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023]), Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023])), Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539]): (Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537]), Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537])), Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865]): (Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225]), Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225])), Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690]): (Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947]), Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947])), Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202]): (Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552]), Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552])), Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079]): (Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444]), Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444])), Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850]): (Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548]), Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548])), Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448]): (Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987]), Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987])), Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041]): (Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035]), Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035])), Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301]): (Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414]), Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414])), Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414]): (Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212]), Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212])), Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703]): (Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439]), Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439])), Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271]): (Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955]), Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955])), Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882]): (Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802]), Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802])), Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152]): (Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887]), Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887])), Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028]): (Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948]), Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948])), Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331]): (Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093]), Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093])), Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394]): (Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134]), Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134])), Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546]): (Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228]), Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228])), Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620]): (Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414]), Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414])), Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800]): (Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703]), Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703])), Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671]): (Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205]), Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205])), Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537]): (Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011]), Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011])), Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516]): (Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301]), Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301])), Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831]): (Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986]), Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986])), Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415]): (Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057]), Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057])), Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722]): (Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689]), Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689])), Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144]): (Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682]), Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682])), Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295]): (Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268]), Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268])), Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818]): (Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513]), Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513])), Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241]): (Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565]), Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565])), Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439]): (Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012]), Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012])), Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512]): (Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850]), Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850])), Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986]): (Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865]), Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865])), Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982]): (Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777]), Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777])), Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808]): (Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394]), Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394])), Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979]): (Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690]), Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690])), Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093]): (Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620]), Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620])), Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902]): (Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789]), Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789])), Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542]): (Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094]), Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094])), Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057]): (Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362]), Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362])), Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205]): (Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961]), Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961])), Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401]): (Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580]), Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580])), Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553]): (Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960]), Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960])), Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169]): (Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031]), Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031])), Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682]): (Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053]), Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053])), Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118]): (Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562]), Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562])), Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725]): (Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666]), Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666])), Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661]): (Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897]), Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897])), Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981]): (Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447]), Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447])), Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072]): (Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646]), Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646])), Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140]): (Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404]), Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404])), Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515]): (Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152]), Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152])), Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709]): (Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664]), Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664])), Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800]): (Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103]), Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103])), Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741]): (Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169]), Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169])), Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005]): (Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758]), Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758])), Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802]): (Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070]), Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070])), Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159]): (Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005]), Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005])), Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350]): (Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443]), Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443])), Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697]): (Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573]), Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573])), Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928]): (Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331]), Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331])), Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320]): (Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166]), Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166])), Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814]): (Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079]), Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079])), Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447]): (Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820]), Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820])), Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284]): (Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057]), Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057])), Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697]): (Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131]), Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131])), Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955]): (Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290]), Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290])), Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910]): (Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202]), Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202])), Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910]): (Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822]), Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822])), Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106]): (Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847]), Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847])), Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404]): (Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441]), Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441])), Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796]): (Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186]), Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186])), Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053]): (Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516]), Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516])), Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992]): (Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818]), Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818])), Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957]): (Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315]), Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315])), Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709]): (Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794]), Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794])), Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091]): (Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539]), Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539])), Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664]): (Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558]), Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558])), Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294]): (Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579]), Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579])), Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947]): (Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502]), Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502])), Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829]): (Word([0, 0, 0, 0]), Word([0, 0, 0, 0])), Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045]): (Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137]), Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137])), Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914]): (Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041]), Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041])), Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573]): (Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378]), Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378])), Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699]): (Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873]), Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873])), Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225]): (Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262]), Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262])), Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057]): (Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692]), Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692])), Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131]): (Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997]), Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997])), Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555]): (Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385]), Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385])), Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195]): (Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709]), Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709])), Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166]): (Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542]), Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542])), Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027]): (Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373]), Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373])), Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378]): (Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509]), Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509])), Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097]): (Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553]), Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553])), Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217]): (Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815]), Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815])), Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873]): (Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864]), Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864])), Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997]): (Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722]), Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722])), Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887]): (Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766]), Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766])), Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589]): (Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757]), Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757])), Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539]): (Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665]), Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665])), Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129]): (Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229]), Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229])), Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137]): (Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312]), Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312])), Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019]): (Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378]), Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378])), Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331]): (Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713]), Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713])), Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]): (Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980]), Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980])), Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325]): (Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546]), Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546])), Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170]): (Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822]), Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822])), Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054]): (Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295]), Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295])), Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925]): (Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848]), Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848])), Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909]): (Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796]), Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796])), Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540]): (Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170]), Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170])), Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214]): (Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448]), Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448])), Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317]): (Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294]), Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294])), Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757]): (Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416]), Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416])), Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378]): (Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091]), Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091])), Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263]): (Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463]), Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463])), Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666]): (Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361]), Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361])), Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174]): (Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992]), Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992])), Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470]): (Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401]), Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401])), Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665]): (Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957]), Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957])), Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262]): (Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144]), Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144])), Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229]): (Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284]), Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284])), Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134]): (Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325]), Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325])), Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855]): (Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765]), Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765])), Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115]): (Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814]), Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814])), Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441]): (Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831]), Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831])), Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977]): (Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446]), Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446])), Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880]): (Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005]), Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005])), Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789]): (Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995]), Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995])), Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000]): (Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267]), Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267])), Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998]): (Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982]), Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982])), Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995]): (Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539]), Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539])), Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507]): (Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512]), Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512])), Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305]): (Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118]), Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118])), Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219]): (Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009]), Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009])), Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416]): (Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089]), Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089])), Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980]): (Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445]), Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445])), Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063]): (Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140]), Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140])), Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713]): (Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159]), Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159])), Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031]): (Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809]), Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809])), Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932]): (Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037]), Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037])), Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094]): (Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925]), Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925])), Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315]): (Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386]), Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386])), Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446]): (Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721]), Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721])), Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742]): (Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981]), Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981])), Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661]): (Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072]), Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072])), Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979]): (Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671]), Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671])), Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361]): (Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269]), Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269])), Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558]): (Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571]), Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571])), Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290]): (Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902]), Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902])), Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987]): (Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741]), Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741])), Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902]): (Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515]), Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515])), Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497]): (Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028]), Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028])), Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948]): (Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709]), Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709])), Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009]): (Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725]), Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725])), Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387]): (Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317]), Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317])), Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159]): (Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808]), Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808])), Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394]): (Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699]), Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699])), Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312]): (Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000]), Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000])), Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987]): (Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821]), Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821])), Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046]): (Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909]), Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909])), Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565]): (Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028]), Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028])), Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269]): (Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352]), Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352])), Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847]): (Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271]), Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271])), Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513]): (Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800]), Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800])), Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054]): (Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394]), Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394])), Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004]): (Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977]), Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977])), Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675]): (Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800]), Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800])), Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692]): (Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159]), Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159])), Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909]): (Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932]), Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932])), Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814]): (Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697]), Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697])), Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186]): (Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387]), Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387])), Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445]): (Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470]), Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470])), Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966]): (Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507]), Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507])), Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548]): (Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253]), Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253])), Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897]): (Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783]), Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783])), Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208]): (Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054]), Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054])), Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268]): (Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661]), Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661])), Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388]): (Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643]), Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643])), Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257]): (Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174]), Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174])), Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960]): (Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241]), Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241])), Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721]): (Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046]), Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046])), Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822]): (Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217]), Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217])), Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253]): (Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697]), Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697])), Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054]): (Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019]), Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019])), Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821]): (Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432]), Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432])), Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864]): (Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105]), Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105])), Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373]): (Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855]), Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855])), Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646]): (Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830]), Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830])), Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460]): (Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208]), Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208])), Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033]): (Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214]), Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214])), Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105]): (Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129]), Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129])), Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281]): (Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909]), Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909])), Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028]): (Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027]), Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027])), Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012]): (Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054]), Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054])), Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562]): (Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589]), Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589])), Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037]): (Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097]), Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097])), Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355]): (Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460]), Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460])), Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223]): (Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355]), Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355])), Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089]): (Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306]), Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306])), Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035]): (Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219]), Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219])), Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432]): (Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297]), Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297])), Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693]): (Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263]), Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263])), Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794]): (Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484]), Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484])), Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552]): (Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941]), Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941])), Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267]): (Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814]), Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814])), Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992]): (Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415]), Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415])), Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941]): (Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966]), Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966])), Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822]): (Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320]), Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320])), Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306]): (Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902]), Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902])), Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820]): (Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880]), Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880])), Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361]): (Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725]), Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725])), Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005]): (Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914]), Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914])), Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783]): (Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781]), Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781])), Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011]): (Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033]), Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033])), Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297]): (Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910]), Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910])), Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070]): (Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134]), Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134])), Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144]): (Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331]), Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331])), Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023]): (Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497]), Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497])), Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103]): (Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540]), Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540])), Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961]): (Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998]), Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998])), Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414]): (Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]), Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]))}, trace_len_summary: TraceLenSummary { main_trace_len: 9, range_trace_len: 39, chiplets_trace_len: ChipletsLengths { hash_chiplet_len: 96, bitwise_chiplet_len: 0, memory_chiplet_len: 0, kernel_rom_len: 0 } } } +ExecutionTrace { main_trace: MainTrace { storage: Parts { core_rm: [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 13719137288158876142, 6221215488690831821, 11468044834296629525, 16720332114142763849, 0, 0, 0, 0, 0, 0, 1, 0, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1032, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 2, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 8, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 3, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 4, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 1, 1, 1, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 5, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 16362180982079134587, 16601100057639640520, 5521682503008444658, 3792208660074152519, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 6, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 1, 1, 1, 13719137288158876142, 6221215488690831821, 11468044834296629525, 16720332114142763849, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 7, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 31, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 33, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 39, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 43, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 47, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 50, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 51, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 53, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 54, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 55, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 59, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 60, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 61, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 67, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 69, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 70, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 71, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 72, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 73, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 74, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 75, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 76, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 77, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 78, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 79, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 81, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 82, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 83, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 86, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 87, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 88, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 89, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 90, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 91, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 92, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 93, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 94, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 97, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 98, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 99, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 101, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 102, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 103, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 104, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 105, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 106, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 107, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 108, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 109, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 110, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 111, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 112, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 113, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 114, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 115, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 116, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 117, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 118, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 119, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 120, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 121, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 122, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 123, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 124, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 125, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 126, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 127, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0], chiplets_rm: [1, 1, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 13719137288158876142, 6221215488690831821, 11468044834296629525, 16720332114142763849, 0, 87, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 2445654027848798773, 13989391813235195492, 481784282030877064, 1887209632430994963, 9346278187721986719, 3141189181316333764, 4622204731995696995, 16701354768447765175, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1032, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 11116382020814057190, 14732796941305378371, 13074361791711182490, 6715193688317415490, 1571558009365433839, 13285275197432594374, 15905141483335727027, 2507840277166973476, 0, 0, 1, 0, 0, 1, 1, 0, 0, 16362180982079134587, 16601100057639640520, 5521682503008444658, 3792208660074152519, 0, 0, 0, 0, 0, 85, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 13719137288158876142, 6221215488690831821, 11468044834296629525, 16720332114142763849, 13962113176908263293, 676026057669832378, 15921241029195116857, 15915352364638718229, 1456698220748515004, 1707540503940690697, 10429997843948879425, 4559651383104503034, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1032, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 15913981378790993016, 12701179462806902902, 9645342555817022514, 6889850077248808033, 678249829196625442, 8726676798253716750, 14136118088409135949, 1027279235140821190, 8048729929177993405, 2542525775606472849, 3283471062508934848, 18058280687405074483, 1, 0, 0, 0, 1, 0, 0, 0, 0, 11899090779839289087, 1701090513954162998, 6953639183117323837, 11460660778637092812, 8345945186928076892, 11308243255833047975, 5734666540714547293, 1546649737555419076, 14643837757854608147, 7477230882792828789, 2359592855656894189, 12732146754685591216, 1, 0, 0, 0, 1, 0, 0, 0, 0, 16283412161296764998, 17261112905912533997, 1498213616014501531, 7707889409925905689, 16090493533591377617, 525010687572874692, 5228788497345464933, 13051466527897639054, 3560924095387897187, 12551242480725370445, 4038828260160651477, 6132317990703151787, 1, 0, 0, 0, 1, 0, 14261694278902826987, 16097544111075686229, 16632169854204459773, 14265791174051766329, 14732671264513481238, 15642599276989292777, 7593738854072541043, 11440582168151819564, 18258483622390056257, 6851601084855956341, 10463349537167637967, 10032876585525342603, 825669147467031185, 16271217766495541082, 9021089524754424392, 1, 0, 0, 0, 1, 0, 16780109665356203593, 16025948514351396737, 4256182047405196535, 4919013996388780384, 6974015548720770018, 10189882052640604940, 12288632186238773648, 7055558833039165669, 9820743264545515107, 7353106531603230851, 5612808106478211181, 362487531847990854, 10259224130335842891, 2374318293393776907, 16208179153232019183, 1, 0, 0, 0, 1, 0, 9496969110446094198, 10424961628901078909, 7587726188775237019, 13423955604028434301, 12288543613568774022, 4068762405627465026, 7288480650179820504, 1035430088689333582, 2651098721515326755, 4524440782000877024, 3013038852551457145, 12536534023666437466, 6560028330562582937, 9090521726813489969, 17634755409309861791, 1, 0, 0, 0, 1, 0, 15761194215082968049, 15796684185970405493, 1294179585337070936, 5701860167148115542, 17707247215386403887, 18419960639673587986, 14570347312565937582, 8634142387233894354, 11938075017385927203, 8060480374868324599, 16699922976999064541, 14234489074154948378, 17210389744085299852, 17331527780947314617, 16356838976302290254, 1, 0, 0, 0, 1, 0, 6184336662619539433, 7106147576739595100, 18237994300618329820, 9768155666925548219, 226714884885574576, 11169479382209254075, 5756676929838789145, 29803495366482069, 13128905441940840949, 18304516631519674746, 3177693875357946498, 10624850715031233718, 16956738608020324589, 10558540052020438814, 7826502712354673600, 1, 0, 0, 0, 1, 0, 1980308537464408089, 6810023246846442283, 9400257804338494201, 11246932855318952856, 7504545710540897051, 5823677062954428984, 9151299935574592196, 15905322272715446259, 18174748553199601666, 9877077233183640995, 2431998410719122545, 3541292002384422941, 5416588529930333172, 15788517205879313917, 2490575598934209003, 1, 0, 0, 0, 1, 0, 17950140321155419078, 9014768943295123367, 10707122777228105884, 10701204914974985643, 15060806908759160804, 7011191650405807117, 13598159658926423040, 3947314552577424057, 12985682730462769834, 18264715466581442035, 7667189540353817157, 7685483800933651249, 16085167604591833455, 16105855167414075111, 16215395602017884846, 1, 0, 0, 0, 1, 0, 8676227747932036802, 0, 0, 11504729673400082663, 3659553513673892306, 10374352082945691939, 15819529278889203623, 18107940902385670152, 8889798095480337831, 12737345777792032790, 456604824069734238, 2859376131275373721, 8758251935142908528, 2364536875264708997, 2435873391009301907, 1, 0, 0, 0, 1, 0, 0, 0, 0, 16797630026773069829, 16954579754978210547, 4393671449525183699, 6245909065255485436, 8311309349844601638, 3305827896314343556, 1615477551160071258, 3897903986825909618, 13015230208471866351, 13839070994009764281, 2415598337053791919, 5526300544248852335, 1, 0, 0, 0, 1, 0, 0, 0, 0, 12827873667465929582, 15892701250663610383, 549489834728826775, 9425334953627649153, 15402634395731091512, 11814416271399500934, 14597718118926923662, 4726679541432826422, 342915941842538663, 11221492717904369823, 17188959961041335276, 13559932473868727168, 1, 0, 0, 0, 1, 0, 0, 0, 0, 8689096602925893779, 4096531352684607500, 8424481237826564505, 15238165026175259240, 10985176737527635898, 2672540837788784952, 6649439643634522762, 7581835251244605715, 17671970641549389116, 18069913154458602790, 749417941228438762, 6150863900366154379, 1, 0, 0, 0, 1, 0, 0, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 11116382020814057190, 14732796941305378371, 13074361791711182490, 6715193688317415490, 1571558009365433839, 13285275197432594374, 15905141483335727027, 2507840277166973476, 1, 0, 0, 0, 1, 0, 0, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 13719137288158876142, 6221215488690831821, 11468044834296629525, 16720332114142763849, 0, 87, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 14526210785099218637, 11847263499640079386, 14727111875255715984, 15492005690507045243, 3560320103534777253, 6108459071875623888, 17010585649681490524, 9461625672567273576, 5346213935533921584, 17324400741801951375, 11366145235097950908, 11020281342858012232, 1, 0, 0, 0, 1, 0, 0, 0, 0, 16197070053425155514, 15404003330998391348, 11930643358177149189, 1706026293115752249, 4860311493079570077, 17106682771221635926, 1613342353291471586, 10021094444428090144, 295368900173018762, 10362371049945425700, 9316163589333399506, 7378950726844095693, 1, 0, 0, 0, 1, 0, 0, 0, 0, 11506810158870826797, 14392904697466827547, 17905937794745323592, 17513565884470753819, 7019811109989114514, 10250939299242755101, 7620822681592706112, 12768902792042039708, 744728025267091276, 16212166364245632221, 10010770609378408333, 15023204573923685916, 1, 0, 0, 0, 1, 0, 9206943447329060417, 1573227013771687083, 7633983188953929869, 14747762092445444483, 12960730896173836507, 5351433366377253619, 4177159482546072600, 17061003377938727239, 9435579121926835049, 9864020053232925179, 11244311170762781618, 2840907732738372264, 7192941522047765124, 6173174116697481058, 13004561835267794042, 1, 0, 0, 0, 1, 0, 12007385695887985386, 13598702180788517287, 3912064789771327196, 11932998954627996911, 3853323028698833085, 11507033346049547360, 10110848241210835991, 15428609857280202530, 17110299148476621277, 12520416593002020608, 9431488564150546187, 2602629576595200800, 15183940660821516128, 15328070744340284046, 9882485700386666987, 1, 0, 0, 0, 1, 0, 2642957852140576392, 12998709907982857483, 4565256592569070651, 4013127352579691203, 10860110376897053120, 13677509527593892026, 2308518476531625659, 6232392686954434349, 13948263847203418837, 7843559618500491242, 7771043128539275771, 18270783924518568037, 16689544634184962614, 16359543813917605495, 8488375023251026510, 1, 0, 0, 0, 1, 0, 13959988857529015221, 12915245760499792818, 14841159553908529338, 14670848694035742368, 13930039566082372841, 9902385290951234306, 3203646694279229751, 13440312555890036471, 10385999516795969620, 11713935020689149772, 12229669264695050570, 402942260260809100, 16753462626177821460, 662362961313881669, 5887183544599407053, 1, 0, 0, 0, 1, 0, 14402936773953440947, 2012430503613052642, 1213953359224393220, 13944145787018602210, 6056959262477445647, 4982640241702718669, 1688381135968391307, 4510633793399532317, 7320984145724666154, 4691989180601120012, 102059673196228558, 1411198915631488472, 1854414388528665842, 16986811917033125654, 795637807896719676, 1, 0, 0, 0, 1, 0, 6294256185997130924, 4739079035802422148, 10935612526477766520, 17716511124280484394, 5021001597521525061, 18126874747305633609, 481644947884807344, 6049685422777720638, 1030047529196261526, 9576302115777192780, 10035472829778314322, 923305066890152615, 12527260620733941943, 11414360666749268526, 17760291183069624834, 1, 0, 0, 0, 1, 0, 10231661581337343904, 1832808263237927056, 6905801525972141190, 7456565975287668714, 12513973463050722371, 15559507328575476525, 2883833371658699080, 3184838730020301861, 18205970767593414562, 2798075613901729544, 189593258747480201, 13243754036156659300, 5745460764532976218, 2786581607585809614, 17436021357923428450, 1, 0, 0, 0, 1, 0, 72056538882336487, 0, 0, 5652048509186166814, 15367385573432163092, 6683125870356394251, 3770937106356856256, 1769679637596203925, 14372844572054653742, 13769745398507346855, 11807785571768521955, 5724215673931049374, 4401662327723853424, 11928715632009092524, 9924361168171239878, 1, 0, 0, 0, 1, 0, 0, 0, 0, 15128667119917371737, 8016996928120686373, 7467419359957362665, 4993381537595555977, 9371037824338144222, 2930594646951740022, 3944515787153841278, 5454163417882053837, 7667177038930845021, 10105079595217614088, 5177647710243780137, 13395674984723106859, 1, 0, 0, 0, 1, 0, 0, 0, 0, 17075658029987678701, 16942975531700611427, 3643709618611291855, 1334709094417075573, 11909212706933233016, 9741605425019020242, 7607696627297382550, 15299729661431018600, 7032572794257903279, 16683658838871091473, 3645139219999290477, 7245544203380098384, 1, 0, 0, 0, 1, 0, 0, 0, 0, 12068304939642236116, 13614044321092849027, 2880541849277464939, 815353510606417922, 14606426392222040491, 10929343986009381754, 18415245620786467058, 16142346014486690114, 10307567187784261413, 3831820208496643010, 14408727760370549811, 16272758710359397343, 1, 0, 0, 0, 1, 0, 0, 0, 0, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 2445654027848798773, 13989391813235195492, 481784282030877064, 1887209632430994963, 9346278187721986719, 3141189181316333764, 4622204731995696995, 16701354768447765175, 1, 0, 0, 0, 1, 0, 0, 0, 0, 16362180982079134587, 16601100057639640520, 5521682503008444658, 3792208660074152519, 0, 0, 0, 0, 0, 85, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 12086689928305136975, 10578835246084642663, 16542988469676950340, 18039575486237140027, 11378817209220925403, 1830288712116369429, 6836951313152193092, 13067316829245445662, 10483719891652983399, 15107628385291453978, 5745482890193398991, 1467598035505522824, 1, 0, 0, 0, 1, 0, 0, 0, 0, 6641033060700930640, 8002128452364190151, 4237597913508652736, 16497663922788367837, 9373930087271682821, 8772840226065969951, 13812790890684464043, 3327344850838518736, 15781875901493184698, 16732525831131872764, 1159309880266465962, 6519234662137256116, 1, 0, 0, 0, 1, 0, 0, 0, 0, 10088943647124252289, 13701383109068607902, 15690388373484222925, 4290213237740108975, 15844775943612000391, 16171043348080529647, 8784789786127538562, 12635460091357573504, 10561363445665196403, 3917577954302608976, 5337858229134527127, 14152777758433279341, 1, 0, 0, 0, 1, 0, 13029570897742009002, 13177254746172619023, 16038571161593335404, 2188338323498964707, 14662423055206707252, 399526319231252303, 14972684080243877319, 16777311805145501140, 6099803173114002593, 11253362042985817221, 10221863501466764826, 13414791437675451535, 2725322839420367772, 11819412321405778772, 13817033321558649088, 1, 0, 0, 0, 1, 0, 13691749519374287845, 15387673422637086663, 6922978787178957527, 2041172898547348571, 14589651886185789070, 5957633751491508475, 11960354433033043999, 15992971255870582512, 11830967408320733184, 15268965263556481837, 9065968121241919240, 14630209597160847101, 3695262652988767746, 6761434464064434034, 4499935311821727041, 1, 0, 0, 0, 1, 0, 15420756780139702261, 12424942891141165558, 6929528357507663172, 12198893338677478437, 18421446739075495822, 8468855093677567166, 14423050383612849622, 15188396328060565700, 16106496456550916799, 4380220556771000987, 18185062664582859482, 3471791712555441489, 5206529722281859812, 12099854936489528262, 3482375809599031896, 1, 0, 0, 0, 1, 0, 15574108340013622137, 15113564352853103247, 11759657553614819330, 8329975443345290464, 17940882943282719830, 715706186220073675, 11225208304861844348, 11251091880797815873, 16487042113140331701, 2684378958809639271, 18420809765897439905, 5225320321320513732, 6305682781245368810, 4669442538207571276, 14700449525371639507, 1, 0, 0, 0, 1, 0, 2979254376677653503, 1883000689168719362, 8104422763610466617, 5576229311275790732, 2194272311725182022, 11069690432331401312, 9059389138265053881, 8765354464725236382, 9222374345361788506, 18259801840836875925, 6516753426367602114, 16862896352549227556, 4308341550229035638, 3265342498516698837, 13464131825573347891, 1, 0, 0, 0, 1, 0, 13700569878861168214, 2688488967505940113, 3894270749155947782, 13272913612051073638, 229891148220106304, 8827790146883078828, 18375171102175520942, 14403529172649637015, 13099700194841873205, 188376523053645225, 1993959712224675182, 14801384607878448444, 10465527702245819388, 17660990215931846922, 908628888712311860, 1, 0, 0, 0, 1, 0, 17841857416383363570, 1410880649834889205, 15205315845157535511, 474005396413342575, 13140045598301896487, 3896472587811302452, 11889483340877797878, 10675872888943407911, 9043988711004206942, 6590644200881402626, 6630214594291443650, 7328314644790889015, 1925120838408255657, 12102121948068675841, 3366469296269798303, 1, 0, 0, 0, 1, 0, 9810051462759316493, 0, 0, 1967048762267479030, 14694789381285854906, 7850615184380239535, 6179804070945807128, 6190847648382551976, 7074541545875785618, 9996122377954848783, 18406348765365233841, 4381980521208731448, 2527214276140522656, 17476881528019612421, 10227790736734811126, 1, 0, 0, 0, 1, 0, 0, 0, 0, 12825387260273911399, 6194529288585122100, 10547428200413979362, 7146038864248149980, 3758150568829560250, 6436891845148661154, 9620702432336511668, 2457824222102594551, 13331592005230563304, 11086532868255377399, 4413541832527011587, 16051730796051624324, 1, 0, 0, 0, 1, 0, 0, 0, 0, 16438196827052442198, 18163112479653478435, 13659775893412875850, 9240379517650154023, 17622738652736541491, 10377502873777599097, 14167784496777925017, 8652392797374596693, 10690605953822876908, 6607959159332506262, 7925296024181542304, 11865355698347075352, 1, 0, 0, 0, 1, 0, 0, 0, 0, 8453841446519729480, 5007921045949414127, 10571120719178391220, 9766554424414228694, 8901262338981550121, 11643533070801732852, 18177267262839360795, 4695688607260963965, 5981212851350180937, 7185340145346514702, 15820300171842782914, 13017849308841041926, 1, 0, 0, 0, 1, 0, 0, 0, 0, 13719137288158876142, 6221215488690831821, 11468044834296629525, 16720332114142763849, 13962113176908263293, 676026057669832378, 15921241029195116857, 15915352364638718229, 1456698220748515004, 1707540503940690697, 10429997843948879425, 4559651383104503034, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], range_checker_cols: [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2187, 4374, 6561, 8748, 10935, 13122, 15309, 17496, 19683, 21870, 24057, 26244, 28431, 30618, 32805, 34992, 37179, 39366, 41553, 43740, 45927, 48114, 50301, 52488, 54675, 56862, 59049, 61236, 63423, 64152, 64881, 65124, 65367, 65448, 65529, 65532, 65535, 65535]], num_rows: 128 }, last_program_row: RowIndex(8) }, program_info: ProgramInfo { program_hash: Word([6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845]), kernel: Kernel([]) }, stack_outputs: StackOutputs { elements: [9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, precompile_requests: [], final_precompile_transcript: PrecompileTranscript { state: Word([0, 0, 0, 0]) }, trace_len_summary: TraceLenSummary { main_trace_len: 9, range_trace_len: 39, chiplets_trace_len: ChipletsLengths { hash_chiplet_len: 64, bitwise_chiplet_len: 0, memory_chiplet_len: 0, ace_chiplet_len: 0, kernel_rom_len: 0 } } } diff --git a/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_08.snap b/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_08.snap index 1d5017e559..dea34ebc3e 100644 --- a/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_08.snap +++ b/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_08.snap @@ -2,4 +2,4 @@ source: processor/src/trace/parallel/tests.rs expression: DeterministicTrace(&trace_from_fragments) --- -ExecutionTrace { main_trace: MainTrace { columns: ColMatrix { columns: [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 33, 33, 33, 1, 65, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [7458506668679174706, 1032, 8, 0, 7458506668679174706, 665741763369239996, 8212736248369912082, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000], [18375473735916206629, 0, 1, 1, 18375473735916206629, 5831108162926480783, 4071281311826053218, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331], [2105717247508690050, 0, 0, 0, 2105717247508690050, 7330889791923421278, 16681111697957494384, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271], [1679902783560062568, 0, 0, 0, 1679902783560062568, 13218130135561237014, 6160598189905115531, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851], [8212736248369912082, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [4071281311826053218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [16681111697957494384, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [6160598189905115531, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 9999, 0, 0, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999], [9999, 9999, 9999, 0, 9999, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2187, 4374, 6561, 8748, 10935, 13122, 15309, 17496, 19683, 21870, 24057, 26244, 28431, 30618, 32805, 34992, 37179, 39366, 41553, 43740, 45927, 48114, 50301, 52488, 54675, 56862, 59049, 61236, 63423, 64152, 64881, 65124, 65367, 65448, 65529, 65532, 65535, 65535], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [7458506668679174706, 8136249212351146192, 10784649219148085459, 128781735205120527, 4547968979093876849, 3546336675446295543, 10817940156349236625, 14189444001012371653, 5493374351233807563, 8311102902317058756, 6249712288789018971, 1614874318552505578, 8181452518454181592, 598477530791288280, 8307036201059139827, 17345949525972330427, 17120430504411685184, 9024048572557701022, 5442249363272202440, 8891889669188699464, 13981710006578989582, 15202252296288325862, 8901049526912687276, 11824695302249715491, 8477037444632037091, 10111259653022775679, 9872576991436394594, 13620574761069749666, 10552500864729979640, 18032794979945654604, 153382829717154572, 8442199976350624000, 1032, 10320, 13024110921086730221, 3587442816163675215, 512402747638547729, 9217956011885162917, 3925750957223009950, 8674177413178223320, 12846799727083908462, 9116601283268739756, 2958792353189815054, 1720195204565087693, 7696852080146622077, 2890877729556257606, 16676527939404087356, 223754558788184593, 4767414622778376421, 14072300156908432530, 16856861612825314654, 11910434229443384600, 15658716527747040980, 14322127566252286435, 4770460127206402609, 10805338145914832851, 1391598300875421210, 18211456042978337510, 11866022853402812888, 6438324596032750504, 13328288515202849800, 17331158106613184460, 18344276842462151560, 7458506668679174706, 665741763369239996, 16242795687146137268, 321461142783715873, 2826379816086788535, 1389982844959459783, 7504428176840094167, 16867052141953300014, 6524645837583534023, 7971642927196132266, 895587693811363643, 14045043160415708545, 17186760898540197468, 11586158328390007250, 12564286920483154715, 14264987096664760063, 13473611649745551608, 3074526273535018608, 8192703318881365638, 11332735769645700919, 16102114657139125593, 17852385312535653754, 2362278605853243291, 7801968558670902550, 8976000347315438733, 13152720785410684086, 15178160026565391559, 16635907827753325426, 2952369032039574593, 2377128724052460864, 4064757387509104114, 5276412771718093926, 8212736248369912082, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [18375473735916206629, 17377183675986858406, 16204388331933209503, 9851558383041711453, 2647731244796610075, 13479103754506160685, 1313884950803363652, 15346175195946058279, 8910192708346993775, 2151299325850503780, 16669085269506854818, 12924378726200437768, 5909277165962634165, 7995732842947875893, 14386798070662103151, 7879022579148049870, 15020611106200374787, 10724238176158470430, 15029834199037822311, 11678935371612262717, 7297009056930466619, 14511898776428524296, 319792799645144231, 13382186579597492216, 2694749223042447691, 13263694931203634375, 6000186529178301892, 16523385558055279056, 7022204645736728964, 5338134468072720249, 15645384100209479912, 9488069924049927331, 0, 8256, 1131208899036558480, 1667157010810320250, 2053960715201569301, 1526213270499333709, 69813565043892453, 14925652377538846871, 1380252317064967448, 9902934070223067140, 3786794161520721521, 664031068804619792, 8470323998416702977, 4965297830526000942, 9404280000999464502, 8244737495337250711, 4784363486033662704, 4680481291290566437, 15373555507761845373, 8780119261264514018, 729009684537575982, 18306419558979237700, 15407410920890065538, 2509966126115291236, 12709897403480972846, 11498596868429821859, 6606875518512322314, 13880694912200059110, 6972406840307481976, 14148490408465275064, 2917966740410115114, 18375473735916206629, 5831108162926480783, 5716807500553500532, 340111207878988785, 18256387944673635196, 10860511098536981986, 8459821732881051520, 6920921369535874813, 16951093806716492481, 13791358524817111974, 5736505110286114902, 6134208873573181149, 9775353746636648794, 10511806043496923148, 16994604820290358508, 8663944065392476082, 7230189013861170101, 5624631671914610235, 6327683047402873297, 4175477208176608783, 954074467059951894, 9430822593953620080, 3254964387338063442, 14616933013502048910, 323829297696706606, 15299582253555179912, 8256585982323809806, 16419251794401517641, 11559790149908051338, 2239581712082993389, 12489932951016483829, 11738733634614750668, 4071281311826053218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [2105717247508690050, 3107344020706784815, 7535295255934147784, 14961534904937133494, 15458110929197782417, 5854257801187918217, 7408528896221680379, 7195773034137126318, 6953015881067099300, 8311075386067189185, 7490596925699016321, 2748780903535738274, 14124675439405907210, 13467811864817035684, 12069265029549314681, 8713544979421645407, 7271740931964389253, 13358005363663908988, 1445604555428043843, 15414631947824553103, 3604233398898996465, 11389542141657004950, 753657943574098354, 16156878489884540028, 1283495432526365661, 15770030010231724104, 4992467617151662209, 9388418952293233141, 12063673466969028652, 6266501778891918617, 17390445613818630245, 3589804369840038271, 0, 2064, 18136552782870868471, 952274539956745973, 15933282259815262093, 9924516287334785738, 18064603646801610993, 5114527609957824263, 11816233963570869158, 17699527003452380450, 14533708946479200173, 17484213571014188868, 832814531422633701, 1508169308733590908, 8423043379628164525, 12595277727969636921, 14226276023010866965, 10485112285448962747, 1783527593060720204, 10145484005384627580, 7463752398658534839, 17345550819494003223, 4432309123412733588, 7086318781105575433, 8830891075082588619, 310185093236608634, 16683125300631590273, 7786799186167080425, 29465347809991832, 8090161351836983773, 8665315444141111469, 2105717247508690050, 7330889791923421278, 17979691280170131106, 16980963677900604856, 15976151213056828438, 92714918004478284, 17365496272474871894, 17001192471520708179, 3321277494654107778, 16893172732645584491, 2027752104829715962, 15452271030076785961, 2501796678284190373, 5676660220829808154, 13123673595423766920, 26738717326360259, 17483757498059224444, 12817208054146358362, 6986963031258272860, 16687757358165325375, 18027249453476092631, 15075850538217806798, 4190259332272306773, 2553182391312160489, 6173756644452043592, 7042376686216238529, 38980987021367719, 12463158039410249198, 7049795244189838947, 7060420962088551737, 9342274029206616333, 1435264878438078251, 16681111697957494384, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1679902783560062568, 1730400919877242464, 8594455900178560628, 5726930420197336139, 13273590888045863622, 8753781667987110661, 12948922070052129184, 6957781166000927195, 11540514940863049397, 3555060714483297014, 9392868496609143397, 1424153760517090352, 9018810402297148417, 2907590405487611226, 16087116659981325603, 6124015441109604199, 15635572367538115795, 2170747068790740224, 3201993911066137312, 11259421084459541380, 9993917348799810609, 17222088454832638116, 15686086798273471220, 12787265931454127207, 607842291318703015, 13403753643599459835, 10689062953812945200, 12619604521626526557, 3744742376692732597, 7474246814889551252, 12416458660228151392, 11846932079106298851, 0, 2064, 9594118340025725004, 16218246678075491818, 11582919835122342747, 5661452934218108707, 3714647928422746674, 13689184893219719187, 1899963197709801965, 8313716591368695784, 17822645741084942000, 18354595702287703799, 12620512717427217848, 10145637708639089787, 1735222492513760332, 14681927838838900060, 9262747238997471758, 11498487923782501751, 8924101344488972446, 2592517964915386184, 4276681409258176044, 3764365715267793208, 3120204268813370353, 6019260256544801113, 2801984351776029768, 16979166255722313516, 2813750347113564525, 16588139065369475399, 12012198471360912693, 2492059183640657261, 16968938268466755316, 1679902783560062568, 13218130135561237014, 8897450981738644183, 8122025352910807675, 14806163515298168591, 5442054526001626765, 3774836954819930057, 7873436160289973996, 1985577549930980807, 379441097109437269, 1582743467085230093, 8777470251655517715, 10400069677678307421, 1177689384604532813, 16561198203506864486, 18413269984357459958, 1623867674755828306, 5071121402113212599, 11851310101017854885, 17866089753923079131, 12853565947951893885, 6966840703169954718, 2619660424044064391, 4642489055874642868, 6457652449305783921, 3582227845111194274, 9002213586940350635, 8120300831241327696, 7598230464484206583, 432418536618916281, 10696618739033813212, 2085147768356017783, 6160598189905115531, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [8212736248369912082, 13582507089316059702, 7058022398850579311, 14448859106484550632, 8488923843888712176, 14387511811111000559, 16343533314104084279, 7144420700209912913, 81438176960127805, 11353579355252691279, 15391029939397732169, 13654856085785737791, 17867630563899600855, 15638494238775280514, 15278759115432814741, 9672833929788573796, 8499991101857103008, 4277878641698006595, 12990966731553386694, 325849556554992531, 16823455732252835952, 10325677389248902106, 17215632082750072073, 5871229270093729693, 1418595653525548799, 1623140794865507125, 3521868013962458536, 7592427336074080103, 8813490692122304227, 15033504818965134746, 671768789535371387, 6002676145170957552, 0, 5160, 1190658701913535022, 9371121588404883743, 7133056533056999470, 7380100170229652082, 14719783382686670107, 4693530971176924881, 11125714198188567552, 2434816259070577714, 17927785478103501878, 834873962620943786, 1091858408197145201, 9293176204765248193, 11318806736621162148, 979530496520387452, 8328113718786640843, 15870139479256453021, 7754853849459016697, 2742936430580983415, 6806060556807781604, 5089080673677611112, 16430235900965466453, 309743103212430298, 15664803780047891222, 3113571524475220627, 17862871362988443440, 1231393200801541530, 15779352999894925288, 6026600320279882336, 6970552753544824994, 4949154992619464010, 0, 17344769878280361092, 2672032990889952726, 10966643852490493990, 2592429945178091576, 8172562148455605634, 14004003701484837955, 12834107981647449396, 9875636580100479976, 12047948199477092131, 8025491038733220165, 491259531166040341, 14832623839190995610, 14697509357953676418, 5789610466730383818, 388263584830521272, 7439414156048078496, 15784515228652197776, 11049955424692728889, 14895470599018577003, 7841617945839187879, 17455550201169057010, 2534236084163066389, 6762591351360230328, 5346858927664762265, 7945321262401027963, 10750885965856570936, 12370887997614982110, 16868606775754956395, 12653757924793616214, 11706271638131904220, 10827276321637451859, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [4071281311826053218, 8965269515246497704, 4610105990937441552, 14871257653827208567, 17566918610707158078, 4662267156400217313, 11925160665074583703, 7006577898090498820, 8933338746704632990, 14704958557312921128, 283685871938470517, 17049945775096584485, 1735922796599632945, 18137828521183364954, 1233454545325180310, 4616679305450045558, 799989113534058041, 9548215660109667029, 17638736186517997026, 12905149264926481878, 9206641926728869527, 11201231447988338022, 6044555324419572909, 4856995795253621298, 5361647435575923081, 6166078860096154852, 6696272579393185401, 1638259147884844478, 10134861521414682067, 17465898446534646298, 2270472397704099161, 5665896864361060199, 0, 4128, 1352424102745866255, 13301242752201603536, 5420135027930584396, 17078794493496835379, 4779811836607866048, 3650219859599657886, 13618468821889769363, 11429589192023659923, 8853101337885331080, 9650238821992519861, 14401087967309285252, 12035560952634921032, 15407186837043713393, 15711028160746246110, 5396976350889627712, 15903424027416555998, 11304777107657759509, 9857843669692965578, 12605480788735099613, 14618970056708743810, 8493993205782554647, 6059068631740368787, 18316971448227884023, 12499808993385025318, 4210674244211222629, 18405965507148502967, 173097048437312502, 15568437290332308327, 11532601739151124629, 10000279862191744493, 0, 2858403750276750521, 18287547865064093386, 16643076982183140204, 17607797632632583753, 4606352897788642339, 16669380908105325740, 6888212917900510506, 9887976024132347018, 15672872160122205909, 10605120439023982124, 17832834191852929098, 11180362325911556985, 1797669589287132096, 18316393283013557997, 17455009848636139677, 4212485662162927177, 2684395608227063909, 10865000669694511781, 13048938138389391460, 13946693875892332716, 300901360739248952, 4186546104164144876, 3265288527569414193, 8781944488148208732, 14923610741876695933, 9614148693204557112, 9347068782470538323, 17518823857230050559, 7139121107914525514, 470824845274439747, 1419643695620305796, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [16681111697957494384, 9850604216542701406, 14292233265078610671, 11560507218468362083, 11435884371355098677, 707619676799722739, 13157092351337171268, 2418773787696448890, 4672379866331806862, 14371817650991869953, 3768839363733198769, 9708763303767628077, 11396390941757961228, 4785785956560501030, 16036499041626449319, 9630510095026498877, 7634220798360289556, 5119649922187981964, 6331607203065781588, 16919596794918736104, 32726321504424883, 10309269913347989302, 14782015448458484884, 14683358530499849942, 7836268277036786901, 15462421617591871273, 12213179217732598594, 14536234064731365163, 3637686875728492502, 2382678006125050452, 14226016292255835291, 589873375673641870, 0, 1032, 4798141223555508282, 12962488577647927717, 10133257770726709126, 332864556927106185, 12116126881643349994, 6604148216925166409, 101015634312276042, 15934992137290074922, 6112274855072540816, 17762248064501548615, 13166189948742588777, 270100349969833402, 13485211244653928073, 3502306881032295169, 13607663468974078519, 8883940618995723208, 10623667092532612652, 12293715092576816840, 10386976621364522928, 9128135834925108269, 15731443845270647366, 13373704167654916087, 13746187061551926812, 11684868053863796759, 3258729720361659960, 10434904637843727165, 7034851303745741351, 16133345873308301364, 5426492436527662130, 2980140658145787783, 0, 18213217674792357841, 6883907187243818989, 10614920431791547888, 13376310260819809150, 970536228322621221, 5786498633534169345, 13904299833493296337, 18182241650367492861, 4671451809489883858, 10519951415050407991, 9409416070961479945, 9277815292140415791, 84450611619755921, 13615028923015526256, 15760906032947657328, 10394291523020808732, 14504653302726904108, 8315708932196998089, 2409075654026148870, 367320422432359503, 6139056775213015570, 6944063758267220406, 4458873320026667405, 12662780608684972080, 15472797447424064358, 4158450525844909688, 2549026714004541517, 3246198533692444934, 3222033110084083257, 5683784147168326312, 7836113917086293276, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [6160598189905115531, 18025956107099608580, 11512968082996599149, 1159818605994823015, 2364926874595277907, 7943063494760571709, 16605271790117727213, 11825547519897455023, 15342799649049057800, 3763048797193456654, 1295787082959371660, 16691905436935888241, 1915507152031483536, 17009264450373861587, 16328475049153986635, 8830519937889782762, 10115241278692937317, 1750096680784451786, 16653566373055583790, 4332235233085094180, 627717841813244731, 4706384122596616028, 219643739348167868, 10259409981493264670, 13239490680913326732, 182727077359841351, 8469105874522435313, 8517021520884886781, 3404810976915461357, 3829882598743334141, 14062283116063151751, 1610809089415408623, 0, 1032, 11702782905971311743, 8115486282645452027, 16425371230714077552, 10333496212804492507, 1572943607289284437, 13244361396034453954, 12880029163967100393, 14716450796809578181, 2618965885956593171, 1606019581379521796, 12562170441304287563, 4599116799417823473, 4257071131168813417, 10446583017549019711, 3570388907037362614, 11170081717188072664, 17238997244398394333, 17231192964516960933, 8123337005847551087, 7060091366977384949, 5719725530909274667, 5057603743378325948, 13848013489728729143, 17729739340387068117, 367186060507240673, 1411195984452924204, 11088333491201093194, 16575090776691519559, 16147396598096989679, 14525300817521856881, 0, 4448725490869322134, 16773782102167370766, 9517551778943323923, 9735157781939056258, 13685677539131842935, 74410881992624137, 16112118280329224188, 16455044890046321010, 3166113086359297763, 4123774883019480954, 8049700212209077372, 9143498805844601837, 1269471574449064045, 17099282884571514622, 17951548125515157165, 15320893071039302787, 16371352256021817139, 17154595820341397772, 5088265715035438397, 12952269508513821163, 2910118210482029454, 1585088611936329987, 16759292612217335519, 9851596960932027140, 8679788143435043297, 7792109010626424915, 3420624790371920563, 7480053259498635867, 3615950593461764641, 16487019928286415392, 10289142213544989468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1090670744084208003, 3080746365611415597, 6133575519759388325, 11695447135684149141, 6615075028106709917, 10277147404869816105, 15962120449122821193, 1254198290967296340, 2925289410746405164, 12104312877316532634, 14739488160024614333, 10743573083299131194, 12707577723315108285, 8945689852522735768, 14566241909712907104, 9028236766089923761, 10185013658812384549, 3941868484557913621, 16462538463092115913, 5673651272129016554, 1223470853173331157, 2788160682175050931, 1502692624900434396, 5566335148331577393, 17762829217961409285, 3389969163810664285, 7437527833076252327, 17084466347038006872, 6606368157240498477, 13093088208853880999, 1276807186500217245, 0, 5160, 18346837778669738664, 15130142357101091527, 6726588340010678615, 8394319278312203283, 15942424551308612685, 7629500615465222065, 14939877513325106589, 17048523965011794048, 2306293645521445312, 823113708878672797, 14981348226783328932, 7432878333905782051, 3482639998457803800, 632277917380007036, 18266437030920184246, 3366715262389109205, 5280275432441977334, 5379329043314533811, 13912213856326486056, 17217059915921675075, 15634373017412823086, 14981257187297131103, 16697350900700022325, 5239234081629986555, 3229291246709926782, 18373224696258292584, 6771862800272250893, 7666370275789511263, 12942227631865082960, 15190222347874856922, 0, 17344769878280361687, 11249881205591563163, 16071218949222383338, 546830354766363539, 7776682728634159270, 11209888800273182957, 14728140374725612977, 8386791303267182172, 9638626268997275972, 822684530408571288, 16951904742993551809, 825915008780272344, 18209952013401698562, 390611853699198814, 11327187383464966515, 12709202232488054070, 11552589705164935867, 12311030232489101343, 5023941437735028493, 16069569499603265432, 18063718751316981145, 4010755700397089888, 10892805137373131994, 9089377676555868962, 1220818432464721625, 13088066304082794059, 8657669536399661454, 419065699932221163, 3886495484944885171, 1240710433266681785, 5374430875291145484, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [87, 2631903040606257959, 11859146482331138479, 12232695746376293294, 995389826954784529, 11949085664163595757, 4404337953750906792, 6908862958628621571, 12608149157887976305, 4754146580783023412, 14308250014803856580, 9454287016901482416, 9789905333959995060, 3771810096516115799, 2150959420327906479, 14538218150241396541, 6425179495446994078, 17565393891424303638, 3667075674391371806, 5731318824387052908, 4241445880929460300, 13107360446062265038, 4176811711023066147, 5250671015911848716, 4722672072326683708, 7171204772415813456, 5618587527864308269, 16458991436693873868, 2626622112813681720, 4599215552676510549, 5363423870755590475, 4352525099414593256, 0, 4128, 6496253015800789210, 18063315295058131399, 14099326864720264780, 16744359797696928029, 11669954633423859445, 10923938539628559259, 10579480970462933513, 17315553376669597828, 12114095292572219189, 16129781670858537825, 67936491912723144, 6285840300661422802, 14359460599290704174, 7597471307904508314, 8469569990667894210, 9117246600999250277, 14614928058075190380, 13738364908865630160, 1806905237893315697, 261412144627674040, 8380596589382515797, 3809925330596605534, 1983199361335541287, 6337901890572878101, 17063257729896061936, 12690697575318882146, 3846044480011221270, 10729939698274680623, 5297971463863936522, 8671284646676347574, 85, 2858403750276751031, 1709210755771630360, 11707086547963657475, 2794745820933624420, 2841923277622193225, 16490991381302584921, 5788783276303277595, 14692549583873964816, 9815954444411995352, 16153761647449809543, 6052645635446937049, 17304693813258262086, 11634259222665431081, 12233143040630128964, 8553846008642101336, 18388379526128378444, 15548258272185388836, 15360138454847963029, 3440439455019208235, 7218244406354738621, 5887183982672949081, 15870877452527488142, 15139518776246125573, 5433537245583001116, 13408133831989321267, 4656955130371010155, 14539571260147117550, 17118765335121629772, 3475198118169682060, 11483695604905597390, 11783370765491737635, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 10468230768888023862, 11664682242720909218, 2500570831459298438, 13004725650794618836, 8624527149940617200, 11524055993362242048, 6182388235200005336, 2589834268393847902, 12931236615531993709, 8584449549244767688, 11899064714918281636, 16246984277558583019, 8772638227416864166, 11946855882944424845, 16440133693312412286, 14737175326378679956, 7842923952979169755, 2398501113047325856, 14599944340506938939, 5936050971291911531, 8286147454062396089, 14343924012975607961, 8190973727913189622, 1134938007864643353, 12054037840221089027, 10050755079785196589, 10469731445849191380, 10906931598039016782, 16150808274840457147, 13280081123993966327, 5571840125263174859, 0, 1032, 13084260837127404333, 4018109146681745349, 14498381569327145056, 3778421823029569719, 1344624249217908323, 3634653398484528177, 1428985706412758663, 11382569756632997337, 13894906302086601399, 3911680161282028629, 11467762927868003365, 10098326072301516020, 16073214466625742345, 16150512194511843089, 11525294274796193451, 15902507139806774023, 13926886722650908730, 2974304378722638293, 5274544965980948277, 9984170014312577610, 639485734140932316, 15088403650698955530, 17189134684458608982, 6515320870350778492, 7902492290152572474, 17310456195349246143, 4070136787975548901, 6345872167795009033, 3095930865537762353, 4232664728858134772, 0, 18213217674792358096, 13599297410359034734, 11548640197966434952, 16397756946501824199, 4509993724149584481, 15279575547763923315, 14387788336990426452, 1679695851270735493, 737550782574904766, 16619718868892680991, 4189079835826917979, 16548334619034420779, 2523584064344323171, 18357860221728901477, 9223263721501613140, 836498427651453899, 11050299770631141961, 1906255442715510922, 16855485989141196504, 12664144355455319157, 17100007635940521879, 307480490272233054, 14791890923980574308, 14809283111081511220, 1272668898289027998, 1746726629032389326, 781443211491376776, 4235062597258109895, 17016381150799971149, 387032599105912823, 13820432364368151262, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 12734367032130478571, 915471480408530766, 18393930191488027312, 13545212286845976163, 18210660875436245579, 1541989510332303929, 5733187932229069792, 8676871105886252208, 15648333801800339703, 12513161021723575557, 9265666514596208448, 10311060571948838328, 15479186567637803235, 9457367929087028434, 10997859361453741844, 4801586725411290698, 8358881080234670725, 14262453638255884367, 3602771739252146288, 6541843013709002421, 3170708104995675453, 10921877432993541182, 10224257779706313529, 15830149545637956450, 13414249448981002451, 11722023958758893627, 18138185027267907899, 13905103948731397841, 9009398081722850699, 16014363687546775515, 10945967283455090973, 0, 1032, 15909096041365347974, 18432189660917429733, 2798890989547891271, 10768372030970716894, 5935807051329113911, 1259182408195029650, 16024750973514577255, 6103595041913569283, 914770550723164908, 5067028895751058275, 5242612139537538536, 13359135899043031769, 4430959127423856282, 16317056360529517539, 2634255659160911215, 15590656855559575839, 6832335878067392309, 6045109056629836176, 18146646330136390606, 6482705684632040588, 2770791364887326735, 7707774010999656594, 3401430074469265273, 3500862351024377705, 5135727797169111985, 14940852959892477883, 9633218853985087472, 16966092255533854383, 3065488485208441055, 15703076512693482766, 0, 4448725490869322219, 4944140066849387506, 2095785635431009262, 12375413327700682072, 11081872751342419742, 18058781214879352230, 17856276381917295190, 6718639559482054424, 668947051234094647, 3868828750372286402, 12122170781554046887, 4343898307694473975, 12690125861105998824, 16799534473726304569, 15934980937477619093, 3969747009451350970, 7686328019139102331, 3785180857099199084, 11986142858341385519, 2506152622879710750, 18430687071203156938, 3054089675267069232, 8760992635981950709, 11143171037695874494, 4733232646684685861, 1219894586292412814, 12600138307490245388, 824784286256764128, 10170016208525526833, 593495485489349093, 11923860796119339735, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] }, last_program_row: RowIndex(8) }, program_info: ProgramInfo { program_hash: Word([8442199976350624000, 9488069924049927331, 3589804369840038271, 11846932079106298851]), kernel: Kernel([]) }, stack_outputs: StackOutputs { elements: [9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, merkle_store_nodes: {Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571]): (Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350]), Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350])), Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484]): (Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693]), Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693])), Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781]): (Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874]), Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874])), Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171]): (Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361]), Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361])), Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815]): (Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305]), Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305])), Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689]): (Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195]), Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195])), Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362]): (Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063]), Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063])), Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848]): (Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661]), Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661])), Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352]): (Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829]), Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829])), Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444]): (Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223]), Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223])), Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386]): (Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388]), Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388])), Word([13190842942618341421, 17548956981569849952, 15418963848144418856, 730733050713174879]): (Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144]), Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144])), Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874]): (Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675]), Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675])), Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594]): (Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115]), Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115])), Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809]): (Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257]), Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257])), Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777]): (Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555]), Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555])), Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509]): (Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882]), Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882])), Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725]): (Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979]), Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979])), Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134]): (Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987]), Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987])), Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828]): (Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910]), Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910])), Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830]): (Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054]), Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054])), Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228]): (Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742]), Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742])), Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443]): (Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928]), Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928])), Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643]): (Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979]), Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979])), Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758]): (Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106]), Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106])), Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580]): (Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594]), Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594])), Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765]): (Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045]), Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045])), Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766]): (Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281]), Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281])), Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385]): (Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828]), Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828])), Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579]): (Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171]), Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171])), Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212]): (Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992]), Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992])), Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463]): (Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004]), Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004])), Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502]): (Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023]), Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023])), Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539]): (Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537]), Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537])), Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865]): (Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225]), Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225])), Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690]): (Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947]), Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947])), Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202]): (Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552]), Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552])), Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079]): (Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444]), Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444])), Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850]): (Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548]), Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548])), Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448]): (Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987]), Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987])), Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041]): (Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035]), Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035])), Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301]): (Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414]), Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414])), Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414]): (Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212]), Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212])), Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703]): (Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439]), Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439])), Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271]): (Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955]), Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955])), Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882]): (Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802]), Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802])), Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152]): (Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887]), Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887])), Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028]): (Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948]), Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948])), Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331]): (Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093]), Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093])), Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394]): (Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134]), Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134])), Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546]): (Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228]), Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228])), Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620]): (Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414]), Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414])), Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800]): (Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703]), Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703])), Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671]): (Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205]), Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205])), Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537]): (Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011]), Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011])), Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516]): (Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301]), Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301])), Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831]): (Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986]), Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986])), Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415]): (Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057]), Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057])), Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722]): (Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689]), Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689])), Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144]): (Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682]), Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682])), Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295]): (Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268]), Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268])), Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818]): (Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513]), Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513])), Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241]): (Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565]), Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565])), Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439]): (Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012]), Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012])), Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512]): (Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850]), Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850])), Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986]): (Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865]), Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865])), Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982]): (Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777]), Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777])), Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808]): (Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394]), Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394])), Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979]): (Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690]), Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690])), Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093]): (Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620]), Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620])), Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902]): (Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789]), Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789])), Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542]): (Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094]), Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094])), Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057]): (Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362]), Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362])), Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205]): (Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961]), Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961])), Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401]): (Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580]), Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580])), Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553]): (Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960]), Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960])), Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169]): (Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031]), Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031])), Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682]): (Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053]), Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053])), Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118]): (Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562]), Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562])), Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725]): (Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666]), Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666])), Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661]): (Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897]), Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897])), Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981]): (Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447]), Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447])), Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072]): (Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646]), Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646])), Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140]): (Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404]), Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404])), Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515]): (Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152]), Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152])), Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709]): (Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664]), Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664])), Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800]): (Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103]), Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103])), Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741]): (Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169]), Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169])), Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005]): (Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758]), Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758])), Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802]): (Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070]), Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070])), Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159]): (Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005]), Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005])), Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350]): (Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443]), Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443])), Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697]): (Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573]), Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573])), Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928]): (Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331]), Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331])), Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320]): (Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166]), Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166])), Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814]): (Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079]), Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079])), Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447]): (Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820]), Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820])), Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284]): (Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057]), Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057])), Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697]): (Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131]), Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131])), Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955]): (Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290]), Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290])), Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910]): (Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202]), Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202])), Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910]): (Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822]), Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822])), Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106]): (Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847]), Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847])), Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404]): (Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441]), Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441])), Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796]): (Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186]), Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186])), Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053]): (Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516]), Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516])), Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992]): (Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818]), Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818])), Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957]): (Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315]), Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315])), Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709]): (Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794]), Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794])), Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091]): (Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539]), Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539])), Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664]): (Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558]), Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558])), Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294]): (Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579]), Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579])), Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947]): (Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502]), Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502])), Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829]): (Word([0, 0, 0, 0]), Word([0, 0, 0, 0])), Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045]): (Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137]), Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137])), Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914]): (Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041]), Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041])), Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573]): (Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378]), Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378])), Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699]): (Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873]), Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873])), Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225]): (Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262]), Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262])), Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057]): (Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692]), Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692])), Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131]): (Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997]), Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997])), Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555]): (Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385]), Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385])), Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195]): (Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709]), Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709])), Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166]): (Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542]), Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542])), Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027]): (Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373]), Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373])), Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378]): (Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509]), Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509])), Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097]): (Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553]), Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553])), Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217]): (Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815]), Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815])), Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873]): (Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864]), Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864])), Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997]): (Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722]), Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722])), Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887]): (Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766]), Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766])), Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589]): (Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757]), Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757])), Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539]): (Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665]), Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665])), Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129]): (Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229]), Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229])), Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137]): (Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312]), Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312])), Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019]): (Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378]), Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378])), Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331]): (Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713]), Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713])), Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]): (Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980]), Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980])), Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325]): (Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546]), Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546])), Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170]): (Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822]), Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822])), Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054]): (Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295]), Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295])), Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925]): (Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848]), Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848])), Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909]): (Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796]), Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796])), Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540]): (Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170]), Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170])), Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214]): (Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448]), Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448])), Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317]): (Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294]), Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294])), Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757]): (Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416]), Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416])), Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378]): (Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091]), Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091])), Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263]): (Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463]), Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463])), Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666]): (Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361]), Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361])), Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174]): (Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992]), Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992])), Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470]): (Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401]), Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401])), Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665]): (Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957]), Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957])), Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262]): (Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144]), Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144])), Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229]): (Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284]), Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284])), Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134]): (Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325]), Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325])), Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855]): (Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765]), Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765])), Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115]): (Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814]), Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814])), Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441]): (Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831]), Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831])), Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977]): (Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446]), Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446])), Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880]): (Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005]), Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005])), Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789]): (Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995]), Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995])), Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000]): (Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267]), Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267])), Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998]): (Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982]), Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982])), Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995]): (Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539]), Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539])), Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507]): (Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512]), Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512])), Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305]): (Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118]), Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118])), Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219]): (Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009]), Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009])), Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416]): (Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089]), Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089])), Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980]): (Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445]), Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445])), Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063]): (Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140]), Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140])), Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713]): (Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159]), Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159])), Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031]): (Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809]), Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809])), Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932]): (Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037]), Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037])), Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094]): (Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925]), Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925])), Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315]): (Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386]), Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386])), Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446]): (Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721]), Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721])), Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742]): (Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981]), Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981])), Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661]): (Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072]), Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072])), Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979]): (Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671]), Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671])), Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361]): (Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269]), Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269])), Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558]): (Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571]), Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571])), Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290]): (Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902]), Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902])), Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987]): (Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741]), Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741])), Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902]): (Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515]), Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515])), Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497]): (Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028]), Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028])), Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948]): (Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709]), Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709])), Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009]): (Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725]), Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725])), Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387]): (Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317]), Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317])), Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159]): (Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808]), Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808])), Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394]): (Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699]), Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699])), Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312]): (Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000]), Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000])), Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987]): (Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821]), Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821])), Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046]): (Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909]), Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909])), Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565]): (Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028]), Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028])), Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269]): (Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352]), Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352])), Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847]): (Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271]), Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271])), Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513]): (Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800]), Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800])), Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054]): (Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394]), Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394])), Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004]): (Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977]), Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977])), Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675]): (Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800]), Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800])), Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692]): (Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159]), Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159])), Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909]): (Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932]), Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932])), Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814]): (Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697]), Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697])), Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186]): (Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387]), Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387])), Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445]): (Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470]), Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470])), Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966]): (Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507]), Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507])), Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548]): (Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253]), Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253])), Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897]): (Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783]), Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783])), Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208]): (Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054]), Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054])), Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268]): (Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661]), Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661])), Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388]): (Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643]), Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643])), Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257]): (Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174]), Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174])), Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960]): (Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241]), Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241])), Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721]): (Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046]), Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046])), Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822]): (Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217]), Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217])), Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253]): (Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697]), Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697])), Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054]): (Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019]), Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019])), Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821]): (Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432]), Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432])), Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864]): (Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105]), Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105])), Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373]): (Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855]), Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855])), Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646]): (Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830]), Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830])), Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460]): (Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208]), Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208])), Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033]): (Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214]), Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214])), Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105]): (Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129]), Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129])), Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281]): (Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909]), Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909])), Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028]): (Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027]), Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027])), Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012]): (Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054]), Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054])), Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562]): (Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589]), Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589])), Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037]): (Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097]), Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097])), Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355]): (Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460]), Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460])), Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223]): (Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355]), Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355])), Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089]): (Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306]), Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306])), Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035]): (Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219]), Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219])), Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432]): (Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297]), Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297])), Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693]): (Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263]), Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263])), Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794]): (Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484]), Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484])), Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552]): (Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941]), Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941])), Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267]): (Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814]), Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814])), Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992]): (Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415]), Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415])), Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941]): (Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966]), Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966])), Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822]): (Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320]), Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320])), Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306]): (Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902]), Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902])), Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820]): (Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880]), Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880])), Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361]): (Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725]), Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725])), Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005]): (Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914]), Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914])), Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783]): (Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781]), Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781])), Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011]): (Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033]), Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033])), Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297]): (Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910]), Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910])), Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070]): (Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134]), Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134])), Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144]): (Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331]), Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331])), Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023]): (Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497]), Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497])), Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103]): (Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540]), Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540])), Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961]): (Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998]), Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998])), Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414]): (Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]), Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]))}, trace_len_summary: TraceLenSummary { main_trace_len: 9, range_trace_len: 39, chiplets_trace_len: ChipletsLengths { hash_chiplet_len: 96, bitwise_chiplet_len: 0, memory_chiplet_len: 0, kernel_rom_len: 0 } } } +ExecutionTrace { main_trace: MainTrace { storage: Parts { core_rm: [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 13719137288158876142, 6221215488690831821, 11468044834296629525, 16720332114142763849, 0, 0, 0, 0, 0, 0, 1, 0, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1032, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 2, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 8, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 3, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 4, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 1, 1, 1, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 5, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 16362180982079134587, 16601100057639640520, 5521682503008444658, 3792208660074152519, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 6, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 1, 1, 1, 13719137288158876142, 6221215488690831821, 11468044834296629525, 16720332114142763849, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 7, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 31, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 33, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 39, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 43, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 47, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 50, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 51, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 53, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 54, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 55, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 59, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 60, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 61, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 67, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 69, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 70, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 71, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 72, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 73, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 74, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 75, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 76, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 77, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 78, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 79, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 81, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 82, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 83, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 86, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 87, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 88, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 89, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 90, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 91, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 92, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 93, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 94, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 97, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 98, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 99, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 101, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 102, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 103, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 104, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 105, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 106, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 107, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 108, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 109, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 110, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 111, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 112, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 113, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 114, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 115, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 116, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 117, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 118, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 119, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 120, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 121, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 122, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 123, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 124, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 125, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 126, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 127, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0], chiplets_rm: [1, 1, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 13719137288158876142, 6221215488690831821, 11468044834296629525, 16720332114142763849, 0, 87, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 2445654027848798773, 13989391813235195492, 481784282030877064, 1887209632430994963, 9346278187721986719, 3141189181316333764, 4622204731995696995, 16701354768447765175, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1032, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 11116382020814057190, 14732796941305378371, 13074361791711182490, 6715193688317415490, 1571558009365433839, 13285275197432594374, 15905141483335727027, 2507840277166973476, 0, 0, 1, 0, 0, 1, 1, 0, 0, 16362180982079134587, 16601100057639640520, 5521682503008444658, 3792208660074152519, 0, 0, 0, 0, 0, 85, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 13719137288158876142, 6221215488690831821, 11468044834296629525, 16720332114142763849, 13962113176908263293, 676026057669832378, 15921241029195116857, 15915352364638718229, 1456698220748515004, 1707540503940690697, 10429997843948879425, 4559651383104503034, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1032, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 15913981378790993016, 12701179462806902902, 9645342555817022514, 6889850077248808033, 678249829196625442, 8726676798253716750, 14136118088409135949, 1027279235140821190, 8048729929177993405, 2542525775606472849, 3283471062508934848, 18058280687405074483, 1, 0, 0, 0, 1, 0, 0, 0, 0, 11899090779839289087, 1701090513954162998, 6953639183117323837, 11460660778637092812, 8345945186928076892, 11308243255833047975, 5734666540714547293, 1546649737555419076, 14643837757854608147, 7477230882792828789, 2359592855656894189, 12732146754685591216, 1, 0, 0, 0, 1, 0, 0, 0, 0, 16283412161296764998, 17261112905912533997, 1498213616014501531, 7707889409925905689, 16090493533591377617, 525010687572874692, 5228788497345464933, 13051466527897639054, 3560924095387897187, 12551242480725370445, 4038828260160651477, 6132317990703151787, 1, 0, 0, 0, 1, 0, 14261694278902826987, 16097544111075686229, 16632169854204459773, 14265791174051766329, 14732671264513481238, 15642599276989292777, 7593738854072541043, 11440582168151819564, 18258483622390056257, 6851601084855956341, 10463349537167637967, 10032876585525342603, 825669147467031185, 16271217766495541082, 9021089524754424392, 1, 0, 0, 0, 1, 0, 16780109665356203593, 16025948514351396737, 4256182047405196535, 4919013996388780384, 6974015548720770018, 10189882052640604940, 12288632186238773648, 7055558833039165669, 9820743264545515107, 7353106531603230851, 5612808106478211181, 362487531847990854, 10259224130335842891, 2374318293393776907, 16208179153232019183, 1, 0, 0, 0, 1, 0, 9496969110446094198, 10424961628901078909, 7587726188775237019, 13423955604028434301, 12288543613568774022, 4068762405627465026, 7288480650179820504, 1035430088689333582, 2651098721515326755, 4524440782000877024, 3013038852551457145, 12536534023666437466, 6560028330562582937, 9090521726813489969, 17634755409309861791, 1, 0, 0, 0, 1, 0, 15761194215082968049, 15796684185970405493, 1294179585337070936, 5701860167148115542, 17707247215386403887, 18419960639673587986, 14570347312565937582, 8634142387233894354, 11938075017385927203, 8060480374868324599, 16699922976999064541, 14234489074154948378, 17210389744085299852, 17331527780947314617, 16356838976302290254, 1, 0, 0, 0, 1, 0, 6184336662619539433, 7106147576739595100, 18237994300618329820, 9768155666925548219, 226714884885574576, 11169479382209254075, 5756676929838789145, 29803495366482069, 13128905441940840949, 18304516631519674746, 3177693875357946498, 10624850715031233718, 16956738608020324589, 10558540052020438814, 7826502712354673600, 1, 0, 0, 0, 1, 0, 1980308537464408089, 6810023246846442283, 9400257804338494201, 11246932855318952856, 7504545710540897051, 5823677062954428984, 9151299935574592196, 15905322272715446259, 18174748553199601666, 9877077233183640995, 2431998410719122545, 3541292002384422941, 5416588529930333172, 15788517205879313917, 2490575598934209003, 1, 0, 0, 0, 1, 0, 17950140321155419078, 9014768943295123367, 10707122777228105884, 10701204914974985643, 15060806908759160804, 7011191650405807117, 13598159658926423040, 3947314552577424057, 12985682730462769834, 18264715466581442035, 7667189540353817157, 7685483800933651249, 16085167604591833455, 16105855167414075111, 16215395602017884846, 1, 0, 0, 0, 1, 0, 8676227747932036802, 0, 0, 11504729673400082663, 3659553513673892306, 10374352082945691939, 15819529278889203623, 18107940902385670152, 8889798095480337831, 12737345777792032790, 456604824069734238, 2859376131275373721, 8758251935142908528, 2364536875264708997, 2435873391009301907, 1, 0, 0, 0, 1, 0, 0, 0, 0, 16797630026773069829, 16954579754978210547, 4393671449525183699, 6245909065255485436, 8311309349844601638, 3305827896314343556, 1615477551160071258, 3897903986825909618, 13015230208471866351, 13839070994009764281, 2415598337053791919, 5526300544248852335, 1, 0, 0, 0, 1, 0, 0, 0, 0, 12827873667465929582, 15892701250663610383, 549489834728826775, 9425334953627649153, 15402634395731091512, 11814416271399500934, 14597718118926923662, 4726679541432826422, 342915941842538663, 11221492717904369823, 17188959961041335276, 13559932473868727168, 1, 0, 0, 0, 1, 0, 0, 0, 0, 8689096602925893779, 4096531352684607500, 8424481237826564505, 15238165026175259240, 10985176737527635898, 2672540837788784952, 6649439643634522762, 7581835251244605715, 17671970641549389116, 18069913154458602790, 749417941228438762, 6150863900366154379, 1, 0, 0, 0, 1, 0, 0, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 11116382020814057190, 14732796941305378371, 13074361791711182490, 6715193688317415490, 1571558009365433839, 13285275197432594374, 15905141483335727027, 2507840277166973476, 1, 0, 0, 0, 1, 0, 0, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 13719137288158876142, 6221215488690831821, 11468044834296629525, 16720332114142763849, 0, 87, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 14526210785099218637, 11847263499640079386, 14727111875255715984, 15492005690507045243, 3560320103534777253, 6108459071875623888, 17010585649681490524, 9461625672567273576, 5346213935533921584, 17324400741801951375, 11366145235097950908, 11020281342858012232, 1, 0, 0, 0, 1, 0, 0, 0, 0, 16197070053425155514, 15404003330998391348, 11930643358177149189, 1706026293115752249, 4860311493079570077, 17106682771221635926, 1613342353291471586, 10021094444428090144, 295368900173018762, 10362371049945425700, 9316163589333399506, 7378950726844095693, 1, 0, 0, 0, 1, 0, 0, 0, 0, 11506810158870826797, 14392904697466827547, 17905937794745323592, 17513565884470753819, 7019811109989114514, 10250939299242755101, 7620822681592706112, 12768902792042039708, 744728025267091276, 16212166364245632221, 10010770609378408333, 15023204573923685916, 1, 0, 0, 0, 1, 0, 9206943447329060417, 1573227013771687083, 7633983188953929869, 14747762092445444483, 12960730896173836507, 5351433366377253619, 4177159482546072600, 17061003377938727239, 9435579121926835049, 9864020053232925179, 11244311170762781618, 2840907732738372264, 7192941522047765124, 6173174116697481058, 13004561835267794042, 1, 0, 0, 0, 1, 0, 12007385695887985386, 13598702180788517287, 3912064789771327196, 11932998954627996911, 3853323028698833085, 11507033346049547360, 10110848241210835991, 15428609857280202530, 17110299148476621277, 12520416593002020608, 9431488564150546187, 2602629576595200800, 15183940660821516128, 15328070744340284046, 9882485700386666987, 1, 0, 0, 0, 1, 0, 2642957852140576392, 12998709907982857483, 4565256592569070651, 4013127352579691203, 10860110376897053120, 13677509527593892026, 2308518476531625659, 6232392686954434349, 13948263847203418837, 7843559618500491242, 7771043128539275771, 18270783924518568037, 16689544634184962614, 16359543813917605495, 8488375023251026510, 1, 0, 0, 0, 1, 0, 13959988857529015221, 12915245760499792818, 14841159553908529338, 14670848694035742368, 13930039566082372841, 9902385290951234306, 3203646694279229751, 13440312555890036471, 10385999516795969620, 11713935020689149772, 12229669264695050570, 402942260260809100, 16753462626177821460, 662362961313881669, 5887183544599407053, 1, 0, 0, 0, 1, 0, 14402936773953440947, 2012430503613052642, 1213953359224393220, 13944145787018602210, 6056959262477445647, 4982640241702718669, 1688381135968391307, 4510633793399532317, 7320984145724666154, 4691989180601120012, 102059673196228558, 1411198915631488472, 1854414388528665842, 16986811917033125654, 795637807896719676, 1, 0, 0, 0, 1, 0, 6294256185997130924, 4739079035802422148, 10935612526477766520, 17716511124280484394, 5021001597521525061, 18126874747305633609, 481644947884807344, 6049685422777720638, 1030047529196261526, 9576302115777192780, 10035472829778314322, 923305066890152615, 12527260620733941943, 11414360666749268526, 17760291183069624834, 1, 0, 0, 0, 1, 0, 10231661581337343904, 1832808263237927056, 6905801525972141190, 7456565975287668714, 12513973463050722371, 15559507328575476525, 2883833371658699080, 3184838730020301861, 18205970767593414562, 2798075613901729544, 189593258747480201, 13243754036156659300, 5745460764532976218, 2786581607585809614, 17436021357923428450, 1, 0, 0, 0, 1, 0, 72056538882336487, 0, 0, 5652048509186166814, 15367385573432163092, 6683125870356394251, 3770937106356856256, 1769679637596203925, 14372844572054653742, 13769745398507346855, 11807785571768521955, 5724215673931049374, 4401662327723853424, 11928715632009092524, 9924361168171239878, 1, 0, 0, 0, 1, 0, 0, 0, 0, 15128667119917371737, 8016996928120686373, 7467419359957362665, 4993381537595555977, 9371037824338144222, 2930594646951740022, 3944515787153841278, 5454163417882053837, 7667177038930845021, 10105079595217614088, 5177647710243780137, 13395674984723106859, 1, 0, 0, 0, 1, 0, 0, 0, 0, 17075658029987678701, 16942975531700611427, 3643709618611291855, 1334709094417075573, 11909212706933233016, 9741605425019020242, 7607696627297382550, 15299729661431018600, 7032572794257903279, 16683658838871091473, 3645139219999290477, 7245544203380098384, 1, 0, 0, 0, 1, 0, 0, 0, 0, 12068304939642236116, 13614044321092849027, 2880541849277464939, 815353510606417922, 14606426392222040491, 10929343986009381754, 18415245620786467058, 16142346014486690114, 10307567187784261413, 3831820208496643010, 14408727760370549811, 16272758710359397343, 1, 0, 0, 0, 1, 0, 0, 0, 0, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 2445654027848798773, 13989391813235195492, 481784282030877064, 1887209632430994963, 9346278187721986719, 3141189181316333764, 4622204731995696995, 16701354768447765175, 1, 0, 0, 0, 1, 0, 0, 0, 0, 16362180982079134587, 16601100057639640520, 5521682503008444658, 3792208660074152519, 0, 0, 0, 0, 0, 85, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 12086689928305136975, 10578835246084642663, 16542988469676950340, 18039575486237140027, 11378817209220925403, 1830288712116369429, 6836951313152193092, 13067316829245445662, 10483719891652983399, 15107628385291453978, 5745482890193398991, 1467598035505522824, 1, 0, 0, 0, 1, 0, 0, 0, 0, 6641033060700930640, 8002128452364190151, 4237597913508652736, 16497663922788367837, 9373930087271682821, 8772840226065969951, 13812790890684464043, 3327344850838518736, 15781875901493184698, 16732525831131872764, 1159309880266465962, 6519234662137256116, 1, 0, 0, 0, 1, 0, 0, 0, 0, 10088943647124252289, 13701383109068607902, 15690388373484222925, 4290213237740108975, 15844775943612000391, 16171043348080529647, 8784789786127538562, 12635460091357573504, 10561363445665196403, 3917577954302608976, 5337858229134527127, 14152777758433279341, 1, 0, 0, 0, 1, 0, 13029570897742009002, 13177254746172619023, 16038571161593335404, 2188338323498964707, 14662423055206707252, 399526319231252303, 14972684080243877319, 16777311805145501140, 6099803173114002593, 11253362042985817221, 10221863501466764826, 13414791437675451535, 2725322839420367772, 11819412321405778772, 13817033321558649088, 1, 0, 0, 0, 1, 0, 13691749519374287845, 15387673422637086663, 6922978787178957527, 2041172898547348571, 14589651886185789070, 5957633751491508475, 11960354433033043999, 15992971255870582512, 11830967408320733184, 15268965263556481837, 9065968121241919240, 14630209597160847101, 3695262652988767746, 6761434464064434034, 4499935311821727041, 1, 0, 0, 0, 1, 0, 15420756780139702261, 12424942891141165558, 6929528357507663172, 12198893338677478437, 18421446739075495822, 8468855093677567166, 14423050383612849622, 15188396328060565700, 16106496456550916799, 4380220556771000987, 18185062664582859482, 3471791712555441489, 5206529722281859812, 12099854936489528262, 3482375809599031896, 1, 0, 0, 0, 1, 0, 15574108340013622137, 15113564352853103247, 11759657553614819330, 8329975443345290464, 17940882943282719830, 715706186220073675, 11225208304861844348, 11251091880797815873, 16487042113140331701, 2684378958809639271, 18420809765897439905, 5225320321320513732, 6305682781245368810, 4669442538207571276, 14700449525371639507, 1, 0, 0, 0, 1, 0, 2979254376677653503, 1883000689168719362, 8104422763610466617, 5576229311275790732, 2194272311725182022, 11069690432331401312, 9059389138265053881, 8765354464725236382, 9222374345361788506, 18259801840836875925, 6516753426367602114, 16862896352549227556, 4308341550229035638, 3265342498516698837, 13464131825573347891, 1, 0, 0, 0, 1, 0, 13700569878861168214, 2688488967505940113, 3894270749155947782, 13272913612051073638, 229891148220106304, 8827790146883078828, 18375171102175520942, 14403529172649637015, 13099700194841873205, 188376523053645225, 1993959712224675182, 14801384607878448444, 10465527702245819388, 17660990215931846922, 908628888712311860, 1, 0, 0, 0, 1, 0, 17841857416383363570, 1410880649834889205, 15205315845157535511, 474005396413342575, 13140045598301896487, 3896472587811302452, 11889483340877797878, 10675872888943407911, 9043988711004206942, 6590644200881402626, 6630214594291443650, 7328314644790889015, 1925120838408255657, 12102121948068675841, 3366469296269798303, 1, 0, 0, 0, 1, 0, 9810051462759316493, 0, 0, 1967048762267479030, 14694789381285854906, 7850615184380239535, 6179804070945807128, 6190847648382551976, 7074541545875785618, 9996122377954848783, 18406348765365233841, 4381980521208731448, 2527214276140522656, 17476881528019612421, 10227790736734811126, 1, 0, 0, 0, 1, 0, 0, 0, 0, 12825387260273911399, 6194529288585122100, 10547428200413979362, 7146038864248149980, 3758150568829560250, 6436891845148661154, 9620702432336511668, 2457824222102594551, 13331592005230563304, 11086532868255377399, 4413541832527011587, 16051730796051624324, 1, 0, 0, 0, 1, 0, 0, 0, 0, 16438196827052442198, 18163112479653478435, 13659775893412875850, 9240379517650154023, 17622738652736541491, 10377502873777599097, 14167784496777925017, 8652392797374596693, 10690605953822876908, 6607959159332506262, 7925296024181542304, 11865355698347075352, 1, 0, 0, 0, 1, 0, 0, 0, 0, 8453841446519729480, 5007921045949414127, 10571120719178391220, 9766554424414228694, 8901262338981550121, 11643533070801732852, 18177267262839360795, 4695688607260963965, 5981212851350180937, 7185340145346514702, 15820300171842782914, 13017849308841041926, 1, 0, 0, 0, 1, 0, 0, 0, 0, 13719137288158876142, 6221215488690831821, 11468044834296629525, 16720332114142763849, 13962113176908263293, 676026057669832378, 15921241029195116857, 15915352364638718229, 1456698220748515004, 1707540503940690697, 10429997843948879425, 4559651383104503034, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], range_checker_cols: [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2187, 4374, 6561, 8748, 10935, 13122, 15309, 17496, 19683, 21870, 24057, 26244, 28431, 30618, 32805, 34992, 37179, 39366, 41553, 43740, 45927, 48114, 50301, 52488, 54675, 56862, 59049, 61236, 63423, 64152, 64881, 65124, 65367, 65448, 65529, 65532, 65535, 65535]], num_rows: 128 }, last_program_row: RowIndex(8) }, program_info: ProgramInfo { program_hash: Word([6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845]), kernel: Kernel([]) }, stack_outputs: StackOutputs { elements: [9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, precompile_requests: [], final_precompile_transcript: PrecompileTranscript { state: Word([0, 0, 0, 0]) }, trace_len_summary: TraceLenSummary { main_trace_len: 9, range_trace_len: 39, chiplets_trace_len: ChipletsLengths { hash_chiplet_len: 64, bitwise_chiplet_len: 0, memory_chiplet_len: 0, ace_chiplet_len: 0, kernel_rom_len: 0 } } } diff --git a/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_09.snap b/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_09.snap index ea5e0b6e37..2bcad58351 100644 --- a/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_09.snap +++ b/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_09.snap @@ -2,4 +2,4 @@ source: processor/src/trace/parallel/tests.rs expression: DeterministicTrace(&trace_from_fragments) --- -ExecutionTrace { main_trace: MainTrace { columns: ColMatrix { columns: [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 33, 33, 33, 1, 65, 97, 97, 97, 65, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [7458506668679174706, 1032, 8, 0, 7458506668679174706, 665741763369239996, 5296, 41, 0, 665741763369239996, 8212736248369912082, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000], [18375473735916206629, 0, 1, 1, 18375473735916206629, 5831108162926480783, 0, 65, 65, 5831108162926480783, 4071281311826053218, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331], [2105717247508690050, 0, 0, 0, 2105717247508690050, 7330889791923421278, 0, 0, 0, 7330889791923421278, 16681111697957494384, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271], [1679902783560062568, 0, 0, 0, 1679902783560062568, 13218130135561237014, 0, 0, 0, 13218130135561237014, 6160598189905115531, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851], [8212736248369912082, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [4071281311826053218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [16681111697957494384, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [6160598189905115531, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999], [0, 0, 0, 1, 0, 0, 9999, 9999, 0, 9999, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [9999, 9999, 9999, 9999, 9999, 9999, 0, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [16, 16, 16, 16, 16, 16, 16, 16, 17, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16], [0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2187, 4374, 6561, 8748, 10935, 13122, 15309, 17496, 19683, 21870, 24057, 26244, 28431, 30618, 32805, 34992, 37179, 39366, 41553, 43740, 45927, 48114, 50301, 52488, 54675, 56862, 59049, 61236, 63423, 64152, 64881, 65124, 65367, 65448, 65529, 65532, 65535, 65535], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [7458506668679174706, 8136249212351146192, 10784649219148085459, 128781735205120527, 4547968979093876849, 3546336675446295543, 10817940156349236625, 14189444001012371653, 5493374351233807563, 8311102902317058756, 6249712288789018971, 1614874318552505578, 8181452518454181592, 598477530791288280, 8307036201059139827, 17345949525972330427, 17120430504411685184, 9024048572557701022, 5442249363272202440, 8891889669188699464, 13981710006578989582, 15202252296288325862, 8901049526912687276, 11824695302249715491, 8477037444632037091, 10111259653022775679, 9872576991436394594, 13620574761069749666, 10552500864729979640, 18032794979945654604, 153382829717154572, 8442199976350624000, 1032, 10320, 13024110921086730221, 3587442816163675215, 512402747638547729, 9217956011885162917, 3925750957223009950, 8674177413178223320, 12846799727083908462, 9116601283268739756, 2958792353189815054, 1720195204565087693, 7696852080146622077, 2890877729556257606, 16676527939404087356, 223754558788184593, 4767414622778376421, 14072300156908432530, 16856861612825314654, 11910434229443384600, 15658716527747040980, 14322127566252286435, 4770460127206402609, 10805338145914832851, 1391598300875421210, 18211456042978337510, 11866022853402812888, 6438324596032750504, 13328288515202849800, 17331158106613184460, 18344276842462151560, 7458506668679174706, 665741763369239996, 16242795687146137268, 321461142783715873, 2826379816086788535, 1389982844959459783, 7504428176840094167, 16867052141953300014, 6524645837583534023, 7971642927196132266, 895587693811363643, 14045043160415708545, 17186760898540197468, 11586158328390007250, 12564286920483154715, 14264987096664760063, 13473611649745551608, 3074526273535018608, 8192703318881365638, 11332735769645700919, 16102114657139125593, 17852385312535653754, 2362278605853243291, 7801968558670902550, 8976000347315438733, 13152720785410684086, 15178160026565391559, 16635907827753325426, 2952369032039574593, 2377128724052460864, 4064757387509104114, 5276412771718093926, 8212736248369912082, 5296, 52960, 6811813611500970866, 12330218901740233931, 16287800225917557614, 2390658038828763199, 4670881323897574211, 15935136064817789611, 2699367049541735206, 5505690989019187676, 4740977976888162022, 5734803687955113279, 14716704723144357988, 4469212567425053522, 15617193812494172197, 4848896952878415343, 18385001813020718595, 3406927099241203725, 6500845817907766790, 14130590127555482700, 10343975768128176185, 15693873175844605389, 2059720903132940981, 3757345954094976880, 3089069334759629752, 18141223932492835937, 11387279664761561894, 5402048984901238600, 12664138717389652380, 8299034149894841811, 4141583402420192864, 665741763369239996, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [18375473735916206629, 17377183675986858406, 16204388331933209503, 9851558383041711453, 2647731244796610075, 13479103754506160685, 1313884950803363652, 15346175195946058279, 8910192708346993775, 2151299325850503780, 16669085269506854818, 12924378726200437768, 5909277165962634165, 7995732842947875893, 14386798070662103151, 7879022579148049870, 15020611106200374787, 10724238176158470430, 15029834199037822311, 11678935371612262717, 7297009056930466619, 14511898776428524296, 319792799645144231, 13382186579597492216, 2694749223042447691, 13263694931203634375, 6000186529178301892, 16523385558055279056, 7022204645736728964, 5338134468072720249, 15645384100209479912, 9488069924049927331, 0, 8256, 1131208899036558480, 1667157010810320250, 2053960715201569301, 1526213270499333709, 69813565043892453, 14925652377538846871, 1380252317064967448, 9902934070223067140, 3786794161520721521, 664031068804619792, 8470323998416702977, 4965297830526000942, 9404280000999464502, 8244737495337250711, 4784363486033662704, 4680481291290566437, 15373555507761845373, 8780119261264514018, 729009684537575982, 18306419558979237700, 15407410920890065538, 2509966126115291236, 12709897403480972846, 11498596868429821859, 6606875518512322314, 13880694912200059110, 6972406840307481976, 14148490408465275064, 2917966740410115114, 18375473735916206629, 5831108162926480783, 5716807500553500532, 340111207878988785, 18256387944673635196, 10860511098536981986, 8459821732881051520, 6920921369535874813, 16951093806716492481, 13791358524817111974, 5736505110286114902, 6134208873573181149, 9775353746636648794, 10511806043496923148, 16994604820290358508, 8663944065392476082, 7230189013861170101, 5624631671914610235, 6327683047402873297, 4175477208176608783, 954074467059951894, 9430822593953620080, 3254964387338063442, 14616933013502048910, 323829297696706606, 15299582253555179912, 8256585982323809806, 16419251794401517641, 11559790149908051338, 2239581712082993389, 12489932951016483829, 11738733634614750668, 4071281311826053218, 0, 42368, 9860311344216082483, 4356844177334189800, 8724150062868049447, 3846911055059526201, 16861225296757755735, 16925961143355054643, 7763338432894318220, 7504506723642096670, 11045006668578082721, 15092595329879644577, 4298948569114582870, 17810272068739440989, 13969944955380272714, 12356982018953263244, 16520418754635432271, 4689628285093180625, 7190852124445770478, 13072354659666011192, 1524422576558323017, 4274963317195893198, 12684756825761097033, 3511571172448102031, 823386573204270152, 9615020079928624381, 16119779393022010645, 17295023900181003317, 16373019178487693626, 13423474518210064130, 10379152206886126257, 5831108162926480783, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [2105717247508690050, 3107344020706784815, 7535295255934147784, 14961534904937133494, 15458110929197782417, 5854257801187918217, 7408528896221680379, 7195773034137126318, 6953015881067099300, 8311075386067189185, 7490596925699016321, 2748780903535738274, 14124675439405907210, 13467811864817035684, 12069265029549314681, 8713544979421645407, 7271740931964389253, 13358005363663908988, 1445604555428043843, 15414631947824553103, 3604233398898996465, 11389542141657004950, 753657943574098354, 16156878489884540028, 1283495432526365661, 15770030010231724104, 4992467617151662209, 9388418952293233141, 12063673466969028652, 6266501778891918617, 17390445613818630245, 3589804369840038271, 0, 2064, 18136552782870868471, 952274539956745973, 15933282259815262093, 9924516287334785738, 18064603646801610993, 5114527609957824263, 11816233963570869158, 17699527003452380450, 14533708946479200173, 17484213571014188868, 832814531422633701, 1508169308733590908, 8423043379628164525, 12595277727969636921, 14226276023010866965, 10485112285448962747, 1783527593060720204, 10145484005384627580, 7463752398658534839, 17345550819494003223, 4432309123412733588, 7086318781105575433, 8830891075082588619, 310185093236608634, 16683125300631590273, 7786799186167080425, 29465347809991832, 8090161351836983773, 8665315444141111469, 2105717247508690050, 7330889791923421278, 17979691280170131106, 16980963677900604856, 15976151213056828438, 92714918004478284, 17365496272474871894, 17001192471520708179, 3321277494654107778, 16893172732645584491, 2027752104829715962, 15452271030076785961, 2501796678284190373, 5676660220829808154, 13123673595423766920, 26738717326360259, 17483757498059224444, 12817208054146358362, 6986963031258272860, 16687757358165325375, 18027249453476092631, 15075850538217806798, 4190259332272306773, 2553182391312160489, 6173756644452043592, 7042376686216238529, 38980987021367719, 12463158039410249198, 7049795244189838947, 7060420962088551737, 9342274029206616333, 1435264878438078251, 16681111697957494384, 0, 10592, 279816225750213135, 3650402777016745376, 1781472746866786234, 10113987313323159199, 9398274187564883752, 16748408482785331310, 30358156203896034, 3074595635178688035, 6205342630873024293, 1697370376582801763, 8815094577559083340, 449557436115663881, 2151092097708635255, 7636620675010033430, 2307825524015342399, 8991051645303444091, 2473911126910605027, 2375720167990024221, 10037026397378548640, 14834683004264726058, 6907102329277961715, 18213897356329070177, 5667698909130756383, 4686287875705541143, 12476469095199609689, 17702654136961983716, 5311930945536331644, 7223353560134237057, 13509433978352760019, 7330889791923421278, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1679902783560062568, 1730400919877242464, 8594455900178560628, 5726930420197336139, 13273590888045863622, 8753781667987110661, 12948922070052129184, 6957781166000927195, 11540514940863049397, 3555060714483297014, 9392868496609143397, 1424153760517090352, 9018810402297148417, 2907590405487611226, 16087116659981325603, 6124015441109604199, 15635572367538115795, 2170747068790740224, 3201993911066137312, 11259421084459541380, 9993917348799810609, 17222088454832638116, 15686086798273471220, 12787265931454127207, 607842291318703015, 13403753643599459835, 10689062953812945200, 12619604521626526557, 3744742376692732597, 7474246814889551252, 12416458660228151392, 11846932079106298851, 0, 2064, 9594118340025725004, 16218246678075491818, 11582919835122342747, 5661452934218108707, 3714647928422746674, 13689184893219719187, 1899963197709801965, 8313716591368695784, 17822645741084942000, 18354595702287703799, 12620512717427217848, 10145637708639089787, 1735222492513760332, 14681927838838900060, 9262747238997471758, 11498487923782501751, 8924101344488972446, 2592517964915386184, 4276681409258176044, 3764365715267793208, 3120204268813370353, 6019260256544801113, 2801984351776029768, 16979166255722313516, 2813750347113564525, 16588139065369475399, 12012198471360912693, 2492059183640657261, 16968938268466755316, 1679902783560062568, 13218130135561237014, 8897450981738644183, 8122025352910807675, 14806163515298168591, 5442054526001626765, 3774836954819930057, 7873436160289973996, 1985577549930980807, 379441097109437269, 1582743467085230093, 8777470251655517715, 10400069677678307421, 1177689384604532813, 16561198203506864486, 18413269984357459958, 1623867674755828306, 5071121402113212599, 11851310101017854885, 17866089753923079131, 12853565947951893885, 6966840703169954718, 2619660424044064391, 4642489055874642868, 6457652449305783921, 3582227845111194274, 9002213586940350635, 8120300831241327696, 7598230464484206583, 432418536618916281, 10696618739033813212, 2085147768356017783, 6160598189905115531, 0, 10592, 1439899159397533405, 14727094498238943916, 10746359213734270257, 1223812058834541930, 1848521703701691504, 1128334504960281357, 6743090978755405998, 7738088049886519458, 17939832698319978092, 13966013418513317366, 2011070876654233589, 12183169551034808723, 9308934663460035993, 3987409101004068842, 6640678206253988218, 15420175838347825984, 2447243913023891846, 16080138638164650345, 11821902144147060712, 5951909302827919869, 138258931412597884, 10064659859509677191, 6862491015452895794, 10574916399821725047, 3278355048806054125, 6884933911815373710, 4616652429570306671, 3777113587480581710, 7620976189553973499, 13218130135561237014, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [8212736248369912082, 13582507089316059702, 7058022398850579311, 14448859106484550632, 8488923843888712176, 14387511811111000559, 16343533314104084279, 7144420700209912913, 81438176960127805, 11353579355252691279, 15391029939397732169, 13654856085785737791, 17867630563899600855, 15638494238775280514, 15278759115432814741, 9672833929788573796, 8499991101857103008, 4277878641698006595, 12990966731553386694, 325849556554992531, 16823455732252835952, 10325677389248902106, 17215632082750072073, 5871229270093729693, 1418595653525548799, 1623140794865507125, 3521868013962458536, 7592427336074080103, 8813490692122304227, 15033504818965134746, 671768789535371387, 6002676145170957552, 0, 5160, 1190658701913535022, 9371121588404883743, 7133056533056999470, 7380100170229652082, 14719783382686670107, 4693530971176924881, 11125714198188567552, 2434816259070577714, 17927785478103501878, 834873962620943786, 1091858408197145201, 9293176204765248193, 11318806736621162148, 979530496520387452, 8328113718786640843, 15870139479256453021, 7754853849459016697, 2742936430580983415, 6806060556807781604, 5089080673677611112, 16430235900965466453, 309743103212430298, 15664803780047891222, 3113571524475220627, 17862871362988443440, 1231393200801541530, 15779352999894925288, 6026600320279882336, 6970552753544824994, 4949154992619464010, 0, 17344769878280361092, 2672032990889952726, 10966643852490493990, 2592429945178091576, 8172562148455605634, 14004003701484837955, 12834107981647449396, 9875636580100479976, 12047948199477092131, 8025491038733220165, 491259531166040341, 14832623839190995610, 14697509357953676418, 5789610466730383818, 388263584830521272, 7439414156048078496, 15784515228652197776, 11049955424692728889, 14895470599018577003, 7841617945839187879, 17455550201169057010, 2534236084163066389, 6762591351360230328, 5346858927664762265, 7945321262401027963, 10750885965856570936, 12370887997614982110, 16868606775754956395, 12653757924793616214, 11706271638131904220, 10827276321637451859, 0, 26480, 4254579990847524851, 17114576923598071233, 14501968992007296006, 7693932549469059792, 10678009787450266287, 2595890940213877342, 12027612752909244618, 11942792976788752435, 8893673039996221512, 15212529265532680398, 977526836722797909, 3774006073579156026, 17701622526704384546, 15389797735547254619, 13767602282518466067, 10581163748471525208, 4912900994653972152, 1666712169140912317, 11001907572334629439, 18179452850399895424, 1689425248988491264, 724394552750888620, 13424695554257597947, 17992577679858152184, 11468668142758644503, 12524389240992679275, 2671393322368710032, 1059544940949021637, 18127894597596272634, 16116071169182046485, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [4071281311826053218, 8965269515246497704, 4610105990937441552, 14871257653827208567, 17566918610707158078, 4662267156400217313, 11925160665074583703, 7006577898090498820, 8933338746704632990, 14704958557312921128, 283685871938470517, 17049945775096584485, 1735922796599632945, 18137828521183364954, 1233454545325180310, 4616679305450045558, 799989113534058041, 9548215660109667029, 17638736186517997026, 12905149264926481878, 9206641926728869527, 11201231447988338022, 6044555324419572909, 4856995795253621298, 5361647435575923081, 6166078860096154852, 6696272579393185401, 1638259147884844478, 10134861521414682067, 17465898446534646298, 2270472397704099161, 5665896864361060199, 0, 4128, 1352424102745866255, 13301242752201603536, 5420135027930584396, 17078794493496835379, 4779811836607866048, 3650219859599657886, 13618468821889769363, 11429589192023659923, 8853101337885331080, 9650238821992519861, 14401087967309285252, 12035560952634921032, 15407186837043713393, 15711028160746246110, 5396976350889627712, 15903424027416555998, 11304777107657759509, 9857843669692965578, 12605480788735099613, 14618970056708743810, 8493993205782554647, 6059068631740368787, 18316971448227884023, 12499808993385025318, 4210674244211222629, 18405965507148502967, 173097048437312502, 15568437290332308327, 11532601739151124629, 10000279862191744493, 0, 2858403750276750521, 18287547865064093386, 16643076982183140204, 17607797632632583753, 4606352897788642339, 16669380908105325740, 6888212917900510506, 9887976024132347018, 15672872160122205909, 10605120439023982124, 17832834191852929098, 11180362325911556985, 1797669589287132096, 18316393283013557997, 17455009848636139677, 4212485662162927177, 2684395608227063909, 10865000669694511781, 13048938138389391460, 13946693875892332716, 300901360739248952, 4186546104164144876, 3265288527569414193, 8781944488148208732, 14923610741876695933, 9614148693204557112, 9347068782470538323, 17518823857230050559, 7139121107914525514, 470824845274439747, 1419643695620305796, 0, 21184, 13079805966919738688, 12218492589526939611, 1562069618543971026, 952986602744509450, 16155494143085714581, 13684626716727802900, 2303575863276843576, 10596243276715621734, 17646165020998189117, 11814345067449767109, 11825442891411236224, 17347702280974326762, 10643130636190759117, 10594562435231095624, 4601317543004968907, 2494640429618639710, 7283529819405604014, 12179021258304518015, 15808731023964574299, 17252671119722267451, 2994890735774817444, 1595171953489970254, 11834064729547782130, 3702466161428093475, 4997071000317359325, 9247736708382385184, 7020445890779083806, 13774982404484476980, 17184349270149775183, 13243492223453509904, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [16681111697957494384, 9850604216542701406, 14292233265078610671, 11560507218468362083, 11435884371355098677, 707619676799722739, 13157092351337171268, 2418773787696448890, 4672379866331806862, 14371817650991869953, 3768839363733198769, 9708763303767628077, 11396390941757961228, 4785785956560501030, 16036499041626449319, 9630510095026498877, 7634220798360289556, 5119649922187981964, 6331607203065781588, 16919596794918736104, 32726321504424883, 10309269913347989302, 14782015448458484884, 14683358530499849942, 7836268277036786901, 15462421617591871273, 12213179217732598594, 14536234064731365163, 3637686875728492502, 2382678006125050452, 14226016292255835291, 589873375673641870, 0, 1032, 4798141223555508282, 12962488577647927717, 10133257770726709126, 332864556927106185, 12116126881643349994, 6604148216925166409, 101015634312276042, 15934992137290074922, 6112274855072540816, 17762248064501548615, 13166189948742588777, 270100349969833402, 13485211244653928073, 3502306881032295169, 13607663468974078519, 8883940618995723208, 10623667092532612652, 12293715092576816840, 10386976621364522928, 9128135834925108269, 15731443845270647366, 13373704167654916087, 13746187061551926812, 11684868053863796759, 3258729720361659960, 10434904637843727165, 7034851303745741351, 16133345873308301364, 5426492436527662130, 2980140658145787783, 0, 18213217674792357841, 6883907187243818989, 10614920431791547888, 13376310260819809150, 970536228322621221, 5786498633534169345, 13904299833493296337, 18182241650367492861, 4671451809489883858, 10519951415050407991, 9409416070961479945, 9277815292140415791, 84450611619755921, 13615028923015526256, 15760906032947657328, 10394291523020808732, 14504653302726904108, 8315708932196998089, 2409075654026148870, 367320422432359503, 6139056775213015570, 6944063758267220406, 4458873320026667405, 12662780608684972080, 15472797447424064358, 4158450525844909688, 2549026714004541517, 3246198533692444934, 3222033110084083257, 5683784147168326312, 7836113917086293276, 0, 5296, 6743125803107521679, 1867163304908812007, 1669000574108639518, 3582028644269610893, 16317815132307200966, 7118493626667445787, 13566879202183211144, 12402898926771175303, 11408064245891139905, 12248403740758614702, 1261452888691293041, 7470708275017896296, 10608583573536775206, 12594414503848564818, 13990563506880433299, 5287408014276309700, 1194675807210157848, 13081677376179713163, 9790979724735385269, 3429994162335743101, 18282263504341243063, 11073532118063625032, 18241092167097720365, 17490629239865315061, 17451936898459652544, 3705015252668379511, 15646972017585065174, 8948369964312160088, 12421841574297279117, 11600144893983875756, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [6160598189905115531, 18025956107099608580, 11512968082996599149, 1159818605994823015, 2364926874595277907, 7943063494760571709, 16605271790117727213, 11825547519897455023, 15342799649049057800, 3763048797193456654, 1295787082959371660, 16691905436935888241, 1915507152031483536, 17009264450373861587, 16328475049153986635, 8830519937889782762, 10115241278692937317, 1750096680784451786, 16653566373055583790, 4332235233085094180, 627717841813244731, 4706384122596616028, 219643739348167868, 10259409981493264670, 13239490680913326732, 182727077359841351, 8469105874522435313, 8517021520884886781, 3404810976915461357, 3829882598743334141, 14062283116063151751, 1610809089415408623, 0, 1032, 11702782905971311743, 8115486282645452027, 16425371230714077552, 10333496212804492507, 1572943607289284437, 13244361396034453954, 12880029163967100393, 14716450796809578181, 2618965885956593171, 1606019581379521796, 12562170441304287563, 4599116799417823473, 4257071131168813417, 10446583017549019711, 3570388907037362614, 11170081717188072664, 17238997244398394333, 17231192964516960933, 8123337005847551087, 7060091366977384949, 5719725530909274667, 5057603743378325948, 13848013489728729143, 17729739340387068117, 367186060507240673, 1411195984452924204, 11088333491201093194, 16575090776691519559, 16147396598096989679, 14525300817521856881, 0, 4448725490869322134, 16773782102167370766, 9517551778943323923, 9735157781939056258, 13685677539131842935, 74410881992624137, 16112118280329224188, 16455044890046321010, 3166113086359297763, 4123774883019480954, 8049700212209077372, 9143498805844601837, 1269471574449064045, 17099282884571514622, 17951548125515157165, 15320893071039302787, 16371352256021817139, 17154595820341397772, 5088265715035438397, 12952269508513821163, 2910118210482029454, 1585088611936329987, 16759292612217335519, 9851596960932027140, 8679788143435043297, 7792109010626424915, 3420624790371920563, 7480053259498635867, 3615950593461764641, 16487019928286415392, 10289142213544989468, 0, 5296, 4681956701739972184, 3297507518564977562, 10978317254779656082, 18354142145846877062, 18082471245109184632, 5915586390509665684, 14991347734816807516, 10215583712512422817, 10329936247150774828, 13253613960908137010, 9477407930706312020, 3959435681151189208, 2924854172257996410, 2653599560818129230, 3882603508690502535, 12153757963762118208, 5905443084652099463, 3326804770534376335, 15700324760341857643, 4711113127161390688, 14532162435088690923, 9731412496448089833, 9087293637868970990, 16672855635472301531, 16157291854026127596, 6164067506556190095, 16340142805513243131, 13982894413446367987, 16491357058269217705, 8055423479702674738, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1090670744084208003, 3080746365611415597, 6133575519759388325, 11695447135684149141, 6615075028106709917, 10277147404869816105, 15962120449122821193, 1254198290967296340, 2925289410746405164, 12104312877316532634, 14739488160024614333, 10743573083299131194, 12707577723315108285, 8945689852522735768, 14566241909712907104, 9028236766089923761, 10185013658812384549, 3941868484557913621, 16462538463092115913, 5673651272129016554, 1223470853173331157, 2788160682175050931, 1502692624900434396, 5566335148331577393, 17762829217961409285, 3389969163810664285, 7437527833076252327, 17084466347038006872, 6606368157240498477, 13093088208853880999, 1276807186500217245, 0, 5160, 18346837778669738664, 15130142357101091527, 6726588340010678615, 8394319278312203283, 15942424551308612685, 7629500615465222065, 14939877513325106589, 17048523965011794048, 2306293645521445312, 823113708878672797, 14981348226783328932, 7432878333905782051, 3482639998457803800, 632277917380007036, 18266437030920184246, 3366715262389109205, 5280275432441977334, 5379329043314533811, 13912213856326486056, 17217059915921675075, 15634373017412823086, 14981257187297131103, 16697350900700022325, 5239234081629986555, 3229291246709926782, 18373224696258292584, 6771862800272250893, 7666370275789511263, 12942227631865082960, 15190222347874856922, 0, 17344769878280361687, 11249881205591563163, 16071218949222383338, 546830354766363539, 7776682728634159270, 11209888800273182957, 14728140374725612977, 8386791303267182172, 9638626268997275972, 822684530408571288, 16951904742993551809, 825915008780272344, 18209952013401698562, 390611853699198814, 11327187383464966515, 12709202232488054070, 11552589705164935867, 12311030232489101343, 5023941437735028493, 16069569499603265432, 18063718751316981145, 4010755700397089888, 10892805137373131994, 9089377676555868962, 1220818432464721625, 13088066304082794059, 8657669536399661454, 419065699932221163, 3886495484944885171, 1240710433266681785, 5374430875291145484, 0, 26480, 7418486580310857761, 17019749743168160467, 4937487787523099272, 9870317658000082520, 9027489043629892579, 4927345804956144414, 15545533182903182788, 3907169825113221089, 2896862965383757523, 13069247508460875244, 6257437454212159648, 3775904100227399669, 16966215805924461950, 5206554086085975117, 10673185398346121565, 8235209133198882488, 9483230364913556480, 10561284120293439668, 17774065041915838082, 8696583885468400324, 9686516267351636652, 5891290976833577870, 6133144642314902299, 4372983987509841442, 2945651218563202825, 17570690068387731452, 2481092360881257830, 10656699665804756215, 2380753665748314674, 14226887805014239710, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [87, 2631903040606257959, 11859146482331138479, 12232695746376293294, 995389826954784529, 11949085664163595757, 4404337953750906792, 6908862958628621571, 12608149157887976305, 4754146580783023412, 14308250014803856580, 9454287016901482416, 9789905333959995060, 3771810096516115799, 2150959420327906479, 14538218150241396541, 6425179495446994078, 17565393891424303638, 3667075674391371806, 5731318824387052908, 4241445880929460300, 13107360446062265038, 4176811711023066147, 5250671015911848716, 4722672072326683708, 7171204772415813456, 5618587527864308269, 16458991436693873868, 2626622112813681720, 4599215552676510549, 5363423870755590475, 4352525099414593256, 0, 4128, 6496253015800789210, 18063315295058131399, 14099326864720264780, 16744359797696928029, 11669954633423859445, 10923938539628559259, 10579480970462933513, 17315553376669597828, 12114095292572219189, 16129781670858537825, 67936491912723144, 6285840300661422802, 14359460599290704174, 7597471307904508314, 8469569990667894210, 9117246600999250277, 14614928058075190380, 13738364908865630160, 1806905237893315697, 261412144627674040, 8380596589382515797, 3809925330596605534, 1983199361335541287, 6337901890572878101, 17063257729896061936, 12690697575318882146, 3846044480011221270, 10729939698274680623, 5297971463863936522, 8671284646676347574, 85, 2858403750276751031, 1709210755771630360, 11707086547963657475, 2794745820933624420, 2841923277622193225, 16490991381302584921, 5788783276303277595, 14692549583873964816, 9815954444411995352, 16153761647449809543, 6052645635446937049, 17304693813258262086, 11634259222665431081, 12233143040630128964, 8553846008642101336, 18388379526128378444, 15548258272185388836, 15360138454847963029, 3440439455019208235, 7218244406354738621, 5887183982672949081, 15870877452527488142, 15139518776246125573, 5433537245583001116, 13408133831989321267, 4656955130371010155, 14539571260147117550, 17118765335121629772, 3475198118169682060, 11483695604905597390, 11783370765491737635, 0, 21184, 7994119771983090684, 1155757367334915164, 14020255521522346779, 17824815497741664585, 5614135143986453745, 7146977362179517856, 3824341730458112374, 16894770516791760289, 2879202081945061688, 5646668393535724753, 1923820538236998308, 5244112822855800046, 11523838157115606042, 654162111745526915, 17566215582742419332, 16153951788992043302, 7571027843561021323, 15400774862911119623, 10370417002357863310, 16053800817166961724, 10524854462256237020, 11096622266210541923, 15395378671807683368, 6912701393383240626, 11746170412650491065, 12730613771714545378, 6535987403990440638, 10122156746538229970, 3728282910211741030, 5183721621480304370, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 10468230768888023862, 11664682242720909218, 2500570831459298438, 13004725650794618836, 8624527149940617200, 11524055993362242048, 6182388235200005336, 2589834268393847902, 12931236615531993709, 8584449549244767688, 11899064714918281636, 16246984277558583019, 8772638227416864166, 11946855882944424845, 16440133693312412286, 14737175326378679956, 7842923952979169755, 2398501113047325856, 14599944340506938939, 5936050971291911531, 8286147454062396089, 14343924012975607961, 8190973727913189622, 1134938007864643353, 12054037840221089027, 10050755079785196589, 10469731445849191380, 10906931598039016782, 16150808274840457147, 13280081123993966327, 5571840125263174859, 0, 1032, 13084260837127404333, 4018109146681745349, 14498381569327145056, 3778421823029569719, 1344624249217908323, 3634653398484528177, 1428985706412758663, 11382569756632997337, 13894906302086601399, 3911680161282028629, 11467762927868003365, 10098326072301516020, 16073214466625742345, 16150512194511843089, 11525294274796193451, 15902507139806774023, 13926886722650908730, 2974304378722638293, 5274544965980948277, 9984170014312577610, 639485734140932316, 15088403650698955530, 17189134684458608982, 6515320870350778492, 7902492290152572474, 17310456195349246143, 4070136787975548901, 6345872167795009033, 3095930865537762353, 4232664728858134772, 0, 18213217674792358096, 13599297410359034734, 11548640197966434952, 16397756946501824199, 4509993724149584481, 15279575547763923315, 14387788336990426452, 1679695851270735493, 737550782574904766, 16619718868892680991, 4189079835826917979, 16548334619034420779, 2523584064344323171, 18357860221728901477, 9223263721501613140, 836498427651453899, 11050299770631141961, 1906255442715510922, 16855485989141196504, 12664144355455319157, 17100007635940521879, 307480490272233054, 14791890923980574308, 14809283111081511220, 1272668898289027998, 1746726629032389326, 781443211491376776, 4235062597258109895, 17016381150799971149, 387032599105912823, 13820432364368151262, 0, 5296, 13498446627995378981, 6649809143130705797, 9522654220689816851, 7559480440412863769, 14249558742787467865, 4471817386074892784, 8930056613191782368, 9155852006764527165, 18377192855492301434, 12836057040498431452, 12282989683528533601, 3467617432525765103, 13766601347831535388, 2925667013227878460, 12822094630311757386, 6738693051085880966, 15661549307393278485, 7649583626848747165, 14069036937855587505, 9495341522376803417, 534616849927909964, 1899062451757954377, 6407581375465580420, 16442451038823818694, 7698809547406684914, 18232885173941026794, 3104393142368480565, 7738728989754721313, 4802195899845329288, 14925669435061449558, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 12734367032130478571, 915471480408530766, 18393930191488027312, 13545212286845976163, 18210660875436245579, 1541989510332303929, 5733187932229069792, 8676871105886252208, 15648333801800339703, 12513161021723575557, 9265666514596208448, 10311060571948838328, 15479186567637803235, 9457367929087028434, 10997859361453741844, 4801586725411290698, 8358881080234670725, 14262453638255884367, 3602771739252146288, 6541843013709002421, 3170708104995675453, 10921877432993541182, 10224257779706313529, 15830149545637956450, 13414249448981002451, 11722023958758893627, 18138185027267907899, 13905103948731397841, 9009398081722850699, 16014363687546775515, 10945967283455090973, 0, 1032, 15909096041365347974, 18432189660917429733, 2798890989547891271, 10768372030970716894, 5935807051329113911, 1259182408195029650, 16024750973514577255, 6103595041913569283, 914770550723164908, 5067028895751058275, 5242612139537538536, 13359135899043031769, 4430959127423856282, 16317056360529517539, 2634255659160911215, 15590656855559575839, 6832335878067392309, 6045109056629836176, 18146646330136390606, 6482705684632040588, 2770791364887326735, 7707774010999656594, 3401430074469265273, 3500862351024377705, 5135727797169111985, 14940852959892477883, 9633218853985087472, 16966092255533854383, 3065488485208441055, 15703076512693482766, 0, 4448725490869322219, 4944140066849387506, 2095785635431009262, 12375413327700682072, 11081872751342419742, 18058781214879352230, 17856276381917295190, 6718639559482054424, 668947051234094647, 3868828750372286402, 12122170781554046887, 4343898307694473975, 12690125861105998824, 16799534473726304569, 15934980937477619093, 3969747009451350970, 7686328019139102331, 3785180857099199084, 11986142858341385519, 2506152622879710750, 18430687071203156938, 3054089675267069232, 8760992635981950709, 11143171037695874494, 4733232646684685861, 1219894586292412814, 12600138307490245388, 824784286256764128, 10170016208525526833, 593495485489349093, 11923860796119339735, 0, 5296, 12442366360197298238, 6098667720777990098, 15014871424912942550, 15008680935203256586, 5625270093505773824, 14457467770650559296, 10887298179723462085, 16706947956141547836, 13310039786220231748, 6132850845308416918, 12403357056402201263, 1240140770639885705, 15461729627686219061, 6574742069523544220, 3131690396120496930, 17758791276367026584, 10046968584624867256, 16910374147545432071, 12405462687145854473, 9006078559482542456, 13476220060215365999, 8384214154009398478, 10365404322190410833, 6851505899182549268, 18261819862243438027, 2823760450959191582, 17079185842171546000, 2573099324947734045, 9396372422985936818, 6899349384621454800, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] }, last_program_row: RowIndex(12) }, program_info: ProgramInfo { program_hash: Word([8442199976350624000, 9488069924049927331, 3589804369840038271, 11846932079106298851]), kernel: Kernel([]) }, stack_outputs: StackOutputs { elements: [9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, merkle_store_nodes: {Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571]): (Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350]), Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350])), Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484]): (Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693]), Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693])), Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781]): (Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874]), Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874])), Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171]): (Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361]), Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361])), Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815]): (Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305]), Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305])), Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689]): (Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195]), Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195])), Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362]): (Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063]), Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063])), Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848]): (Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661]), Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661])), Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352]): (Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829]), Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829])), Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444]): (Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223]), Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223])), Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386]): (Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388]), Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388])), Word([13190842942618341421, 17548956981569849952, 15418963848144418856, 730733050713174879]): (Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144]), Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144])), Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874]): (Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675]), Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675])), Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594]): (Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115]), Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115])), Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809]): (Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257]), Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257])), Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777]): (Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555]), Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555])), Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509]): (Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882]), Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882])), Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725]): (Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979]), Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979])), Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134]): (Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987]), Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987])), Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828]): (Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910]), Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910])), Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830]): (Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054]), Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054])), Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228]): (Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742]), Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742])), Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443]): (Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928]), Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928])), Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643]): (Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979]), Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979])), Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758]): (Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106]), Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106])), Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580]): (Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594]), Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594])), Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765]): (Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045]), Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045])), Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766]): (Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281]), Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281])), Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385]): (Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828]), Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828])), Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579]): (Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171]), Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171])), Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212]): (Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992]), Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992])), Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463]): (Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004]), Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004])), Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502]): (Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023]), Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023])), Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539]): (Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537]), Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537])), Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865]): (Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225]), Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225])), Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690]): (Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947]), Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947])), Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202]): (Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552]), Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552])), Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079]): (Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444]), Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444])), Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850]): (Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548]), Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548])), Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448]): (Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987]), Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987])), Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041]): (Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035]), Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035])), Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301]): (Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414]), Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414])), Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414]): (Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212]), Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212])), Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703]): (Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439]), Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439])), Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271]): (Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955]), Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955])), Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882]): (Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802]), Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802])), Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152]): (Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887]), Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887])), Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028]): (Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948]), Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948])), Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331]): (Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093]), Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093])), Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394]): (Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134]), Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134])), Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546]): (Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228]), Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228])), Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620]): (Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414]), Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414])), Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800]): (Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703]), Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703])), Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671]): (Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205]), Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205])), Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537]): (Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011]), Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011])), Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516]): (Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301]), Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301])), Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831]): (Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986]), Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986])), Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415]): (Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057]), Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057])), Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722]): (Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689]), Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689])), Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144]): (Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682]), Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682])), Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295]): (Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268]), Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268])), Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818]): (Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513]), Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513])), Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241]): (Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565]), Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565])), Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439]): (Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012]), Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012])), Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512]): (Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850]), Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850])), Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986]): (Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865]), Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865])), Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982]): (Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777]), Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777])), Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808]): (Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394]), Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394])), Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979]): (Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690]), Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690])), Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093]): (Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620]), Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620])), Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902]): (Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789]), Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789])), Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542]): (Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094]), Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094])), Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057]): (Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362]), Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362])), Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205]): (Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961]), Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961])), Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401]): (Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580]), Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580])), Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553]): (Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960]), Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960])), Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169]): (Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031]), Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031])), Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682]): (Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053]), Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053])), Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118]): (Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562]), Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562])), Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725]): (Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666]), Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666])), Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661]): (Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897]), Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897])), Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981]): (Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447]), Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447])), Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072]): (Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646]), Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646])), Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140]): (Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404]), Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404])), Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515]): (Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152]), Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152])), Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709]): (Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664]), Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664])), Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800]): (Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103]), Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103])), Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741]): (Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169]), Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169])), Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005]): (Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758]), Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758])), Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802]): (Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070]), Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070])), Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159]): (Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005]), Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005])), Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350]): (Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443]), Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443])), Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697]): (Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573]), Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573])), Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928]): (Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331]), Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331])), Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320]): (Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166]), Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166])), Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814]): (Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079]), Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079])), Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447]): (Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820]), Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820])), Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284]): (Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057]), Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057])), Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697]): (Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131]), Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131])), Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955]): (Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290]), Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290])), Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910]): (Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202]), Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202])), Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910]): (Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822]), Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822])), Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106]): (Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847]), Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847])), Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404]): (Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441]), Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441])), Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796]): (Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186]), Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186])), Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053]): (Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516]), Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516])), Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992]): (Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818]), Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818])), Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957]): (Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315]), Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315])), Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709]): (Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794]), Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794])), Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091]): (Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539]), Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539])), Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664]): (Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558]), Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558])), Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294]): (Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579]), Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579])), Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947]): (Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502]), Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502])), Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829]): (Word([0, 0, 0, 0]), Word([0, 0, 0, 0])), Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045]): (Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137]), Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137])), Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914]): (Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041]), Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041])), Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573]): (Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378]), Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378])), Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699]): (Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873]), Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873])), Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225]): (Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262]), Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262])), Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057]): (Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692]), Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692])), Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131]): (Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997]), Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997])), Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555]): (Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385]), Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385])), Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195]): (Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709]), Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709])), Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166]): (Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542]), Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542])), Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027]): (Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373]), Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373])), Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378]): (Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509]), Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509])), Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097]): (Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553]), Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553])), Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217]): (Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815]), Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815])), Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873]): (Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864]), Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864])), Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997]): (Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722]), Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722])), Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887]): (Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766]), Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766])), Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589]): (Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757]), Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757])), Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539]): (Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665]), Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665])), Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129]): (Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229]), Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229])), Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137]): (Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312]), Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312])), Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019]): (Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378]), Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378])), Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331]): (Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713]), Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713])), Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]): (Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980]), Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980])), Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325]): (Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546]), Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546])), Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170]): (Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822]), Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822])), Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054]): (Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295]), Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295])), Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925]): (Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848]), Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848])), Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909]): (Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796]), Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796])), Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540]): (Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170]), Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170])), Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214]): (Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448]), Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448])), Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317]): (Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294]), Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294])), Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757]): (Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416]), Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416])), Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378]): (Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091]), Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091])), Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263]): (Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463]), Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463])), Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666]): (Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361]), Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361])), Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174]): (Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992]), Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992])), Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470]): (Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401]), Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401])), Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665]): (Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957]), Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957])), Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262]): (Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144]), Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144])), Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229]): (Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284]), Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284])), Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134]): (Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325]), Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325])), Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855]): (Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765]), Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765])), Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115]): (Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814]), Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814])), Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441]): (Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831]), Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831])), Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977]): (Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446]), Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446])), Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880]): (Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005]), Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005])), Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789]): (Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995]), Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995])), Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000]): (Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267]), Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267])), Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998]): (Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982]), Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982])), Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995]): (Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539]), Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539])), Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507]): (Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512]), Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512])), Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305]): (Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118]), Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118])), Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219]): (Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009]), Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009])), Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416]): (Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089]), Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089])), Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980]): (Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445]), Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445])), Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063]): (Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140]), Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140])), Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713]): (Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159]), Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159])), Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031]): (Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809]), Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809])), Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932]): (Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037]), Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037])), Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094]): (Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925]), Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925])), Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315]): (Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386]), Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386])), Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446]): (Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721]), Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721])), Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742]): (Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981]), Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981])), Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661]): (Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072]), Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072])), Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979]): (Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671]), Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671])), Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361]): (Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269]), Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269])), Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558]): (Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571]), Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571])), Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290]): (Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902]), Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902])), Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987]): (Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741]), Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741])), Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902]): (Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515]), Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515])), Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497]): (Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028]), Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028])), Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948]): (Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709]), Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709])), Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009]): (Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725]), Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725])), Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387]): (Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317]), Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317])), Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159]): (Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808]), Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808])), Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394]): (Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699]), Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699])), Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312]): (Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000]), Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000])), Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987]): (Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821]), Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821])), Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046]): (Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909]), Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909])), Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565]): (Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028]), Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028])), Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269]): (Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352]), Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352])), Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847]): (Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271]), Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271])), Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513]): (Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800]), Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800])), Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054]): (Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394]), Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394])), Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004]): (Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977]), Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977])), Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675]): (Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800]), Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800])), Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692]): (Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159]), Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159])), Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909]): (Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932]), Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932])), Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814]): (Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697]), Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697])), Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186]): (Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387]), Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387])), Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445]): (Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470]), Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470])), Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966]): (Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507]), Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507])), Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548]): (Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253]), Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253])), Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897]): (Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783]), Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783])), Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208]): (Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054]), Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054])), Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268]): (Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661]), Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661])), Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388]): (Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643]), Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643])), Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257]): (Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174]), Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174])), Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960]): (Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241]), Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241])), Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721]): (Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046]), Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046])), Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822]): (Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217]), Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217])), Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253]): (Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697]), Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697])), Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054]): (Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019]), Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019])), Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821]): (Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432]), Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432])), Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864]): (Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105]), Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105])), Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373]): (Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855]), Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855])), Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646]): (Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830]), Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830])), Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460]): (Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208]), Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208])), Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033]): (Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214]), Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214])), Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105]): (Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129]), Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129])), Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281]): (Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909]), Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909])), Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028]): (Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027]), Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027])), Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012]): (Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054]), Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054])), Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562]): (Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589]), Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589])), Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037]): (Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097]), Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097])), Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355]): (Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460]), Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460])), Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223]): (Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355]), Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355])), Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089]): (Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306]), Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306])), Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035]): (Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219]), Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219])), Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432]): (Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297]), Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297])), Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693]): (Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263]), Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263])), Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794]): (Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484]), Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484])), Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552]): (Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941]), Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941])), Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267]): (Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814]), Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814])), Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992]): (Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415]), Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415])), Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941]): (Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966]), Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966])), Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822]): (Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320]), Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320])), Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306]): (Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902]), Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902])), Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820]): (Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880]), Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880])), Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361]): (Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725]), Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725])), Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005]): (Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914]), Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914])), Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783]): (Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781]), Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781])), Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011]): (Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033]), Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033])), Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297]): (Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910]), Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910])), Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070]): (Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134]), Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134])), Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144]): (Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331]), Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331])), Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023]): (Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497]), Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497])), Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103]): (Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540]), Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540])), Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961]): (Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998]), Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998])), Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414]): (Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]), Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]))}, trace_len_summary: TraceLenSummary { main_trace_len: 13, range_trace_len: 39, chiplets_trace_len: ChipletsLengths { hash_chiplet_len: 128, bitwise_chiplet_len: 0, memory_chiplet_len: 0, kernel_rom_len: 0 } } } +ExecutionTrace { main_trace: MainTrace { storage: Parts { core_rm: [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 13719137288158876142, 6221215488690831821, 11468044834296629525, 16720332114142763849, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1032, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 2, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 8, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 3, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 4, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 1, 1, 1, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 5, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 16362180982079134587, 16601100057639640520, 5521682503008444658, 3792208660074152519, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 6, 0, 0, 0, 0, 0, 5, 0, 1, 1, 0, 1, 0, 1, 5296, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 7, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 1, 1, 0, 41, 5, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 8, 0, 0, 0, 0, 0, 7, 1, 0, 0, 1, 0, 1, 0, 0, 5, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 7, 1, 9, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 1, 1, 1, 16362180982079134587, 16601100057639640520, 5521682503008444658, 3792208660074152519, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 10, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 1, 1, 1, 13719137288158876142, 6221215488690831821, 11468044834296629525, 16720332114142763849, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 11, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 31, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 33, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 39, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 43, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 47, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 50, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 51, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 53, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 54, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 55, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 59, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 60, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 61, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 67, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 69, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 70, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 71, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 72, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 73, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 74, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 75, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 76, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 77, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 78, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 79, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 81, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 82, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 83, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 86, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 87, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 88, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 89, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 90, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 91, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 92, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 93, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 94, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 97, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 98, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 99, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 101, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 102, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 103, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 104, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 105, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 106, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 107, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 108, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 109, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 110, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 111, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 112, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 113, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 114, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 115, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 116, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 117, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 118, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 119, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 120, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 121, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 122, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 123, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 124, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 125, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 126, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 127, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0], chiplets_rm: [1, 1, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 13719137288158876142, 6221215488690831821, 11468044834296629525, 16720332114142763849, 0, 87, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 2445654027848798773, 13989391813235195492, 481784282030877064, 1887209632430994963, 9346278187721986719, 3141189181316333764, 4622204731995696995, 16701354768447765175, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1032, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 11116382020814057190, 14732796941305378371, 13074361791711182490, 6715193688317415490, 1571558009365433839, 13285275197432594374, 15905141483335727027, 2507840277166973476, 0, 0, 1, 0, 0, 1, 1, 0, 0, 16362180982079134587, 16601100057639640520, 5521682503008444658, 3792208660074152519, 0, 0, 0, 0, 0, 85, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 13719137288158876142, 6221215488690831821, 11468044834296629525, 16720332114142763849, 13962113176908263293, 676026057669832378, 15921241029195116857, 15915352364638718229, 1456698220748515004, 1707540503940690697, 10429997843948879425, 4559651383104503034, 0, 0, 1, 0, 0, 1, 1, 0, 0, 5296, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 16362180982079134587, 16601100057639640520, 5521682503008444658, 3792208660074152519, 6708412556839205818, 3204764821942414262, 2382590011410319125, 5080678178504844773, 6374574376632329694, 13516826603120023138, 12611398678228181741, 13552592212104960667, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1032, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 15913981378790993016, 12701179462806902902, 9645342555817022514, 6889850077248808033, 678249829196625442, 8726676798253716750, 14136118088409135949, 1027279235140821190, 8048729929177993405, 2542525775606472849, 3283471062508934848, 18058280687405074483, 1, 0, 0, 0, 1, 0, 0, 0, 0, 11899090779839289087, 1701090513954162998, 6953639183117323837, 11460660778637092812, 8345945186928076892, 11308243255833047975, 5734666540714547293, 1546649737555419076, 14643837757854608147, 7477230882792828789, 2359592855656894189, 12732146754685591216, 1, 0, 0, 0, 1, 0, 0, 0, 0, 16283412161296764998, 17261112905912533997, 1498213616014501531, 7707889409925905689, 16090493533591377617, 525010687572874692, 5228788497345464933, 13051466527897639054, 3560924095387897187, 12551242480725370445, 4038828260160651477, 6132317990703151787, 1, 0, 0, 0, 1, 0, 14261694278902826987, 16097544111075686229, 16632169854204459773, 14265791174051766329, 14732671264513481238, 15642599276989292777, 7593738854072541043, 11440582168151819564, 18258483622390056257, 6851601084855956341, 10463349537167637967, 10032876585525342603, 825669147467031185, 16271217766495541082, 9021089524754424392, 1, 0, 0, 0, 1, 0, 16780109665356203593, 16025948514351396737, 4256182047405196535, 4919013996388780384, 6974015548720770018, 10189882052640604940, 12288632186238773648, 7055558833039165669, 9820743264545515107, 7353106531603230851, 5612808106478211181, 362487531847990854, 10259224130335842891, 2374318293393776907, 16208179153232019183, 1, 0, 0, 0, 1, 0, 9496969110446094198, 10424961628901078909, 7587726188775237019, 13423955604028434301, 12288543613568774022, 4068762405627465026, 7288480650179820504, 1035430088689333582, 2651098721515326755, 4524440782000877024, 3013038852551457145, 12536534023666437466, 6560028330562582937, 9090521726813489969, 17634755409309861791, 1, 0, 0, 0, 1, 0, 15761194215082968049, 15796684185970405493, 1294179585337070936, 5701860167148115542, 17707247215386403887, 18419960639673587986, 14570347312565937582, 8634142387233894354, 11938075017385927203, 8060480374868324599, 16699922976999064541, 14234489074154948378, 17210389744085299852, 17331527780947314617, 16356838976302290254, 1, 0, 0, 0, 1, 0, 6184336662619539433, 7106147576739595100, 18237994300618329820, 9768155666925548219, 226714884885574576, 11169479382209254075, 5756676929838789145, 29803495366482069, 13128905441940840949, 18304516631519674746, 3177693875357946498, 10624850715031233718, 16956738608020324589, 10558540052020438814, 7826502712354673600, 1, 0, 0, 0, 1, 0, 1980308537464408089, 6810023246846442283, 9400257804338494201, 11246932855318952856, 7504545710540897051, 5823677062954428984, 9151299935574592196, 15905322272715446259, 18174748553199601666, 9877077233183640995, 2431998410719122545, 3541292002384422941, 5416588529930333172, 15788517205879313917, 2490575598934209003, 1, 0, 0, 0, 1, 0, 17950140321155419078, 9014768943295123367, 10707122777228105884, 10701204914974985643, 15060806908759160804, 7011191650405807117, 13598159658926423040, 3947314552577424057, 12985682730462769834, 18264715466581442035, 7667189540353817157, 7685483800933651249, 16085167604591833455, 16105855167414075111, 16215395602017884846, 1, 0, 0, 0, 1, 0, 8676227747932036802, 0, 0, 11504729673400082663, 3659553513673892306, 10374352082945691939, 15819529278889203623, 18107940902385670152, 8889798095480337831, 12737345777792032790, 456604824069734238, 2859376131275373721, 8758251935142908528, 2364536875264708997, 2435873391009301907, 1, 0, 0, 0, 1, 0, 0, 0, 0, 16797630026773069829, 16954579754978210547, 4393671449525183699, 6245909065255485436, 8311309349844601638, 3305827896314343556, 1615477551160071258, 3897903986825909618, 13015230208471866351, 13839070994009764281, 2415598337053791919, 5526300544248852335, 1, 0, 0, 0, 1, 0, 0, 0, 0, 12827873667465929582, 15892701250663610383, 549489834728826775, 9425334953627649153, 15402634395731091512, 11814416271399500934, 14597718118926923662, 4726679541432826422, 342915941842538663, 11221492717904369823, 17188959961041335276, 13559932473868727168, 1, 0, 0, 0, 1, 0, 0, 0, 0, 8689096602925893779, 4096531352684607500, 8424481237826564505, 15238165026175259240, 10985176737527635898, 2672540837788784952, 6649439643634522762, 7581835251244605715, 17671970641549389116, 18069913154458602790, 749417941228438762, 6150863900366154379, 1, 0, 0, 0, 1, 0, 0, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 11116382020814057190, 14732796941305378371, 13074361791711182490, 6715193688317415490, 1571558009365433839, 13285275197432594374, 15905141483335727027, 2507840277166973476, 1, 0, 0, 0, 1, 0, 0, 0, 0, 5296, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 9406198837081470939, 12454644480646831381, 5357297729805547264, 15695767008081417024, 17081781165782008305, 18173774266735228622, 6597958223090468622, 10058815580948772803, 9341085403015625984, 17305809056185869492, 16092333721991261411, 14466140396882267896, 1, 0, 0, 0, 1, 0, 0, 0, 0, 10022220918800215931, 6625466299838152616, 14873368774111773763, 13822207310342005989, 11851640107665623803, 4144160359412257714, 1001954617881206717, 2558852513241095712, 8048571622541726255, 3796262690630383451, 12690029978283677858, 7698456735078463171, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1529838978363474364, 5877585793149040063, 11620602129319348479, 3184399423922769699, 4766473366160256877, 7300042540399827448, 2462275239493078851, 11288811565422176008, 16822095754433680909, 18301782264345075251, 18087044935643148806, 510047809549721667, 1, 0, 0, 0, 1, 0, 17625583494235189807, 10622457062204255065, 2653216356844660597, 9475027500051639757, 10463750966311648190, 11600868756246964674, 15662168292079378087, 14737424852298451342, 117344945972585870, 3251083096698399603, 12684542007451613640, 4788924408482455108, 6902797868122893844, 15800238251163812693, 12046292011878974455, 1, 0, 0, 0, 1, 0, 7496472832454263388, 12998172934440185624, 17507911152779544052, 16456090005001040440, 16590029451027219509, 2617628953138715244, 622817961215058190, 1598986500188737220, 17607068252592942451, 15060402253986549440, 16875740049367006869, 4040451923151286438, 5925341866968505601, 14259707661873610422, 10732873470134113982, 1, 0, 0, 0, 1, 0, 1452526314939094806, 1479000593888603377, 246310986971833963, 4152569545950646704, 4118156517299583310, 17663239633609473365, 8127661496786659791, 17689549836214880979, 14746946312861632567, 602662289136933629, 11216558892028292475, 5188174964157774722, 7100861533945618475, 3714941418598094928, 1377039040653060055, 1, 0, 0, 0, 1, 0, 2930684747787414446, 1754494303819808128, 669923854651336066, 5941781742039952076, 876859729835418933, 790907098378102911, 115518666891692872, 16890877536441094576, 16820881161920465009, 241154565549913410, 44006951265386772, 5087127128059490065, 18106355872892957036, 3269612205224843731, 8638796096796806719, 1, 0, 0, 0, 1, 0, 2414727401863600363, 7617116592575512612, 18041147314657306922, 15957716643783059543, 11912796059449786962, 11153176059938326063, 14174738803865199162, 11999349000942665761, 17632700466101721722, 6582530104605672978, 16757182470542785800, 12431955029502155155, 17163152133935520513, 1237894940644049096, 6188646281997977531, 1, 0, 0, 0, 1, 0, 2319532296399149270, 9283783715220787949, 810281363185644618, 4756894436878044936, 12165478487736095233, 13041376666032139342, 3740623961436206385, 6384260880460211781, 17121495806538343926, 14583996149149192254, 11562370595738293151, 8268709300694246348, 17892562184847802024, 3859704522936614211, 7366245284644652757, 1, 0, 0, 0, 1, 0, 949011576700156842, 1533322811274401426, 15060757839378359292, 1432035093691797337, 206692693307936550, 378907012515670704, 10248912138703390835, 10128144445036454539, 5042107387767762304, 9843022881405494656, 11880883914254039546, 13220616153049902, 455311511731825064, 5381232113954376086, 5364482943654507461, 1, 0, 0, 0, 1, 0, 5881102500383619035, 0, 0, 2424299330597632902, 607119689966087280, 17283177276798307300, 475409702871185800, 15518804315920479075, 4578339057778509415, 4685043752195987874, 10392430241191498892, 11507515262772595129, 14439767021292397992, 13673908725375817159, 5378163831543087962, 1, 0, 0, 0, 1, 0, 0, 0, 0, 14342875730731176181, 6225072162372691712, 8577974921324183601, 751519865506756952, 9824595797538483612, 10360631973465438301, 10226703749989732907, 13840269947314152185, 1831374399934529359, 14389265827404554261, 11392184682219726353, 17676970157216697757, 1, 0, 0, 0, 1, 0, 0, 0, 0, 10605591699135631895, 525785012032090331, 1824237168047932550, 3952375305216254717, 9821754274536606782, 7855314197760224131, 17861834154975224793, 9836275050510148653, 17819027328170218375, 2840178708967434753, 15534576285961723627, 15357405679043026976, 1, 0, 0, 0, 1, 0, 0, 0, 0, 9793600913424407404, 14104167067920766779, 12309619471118709560, 12550056362664815329, 320739284087105326, 3762140957859872022, 10326389091316073307, 18366686834124399227, 5296819603037261258, 8152022108836431115, 8031664516364171852, 12133015237048791800, 1, 0, 0, 0, 1, 0, 0, 0, 0, 16362180982079134587, 16601100057639640520, 5521682503008444658, 3792208660074152519, 6708412556839205818, 3204764821942414262, 2382590011410319125, 5080678178504844773, 6374574376632329694, 13516826603120023138, 12611398678228181741, 13552592212104960667, 1, 0, 0, 0, 1, 0, 0, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 13719137288158876142, 6221215488690831821, 11468044834296629525, 16720332114142763849, 0, 87, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 14526210785099218637, 11847263499640079386, 14727111875255715984, 15492005690507045243, 3560320103534777253, 6108459071875623888, 17010585649681490524, 9461625672567273576, 5346213935533921584, 17324400741801951375, 11366145235097950908, 11020281342858012232, 1, 0, 0, 0, 1, 0, 0, 0, 0, 16197070053425155514, 15404003330998391348, 11930643358177149189, 1706026293115752249, 4860311493079570077, 17106682771221635926, 1613342353291471586, 10021094444428090144, 295368900173018762, 10362371049945425700, 9316163589333399506, 7378950726844095693, 1, 0, 0, 0, 1, 0, 0, 0, 0, 11506810158870826797, 14392904697466827547, 17905937794745323592, 17513565884470753819, 7019811109989114514, 10250939299242755101, 7620822681592706112, 12768902792042039708, 744728025267091276, 16212166364245632221, 10010770609378408333, 15023204573923685916, 1, 0, 0, 0, 1, 0, 9206943447329060417, 1573227013771687083, 7633983188953929869, 14747762092445444483, 12960730896173836507, 5351433366377253619, 4177159482546072600, 17061003377938727239, 9435579121926835049, 9864020053232925179, 11244311170762781618, 2840907732738372264, 7192941522047765124, 6173174116697481058, 13004561835267794042, 1, 0, 0, 0, 1, 0, 12007385695887985386, 13598702180788517287, 3912064789771327196, 11932998954627996911, 3853323028698833085, 11507033346049547360, 10110848241210835991, 15428609857280202530, 17110299148476621277, 12520416593002020608, 9431488564150546187, 2602629576595200800, 15183940660821516128, 15328070744340284046, 9882485700386666987, 1, 0, 0, 0, 1, 0, 2642957852140576392, 12998709907982857483, 4565256592569070651, 4013127352579691203, 10860110376897053120, 13677509527593892026, 2308518476531625659, 6232392686954434349, 13948263847203418837, 7843559618500491242, 7771043128539275771, 18270783924518568037, 16689544634184962614, 16359543813917605495, 8488375023251026510, 1, 0, 0, 0, 1, 0, 13959988857529015221, 12915245760499792818, 14841159553908529338, 14670848694035742368, 13930039566082372841, 9902385290951234306, 3203646694279229751, 13440312555890036471, 10385999516795969620, 11713935020689149772, 12229669264695050570, 402942260260809100, 16753462626177821460, 662362961313881669, 5887183544599407053, 1, 0, 0, 0, 1, 0, 14402936773953440947, 2012430503613052642, 1213953359224393220, 13944145787018602210, 6056959262477445647, 4982640241702718669, 1688381135968391307, 4510633793399532317, 7320984145724666154, 4691989180601120012, 102059673196228558, 1411198915631488472, 1854414388528665842, 16986811917033125654, 795637807896719676, 1, 0, 0, 0, 1, 0, 6294256185997130924, 4739079035802422148, 10935612526477766520, 17716511124280484394, 5021001597521525061, 18126874747305633609, 481644947884807344, 6049685422777720638, 1030047529196261526, 9576302115777192780, 10035472829778314322, 923305066890152615, 12527260620733941943, 11414360666749268526, 17760291183069624834, 1, 0, 0, 0, 1, 0, 10231661581337343904, 1832808263237927056, 6905801525972141190, 7456565975287668714, 12513973463050722371, 15559507328575476525, 2883833371658699080, 3184838730020301861, 18205970767593414562, 2798075613901729544, 189593258747480201, 13243754036156659300, 5745460764532976218, 2786581607585809614, 17436021357923428450, 1, 0, 0, 0, 1, 0, 72056538882336487, 0, 0, 5652048509186166814, 15367385573432163092, 6683125870356394251, 3770937106356856256, 1769679637596203925, 14372844572054653742, 13769745398507346855, 11807785571768521955, 5724215673931049374, 4401662327723853424, 11928715632009092524, 9924361168171239878, 1, 0, 0, 0, 1, 0, 0, 0, 0, 15128667119917371737, 8016996928120686373, 7467419359957362665, 4993381537595555977, 9371037824338144222, 2930594646951740022, 3944515787153841278, 5454163417882053837, 7667177038930845021, 10105079595217614088, 5177647710243780137, 13395674984723106859, 1, 0, 0, 0, 1, 0, 0, 0, 0, 17075658029987678701, 16942975531700611427, 3643709618611291855, 1334709094417075573, 11909212706933233016, 9741605425019020242, 7607696627297382550, 15299729661431018600, 7032572794257903279, 16683658838871091473, 3645139219999290477, 7245544203380098384, 1, 0, 0, 0, 1, 0, 0, 0, 0, 12068304939642236116, 13614044321092849027, 2880541849277464939, 815353510606417922, 14606426392222040491, 10929343986009381754, 18415245620786467058, 16142346014486690114, 10307567187784261413, 3831820208496643010, 14408727760370549811, 16272758710359397343, 1, 0, 0, 0, 1, 0, 0, 0, 0, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 2445654027848798773, 13989391813235195492, 481784282030877064, 1887209632430994963, 9346278187721986719, 3141189181316333764, 4622204731995696995, 16701354768447765175, 1, 0, 0, 0, 1, 0, 0, 0, 0, 16362180982079134587, 16601100057639640520, 5521682503008444658, 3792208660074152519, 0, 0, 0, 0, 0, 85, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 12086689928305136975, 10578835246084642663, 16542988469676950340, 18039575486237140027, 11378817209220925403, 1830288712116369429, 6836951313152193092, 13067316829245445662, 10483719891652983399, 15107628385291453978, 5745482890193398991, 1467598035505522824, 1, 0, 0, 0, 1, 0, 0, 0, 0, 6641033060700930640, 8002128452364190151, 4237597913508652736, 16497663922788367837, 9373930087271682821, 8772840226065969951, 13812790890684464043, 3327344850838518736, 15781875901493184698, 16732525831131872764, 1159309880266465962, 6519234662137256116, 1, 0, 0, 0, 1, 0, 0, 0, 0, 10088943647124252289, 13701383109068607902, 15690388373484222925, 4290213237740108975, 15844775943612000391, 16171043348080529647, 8784789786127538562, 12635460091357573504, 10561363445665196403, 3917577954302608976, 5337858229134527127, 14152777758433279341, 1, 0, 0, 0, 1, 0, 13029570897742009002, 13177254746172619023, 16038571161593335404, 2188338323498964707, 14662423055206707252, 399526319231252303, 14972684080243877319, 16777311805145501140, 6099803173114002593, 11253362042985817221, 10221863501466764826, 13414791437675451535, 2725322839420367772, 11819412321405778772, 13817033321558649088, 1, 0, 0, 0, 1, 0, 13691749519374287845, 15387673422637086663, 6922978787178957527, 2041172898547348571, 14589651886185789070, 5957633751491508475, 11960354433033043999, 15992971255870582512, 11830967408320733184, 15268965263556481837, 9065968121241919240, 14630209597160847101, 3695262652988767746, 6761434464064434034, 4499935311821727041, 1, 0, 0, 0, 1, 0, 15420756780139702261, 12424942891141165558, 6929528357507663172, 12198893338677478437, 18421446739075495822, 8468855093677567166, 14423050383612849622, 15188396328060565700, 16106496456550916799, 4380220556771000987, 18185062664582859482, 3471791712555441489, 5206529722281859812, 12099854936489528262, 3482375809599031896, 1, 0, 0, 0, 1, 0, 15574108340013622137, 15113564352853103247, 11759657553614819330, 8329975443345290464, 17940882943282719830, 715706186220073675, 11225208304861844348, 11251091880797815873, 16487042113140331701, 2684378958809639271, 18420809765897439905, 5225320321320513732, 6305682781245368810, 4669442538207571276, 14700449525371639507, 1, 0, 0, 0, 1, 0, 2979254376677653503, 1883000689168719362, 8104422763610466617, 5576229311275790732, 2194272311725182022, 11069690432331401312, 9059389138265053881, 8765354464725236382, 9222374345361788506, 18259801840836875925, 6516753426367602114, 16862896352549227556, 4308341550229035638, 3265342498516698837, 13464131825573347891, 1, 0, 0, 0, 1, 0, 13700569878861168214, 2688488967505940113, 3894270749155947782, 13272913612051073638, 229891148220106304, 8827790146883078828, 18375171102175520942, 14403529172649637015, 13099700194841873205, 188376523053645225, 1993959712224675182, 14801384607878448444, 10465527702245819388, 17660990215931846922, 908628888712311860, 1, 0, 0, 0, 1, 0, 17841857416383363570, 1410880649834889205, 15205315845157535511, 474005396413342575, 13140045598301896487, 3896472587811302452, 11889483340877797878, 10675872888943407911, 9043988711004206942, 6590644200881402626, 6630214594291443650, 7328314644790889015, 1925120838408255657, 12102121948068675841, 3366469296269798303, 1, 0, 0, 0, 1, 0, 9810051462759316493, 0, 0, 1967048762267479030, 14694789381285854906, 7850615184380239535, 6179804070945807128, 6190847648382551976, 7074541545875785618, 9996122377954848783, 18406348765365233841, 4381980521208731448, 2527214276140522656, 17476881528019612421, 10227790736734811126, 1, 0, 0, 0, 1, 0, 0, 0, 0, 12825387260273911399, 6194529288585122100, 10547428200413979362, 7146038864248149980, 3758150568829560250, 6436891845148661154, 9620702432336511668, 2457824222102594551, 13331592005230563304, 11086532868255377399, 4413541832527011587, 16051730796051624324, 1, 0, 0, 0, 1, 0, 0, 0, 0, 16438196827052442198, 18163112479653478435, 13659775893412875850, 9240379517650154023, 17622738652736541491, 10377502873777599097, 14167784496777925017, 8652392797374596693, 10690605953822876908, 6607959159332506262, 7925296024181542304, 11865355698347075352, 1, 0, 0, 0, 1, 0, 0, 0, 0, 8453841446519729480, 5007921045949414127, 10571120719178391220, 9766554424414228694, 8901262338981550121, 11643533070801732852, 18177267262839360795, 4695688607260963965, 5981212851350180937, 7185340145346514702, 15820300171842782914, 13017849308841041926, 1, 0, 0, 0, 1, 0, 0, 0, 0, 13719137288158876142, 6221215488690831821, 11468044834296629525, 16720332114142763849, 13962113176908263293, 676026057669832378, 15921241029195116857, 15915352364638718229, 1456698220748515004, 1707540503940690697, 10429997843948879425, 4559651383104503034, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], range_checker_cols: [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2187, 4374, 6561, 8748, 10935, 13122, 15309, 17496, 19683, 21870, 24057, 26244, 28431, 30618, 32805, 34992, 37179, 39366, 41553, 43740, 45927, 48114, 50301, 52488, 54675, 56862, 59049, 61236, 63423, 64152, 64881, 65124, 65367, 65448, 65529, 65532, 65535, 65535]], num_rows: 128 }, last_program_row: RowIndex(12) }, program_info: ProgramInfo { program_hash: Word([6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845]), kernel: Kernel([]) }, stack_outputs: StackOutputs { elements: [9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, precompile_requests: [], final_precompile_transcript: PrecompileTranscript { state: Word([0, 0, 0, 0]) }, trace_len_summary: TraceLenSummary { main_trace_len: 13, range_trace_len: 39, chiplets_trace_len: ChipletsLengths { hash_chiplet_len: 80, bitwise_chiplet_len: 0, memory_chiplet_len: 0, ace_chiplet_len: 0, kernel_rom_len: 0 } } } diff --git a/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_10.snap b/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_10.snap index 0c821b02ba..fb7b71f184 100644 --- a/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_10.snap +++ b/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_10.snap @@ -2,4 +2,4 @@ source: processor/src/trace/parallel/tests.rs expression: DeterministicTrace(&trace_from_fragments) --- -ExecutionTrace { main_trace: MainTrace { columns: ColMatrix { columns: [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 33, 33, 33, 1, 65, 97, 97, 97, 65, 65, 129, 129, 129, 65, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [7458506668679174706, 1032, 8, 0, 7458506668679174706, 665741763369239996, 5296, 41, 0, 665741763369239996, 665741763369239996, 5296, 41, 0, 665741763369239996, 8212736248369912082, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000, 8442199976350624000], [18375473735916206629, 0, 1, 1, 18375473735916206629, 5831108162926480783, 0, 65, 65, 5831108162926480783, 5831108162926480783, 0, 65, 65, 5831108162926480783, 4071281311826053218, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331, 9488069924049927331], [2105717247508690050, 0, 0, 0, 2105717247508690050, 7330889791923421278, 0, 0, 0, 7330889791923421278, 7330889791923421278, 0, 0, 0, 7330889791923421278, 16681111697957494384, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271, 3589804369840038271], [1679902783560062568, 0, 0, 0, 1679902783560062568, 13218130135561237014, 0, 0, 0, 13218130135561237014, 13218130135561237014, 0, 0, 0, 13218130135561237014, 6160598189905115531, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851, 11846932079106298851], [8212736248369912082, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [4071281311826053218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [16681111697957494384, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [6160598189905115531, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999], [1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 9999, 9999, 0, 9999, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 9999, 9999, 0, 9999, 9999, 0, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [9999, 9999, 9999, 9999, 9999, 9999, 0, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [16, 16, 16, 16, 16, 16, 16, 16, 17, 16, 16, 16, 16, 17, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16], [0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2187, 4374, 6561, 8748, 10935, 13122, 15309, 17496, 19683, 21870, 24057, 26244, 28431, 30618, 32805, 34992, 37179, 39366, 41553, 43740, 45927, 48114, 50301, 52488, 54675, 56862, 59049, 61236, 63423, 64152, 64881, 65124, 65367, 65448, 65529, 65532, 65535, 65535], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [7458506668679174706, 8136249212351146192, 10784649219148085459, 128781735205120527, 4547968979093876849, 3546336675446295543, 10817940156349236625, 14189444001012371653, 5493374351233807563, 8311102902317058756, 6249712288789018971, 1614874318552505578, 8181452518454181592, 598477530791288280, 8307036201059139827, 17345949525972330427, 17120430504411685184, 9024048572557701022, 5442249363272202440, 8891889669188699464, 13981710006578989582, 15202252296288325862, 8901049526912687276, 11824695302249715491, 8477037444632037091, 10111259653022775679, 9872576991436394594, 13620574761069749666, 10552500864729979640, 18032794979945654604, 153382829717154572, 8442199976350624000, 1032, 10320, 13024110921086730221, 3587442816163675215, 512402747638547729, 9217956011885162917, 3925750957223009950, 8674177413178223320, 12846799727083908462, 9116601283268739756, 2958792353189815054, 1720195204565087693, 7696852080146622077, 2890877729556257606, 16676527939404087356, 223754558788184593, 4767414622778376421, 14072300156908432530, 16856861612825314654, 11910434229443384600, 15658716527747040980, 14322127566252286435, 4770460127206402609, 10805338145914832851, 1391598300875421210, 18211456042978337510, 11866022853402812888, 6438324596032750504, 13328288515202849800, 17331158106613184460, 18344276842462151560, 7458506668679174706, 665741763369239996, 16242795687146137268, 321461142783715873, 2826379816086788535, 1389982844959459783, 7504428176840094167, 16867052141953300014, 6524645837583534023, 7971642927196132266, 895587693811363643, 14045043160415708545, 17186760898540197468, 11586158328390007250, 12564286920483154715, 14264987096664760063, 13473611649745551608, 3074526273535018608, 8192703318881365638, 11332735769645700919, 16102114657139125593, 17852385312535653754, 2362278605853243291, 7801968558670902550, 8976000347315438733, 13152720785410684086, 15178160026565391559, 16635907827753325426, 2952369032039574593, 2377128724052460864, 4064757387509104114, 5276412771718093926, 8212736248369912082, 5296, 52960, 6811813611500970866, 12330218901740233931, 16287800225917557614, 2390658038828763199, 4670881323897574211, 15935136064817789611, 2699367049541735206, 5505690989019187676, 4740977976888162022, 5734803687955113279, 14716704723144357988, 4469212567425053522, 15617193812494172197, 4848896952878415343, 18385001813020718595, 3406927099241203725, 6500845817907766790, 14130590127555482700, 10343975768128176185, 15693873175844605389, 2059720903132940981, 3757345954094976880, 3089069334759629752, 18141223932492835937, 11387279664761561894, 5402048984901238600, 12664138717389652380, 8299034149894841811, 4141583402420192864, 665741763369239996, 5296, 52960, 6811813611500970866, 12330218901740233931, 16287800225917557614, 2390658038828763199, 4670881323897574211, 15935136064817789611, 2699367049541735206, 5505690989019187676, 4740977976888162022, 5734803687955113279, 14716704723144357988, 4469212567425053522, 15617193812494172197, 4848896952878415343, 18385001813020718595, 3406927099241203725, 6500845817907766790, 14130590127555482700, 10343975768128176185, 15693873175844605389, 2059720903132940981, 3757345954094976880, 3089069334759629752, 18141223932492835937, 11387279664761561894, 5402048984901238600, 12664138717389652380, 8299034149894841811, 4141583402420192864, 665741763369239996, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [18375473735916206629, 17377183675986858406, 16204388331933209503, 9851558383041711453, 2647731244796610075, 13479103754506160685, 1313884950803363652, 15346175195946058279, 8910192708346993775, 2151299325850503780, 16669085269506854818, 12924378726200437768, 5909277165962634165, 7995732842947875893, 14386798070662103151, 7879022579148049870, 15020611106200374787, 10724238176158470430, 15029834199037822311, 11678935371612262717, 7297009056930466619, 14511898776428524296, 319792799645144231, 13382186579597492216, 2694749223042447691, 13263694931203634375, 6000186529178301892, 16523385558055279056, 7022204645736728964, 5338134468072720249, 15645384100209479912, 9488069924049927331, 0, 8256, 1131208899036558480, 1667157010810320250, 2053960715201569301, 1526213270499333709, 69813565043892453, 14925652377538846871, 1380252317064967448, 9902934070223067140, 3786794161520721521, 664031068804619792, 8470323998416702977, 4965297830526000942, 9404280000999464502, 8244737495337250711, 4784363486033662704, 4680481291290566437, 15373555507761845373, 8780119261264514018, 729009684537575982, 18306419558979237700, 15407410920890065538, 2509966126115291236, 12709897403480972846, 11498596868429821859, 6606875518512322314, 13880694912200059110, 6972406840307481976, 14148490408465275064, 2917966740410115114, 18375473735916206629, 5831108162926480783, 5716807500553500532, 340111207878988785, 18256387944673635196, 10860511098536981986, 8459821732881051520, 6920921369535874813, 16951093806716492481, 13791358524817111974, 5736505110286114902, 6134208873573181149, 9775353746636648794, 10511806043496923148, 16994604820290358508, 8663944065392476082, 7230189013861170101, 5624631671914610235, 6327683047402873297, 4175477208176608783, 954074467059951894, 9430822593953620080, 3254964387338063442, 14616933013502048910, 323829297696706606, 15299582253555179912, 8256585982323809806, 16419251794401517641, 11559790149908051338, 2239581712082993389, 12489932951016483829, 11738733634614750668, 4071281311826053218, 0, 42368, 9860311344216082483, 4356844177334189800, 8724150062868049447, 3846911055059526201, 16861225296757755735, 16925961143355054643, 7763338432894318220, 7504506723642096670, 11045006668578082721, 15092595329879644577, 4298948569114582870, 17810272068739440989, 13969944955380272714, 12356982018953263244, 16520418754635432271, 4689628285093180625, 7190852124445770478, 13072354659666011192, 1524422576558323017, 4274963317195893198, 12684756825761097033, 3511571172448102031, 823386573204270152, 9615020079928624381, 16119779393022010645, 17295023900181003317, 16373019178487693626, 13423474518210064130, 10379152206886126257, 5831108162926480783, 0, 42368, 9860311344216082483, 4356844177334189800, 8724150062868049447, 3846911055059526201, 16861225296757755735, 16925961143355054643, 7763338432894318220, 7504506723642096670, 11045006668578082721, 15092595329879644577, 4298948569114582870, 17810272068739440989, 13969944955380272714, 12356982018953263244, 16520418754635432271, 4689628285093180625, 7190852124445770478, 13072354659666011192, 1524422576558323017, 4274963317195893198, 12684756825761097033, 3511571172448102031, 823386573204270152, 9615020079928624381, 16119779393022010645, 17295023900181003317, 16373019178487693626, 13423474518210064130, 10379152206886126257, 5831108162926480783, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [2105717247508690050, 3107344020706784815, 7535295255934147784, 14961534904937133494, 15458110929197782417, 5854257801187918217, 7408528896221680379, 7195773034137126318, 6953015881067099300, 8311075386067189185, 7490596925699016321, 2748780903535738274, 14124675439405907210, 13467811864817035684, 12069265029549314681, 8713544979421645407, 7271740931964389253, 13358005363663908988, 1445604555428043843, 15414631947824553103, 3604233398898996465, 11389542141657004950, 753657943574098354, 16156878489884540028, 1283495432526365661, 15770030010231724104, 4992467617151662209, 9388418952293233141, 12063673466969028652, 6266501778891918617, 17390445613818630245, 3589804369840038271, 0, 2064, 18136552782870868471, 952274539956745973, 15933282259815262093, 9924516287334785738, 18064603646801610993, 5114527609957824263, 11816233963570869158, 17699527003452380450, 14533708946479200173, 17484213571014188868, 832814531422633701, 1508169308733590908, 8423043379628164525, 12595277727969636921, 14226276023010866965, 10485112285448962747, 1783527593060720204, 10145484005384627580, 7463752398658534839, 17345550819494003223, 4432309123412733588, 7086318781105575433, 8830891075082588619, 310185093236608634, 16683125300631590273, 7786799186167080425, 29465347809991832, 8090161351836983773, 8665315444141111469, 2105717247508690050, 7330889791923421278, 17979691280170131106, 16980963677900604856, 15976151213056828438, 92714918004478284, 17365496272474871894, 17001192471520708179, 3321277494654107778, 16893172732645584491, 2027752104829715962, 15452271030076785961, 2501796678284190373, 5676660220829808154, 13123673595423766920, 26738717326360259, 17483757498059224444, 12817208054146358362, 6986963031258272860, 16687757358165325375, 18027249453476092631, 15075850538217806798, 4190259332272306773, 2553182391312160489, 6173756644452043592, 7042376686216238529, 38980987021367719, 12463158039410249198, 7049795244189838947, 7060420962088551737, 9342274029206616333, 1435264878438078251, 16681111697957494384, 0, 10592, 279816225750213135, 3650402777016745376, 1781472746866786234, 10113987313323159199, 9398274187564883752, 16748408482785331310, 30358156203896034, 3074595635178688035, 6205342630873024293, 1697370376582801763, 8815094577559083340, 449557436115663881, 2151092097708635255, 7636620675010033430, 2307825524015342399, 8991051645303444091, 2473911126910605027, 2375720167990024221, 10037026397378548640, 14834683004264726058, 6907102329277961715, 18213897356329070177, 5667698909130756383, 4686287875705541143, 12476469095199609689, 17702654136961983716, 5311930945536331644, 7223353560134237057, 13509433978352760019, 7330889791923421278, 0, 10592, 279816225750213135, 3650402777016745376, 1781472746866786234, 10113987313323159199, 9398274187564883752, 16748408482785331310, 30358156203896034, 3074595635178688035, 6205342630873024293, 1697370376582801763, 8815094577559083340, 449557436115663881, 2151092097708635255, 7636620675010033430, 2307825524015342399, 8991051645303444091, 2473911126910605027, 2375720167990024221, 10037026397378548640, 14834683004264726058, 6907102329277961715, 18213897356329070177, 5667698909130756383, 4686287875705541143, 12476469095199609689, 17702654136961983716, 5311930945536331644, 7223353560134237057, 13509433978352760019, 7330889791923421278, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1679902783560062568, 1730400919877242464, 8594455900178560628, 5726930420197336139, 13273590888045863622, 8753781667987110661, 12948922070052129184, 6957781166000927195, 11540514940863049397, 3555060714483297014, 9392868496609143397, 1424153760517090352, 9018810402297148417, 2907590405487611226, 16087116659981325603, 6124015441109604199, 15635572367538115795, 2170747068790740224, 3201993911066137312, 11259421084459541380, 9993917348799810609, 17222088454832638116, 15686086798273471220, 12787265931454127207, 607842291318703015, 13403753643599459835, 10689062953812945200, 12619604521626526557, 3744742376692732597, 7474246814889551252, 12416458660228151392, 11846932079106298851, 0, 2064, 9594118340025725004, 16218246678075491818, 11582919835122342747, 5661452934218108707, 3714647928422746674, 13689184893219719187, 1899963197709801965, 8313716591368695784, 17822645741084942000, 18354595702287703799, 12620512717427217848, 10145637708639089787, 1735222492513760332, 14681927838838900060, 9262747238997471758, 11498487923782501751, 8924101344488972446, 2592517964915386184, 4276681409258176044, 3764365715267793208, 3120204268813370353, 6019260256544801113, 2801984351776029768, 16979166255722313516, 2813750347113564525, 16588139065369475399, 12012198471360912693, 2492059183640657261, 16968938268466755316, 1679902783560062568, 13218130135561237014, 8897450981738644183, 8122025352910807675, 14806163515298168591, 5442054526001626765, 3774836954819930057, 7873436160289973996, 1985577549930980807, 379441097109437269, 1582743467085230093, 8777470251655517715, 10400069677678307421, 1177689384604532813, 16561198203506864486, 18413269984357459958, 1623867674755828306, 5071121402113212599, 11851310101017854885, 17866089753923079131, 12853565947951893885, 6966840703169954718, 2619660424044064391, 4642489055874642868, 6457652449305783921, 3582227845111194274, 9002213586940350635, 8120300831241327696, 7598230464484206583, 432418536618916281, 10696618739033813212, 2085147768356017783, 6160598189905115531, 0, 10592, 1439899159397533405, 14727094498238943916, 10746359213734270257, 1223812058834541930, 1848521703701691504, 1128334504960281357, 6743090978755405998, 7738088049886519458, 17939832698319978092, 13966013418513317366, 2011070876654233589, 12183169551034808723, 9308934663460035993, 3987409101004068842, 6640678206253988218, 15420175838347825984, 2447243913023891846, 16080138638164650345, 11821902144147060712, 5951909302827919869, 138258931412597884, 10064659859509677191, 6862491015452895794, 10574916399821725047, 3278355048806054125, 6884933911815373710, 4616652429570306671, 3777113587480581710, 7620976189553973499, 13218130135561237014, 0, 10592, 1439899159397533405, 14727094498238943916, 10746359213734270257, 1223812058834541930, 1848521703701691504, 1128334504960281357, 6743090978755405998, 7738088049886519458, 17939832698319978092, 13966013418513317366, 2011070876654233589, 12183169551034808723, 9308934663460035993, 3987409101004068842, 6640678206253988218, 15420175838347825984, 2447243913023891846, 16080138638164650345, 11821902144147060712, 5951909302827919869, 138258931412597884, 10064659859509677191, 6862491015452895794, 10574916399821725047, 3278355048806054125, 6884933911815373710, 4616652429570306671, 3777113587480581710, 7620976189553973499, 13218130135561237014, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [8212736248369912082, 13582507089316059702, 7058022398850579311, 14448859106484550632, 8488923843888712176, 14387511811111000559, 16343533314104084279, 7144420700209912913, 81438176960127805, 11353579355252691279, 15391029939397732169, 13654856085785737791, 17867630563899600855, 15638494238775280514, 15278759115432814741, 9672833929788573796, 8499991101857103008, 4277878641698006595, 12990966731553386694, 325849556554992531, 16823455732252835952, 10325677389248902106, 17215632082750072073, 5871229270093729693, 1418595653525548799, 1623140794865507125, 3521868013962458536, 7592427336074080103, 8813490692122304227, 15033504818965134746, 671768789535371387, 6002676145170957552, 0, 5160, 1190658701913535022, 9371121588404883743, 7133056533056999470, 7380100170229652082, 14719783382686670107, 4693530971176924881, 11125714198188567552, 2434816259070577714, 17927785478103501878, 834873962620943786, 1091858408197145201, 9293176204765248193, 11318806736621162148, 979530496520387452, 8328113718786640843, 15870139479256453021, 7754853849459016697, 2742936430580983415, 6806060556807781604, 5089080673677611112, 16430235900965466453, 309743103212430298, 15664803780047891222, 3113571524475220627, 17862871362988443440, 1231393200801541530, 15779352999894925288, 6026600320279882336, 6970552753544824994, 4949154992619464010, 0, 17344769878280361092, 2672032990889952726, 10966643852490493990, 2592429945178091576, 8172562148455605634, 14004003701484837955, 12834107981647449396, 9875636580100479976, 12047948199477092131, 8025491038733220165, 491259531166040341, 14832623839190995610, 14697509357953676418, 5789610466730383818, 388263584830521272, 7439414156048078496, 15784515228652197776, 11049955424692728889, 14895470599018577003, 7841617945839187879, 17455550201169057010, 2534236084163066389, 6762591351360230328, 5346858927664762265, 7945321262401027963, 10750885965856570936, 12370887997614982110, 16868606775754956395, 12653757924793616214, 11706271638131904220, 10827276321637451859, 0, 26480, 4254579990847524851, 17114576923598071233, 14501968992007296006, 7693932549469059792, 10678009787450266287, 2595890940213877342, 12027612752909244618, 11942792976788752435, 8893673039996221512, 15212529265532680398, 977526836722797909, 3774006073579156026, 17701622526704384546, 15389797735547254619, 13767602282518466067, 10581163748471525208, 4912900994653972152, 1666712169140912317, 11001907572334629439, 18179452850399895424, 1689425248988491264, 724394552750888620, 13424695554257597947, 17992577679858152184, 11468668142758644503, 12524389240992679275, 2671393322368710032, 1059544940949021637, 18127894597596272634, 16116071169182046485, 0, 26480, 4254579990847524851, 17114576923598071233, 14501968992007296006, 7693932549469059792, 10678009787450266287, 2595890940213877342, 12027612752909244618, 11942792976788752435, 8893673039996221512, 15212529265532680398, 977526836722797909, 3774006073579156026, 17701622526704384546, 15389797735547254619, 13767602282518466067, 10581163748471525208, 4912900994653972152, 1666712169140912317, 11001907572334629439, 18179452850399895424, 1689425248988491264, 724394552750888620, 13424695554257597947, 17992577679858152184, 11468668142758644503, 12524389240992679275, 2671393322368710032, 1059544940949021637, 18127894597596272634, 16116071169182046485, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [4071281311826053218, 8965269515246497704, 4610105990937441552, 14871257653827208567, 17566918610707158078, 4662267156400217313, 11925160665074583703, 7006577898090498820, 8933338746704632990, 14704958557312921128, 283685871938470517, 17049945775096584485, 1735922796599632945, 18137828521183364954, 1233454545325180310, 4616679305450045558, 799989113534058041, 9548215660109667029, 17638736186517997026, 12905149264926481878, 9206641926728869527, 11201231447988338022, 6044555324419572909, 4856995795253621298, 5361647435575923081, 6166078860096154852, 6696272579393185401, 1638259147884844478, 10134861521414682067, 17465898446534646298, 2270472397704099161, 5665896864361060199, 0, 4128, 1352424102745866255, 13301242752201603536, 5420135027930584396, 17078794493496835379, 4779811836607866048, 3650219859599657886, 13618468821889769363, 11429589192023659923, 8853101337885331080, 9650238821992519861, 14401087967309285252, 12035560952634921032, 15407186837043713393, 15711028160746246110, 5396976350889627712, 15903424027416555998, 11304777107657759509, 9857843669692965578, 12605480788735099613, 14618970056708743810, 8493993205782554647, 6059068631740368787, 18316971448227884023, 12499808993385025318, 4210674244211222629, 18405965507148502967, 173097048437312502, 15568437290332308327, 11532601739151124629, 10000279862191744493, 0, 2858403750276750521, 18287547865064093386, 16643076982183140204, 17607797632632583753, 4606352897788642339, 16669380908105325740, 6888212917900510506, 9887976024132347018, 15672872160122205909, 10605120439023982124, 17832834191852929098, 11180362325911556985, 1797669589287132096, 18316393283013557997, 17455009848636139677, 4212485662162927177, 2684395608227063909, 10865000669694511781, 13048938138389391460, 13946693875892332716, 300901360739248952, 4186546104164144876, 3265288527569414193, 8781944488148208732, 14923610741876695933, 9614148693204557112, 9347068782470538323, 17518823857230050559, 7139121107914525514, 470824845274439747, 1419643695620305796, 0, 21184, 13079805966919738688, 12218492589526939611, 1562069618543971026, 952986602744509450, 16155494143085714581, 13684626716727802900, 2303575863276843576, 10596243276715621734, 17646165020998189117, 11814345067449767109, 11825442891411236224, 17347702280974326762, 10643130636190759117, 10594562435231095624, 4601317543004968907, 2494640429618639710, 7283529819405604014, 12179021258304518015, 15808731023964574299, 17252671119722267451, 2994890735774817444, 1595171953489970254, 11834064729547782130, 3702466161428093475, 4997071000317359325, 9247736708382385184, 7020445890779083806, 13774982404484476980, 17184349270149775183, 13243492223453509904, 0, 21184, 13079805966919738688, 12218492589526939611, 1562069618543971026, 952986602744509450, 16155494143085714581, 13684626716727802900, 2303575863276843576, 10596243276715621734, 17646165020998189117, 11814345067449767109, 11825442891411236224, 17347702280974326762, 10643130636190759117, 10594562435231095624, 4601317543004968907, 2494640429618639710, 7283529819405604014, 12179021258304518015, 15808731023964574299, 17252671119722267451, 2994890735774817444, 1595171953489970254, 11834064729547782130, 3702466161428093475, 4997071000317359325, 9247736708382385184, 7020445890779083806, 13774982404484476980, 17184349270149775183, 13243492223453509904, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [16681111697957494384, 9850604216542701406, 14292233265078610671, 11560507218468362083, 11435884371355098677, 707619676799722739, 13157092351337171268, 2418773787696448890, 4672379866331806862, 14371817650991869953, 3768839363733198769, 9708763303767628077, 11396390941757961228, 4785785956560501030, 16036499041626449319, 9630510095026498877, 7634220798360289556, 5119649922187981964, 6331607203065781588, 16919596794918736104, 32726321504424883, 10309269913347989302, 14782015448458484884, 14683358530499849942, 7836268277036786901, 15462421617591871273, 12213179217732598594, 14536234064731365163, 3637686875728492502, 2382678006125050452, 14226016292255835291, 589873375673641870, 0, 1032, 4798141223555508282, 12962488577647927717, 10133257770726709126, 332864556927106185, 12116126881643349994, 6604148216925166409, 101015634312276042, 15934992137290074922, 6112274855072540816, 17762248064501548615, 13166189948742588777, 270100349969833402, 13485211244653928073, 3502306881032295169, 13607663468974078519, 8883940618995723208, 10623667092532612652, 12293715092576816840, 10386976621364522928, 9128135834925108269, 15731443845270647366, 13373704167654916087, 13746187061551926812, 11684868053863796759, 3258729720361659960, 10434904637843727165, 7034851303745741351, 16133345873308301364, 5426492436527662130, 2980140658145787783, 0, 18213217674792357841, 6883907187243818989, 10614920431791547888, 13376310260819809150, 970536228322621221, 5786498633534169345, 13904299833493296337, 18182241650367492861, 4671451809489883858, 10519951415050407991, 9409416070961479945, 9277815292140415791, 84450611619755921, 13615028923015526256, 15760906032947657328, 10394291523020808732, 14504653302726904108, 8315708932196998089, 2409075654026148870, 367320422432359503, 6139056775213015570, 6944063758267220406, 4458873320026667405, 12662780608684972080, 15472797447424064358, 4158450525844909688, 2549026714004541517, 3246198533692444934, 3222033110084083257, 5683784147168326312, 7836113917086293276, 0, 5296, 6743125803107521679, 1867163304908812007, 1669000574108639518, 3582028644269610893, 16317815132307200966, 7118493626667445787, 13566879202183211144, 12402898926771175303, 11408064245891139905, 12248403740758614702, 1261452888691293041, 7470708275017896296, 10608583573536775206, 12594414503848564818, 13990563506880433299, 5287408014276309700, 1194675807210157848, 13081677376179713163, 9790979724735385269, 3429994162335743101, 18282263504341243063, 11073532118063625032, 18241092167097720365, 17490629239865315061, 17451936898459652544, 3705015252668379511, 15646972017585065174, 8948369964312160088, 12421841574297279117, 11600144893983875756, 0, 5296, 6743125803107521679, 1867163304908812007, 1669000574108639518, 3582028644269610893, 16317815132307200966, 7118493626667445787, 13566879202183211144, 12402898926771175303, 11408064245891139905, 12248403740758614702, 1261452888691293041, 7470708275017896296, 10608583573536775206, 12594414503848564818, 13990563506880433299, 5287408014276309700, 1194675807210157848, 13081677376179713163, 9790979724735385269, 3429994162335743101, 18282263504341243063, 11073532118063625032, 18241092167097720365, 17490629239865315061, 17451936898459652544, 3705015252668379511, 15646972017585065174, 8948369964312160088, 12421841574297279117, 11600144893983875756, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [6160598189905115531, 18025956107099608580, 11512968082996599149, 1159818605994823015, 2364926874595277907, 7943063494760571709, 16605271790117727213, 11825547519897455023, 15342799649049057800, 3763048797193456654, 1295787082959371660, 16691905436935888241, 1915507152031483536, 17009264450373861587, 16328475049153986635, 8830519937889782762, 10115241278692937317, 1750096680784451786, 16653566373055583790, 4332235233085094180, 627717841813244731, 4706384122596616028, 219643739348167868, 10259409981493264670, 13239490680913326732, 182727077359841351, 8469105874522435313, 8517021520884886781, 3404810976915461357, 3829882598743334141, 14062283116063151751, 1610809089415408623, 0, 1032, 11702782905971311743, 8115486282645452027, 16425371230714077552, 10333496212804492507, 1572943607289284437, 13244361396034453954, 12880029163967100393, 14716450796809578181, 2618965885956593171, 1606019581379521796, 12562170441304287563, 4599116799417823473, 4257071131168813417, 10446583017549019711, 3570388907037362614, 11170081717188072664, 17238997244398394333, 17231192964516960933, 8123337005847551087, 7060091366977384949, 5719725530909274667, 5057603743378325948, 13848013489728729143, 17729739340387068117, 367186060507240673, 1411195984452924204, 11088333491201093194, 16575090776691519559, 16147396598096989679, 14525300817521856881, 0, 4448725490869322134, 16773782102167370766, 9517551778943323923, 9735157781939056258, 13685677539131842935, 74410881992624137, 16112118280329224188, 16455044890046321010, 3166113086359297763, 4123774883019480954, 8049700212209077372, 9143498805844601837, 1269471574449064045, 17099282884571514622, 17951548125515157165, 15320893071039302787, 16371352256021817139, 17154595820341397772, 5088265715035438397, 12952269508513821163, 2910118210482029454, 1585088611936329987, 16759292612217335519, 9851596960932027140, 8679788143435043297, 7792109010626424915, 3420624790371920563, 7480053259498635867, 3615950593461764641, 16487019928286415392, 10289142213544989468, 0, 5296, 4681956701739972184, 3297507518564977562, 10978317254779656082, 18354142145846877062, 18082471245109184632, 5915586390509665684, 14991347734816807516, 10215583712512422817, 10329936247150774828, 13253613960908137010, 9477407930706312020, 3959435681151189208, 2924854172257996410, 2653599560818129230, 3882603508690502535, 12153757963762118208, 5905443084652099463, 3326804770534376335, 15700324760341857643, 4711113127161390688, 14532162435088690923, 9731412496448089833, 9087293637868970990, 16672855635472301531, 16157291854026127596, 6164067506556190095, 16340142805513243131, 13982894413446367987, 16491357058269217705, 8055423479702674738, 0, 5296, 4681956701739972184, 3297507518564977562, 10978317254779656082, 18354142145846877062, 18082471245109184632, 5915586390509665684, 14991347734816807516, 10215583712512422817, 10329936247150774828, 13253613960908137010, 9477407930706312020, 3959435681151189208, 2924854172257996410, 2653599560818129230, 3882603508690502535, 12153757963762118208, 5905443084652099463, 3326804770534376335, 15700324760341857643, 4711113127161390688, 14532162435088690923, 9731412496448089833, 9087293637868970990, 16672855635472301531, 16157291854026127596, 6164067506556190095, 16340142805513243131, 13982894413446367987, 16491357058269217705, 8055423479702674738, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1090670744084208003, 3080746365611415597, 6133575519759388325, 11695447135684149141, 6615075028106709917, 10277147404869816105, 15962120449122821193, 1254198290967296340, 2925289410746405164, 12104312877316532634, 14739488160024614333, 10743573083299131194, 12707577723315108285, 8945689852522735768, 14566241909712907104, 9028236766089923761, 10185013658812384549, 3941868484557913621, 16462538463092115913, 5673651272129016554, 1223470853173331157, 2788160682175050931, 1502692624900434396, 5566335148331577393, 17762829217961409285, 3389969163810664285, 7437527833076252327, 17084466347038006872, 6606368157240498477, 13093088208853880999, 1276807186500217245, 0, 5160, 18346837778669738664, 15130142357101091527, 6726588340010678615, 8394319278312203283, 15942424551308612685, 7629500615465222065, 14939877513325106589, 17048523965011794048, 2306293645521445312, 823113708878672797, 14981348226783328932, 7432878333905782051, 3482639998457803800, 632277917380007036, 18266437030920184246, 3366715262389109205, 5280275432441977334, 5379329043314533811, 13912213856326486056, 17217059915921675075, 15634373017412823086, 14981257187297131103, 16697350900700022325, 5239234081629986555, 3229291246709926782, 18373224696258292584, 6771862800272250893, 7666370275789511263, 12942227631865082960, 15190222347874856922, 0, 17344769878280361687, 11249881205591563163, 16071218949222383338, 546830354766363539, 7776682728634159270, 11209888800273182957, 14728140374725612977, 8386791303267182172, 9638626268997275972, 822684530408571288, 16951904742993551809, 825915008780272344, 18209952013401698562, 390611853699198814, 11327187383464966515, 12709202232488054070, 11552589705164935867, 12311030232489101343, 5023941437735028493, 16069569499603265432, 18063718751316981145, 4010755700397089888, 10892805137373131994, 9089377676555868962, 1220818432464721625, 13088066304082794059, 8657669536399661454, 419065699932221163, 3886495484944885171, 1240710433266681785, 5374430875291145484, 0, 26480, 7418486580310857761, 17019749743168160467, 4937487787523099272, 9870317658000082520, 9027489043629892579, 4927345804956144414, 15545533182903182788, 3907169825113221089, 2896862965383757523, 13069247508460875244, 6257437454212159648, 3775904100227399669, 16966215805924461950, 5206554086085975117, 10673185398346121565, 8235209133198882488, 9483230364913556480, 10561284120293439668, 17774065041915838082, 8696583885468400324, 9686516267351636652, 5891290976833577870, 6133144642314902299, 4372983987509841442, 2945651218563202825, 17570690068387731452, 2481092360881257830, 10656699665804756215, 2380753665748314674, 14226887805014239710, 0, 26480, 7418486580310857761, 17019749743168160467, 4937487787523099272, 9870317658000082520, 9027489043629892579, 4927345804956144414, 15545533182903182788, 3907169825113221089, 2896862965383757523, 13069247508460875244, 6257437454212159648, 3775904100227399669, 16966215805924461950, 5206554086085975117, 10673185398346121565, 8235209133198882488, 9483230364913556480, 10561284120293439668, 17774065041915838082, 8696583885468400324, 9686516267351636652, 5891290976833577870, 6133144642314902299, 4372983987509841442, 2945651218563202825, 17570690068387731452, 2481092360881257830, 10656699665804756215, 2380753665748314674, 14226887805014239710, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [87, 2631903040606257959, 11859146482331138479, 12232695746376293294, 995389826954784529, 11949085664163595757, 4404337953750906792, 6908862958628621571, 12608149157887976305, 4754146580783023412, 14308250014803856580, 9454287016901482416, 9789905333959995060, 3771810096516115799, 2150959420327906479, 14538218150241396541, 6425179495446994078, 17565393891424303638, 3667075674391371806, 5731318824387052908, 4241445880929460300, 13107360446062265038, 4176811711023066147, 5250671015911848716, 4722672072326683708, 7171204772415813456, 5618587527864308269, 16458991436693873868, 2626622112813681720, 4599215552676510549, 5363423870755590475, 4352525099414593256, 0, 4128, 6496253015800789210, 18063315295058131399, 14099326864720264780, 16744359797696928029, 11669954633423859445, 10923938539628559259, 10579480970462933513, 17315553376669597828, 12114095292572219189, 16129781670858537825, 67936491912723144, 6285840300661422802, 14359460599290704174, 7597471307904508314, 8469569990667894210, 9117246600999250277, 14614928058075190380, 13738364908865630160, 1806905237893315697, 261412144627674040, 8380596589382515797, 3809925330596605534, 1983199361335541287, 6337901890572878101, 17063257729896061936, 12690697575318882146, 3846044480011221270, 10729939698274680623, 5297971463863936522, 8671284646676347574, 85, 2858403750276751031, 1709210755771630360, 11707086547963657475, 2794745820933624420, 2841923277622193225, 16490991381302584921, 5788783276303277595, 14692549583873964816, 9815954444411995352, 16153761647449809543, 6052645635446937049, 17304693813258262086, 11634259222665431081, 12233143040630128964, 8553846008642101336, 18388379526128378444, 15548258272185388836, 15360138454847963029, 3440439455019208235, 7218244406354738621, 5887183982672949081, 15870877452527488142, 15139518776246125573, 5433537245583001116, 13408133831989321267, 4656955130371010155, 14539571260147117550, 17118765335121629772, 3475198118169682060, 11483695604905597390, 11783370765491737635, 0, 21184, 7994119771983090684, 1155757367334915164, 14020255521522346779, 17824815497741664585, 5614135143986453745, 7146977362179517856, 3824341730458112374, 16894770516791760289, 2879202081945061688, 5646668393535724753, 1923820538236998308, 5244112822855800046, 11523838157115606042, 654162111745526915, 17566215582742419332, 16153951788992043302, 7571027843561021323, 15400774862911119623, 10370417002357863310, 16053800817166961724, 10524854462256237020, 11096622266210541923, 15395378671807683368, 6912701393383240626, 11746170412650491065, 12730613771714545378, 6535987403990440638, 10122156746538229970, 3728282910211741030, 5183721621480304370, 0, 21184, 7994119771983090684, 1155757367334915164, 14020255521522346779, 17824815497741664585, 5614135143986453745, 7146977362179517856, 3824341730458112374, 16894770516791760289, 2879202081945061688, 5646668393535724753, 1923820538236998308, 5244112822855800046, 11523838157115606042, 654162111745526915, 17566215582742419332, 16153951788992043302, 7571027843561021323, 15400774862911119623, 10370417002357863310, 16053800817166961724, 10524854462256237020, 11096622266210541923, 15395378671807683368, 6912701393383240626, 11746170412650491065, 12730613771714545378, 6535987403990440638, 10122156746538229970, 3728282910211741030, 5183721621480304370, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 10468230768888023862, 11664682242720909218, 2500570831459298438, 13004725650794618836, 8624527149940617200, 11524055993362242048, 6182388235200005336, 2589834268393847902, 12931236615531993709, 8584449549244767688, 11899064714918281636, 16246984277558583019, 8772638227416864166, 11946855882944424845, 16440133693312412286, 14737175326378679956, 7842923952979169755, 2398501113047325856, 14599944340506938939, 5936050971291911531, 8286147454062396089, 14343924012975607961, 8190973727913189622, 1134938007864643353, 12054037840221089027, 10050755079785196589, 10469731445849191380, 10906931598039016782, 16150808274840457147, 13280081123993966327, 5571840125263174859, 0, 1032, 13084260837127404333, 4018109146681745349, 14498381569327145056, 3778421823029569719, 1344624249217908323, 3634653398484528177, 1428985706412758663, 11382569756632997337, 13894906302086601399, 3911680161282028629, 11467762927868003365, 10098326072301516020, 16073214466625742345, 16150512194511843089, 11525294274796193451, 15902507139806774023, 13926886722650908730, 2974304378722638293, 5274544965980948277, 9984170014312577610, 639485734140932316, 15088403650698955530, 17189134684458608982, 6515320870350778492, 7902492290152572474, 17310456195349246143, 4070136787975548901, 6345872167795009033, 3095930865537762353, 4232664728858134772, 0, 18213217674792358096, 13599297410359034734, 11548640197966434952, 16397756946501824199, 4509993724149584481, 15279575547763923315, 14387788336990426452, 1679695851270735493, 737550782574904766, 16619718868892680991, 4189079835826917979, 16548334619034420779, 2523584064344323171, 18357860221728901477, 9223263721501613140, 836498427651453899, 11050299770631141961, 1906255442715510922, 16855485989141196504, 12664144355455319157, 17100007635940521879, 307480490272233054, 14791890923980574308, 14809283111081511220, 1272668898289027998, 1746726629032389326, 781443211491376776, 4235062597258109895, 17016381150799971149, 387032599105912823, 13820432364368151262, 0, 5296, 13498446627995378981, 6649809143130705797, 9522654220689816851, 7559480440412863769, 14249558742787467865, 4471817386074892784, 8930056613191782368, 9155852006764527165, 18377192855492301434, 12836057040498431452, 12282989683528533601, 3467617432525765103, 13766601347831535388, 2925667013227878460, 12822094630311757386, 6738693051085880966, 15661549307393278485, 7649583626848747165, 14069036937855587505, 9495341522376803417, 534616849927909964, 1899062451757954377, 6407581375465580420, 16442451038823818694, 7698809547406684914, 18232885173941026794, 3104393142368480565, 7738728989754721313, 4802195899845329288, 14925669435061449558, 0, 5296, 13498446627995378981, 6649809143130705797, 9522654220689816851, 7559480440412863769, 14249558742787467865, 4471817386074892784, 8930056613191782368, 9155852006764527165, 18377192855492301434, 12836057040498431452, 12282989683528533601, 3467617432525765103, 13766601347831535388, 2925667013227878460, 12822094630311757386, 6738693051085880966, 15661549307393278485, 7649583626848747165, 14069036937855587505, 9495341522376803417, 534616849927909964, 1899062451757954377, 6407581375465580420, 16442451038823818694, 7698809547406684914, 18232885173941026794, 3104393142368480565, 7738728989754721313, 4802195899845329288, 14925669435061449558, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 12734367032130478571, 915471480408530766, 18393930191488027312, 13545212286845976163, 18210660875436245579, 1541989510332303929, 5733187932229069792, 8676871105886252208, 15648333801800339703, 12513161021723575557, 9265666514596208448, 10311060571948838328, 15479186567637803235, 9457367929087028434, 10997859361453741844, 4801586725411290698, 8358881080234670725, 14262453638255884367, 3602771739252146288, 6541843013709002421, 3170708104995675453, 10921877432993541182, 10224257779706313529, 15830149545637956450, 13414249448981002451, 11722023958758893627, 18138185027267907899, 13905103948731397841, 9009398081722850699, 16014363687546775515, 10945967283455090973, 0, 1032, 15909096041365347974, 18432189660917429733, 2798890989547891271, 10768372030970716894, 5935807051329113911, 1259182408195029650, 16024750973514577255, 6103595041913569283, 914770550723164908, 5067028895751058275, 5242612139537538536, 13359135899043031769, 4430959127423856282, 16317056360529517539, 2634255659160911215, 15590656855559575839, 6832335878067392309, 6045109056629836176, 18146646330136390606, 6482705684632040588, 2770791364887326735, 7707774010999656594, 3401430074469265273, 3500862351024377705, 5135727797169111985, 14940852959892477883, 9633218853985087472, 16966092255533854383, 3065488485208441055, 15703076512693482766, 0, 4448725490869322219, 4944140066849387506, 2095785635431009262, 12375413327700682072, 11081872751342419742, 18058781214879352230, 17856276381917295190, 6718639559482054424, 668947051234094647, 3868828750372286402, 12122170781554046887, 4343898307694473975, 12690125861105998824, 16799534473726304569, 15934980937477619093, 3969747009451350970, 7686328019139102331, 3785180857099199084, 11986142858341385519, 2506152622879710750, 18430687071203156938, 3054089675267069232, 8760992635981950709, 11143171037695874494, 4733232646684685861, 1219894586292412814, 12600138307490245388, 824784286256764128, 10170016208525526833, 593495485489349093, 11923860796119339735, 0, 5296, 12442366360197298238, 6098667720777990098, 15014871424912942550, 15008680935203256586, 5625270093505773824, 14457467770650559296, 10887298179723462085, 16706947956141547836, 13310039786220231748, 6132850845308416918, 12403357056402201263, 1240140770639885705, 15461729627686219061, 6574742069523544220, 3131690396120496930, 17758791276367026584, 10046968584624867256, 16910374147545432071, 12405462687145854473, 9006078559482542456, 13476220060215365999, 8384214154009398478, 10365404322190410833, 6851505899182549268, 18261819862243438027, 2823760450959191582, 17079185842171546000, 2573099324947734045, 9396372422985936818, 6899349384621454800, 0, 5296, 12442366360197298238, 6098667720777990098, 15014871424912942550, 15008680935203256586, 5625270093505773824, 14457467770650559296, 10887298179723462085, 16706947956141547836, 13310039786220231748, 6132850845308416918, 12403357056402201263, 1240140770639885705, 15461729627686219061, 6574742069523544220, 3131690396120496930, 17758791276367026584, 10046968584624867256, 16910374147545432071, 12405462687145854473, 9006078559482542456, 13476220060215365999, 8384214154009398478, 10365404322190410833, 6851505899182549268, 18261819862243438027, 2823760450959191582, 17079185842171546000, 2573099324947734045, 9396372422985936818, 6899349384621454800, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] }, last_program_row: RowIndex(17) }, program_info: ProgramInfo { program_hash: Word([8442199976350624000, 9488069924049927331, 3589804369840038271, 11846932079106298851]), kernel: Kernel([]) }, stack_outputs: StackOutputs { elements: [9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, merkle_store_nodes: {Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571]): (Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350]), Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350])), Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484]): (Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693]), Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693])), Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781]): (Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874]), Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874])), Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171]): (Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361]), Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361])), Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815]): (Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305]), Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305])), Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689]): (Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195]), Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195])), Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362]): (Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063]), Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063])), Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848]): (Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661]), Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661])), Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352]): (Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829]), Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829])), Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444]): (Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223]), Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223])), Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386]): (Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388]), Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388])), Word([13190842942618341421, 17548956981569849952, 15418963848144418856, 730733050713174879]): (Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144]), Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144])), Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874]): (Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675]), Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675])), Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594]): (Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115]), Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115])), Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809]): (Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257]), Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257])), Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777]): (Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555]), Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555])), Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509]): (Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882]), Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882])), Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725]): (Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979]), Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979])), Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134]): (Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987]), Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987])), Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828]): (Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910]), Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910])), Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830]): (Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054]), Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054])), Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228]): (Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742]), Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742])), Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443]): (Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928]), Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928])), Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643]): (Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979]), Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979])), Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758]): (Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106]), Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106])), Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580]): (Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594]), Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594])), Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765]): (Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045]), Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045])), Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766]): (Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281]), Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281])), Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385]): (Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828]), Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828])), Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579]): (Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171]), Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171])), Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212]): (Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992]), Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992])), Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463]): (Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004]), Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004])), Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502]): (Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023]), Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023])), Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539]): (Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537]), Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537])), Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865]): (Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225]), Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225])), Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690]): (Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947]), Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947])), Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202]): (Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552]), Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552])), Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079]): (Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444]), Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444])), Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850]): (Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548]), Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548])), Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448]): (Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987]), Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987])), Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041]): (Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035]), Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035])), Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301]): (Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414]), Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414])), Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414]): (Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212]), Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212])), Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703]): (Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439]), Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439])), Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271]): (Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955]), Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955])), Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882]): (Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802]), Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802])), Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152]): (Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887]), Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887])), Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028]): (Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948]), Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948])), Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331]): (Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093]), Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093])), Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394]): (Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134]), Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134])), Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546]): (Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228]), Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228])), Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620]): (Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414]), Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414])), Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800]): (Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703]), Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703])), Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671]): (Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205]), Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205])), Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537]): (Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011]), Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011])), Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516]): (Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301]), Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301])), Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831]): (Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986]), Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986])), Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415]): (Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057]), Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057])), Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722]): (Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689]), Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689])), Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144]): (Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682]), Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682])), Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295]): (Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268]), Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268])), Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818]): (Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513]), Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513])), Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241]): (Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565]), Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565])), Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439]): (Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012]), Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012])), Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512]): (Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850]), Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850])), Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986]): (Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865]), Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865])), Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982]): (Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777]), Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777])), Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808]): (Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394]), Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394])), Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979]): (Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690]), Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690])), Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093]): (Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620]), Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620])), Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902]): (Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789]), Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789])), Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542]): (Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094]), Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094])), Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057]): (Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362]), Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362])), Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205]): (Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961]), Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961])), Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401]): (Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580]), Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580])), Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553]): (Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960]), Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960])), Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169]): (Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031]), Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031])), Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682]): (Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053]), Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053])), Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118]): (Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562]), Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562])), Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725]): (Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666]), Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666])), Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661]): (Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897]), Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897])), Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981]): (Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447]), Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447])), Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072]): (Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646]), Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646])), Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140]): (Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404]), Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404])), Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515]): (Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152]), Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152])), Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709]): (Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664]), Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664])), Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800]): (Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103]), Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103])), Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741]): (Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169]), Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169])), Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005]): (Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758]), Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758])), Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802]): (Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070]), Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070])), Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159]): (Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005]), Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005])), Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350]): (Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443]), Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443])), Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697]): (Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573]), Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573])), Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928]): (Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331]), Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331])), Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320]): (Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166]), Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166])), Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814]): (Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079]), Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079])), Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447]): (Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820]), Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820])), Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284]): (Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057]), Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057])), Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697]): (Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131]), Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131])), Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955]): (Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290]), Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290])), Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910]): (Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202]), Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202])), Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910]): (Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822]), Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822])), Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106]): (Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847]), Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847])), Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404]): (Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441]), Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441])), Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796]): (Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186]), Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186])), Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053]): (Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516]), Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516])), Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992]): (Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818]), Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818])), Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957]): (Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315]), Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315])), Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709]): (Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794]), Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794])), Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091]): (Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539]), Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539])), Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664]): (Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558]), Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558])), Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294]): (Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579]), Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579])), Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947]): (Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502]), Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502])), Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829]): (Word([0, 0, 0, 0]), Word([0, 0, 0, 0])), Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045]): (Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137]), Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137])), Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914]): (Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041]), Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041])), Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573]): (Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378]), Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378])), Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699]): (Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873]), Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873])), Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225]): (Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262]), Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262])), Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057]): (Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692]), Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692])), Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131]): (Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997]), Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997])), Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555]): (Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385]), Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385])), Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195]): (Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709]), Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709])), Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166]): (Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542]), Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542])), Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027]): (Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373]), Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373])), Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378]): (Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509]), Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509])), Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097]): (Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553]), Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553])), Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217]): (Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815]), Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815])), Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873]): (Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864]), Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864])), Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997]): (Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722]), Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722])), Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887]): (Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766]), Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766])), Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589]): (Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757]), Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757])), Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539]): (Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665]), Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665])), Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129]): (Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229]), Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229])), Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137]): (Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312]), Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312])), Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019]): (Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378]), Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378])), Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331]): (Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713]), Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713])), Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]): (Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980]), Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980])), Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325]): (Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546]), Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546])), Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170]): (Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822]), Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822])), Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054]): (Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295]), Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295])), Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925]): (Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848]), Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848])), Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909]): (Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796]), Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796])), Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540]): (Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170]), Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170])), Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214]): (Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448]), Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448])), Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317]): (Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294]), Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294])), Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757]): (Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416]), Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416])), Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378]): (Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091]), Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091])), Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263]): (Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463]), Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463])), Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666]): (Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361]), Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361])), Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174]): (Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992]), Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992])), Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470]): (Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401]), Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401])), Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665]): (Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957]), Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957])), Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262]): (Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144]), Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144])), Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229]): (Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284]), Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284])), Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134]): (Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325]), Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325])), Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855]): (Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765]), Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765])), Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115]): (Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814]), Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814])), Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441]): (Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831]), Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831])), Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977]): (Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446]), Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446])), Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880]): (Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005]), Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005])), Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789]): (Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995]), Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995])), Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000]): (Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267]), Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267])), Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998]): (Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982]), Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982])), Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995]): (Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539]), Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539])), Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507]): (Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512]), Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512])), Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305]): (Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118]), Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118])), Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219]): (Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009]), Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009])), Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416]): (Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089]), Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089])), Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980]): (Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445]), Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445])), Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063]): (Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140]), Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140])), Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713]): (Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159]), Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159])), Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031]): (Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809]), Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809])), Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932]): (Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037]), Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037])), Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094]): (Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925]), Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925])), Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315]): (Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386]), Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386])), Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446]): (Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721]), Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721])), Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742]): (Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981]), Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981])), Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661]): (Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072]), Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072])), Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979]): (Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671]), Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671])), Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361]): (Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269]), Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269])), Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558]): (Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571]), Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571])), Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290]): (Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902]), Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902])), Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987]): (Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741]), Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741])), Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902]): (Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515]), Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515])), Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497]): (Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028]), Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028])), Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948]): (Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709]), Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709])), Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009]): (Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725]), Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725])), Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387]): (Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317]), Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317])), Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159]): (Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808]), Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808])), Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394]): (Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699]), Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699])), Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312]): (Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000]), Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000])), Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987]): (Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821]), Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821])), Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046]): (Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909]), Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909])), Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565]): (Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028]), Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028])), Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269]): (Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352]), Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352])), Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847]): (Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271]), Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271])), Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513]): (Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800]), Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800])), Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054]): (Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394]), Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394])), Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004]): (Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977]), Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977])), Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675]): (Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800]), Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800])), Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692]): (Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159]), Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159])), Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909]): (Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932]), Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932])), Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814]): (Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697]), Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697])), Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186]): (Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387]), Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387])), Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445]): (Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470]), Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470])), Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966]): (Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507]), Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507])), Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548]): (Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253]), Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253])), Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897]): (Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783]), Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783])), Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208]): (Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054]), Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054])), Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268]): (Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661]), Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661])), Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388]): (Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643]), Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643])), Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257]): (Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174]), Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174])), Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960]): (Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241]), Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241])), Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721]): (Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046]), Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046])), Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822]): (Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217]), Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217])), Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253]): (Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697]), Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697])), Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054]): (Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019]), Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019])), Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821]): (Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432]), Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432])), Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864]): (Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105]), Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105])), Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373]): (Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855]), Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855])), Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646]): (Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830]), Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830])), Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460]): (Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208]), Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208])), Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033]): (Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214]), Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214])), Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105]): (Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129]), Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129])), Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281]): (Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909]), Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909])), Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028]): (Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027]), Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027])), Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012]): (Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054]), Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054])), Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562]): (Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589]), Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589])), Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037]): (Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097]), Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097])), Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355]): (Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460]), Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460])), Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223]): (Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355]), Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355])), Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089]): (Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306]), Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306])), Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035]): (Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219]), Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219])), Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432]): (Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297]), Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297])), Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693]): (Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263]), Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263])), Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794]): (Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484]), Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484])), Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552]): (Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941]), Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941])), Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267]): (Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814]), Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814])), Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992]): (Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415]), Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415])), Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941]): (Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966]), Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966])), Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822]): (Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320]), Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320])), Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306]): (Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902]), Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902])), Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820]): (Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880]), Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880])), Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361]): (Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725]), Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725])), Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005]): (Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914]), Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914])), Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783]): (Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781]), Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781])), Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011]): (Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033]), Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033])), Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297]): (Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910]), Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910])), Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070]): (Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134]), Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134])), Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144]): (Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331]), Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331])), Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023]): (Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497]), Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497])), Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103]): (Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540]), Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540])), Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961]): (Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998]), Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998])), Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414]): (Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]), Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]))}, trace_len_summary: TraceLenSummary { main_trace_len: 18, range_trace_len: 39, chiplets_trace_len: ChipletsLengths { hash_chiplet_len: 160, bitwise_chiplet_len: 0, memory_chiplet_len: 0, kernel_rom_len: 0 } } } +ExecutionTrace { main_trace: MainTrace { storage: Parts { core_rm: [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 13719137288158876142, 6221215488690831821, 11468044834296629525, 16720332114142763849, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1032, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 2, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 8, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 3, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 4, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 1, 1, 1, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 5, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 16362180982079134587, 16601100057639640520, 5521682503008444658, 3792208660074152519, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 6, 0, 0, 0, 0, 0, 5, 0, 1, 1, 0, 1, 0, 1, 5296, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 7, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 1, 1, 0, 41, 5, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 8, 0, 0, 0, 0, 0, 7, 1, 0, 0, 1, 0, 1, 0, 0, 5, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 7, 1, 9, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 1, 1, 1, 16362180982079134587, 16601100057639640520, 5521682503008444658, 3792208660074152519, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 10, 0, 0, 0, 0, 0, 5, 0, 0, 1, 0, 1, 1, 1, 16362180982079134587, 16601100057639640520, 5521682503008444658, 3792208660074152519, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 11, 0, 0, 0, 0, 0, 5, 0, 1, 1, 0, 1, 0, 1, 5296, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 12, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 1, 1, 0, 41, 5, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 13, 0, 0, 0, 0, 0, 9, 1, 0, 0, 1, 0, 1, 0, 0, 5, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 12, 1, 14, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 1, 1, 1, 16362180982079134587, 16601100057639640520, 5521682503008444658, 3792208660074152519, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 15, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 1, 1, 1, 13719137288158876142, 6221215488690831821, 11468044834296629525, 16720332114142763849, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 16, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 31, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 33, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 39, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 43, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 47, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 50, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 51, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 53, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 54, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 55, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 59, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 60, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 61, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 67, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 69, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 70, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 71, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 72, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 73, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 74, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 75, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 76, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 77, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 78, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 79, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 81, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 82, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 83, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 86, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 87, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 88, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 89, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 90, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 91, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 92, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 93, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 94, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 97, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 98, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 99, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 101, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 102, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 103, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 104, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 105, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 106, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 107, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 108, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 109, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 110, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 111, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 112, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 113, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 114, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 115, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 116, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 117, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 118, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 119, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 120, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 121, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 122, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 123, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 124, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 125, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 126, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 127, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0], chiplets_rm: [1, 1, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 13719137288158876142, 6221215488690831821, 11468044834296629525, 16720332114142763849, 0, 87, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 2445654027848798773, 13989391813235195492, 481784282030877064, 1887209632430994963, 9346278187721986719, 3141189181316333764, 4622204731995696995, 16701354768447765175, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1032, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 11116382020814057190, 14732796941305378371, 13074361791711182490, 6715193688317415490, 1571558009365433839, 13285275197432594374, 15905141483335727027, 2507840277166973476, 0, 0, 1, 0, 0, 1, 1, 0, 0, 16362180982079134587, 16601100057639640520, 5521682503008444658, 3792208660074152519, 0, 0, 0, 0, 0, 85, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 13719137288158876142, 6221215488690831821, 11468044834296629525, 16720332114142763849, 13962113176908263293, 676026057669832378, 15921241029195116857, 15915352364638718229, 1456698220748515004, 1707540503940690697, 10429997843948879425, 4559651383104503034, 0, 0, 1, 0, 0, 1, 1, 0, 0, 5296, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 16362180982079134587, 16601100057639640520, 5521682503008444658, 3792208660074152519, 6708412556839205818, 3204764821942414262, 2382590011410319125, 5080678178504844773, 6374574376632329694, 13516826603120023138, 12611398678228181741, 13552592212104960667, 0, 0, 1, 0, 0, 1, 1, 0, 0, 5296, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 16362180982079134587, 16601100057639640520, 5521682503008444658, 3792208660074152519, 6708412556839205818, 3204764821942414262, 2382590011410319125, 5080678178504844773, 6374574376632329694, 13516826603120023138, 12611398678228181741, 13552592212104960667, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1032, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 15913981378790993016, 12701179462806902902, 9645342555817022514, 6889850077248808033, 678249829196625442, 8726676798253716750, 14136118088409135949, 1027279235140821190, 8048729929177993405, 2542525775606472849, 3283471062508934848, 18058280687405074483, 1, 0, 0, 0, 1, 0, 0, 0, 0, 11899090779839289087, 1701090513954162998, 6953639183117323837, 11460660778637092812, 8345945186928076892, 11308243255833047975, 5734666540714547293, 1546649737555419076, 14643837757854608147, 7477230882792828789, 2359592855656894189, 12732146754685591216, 1, 0, 0, 0, 1, 0, 0, 0, 0, 16283412161296764998, 17261112905912533997, 1498213616014501531, 7707889409925905689, 16090493533591377617, 525010687572874692, 5228788497345464933, 13051466527897639054, 3560924095387897187, 12551242480725370445, 4038828260160651477, 6132317990703151787, 1, 0, 0, 0, 1, 0, 14261694278902826987, 16097544111075686229, 16632169854204459773, 14265791174051766329, 14732671264513481238, 15642599276989292777, 7593738854072541043, 11440582168151819564, 18258483622390056257, 6851601084855956341, 10463349537167637967, 10032876585525342603, 825669147467031185, 16271217766495541082, 9021089524754424392, 1, 0, 0, 0, 1, 0, 16780109665356203593, 16025948514351396737, 4256182047405196535, 4919013996388780384, 6974015548720770018, 10189882052640604940, 12288632186238773648, 7055558833039165669, 9820743264545515107, 7353106531603230851, 5612808106478211181, 362487531847990854, 10259224130335842891, 2374318293393776907, 16208179153232019183, 1, 0, 0, 0, 1, 0, 9496969110446094198, 10424961628901078909, 7587726188775237019, 13423955604028434301, 12288543613568774022, 4068762405627465026, 7288480650179820504, 1035430088689333582, 2651098721515326755, 4524440782000877024, 3013038852551457145, 12536534023666437466, 6560028330562582937, 9090521726813489969, 17634755409309861791, 1, 0, 0, 0, 1, 0, 15761194215082968049, 15796684185970405493, 1294179585337070936, 5701860167148115542, 17707247215386403887, 18419960639673587986, 14570347312565937582, 8634142387233894354, 11938075017385927203, 8060480374868324599, 16699922976999064541, 14234489074154948378, 17210389744085299852, 17331527780947314617, 16356838976302290254, 1, 0, 0, 0, 1, 0, 6184336662619539433, 7106147576739595100, 18237994300618329820, 9768155666925548219, 226714884885574576, 11169479382209254075, 5756676929838789145, 29803495366482069, 13128905441940840949, 18304516631519674746, 3177693875357946498, 10624850715031233718, 16956738608020324589, 10558540052020438814, 7826502712354673600, 1, 0, 0, 0, 1, 0, 1980308537464408089, 6810023246846442283, 9400257804338494201, 11246932855318952856, 7504545710540897051, 5823677062954428984, 9151299935574592196, 15905322272715446259, 18174748553199601666, 9877077233183640995, 2431998410719122545, 3541292002384422941, 5416588529930333172, 15788517205879313917, 2490575598934209003, 1, 0, 0, 0, 1, 0, 17950140321155419078, 9014768943295123367, 10707122777228105884, 10701204914974985643, 15060806908759160804, 7011191650405807117, 13598159658926423040, 3947314552577424057, 12985682730462769834, 18264715466581442035, 7667189540353817157, 7685483800933651249, 16085167604591833455, 16105855167414075111, 16215395602017884846, 1, 0, 0, 0, 1, 0, 8676227747932036802, 0, 0, 11504729673400082663, 3659553513673892306, 10374352082945691939, 15819529278889203623, 18107940902385670152, 8889798095480337831, 12737345777792032790, 456604824069734238, 2859376131275373721, 8758251935142908528, 2364536875264708997, 2435873391009301907, 1, 0, 0, 0, 1, 0, 0, 0, 0, 16797630026773069829, 16954579754978210547, 4393671449525183699, 6245909065255485436, 8311309349844601638, 3305827896314343556, 1615477551160071258, 3897903986825909618, 13015230208471866351, 13839070994009764281, 2415598337053791919, 5526300544248852335, 1, 0, 0, 0, 1, 0, 0, 0, 0, 12827873667465929582, 15892701250663610383, 549489834728826775, 9425334953627649153, 15402634395731091512, 11814416271399500934, 14597718118926923662, 4726679541432826422, 342915941842538663, 11221492717904369823, 17188959961041335276, 13559932473868727168, 1, 0, 0, 0, 1, 0, 0, 0, 0, 8689096602925893779, 4096531352684607500, 8424481237826564505, 15238165026175259240, 10985176737527635898, 2672540837788784952, 6649439643634522762, 7581835251244605715, 17671970641549389116, 18069913154458602790, 749417941228438762, 6150863900366154379, 1, 0, 0, 0, 1, 0, 0, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 11116382020814057190, 14732796941305378371, 13074361791711182490, 6715193688317415490, 1571558009365433839, 13285275197432594374, 15905141483335727027, 2507840277166973476, 1, 0, 0, 0, 1, 0, 0, 0, 0, 5296, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 0, 9406198837081470939, 12454644480646831381, 5357297729805547264, 15695767008081417024, 17081781165782008305, 18173774266735228622, 6597958223090468622, 10058815580948772803, 9341085403015625984, 17305809056185869492, 16092333721991261411, 14466140396882267896, 2, 0, 0, 0, 1, 0, 0, 0, 0, 10022220918800215931, 6625466299838152616, 14873368774111773763, 13822207310342005989, 11851640107665623803, 4144160359412257714, 1001954617881206717, 2558852513241095712, 8048571622541726255, 3796262690630383451, 12690029978283677858, 7698456735078463171, 2, 0, 0, 0, 1, 0, 0, 0, 0, 1529838978363474364, 5877585793149040063, 11620602129319348479, 3184399423922769699, 4766473366160256877, 7300042540399827448, 2462275239493078851, 11288811565422176008, 16822095754433680909, 18301782264345075251, 18087044935643148806, 510047809549721667, 2, 0, 0, 0, 1, 0, 17625583494235189807, 10622457062204255065, 2653216356844660597, 9475027500051639757, 10463750966311648190, 11600868756246964674, 15662168292079378087, 14737424852298451342, 117344945972585870, 3251083096698399603, 12684542007451613640, 4788924408482455108, 6902797868122893844, 15800238251163812693, 12046292011878974455, 2, 0, 0, 0, 1, 0, 7496472832454263388, 12998172934440185624, 17507911152779544052, 16456090005001040440, 16590029451027219509, 2617628953138715244, 622817961215058190, 1598986500188737220, 17607068252592942451, 15060402253986549440, 16875740049367006869, 4040451923151286438, 5925341866968505601, 14259707661873610422, 10732873470134113982, 2, 0, 0, 0, 1, 0, 1452526314939094806, 1479000593888603377, 246310986971833963, 4152569545950646704, 4118156517299583310, 17663239633609473365, 8127661496786659791, 17689549836214880979, 14746946312861632567, 602662289136933629, 11216558892028292475, 5188174964157774722, 7100861533945618475, 3714941418598094928, 1377039040653060055, 2, 0, 0, 0, 1, 0, 2930684747787414446, 1754494303819808128, 669923854651336066, 5941781742039952076, 876859729835418933, 790907098378102911, 115518666891692872, 16890877536441094576, 16820881161920465009, 241154565549913410, 44006951265386772, 5087127128059490065, 18106355872892957036, 3269612205224843731, 8638796096796806719, 2, 0, 0, 0, 1, 0, 2414727401863600363, 7617116592575512612, 18041147314657306922, 15957716643783059543, 11912796059449786962, 11153176059938326063, 14174738803865199162, 11999349000942665761, 17632700466101721722, 6582530104605672978, 16757182470542785800, 12431955029502155155, 17163152133935520513, 1237894940644049096, 6188646281997977531, 2, 0, 0, 0, 1, 0, 2319532296399149270, 9283783715220787949, 810281363185644618, 4756894436878044936, 12165478487736095233, 13041376666032139342, 3740623961436206385, 6384260880460211781, 17121495806538343926, 14583996149149192254, 11562370595738293151, 8268709300694246348, 17892562184847802024, 3859704522936614211, 7366245284644652757, 2, 0, 0, 0, 1, 0, 949011576700156842, 1533322811274401426, 15060757839378359292, 1432035093691797337, 206692693307936550, 378907012515670704, 10248912138703390835, 10128144445036454539, 5042107387767762304, 9843022881405494656, 11880883914254039546, 13220616153049902, 455311511731825064, 5381232113954376086, 5364482943654507461, 2, 0, 0, 0, 1, 0, 5881102500383619035, 0, 0, 2424299330597632902, 607119689966087280, 17283177276798307300, 475409702871185800, 15518804315920479075, 4578339057778509415, 4685043752195987874, 10392430241191498892, 11507515262772595129, 14439767021292397992, 13673908725375817159, 5378163831543087962, 2, 0, 0, 0, 1, 0, 0, 0, 0, 14342875730731176181, 6225072162372691712, 8577974921324183601, 751519865506756952, 9824595797538483612, 10360631973465438301, 10226703749989732907, 13840269947314152185, 1831374399934529359, 14389265827404554261, 11392184682219726353, 17676970157216697757, 2, 0, 0, 0, 1, 0, 0, 0, 0, 10605591699135631895, 525785012032090331, 1824237168047932550, 3952375305216254717, 9821754274536606782, 7855314197760224131, 17861834154975224793, 9836275050510148653, 17819027328170218375, 2840178708967434753, 15534576285961723627, 15357405679043026976, 2, 0, 0, 0, 1, 0, 0, 0, 0, 9793600913424407404, 14104167067920766779, 12309619471118709560, 12550056362664815329, 320739284087105326, 3762140957859872022, 10326389091316073307, 18366686834124399227, 5296819603037261258, 8152022108836431115, 8031664516364171852, 12133015237048791800, 2, 0, 0, 0, 1, 0, 0, 0, 0, 16362180982079134587, 16601100057639640520, 5521682503008444658, 3792208660074152519, 6708412556839205818, 3204764821942414262, 2382590011410319125, 5080678178504844773, 6374574376632329694, 13516826603120023138, 12611398678228181741, 13552592212104960667, 2, 0, 0, 0, 1, 0, 0, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 13719137288158876142, 6221215488690831821, 11468044834296629525, 16720332114142763849, 0, 87, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 14526210785099218637, 11847263499640079386, 14727111875255715984, 15492005690507045243, 3560320103534777253, 6108459071875623888, 17010585649681490524, 9461625672567273576, 5346213935533921584, 17324400741801951375, 11366145235097950908, 11020281342858012232, 1, 0, 0, 0, 1, 0, 0, 0, 0, 16197070053425155514, 15404003330998391348, 11930643358177149189, 1706026293115752249, 4860311493079570077, 17106682771221635926, 1613342353291471586, 10021094444428090144, 295368900173018762, 10362371049945425700, 9316163589333399506, 7378950726844095693, 1, 0, 0, 0, 1, 0, 0, 0, 0, 11506810158870826797, 14392904697466827547, 17905937794745323592, 17513565884470753819, 7019811109989114514, 10250939299242755101, 7620822681592706112, 12768902792042039708, 744728025267091276, 16212166364245632221, 10010770609378408333, 15023204573923685916, 1, 0, 0, 0, 1, 0, 9206943447329060417, 1573227013771687083, 7633983188953929869, 14747762092445444483, 12960730896173836507, 5351433366377253619, 4177159482546072600, 17061003377938727239, 9435579121926835049, 9864020053232925179, 11244311170762781618, 2840907732738372264, 7192941522047765124, 6173174116697481058, 13004561835267794042, 1, 0, 0, 0, 1, 0, 12007385695887985386, 13598702180788517287, 3912064789771327196, 11932998954627996911, 3853323028698833085, 11507033346049547360, 10110848241210835991, 15428609857280202530, 17110299148476621277, 12520416593002020608, 9431488564150546187, 2602629576595200800, 15183940660821516128, 15328070744340284046, 9882485700386666987, 1, 0, 0, 0, 1, 0, 2642957852140576392, 12998709907982857483, 4565256592569070651, 4013127352579691203, 10860110376897053120, 13677509527593892026, 2308518476531625659, 6232392686954434349, 13948263847203418837, 7843559618500491242, 7771043128539275771, 18270783924518568037, 16689544634184962614, 16359543813917605495, 8488375023251026510, 1, 0, 0, 0, 1, 0, 13959988857529015221, 12915245760499792818, 14841159553908529338, 14670848694035742368, 13930039566082372841, 9902385290951234306, 3203646694279229751, 13440312555890036471, 10385999516795969620, 11713935020689149772, 12229669264695050570, 402942260260809100, 16753462626177821460, 662362961313881669, 5887183544599407053, 1, 0, 0, 0, 1, 0, 14402936773953440947, 2012430503613052642, 1213953359224393220, 13944145787018602210, 6056959262477445647, 4982640241702718669, 1688381135968391307, 4510633793399532317, 7320984145724666154, 4691989180601120012, 102059673196228558, 1411198915631488472, 1854414388528665842, 16986811917033125654, 795637807896719676, 1, 0, 0, 0, 1, 0, 6294256185997130924, 4739079035802422148, 10935612526477766520, 17716511124280484394, 5021001597521525061, 18126874747305633609, 481644947884807344, 6049685422777720638, 1030047529196261526, 9576302115777192780, 10035472829778314322, 923305066890152615, 12527260620733941943, 11414360666749268526, 17760291183069624834, 1, 0, 0, 0, 1, 0, 10231661581337343904, 1832808263237927056, 6905801525972141190, 7456565975287668714, 12513973463050722371, 15559507328575476525, 2883833371658699080, 3184838730020301861, 18205970767593414562, 2798075613901729544, 189593258747480201, 13243754036156659300, 5745460764532976218, 2786581607585809614, 17436021357923428450, 1, 0, 0, 0, 1, 0, 72056538882336487, 0, 0, 5652048509186166814, 15367385573432163092, 6683125870356394251, 3770937106356856256, 1769679637596203925, 14372844572054653742, 13769745398507346855, 11807785571768521955, 5724215673931049374, 4401662327723853424, 11928715632009092524, 9924361168171239878, 1, 0, 0, 0, 1, 0, 0, 0, 0, 15128667119917371737, 8016996928120686373, 7467419359957362665, 4993381537595555977, 9371037824338144222, 2930594646951740022, 3944515787153841278, 5454163417882053837, 7667177038930845021, 10105079595217614088, 5177647710243780137, 13395674984723106859, 1, 0, 0, 0, 1, 0, 0, 0, 0, 17075658029987678701, 16942975531700611427, 3643709618611291855, 1334709094417075573, 11909212706933233016, 9741605425019020242, 7607696627297382550, 15299729661431018600, 7032572794257903279, 16683658838871091473, 3645139219999290477, 7245544203380098384, 1, 0, 0, 0, 1, 0, 0, 0, 0, 12068304939642236116, 13614044321092849027, 2880541849277464939, 815353510606417922, 14606426392222040491, 10929343986009381754, 18415245620786467058, 16142346014486690114, 10307567187784261413, 3831820208496643010, 14408727760370549811, 16272758710359397343, 1, 0, 0, 0, 1, 0, 0, 0, 0, 6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845, 2445654027848798773, 13989391813235195492, 481784282030877064, 1887209632430994963, 9346278187721986719, 3141189181316333764, 4622204731995696995, 16701354768447765175, 1, 0, 0, 0, 1, 0, 0, 0, 0, 16362180982079134587, 16601100057639640520, 5521682503008444658, 3792208660074152519, 0, 0, 0, 0, 0, 85, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 12086689928305136975, 10578835246084642663, 16542988469676950340, 18039575486237140027, 11378817209220925403, 1830288712116369429, 6836951313152193092, 13067316829245445662, 10483719891652983399, 15107628385291453978, 5745482890193398991, 1467598035505522824, 1, 0, 0, 0, 1, 0, 0, 0, 0, 6641033060700930640, 8002128452364190151, 4237597913508652736, 16497663922788367837, 9373930087271682821, 8772840226065969951, 13812790890684464043, 3327344850838518736, 15781875901493184698, 16732525831131872764, 1159309880266465962, 6519234662137256116, 1, 0, 0, 0, 1, 0, 0, 0, 0, 10088943647124252289, 13701383109068607902, 15690388373484222925, 4290213237740108975, 15844775943612000391, 16171043348080529647, 8784789786127538562, 12635460091357573504, 10561363445665196403, 3917577954302608976, 5337858229134527127, 14152777758433279341, 1, 0, 0, 0, 1, 0, 13029570897742009002, 13177254746172619023, 16038571161593335404, 2188338323498964707, 14662423055206707252, 399526319231252303, 14972684080243877319, 16777311805145501140, 6099803173114002593, 11253362042985817221, 10221863501466764826, 13414791437675451535, 2725322839420367772, 11819412321405778772, 13817033321558649088, 1, 0, 0, 0, 1, 0, 13691749519374287845, 15387673422637086663, 6922978787178957527, 2041172898547348571, 14589651886185789070, 5957633751491508475, 11960354433033043999, 15992971255870582512, 11830967408320733184, 15268965263556481837, 9065968121241919240, 14630209597160847101, 3695262652988767746, 6761434464064434034, 4499935311821727041, 1, 0, 0, 0, 1, 0, 15420756780139702261, 12424942891141165558, 6929528357507663172, 12198893338677478437, 18421446739075495822, 8468855093677567166, 14423050383612849622, 15188396328060565700, 16106496456550916799, 4380220556771000987, 18185062664582859482, 3471791712555441489, 5206529722281859812, 12099854936489528262, 3482375809599031896, 1, 0, 0, 0, 1, 0, 15574108340013622137, 15113564352853103247, 11759657553614819330, 8329975443345290464, 17940882943282719830, 715706186220073675, 11225208304861844348, 11251091880797815873, 16487042113140331701, 2684378958809639271, 18420809765897439905, 5225320321320513732, 6305682781245368810, 4669442538207571276, 14700449525371639507, 1, 0, 0, 0, 1, 0, 2979254376677653503, 1883000689168719362, 8104422763610466617, 5576229311275790732, 2194272311725182022, 11069690432331401312, 9059389138265053881, 8765354464725236382, 9222374345361788506, 18259801840836875925, 6516753426367602114, 16862896352549227556, 4308341550229035638, 3265342498516698837, 13464131825573347891, 1, 0, 0, 0, 1, 0, 13700569878861168214, 2688488967505940113, 3894270749155947782, 13272913612051073638, 229891148220106304, 8827790146883078828, 18375171102175520942, 14403529172649637015, 13099700194841873205, 188376523053645225, 1993959712224675182, 14801384607878448444, 10465527702245819388, 17660990215931846922, 908628888712311860, 1, 0, 0, 0, 1, 0, 17841857416383363570, 1410880649834889205, 15205315845157535511, 474005396413342575, 13140045598301896487, 3896472587811302452, 11889483340877797878, 10675872888943407911, 9043988711004206942, 6590644200881402626, 6630214594291443650, 7328314644790889015, 1925120838408255657, 12102121948068675841, 3366469296269798303, 1, 0, 0, 0, 1, 0, 9810051462759316493, 0, 0, 1967048762267479030, 14694789381285854906, 7850615184380239535, 6179804070945807128, 6190847648382551976, 7074541545875785618, 9996122377954848783, 18406348765365233841, 4381980521208731448, 2527214276140522656, 17476881528019612421, 10227790736734811126, 1, 0, 0, 0, 1, 0, 0, 0, 0, 12825387260273911399, 6194529288585122100, 10547428200413979362, 7146038864248149980, 3758150568829560250, 6436891845148661154, 9620702432336511668, 2457824222102594551, 13331592005230563304, 11086532868255377399, 4413541832527011587, 16051730796051624324, 1, 0, 0, 0, 1, 0, 0, 0, 0, 16438196827052442198, 18163112479653478435, 13659775893412875850, 9240379517650154023, 17622738652736541491, 10377502873777599097, 14167784496777925017, 8652392797374596693, 10690605953822876908, 6607959159332506262, 7925296024181542304, 11865355698347075352, 1, 0, 0, 0, 1, 0, 0, 0, 0, 8453841446519729480, 5007921045949414127, 10571120719178391220, 9766554424414228694, 8901262338981550121, 11643533070801732852, 18177267262839360795, 4695688607260963965, 5981212851350180937, 7185340145346514702, 15820300171842782914, 13017849308841041926, 1, 0, 0, 0, 1, 0, 0, 0, 0, 13719137288158876142, 6221215488690831821, 11468044834296629525, 16720332114142763849, 13962113176908263293, 676026057669832378, 15921241029195116857, 15915352364638718229, 1456698220748515004, 1707540503940690697, 10429997843948879425, 4559651383104503034, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], range_checker_cols: [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2187, 4374, 6561, 8748, 10935, 13122, 15309, 17496, 19683, 21870, 24057, 26244, 28431, 30618, 32805, 34992, 37179, 39366, 41553, 43740, 45927, 48114, 50301, 52488, 54675, 56862, 59049, 61236, 63423, 64152, 64881, 65124, 65367, 65448, 65529, 65532, 65535, 65535]], num_rows: 128 }, last_program_row: RowIndex(17) }, program_info: ProgramInfo { program_hash: Word([6406609362174192544, 2141985200726836626, 6661786482229909687, 13187921859861146845]), kernel: Kernel([]) }, stack_outputs: StackOutputs { elements: [9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, precompile_requests: [], final_precompile_transcript: PrecompileTranscript { state: Word([0, 0, 0, 0]) }, trace_len_summary: TraceLenSummary { main_trace_len: 18, range_trace_len: 39, chiplets_trace_len: ChipletsLengths { hash_chiplet_len: 80, bitwise_chiplet_len: 0, memory_chiplet_len: 0, ace_chiplet_len: 0, kernel_rom_len: 0 } } } diff --git a/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_11.snap b/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_11.snap index 40691a79f7..0e6abdbd90 100644 --- a/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_11.snap +++ b/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_11.snap @@ -2,4 +2,4 @@ source: processor/src/trace/parallel/tests.rs expression: DeterministicTrace(&trace_from_fragments) --- -ExecutionTrace { main_trace: MainTrace { columns: ColMatrix { columns: [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255], [0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 7458506668679174706, 7458506668679174706, 7458506668679174706, 7458506668679174706, 7458506668679174706, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 18375473735916206629, 18375473735916206629, 18375473735916206629, 18375473735916206629, 18375473735916206629, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 2105717247508690050, 2105717247508690050, 2105717247508690050, 2105717247508690050, 2105717247508690050, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1679902783560062568, 1679902783560062568, 1679902783560062568, 1679902783560062568, 1679902783560062568, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 33, 33, 33, 1, 65, 97, 97, 97, 65, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [7458506668679174706, 1032, 8, 0, 7458506668679174706, 7458506668679174706, 1032, 8, 0, 7458506668679174706, 8038422000946611307, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111], [18375473735916206629, 0, 1, 1, 18375473735916206629, 18375473735916206629, 0, 65, 65, 18375473735916206629, 14346009158187546482, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290], [2105717247508690050, 0, 0, 0, 2105717247508690050, 2105717247508690050, 0, 0, 0, 2105717247508690050, 2190566822905267077, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045], [1679902783560062568, 0, 0, 0, 1679902783560062568, 1679902783560062568, 0, 0, 0, 1679902783560062568, 2591468219526413421, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704], [8038422000946611307, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [14346009158187546482, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [2190566822905267077, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [2591468219526413421, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2], [3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2188, 4375, 6562, 8749, 10936, 13123, 15310, 17497, 19684, 21871, 24058, 26245, 28432, 30619, 32806, 34993, 37180, 39367, 41554, 43741, 45928, 48115, 50302, 52489, 54676, 56863, 59050, 61237, 63424, 64153, 64882, 65125, 65368, 65449, 65530, 65533, 65534, 65535, 65535], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [7458506668679174706, 17096349974747592886, 18361620591822500183, 16289398515402274208, 12841425204405288471, 15487398038599823036, 14276138499607098431, 10749365977722278245, 6523151203286366650, 4335325190849710619, 15614163639554121613, 12559670426893619349, 2624231249184618532, 172006848477927500, 14464825374273596237, 17032775430832607567, 5313985443683323356, 5926060660140296438, 17163852599398532090, 13307451342254896743, 6745543631073250405, 5541607425778637052, 17242934273716413404, 8175629301673337378, 9641946119039093964, 13376211201769313404, 3983555747063229007, 2734833199126280117, 726265693390881232, 14561475405601408308, 12499075216226282978, 385638883771950111, 1032, 10320, 13024110921086730221, 3587442816163675215, 512402747638547729, 9217956011885162917, 3925750957223009950, 8674177413178223320, 12846799727083908462, 9116601283268739756, 2958792353189815054, 1720195204565087693, 7696852080146622077, 2890877729556257606, 16676527939404087356, 223754558788184593, 4767414622778376421, 14072300156908432530, 16856861612825314654, 11910434229443384600, 15658716527747040980, 14322127566252286435, 4770460127206402609, 10805338145914832851, 1391598300875421210, 18211456042978337510, 11866022853402812888, 6438324596032750504, 13328288515202849800, 17331158106613184460, 18344276842462151560, 7458506668679174706, 7458506668679174706, 14091156936533878352, 9449073279161460587, 12931192181764701571, 984010488942368543, 9685532581221734183, 7253373568681004065, 3375237562644883775, 6753674160453463758, 3441205833090784550, 2852031204586017293, 17888529253300920997, 14261166963032608042, 7584983368183421126, 6933428701043454429, 6613788239612360156, 12188550669627194766, 11116051071552283912, 12942594340955341249, 15973329405569184071, 6599410081338642359, 9166275669564489461, 16205691190134424749, 10240544379350652389, 617488447888956772, 10444963251954281557, 1760171480459315772, 225922431704781657, 6781621337133548780, 6905620312272855934, 11742310966982885025, 8038422000946611307, 1032, 10320, 13024110921086730221, 3587442816163675215, 512402747638547729, 9217956011885162917, 3925750957223009950, 8674177413178223320, 12846799727083908462, 9116601283268739756, 2958792353189815054, 1720195204565087693, 7696852080146622077, 2890877729556257606, 16676527939404087356, 223754558788184593, 4767414622778376421, 14072300156908432530, 16856861612825314654, 11910434229443384600, 15658716527747040980, 14322127566252286435, 4770460127206402609, 10805338145914832851, 1391598300875421210, 18211456042978337510, 11866022853402812888, 6438324596032750504, 13328288515202849800, 17331158106613184460, 18344276842462151560, 7458506668679174706, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [18375473735916206629, 4928386710787932510, 1059957073285149997, 7414794499417747342, 8707706418338537128, 18233967745224015541, 14225356453364529209, 16969240713191698060, 2722387933855210372, 10882627342955990743, 8403803192675895448, 16245041381764943451, 3708333802929870625, 6959279407809842059, 13217946414061638961, 18053036458820754856, 14921461448469870468, 560525447297576809, 7018646217871183595, 13178251276894296346, 6921572661546485589, 15572457938054287524, 2649667358943828601, 7478653578860599304, 10687080159641340324, 2690283767645584259, 18436093682323240213, 7844418673662650289, 14896924519547367367, 5700869957895642798, 1468047895374295633, 14533042520471865290, 0, 8256, 1131208899036558480, 1667157010810320250, 2053960715201569301, 1526213270499333709, 69813565043892453, 14925652377538846871, 1380252317064967448, 9902934070223067140, 3786794161520721521, 664031068804619792, 8470323998416702977, 4965297830526000942, 9404280000999464502, 8244737495337250711, 4784363486033662704, 4680481291290566437, 15373555507761845373, 8780119261264514018, 729009684537575982, 18306419558979237700, 15407410920890065538, 2509966126115291236, 12709897403480972846, 11498596868429821859, 6606875518512322314, 13880694912200059110, 6972406840307481976, 14148490408465275064, 2917966740410115114, 18375473735916206629, 18375473735916206629, 11043817201346618265, 1121487758252150877, 11145191037714825824, 1213485180702191508, 7846971226962020365, 6910576852826920348, 16299106229207932049, 13494897806355030713, 14683406224909707924, 7225022863877466358, 8659258489615358612, 1007283657566761474, 3461275599657397285, 13991061905462032659, 7694544543570254942, 13915724103240909421, 3035711690563019728, 12166494415818485436, 8309121944568509175, 14938409169697365298, 8594201398583676528, 10975429338366528094, 12203611326855107051, 13805253251340915462, 17236773525845958123, 8285118005586313889, 4578896616328629575, 4956581778649408453, 2207149270543631094, 14846185326871759573, 14346009158187546482, 0, 8256, 1131208899036558480, 1667157010810320250, 2053960715201569301, 1526213270499333709, 69813565043892453, 14925652377538846871, 1380252317064967448, 9902934070223067140, 3786794161520721521, 664031068804619792, 8470323998416702977, 4965297830526000942, 9404280000999464502, 8244737495337250711, 4784363486033662704, 4680481291290566437, 15373555507761845373, 8780119261264514018, 729009684537575982, 18306419558979237700, 15407410920890065538, 2509966126115291236, 12709897403480972846, 11498596868429821859, 6606875518512322314, 13880694912200059110, 6972406840307481976, 14148490408465275064, 2917966740410115114, 18375473735916206629, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [2105717247508690050, 10107555422114249811, 10238372411792495411, 5045095827015758924, 712045908447132336, 5489587686936736744, 16325305247621291738, 3474647312056323841, 17923261380734419001, 6422147522697035080, 14808436219267178190, 498420322150313505, 13431378003732567637, 7624522606684096342, 16563220449590599184, 17295714046586140515, 670583892751407031, 2602239721821758274, 6195887607206027232, 2861627473244922884, 4750941303537176677, 9649080575881148937, 13116712088373847968, 6713440703831969386, 8417294471144249339, 1401889430288725516, 4371677581775699941, 4682611113744629451, 15268715163867613574, 18046680204045439410, 4916517868000584486, 12416920551073560045, 0, 2064, 18136552782870868471, 952274539956745973, 15933282259815262093, 9924516287334785738, 18064603646801610993, 5114527609957824263, 11816233963570869158, 17699527003452380450, 14533708946479200173, 17484213571014188868, 832814531422633701, 1508169308733590908, 8423043379628164525, 12595277727969636921, 14226276023010866965, 10485112285448962747, 1783527593060720204, 10145484005384627580, 7463752398658534839, 17345550819494003223, 4432309123412733588, 7086318781105575433, 8830891075082588619, 310185093236608634, 16683125300631590273, 7786799186167080425, 29465347809991832, 8090161351836983773, 8665315444141111469, 2105717247508690050, 2105717247508690050, 3724970573052107073, 8941582041334934334, 8312329417918475026, 1987590179830007973, 2110379688364488268, 2640821370997726846, 8705349523122969177, 17635305137043271645, 5321945504199945322, 14864981808156728804, 12170067272088757680, 9570740252338888760, 8752234911193229380, 7657051830321493279, 10054332690091372507, 9785276524271352823, 11645316320468991699, 16682105615873122608, 11466817788450225616, 11077840439234171924, 8390120315669274279, 15664297021877418193, 9890840092123213718, 14010940161066467221, 6608692618887145744, 7336759030812521166, 6773864172894681873, 14718016860648898221, 10620364686165750780, 13091258350263300328, 2190566822905267077, 0, 2064, 18136552782870868471, 952274539956745973, 15933282259815262093, 9924516287334785738, 18064603646801610993, 5114527609957824263, 11816233963570869158, 17699527003452380450, 14533708946479200173, 17484213571014188868, 832814531422633701, 1508169308733590908, 8423043379628164525, 12595277727969636921, 14226276023010866965, 10485112285448962747, 1783527593060720204, 10145484005384627580, 7463752398658534839, 17345550819494003223, 4432309123412733588, 7086318781105575433, 8830891075082588619, 310185093236608634, 16683125300631590273, 7786799186167080425, 29465347809991832, 8090161351836983773, 8665315444141111469, 2105717247508690050, 4294967292, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1679902783560062568, 6240831473992650349, 7295075507077524016, 1708983071443589586, 5101441454781013927, 1762085221214582981, 4624893715923722401, 5034791698378793493, 2426086071573235308, 5506620828865036918, 7907851684587935310, 191858132690363422, 12189827080513272685, 4161952004851845371, 3113047032182286095, 9384643295764542420, 16611260466052466604, 10297192864125327962, 8420396089584454313, 17843538048800435721, 49291998290789182, 15454664486445800726, 3574645404922812405, 11401680143523240515, 4109004423430966857, 16206235872347886942, 1597537279118331686, 11520518532281367191, 3135755890995221672, 15097801996593502346, 4266164594774171363, 6947485957721124704, 0, 2064, 9594118340025725004, 16218246678075491818, 11582919835122342747, 5661452934218108707, 3714647928422746674, 13689184893219719187, 1899963197709801965, 8313716591368695784, 17822645741084942000, 18354595702287703799, 12620512717427217848, 10145637708639089787, 1735222492513760332, 14681927838838900060, 9262747238997471758, 11498487923782501751, 8924101344488972446, 2592517964915386184, 4276681409258176044, 3764365715267793208, 3120204268813370353, 6019260256544801113, 2801984351776029768, 16979166255722313516, 2813750347113564525, 16588139065369475399, 12012198471360912693, 2492059183640657261, 16968938268466755316, 1679902783560062568, 1679902783560062568, 14885555914322696710, 11595861135030037790, 15790255405818319154, 1788244094476607025, 3713346340151405890, 10088532170345334842, 17854024334494248585, 12211195930325373909, 14810607828402585285, 6176927505545789216, 7340196426348852368, 4385801084072612889, 14434159451233581456, 16984288007453782663, 5968497068768213078, 13891165676869534375, 11051615708535243788, 18406940479749704351, 4657122466881791459, 11427117893432527856, 9342747858627858744, 4615623292891883658, 2986843800380659541, 3219777777177975421, 8998753509000282586, 14589941254121359798, 3914101860949270917, 12606215244329868526, 16670383938906392554, 9639583597360292920, 2591468219526413421, 0, 2064, 9594118340025725004, 16218246678075491818, 11582919835122342747, 5661452934218108707, 3714647928422746674, 13689184893219719187, 1899963197709801965, 8313716591368695784, 17822645741084942000, 18354595702287703799, 12620512717427217848, 10145637708639089787, 1735222492513760332, 14681927838838900060, 9262747238997471758, 11498487923782501751, 8924101344488972446, 2592517964915386184, 4276681409258176044, 3764365715267793208, 3120204268813370353, 6019260256544801113, 2801984351776029768, 16979166255722313516, 2813750347113564525, 16588139065369475399, 12012198471360912693, 2492059183640657261, 16968938268466755316, 1679902783560062568, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [8038422000946611307, 13055964544694368769, 7749914311668337250, 2490550827364591193, 4834428694324052171, 1237735850038716981, 8896240793576304991, 6582069168543167041, 3706649958322292721, 6839310826708053103, 12095513884410398346, 12922970210395916603, 12358523363220613934, 16454123186601925336, 4991814670781152799, 2040061269519504799, 17488717307568714132, 17317480533129930885, 2098096181527665460, 4697187904025813178, 1478747224857255407, 4468957360091397608, 17536692358706723977, 13559769323964866828, 10531481423547827694, 5398218750581689859, 8391144048742825188, 16471665752727725784, 3043860411079700945, 3316394317418127534, 7755478137750309004, 15345115023987982060, 0, 5160, 1190658701913535022, 9371121588404883743, 7133056533056999470, 7380100170229652082, 14719783382686670107, 4693530971176924881, 11125714198188567552, 2434816259070577714, 17927785478103501878, 834873962620943786, 1091858408197145201, 9293176204765248193, 11318806736621162148, 979530496520387452, 8328113718786640843, 15870139479256453021, 7754853849459016697, 2742936430580983415, 6806060556807781604, 5089080673677611112, 16430235900965466453, 309743103212430298, 15664803780047891222, 3113571524475220627, 17862871362988443440, 1231393200801541530, 15779352999894925288, 6026600320279882336, 6970552753544824994, 4949154992619464010, 0, 7045578468266939554, 7760605592330700907, 8360793687611805321, 738095676972904954, 15564477193367915463, 5876321119815014086, 17552573089477749612, 11411212736325006200, 13815587307529680030, 17156301712489415615, 17351081171119935003, 8966918709601352564, 3417326002908165374, 5362234606277969799, 6579629986598330856, 12247315276947966697, 18410067321498813805, 16182198715872613358, 11840483485843621799, 10053996112039279419, 8402815695409633837, 14225254012036856662, 269445170964238763, 7745973219325669511, 13587984894488746939, 8094627026199116369, 3994495212216710235, 9140718271797260749, 16931156974940547986, 14990750302990274425, 2224156252998910395, 0, 5160, 1190658701913535022, 9371121588404883743, 7133056533056999470, 7380100170229652082, 14719783382686670107, 4693530971176924881, 11125714198188567552, 2434816259070577714, 17927785478103501878, 834873962620943786, 1091858408197145201, 9293176204765248193, 11318806736621162148, 979530496520387452, 8328113718786640843, 15870139479256453021, 7754853849459016697, 2742936430580983415, 6806060556807781604, 5089080673677611112, 16430235900965466453, 309743103212430298, 15664803780047891222, 3113571524475220627, 17862871362988443440, 1231393200801541530, 15779352999894925288, 6026600320279882336, 6970552753544824994, 4949154992619464010, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [14346009158187546482, 2514419654263230233, 10868075426920088717, 14626639685450047092, 15824191413144451094, 3872785008711037698, 15159572856872914175, 13499848828490637487, 12504162360551599075, 6704874092885621909, 8482918267067478031, 11182299479692082524, 1644784474325024851, 10866220166037749110, 13011220300525187244, 5714286046111667701, 3271812982662883550, 4912758288798487759, 12958366352003970496, 11568317646859944473, 1188141313951948960, 12777681205968064182, 13771180111214880533, 3688955093092273987, 1949816493804567768, 12058362437595143266, 18379600813280833240, 11754259659339519197, 7370638446447886746, 2915034789487291427, 17553720084081617212, 15041334301981527295, 0, 4128, 1352424102745866255, 13301242752201603536, 5420135027930584396, 17078794493496835379, 4779811836607866048, 3650219859599657886, 13618468821889769363, 11429589192023659923, 8853101337885331080, 9650238821992519861, 14401087967309285252, 12035560952634921032, 15407186837043713393, 15711028160746246110, 5396976350889627712, 15903424027416555998, 11304777107657759509, 9857843669692965578, 12605480788735099613, 14618970056708743810, 8493993205782554647, 6059068631740368787, 18316971448227884023, 12499808993385025318, 4210674244211222629, 18405965507148502967, 173097048437312502, 15568437290332308327, 11532601739151124629, 10000279862191744493, 0, 14745280635380601617, 3718367898484243235, 9018263790739496394, 11183632545038441118, 11084602196898449287, 10533306301610546918, 1420887495241955081, 4459785951807836148, 12821108383646715262, 10486453955800644813, 1149237165662367781, 14820375481022552179, 16262631485420346362, 15566979183400849953, 16057390897683363413, 11254638356144199099, 15872210457308658069, 81952248385650954, 18028966990791016994, 6002088535876283975, 14457561209066214295, 12899353015952976468, 2384048206878222613, 11488447290357428274, 7532999527428712911, 63498412877849097, 17284768262212667433, 15648250834702978300, 8529394818161928928, 12738537911867917740, 15275140426936934232, 0, 4128, 1352424102745866255, 13301242752201603536, 5420135027930584396, 17078794493496835379, 4779811836607866048, 3650219859599657886, 13618468821889769363, 11429589192023659923, 8853101337885331080, 9650238821992519861, 14401087967309285252, 12035560952634921032, 15407186837043713393, 15711028160746246110, 5396976350889627712, 15903424027416555998, 11304777107657759509, 9857843669692965578, 12605480788735099613, 14618970056708743810, 8493993205782554647, 6059068631740368787, 18316971448227884023, 12499808993385025318, 4210674244211222629, 18405965507148502967, 173097048437312502, 15568437290332308327, 11532601739151124629, 10000279862191744493, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [2190566822905267077, 5404282949943047077, 5620556269036690141, 14491113445439742990, 3583407126333665201, 11553681770295205503, 1216093779061977398, 9009035935586042381, 10160118687758838044, 5189341129501661569, 552602416783565214, 13892332176168710533, 4210303372183975982, 9918111397467437847, 13191859809007430670, 12682554283327491677, 6159734265799796346, 3655472932705407889, 6138462302257325090, 9507551446430113809, 477055463074084789, 5562148904013569055, 16089614614433980121, 11132173538218883660, 2369773375363070297, 8734570802518415843, 13624820787911837119, 15026940072471861444, 10407697142160461181, 14258174989754257767, 11934701342627358954, 17583525004205959015, 0, 1032, 4798141223555508282, 12962488577647927717, 10133257770726709126, 332864556927106185, 12116126881643349994, 6604148216925166409, 101015634312276042, 15934992137290074922, 6112274855072540816, 17762248064501548615, 13166189948742588777, 270100349969833402, 13485211244653928073, 3502306881032295169, 13607663468974078519, 8883940618995723208, 10623667092532612652, 12293715092576816840, 10386976621364522928, 9128135834925108269, 15731443845270647366, 13373704167654916087, 13746187061551926812, 11684868053863796759, 3258729720361659960, 10434904637843727165, 7034851303745741351, 16133345873308301364, 5426492436527662130, 2980140658145787783, 0, 11085857321233345859, 6502498117283132750, 10381882708453841125, 13452669420839074331, 4680755747100261382, 2695613323752232712, 17146809849277743421, 9239864853466318604, 14768453813159795872, 18276894718067265811, 17257251339549225733, 5284904431001214307, 5764961239481152941, 10517783806308559735, 15410914971073808541, 3344855092587244940, 10472918269298152403, 12402503503713090948, 2754408248470837514, 15057664949131650205, 4187574032621547594, 5855521755089516239, 13990442832618678273, 14308234035637757543, 11933928216400818327, 15524863835262422966, 11531650814746237864, 7664866084994005813, 6402603575808426205, 15478402516028642985, 9020969347685648365, 0, 1032, 4798141223555508282, 12962488577647927717, 10133257770726709126, 332864556927106185, 12116126881643349994, 6604148216925166409, 101015634312276042, 15934992137290074922, 6112274855072540816, 17762248064501548615, 13166189948742588777, 270100349969833402, 13485211244653928073, 3502306881032295169, 13607663468974078519, 8883940618995723208, 10623667092532612652, 12293715092576816840, 10386976621364522928, 9128135834925108269, 15731443845270647366, 13373704167654916087, 13746187061551926812, 11684868053863796759, 3258729720361659960, 10434904637843727165, 7034851303745741351, 16133345873308301364, 5426492436527662130, 2980140658145787783, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [2591468219526413421, 8600073145915840029, 9972703476491052945, 7474968551123382164, 7181997692355145187, 15428345773987404117, 11743605500774065098, 11268864392770353056, 12211833414579612038, 15717209816757714363, 890156557088959300, 4859169418838628114, 17769229151585966679, 14412689958488784376, 3341988471057096642, 3129947071292798718, 17633680398960744148, 9040916820504033241, 5930774742161220001, 13876115104798876568, 6388325427377182963, 14330705119681412991, 15768069489925358116, 6157532873490141938, 2469680878449864864, 12328809527998355692, 16304509166225849524, 3168032149605842623, 935982989392333515, 1210836981232166821, 15698638297176561506, 17830733542807512157, 0, 1032, 11702782905971311743, 8115486282645452027, 16425371230714077552, 10333496212804492507, 1572943607289284437, 13244361396034453954, 12880029163967100393, 14716450796809578181, 2618965885956593171, 1606019581379521796, 12562170441304287563, 4599116799417823473, 4257071131168813417, 10446583017549019711, 3570388907037362614, 11170081717188072664, 17238997244398394333, 17231192964516960933, 8123337005847551087, 7060091366977384949, 5719725530909274667, 5057603743378325948, 13848013489728729143, 17729739340387068117, 367186060507240673, 1411195984452924204, 11088333491201093194, 16575090776691519559, 16147396598096989679, 14525300817521856881, 0, 7442777957161348409, 12950881678740459660, 6646706469455563416, 5900873935105415470, 17072140113884084441, 13172589932512713520, 5522401646053069342, 3133914205806983551, 13779823240426764791, 17224433130794138533, 14489298897463599319, 1940759318652413905, 7694480472126993559, 17366018125192157291, 16887976527497663730, 1916565854454348991, 2294268388330909452, 8983416234083684410, 11974102734257880906, 11534526793163396841, 10005306190103088231, 12997092893241557181, 2268817966601289631, 8051413784985211055, 5191686653404052624, 18373940558834700052, 4703711900874228713, 2364324903714729084, 11224300914395639224, 6723817418214557043, 2429828201690573781, 0, 1032, 11702782905971311743, 8115486282645452027, 16425371230714077552, 10333496212804492507, 1572943607289284437, 13244361396034453954, 12880029163967100393, 14716450796809578181, 2618965885956593171, 1606019581379521796, 12562170441304287563, 4599116799417823473, 4257071131168813417, 10446583017549019711, 3570388907037362614, 11170081717188072664, 17238997244398394333, 17231192964516960933, 8123337005847551087, 7060091366977384949, 5719725530909274667, 5057603743378325948, 13848013489728729143, 17729739340387068117, 367186060507240673, 1411195984452924204, 11088333491201093194, 16575090776691519559, 16147396598096989679, 14525300817521856881, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 10050771506480654697, 13420837528738763520, 8496521368864059734, 2484674105691110618, 14534130756197581682, 5302125583480436763, 17447925507451726835, 6158355997654729039, 2747272733640735637, 16008460117209203149, 7966664559987380274, 12228289745234304260, 5769015309045246106, 10117630725268935850, 1928165892714903315, 13757138220331554723, 3415891051222089939, 9614135373790971720, 15460760939838461118, 3083939397091390513, 5208743639505571028, 10512816629673800187, 1038453745979635965, 11152507394095411482, 16277833565401448399, 1857640599304385129, 15507736315414043252, 10006390466474490543, 14803299263866517418, 15066726409373257878, 5538305542985598681, 0, 5160, 18346837778669738664, 15130142357101091527, 6726588340010678615, 8394319278312203283, 15942424551308612685, 7629500615465222065, 14939877513325106589, 17048523965011794048, 2306293645521445312, 823113708878672797, 14981348226783328932, 7432878333905782051, 3482639998457803800, 632277917380007036, 18266437030920184246, 3366715262389109205, 5280275432441977334, 5379329043314533811, 13912213856326486056, 17217059915921675075, 15634373017412823086, 14981257187297131103, 16697350900700022325, 5239234081629986555, 3229291246709926782, 18373224696258292584, 6771862800272250893, 7666370275789511263, 12942227631865082960, 15190222347874856922, 0, 7045578468266940310, 11422404183367723688, 4734813192583045175, 16795465921267519808, 12362009349652409415, 3020519614827991855, 2942658800463567237, 18428726703177922018, 10231394582054281621, 8503976903131851970, 11539035678955040518, 6287740157380564628, 3273842793073629785, 15356197472622263350, 8793463497412363872, 15129820397597713369, 2881507314714938985, 10712615481926377093, 9279961334386063516, 4068525996563916658, 13774208723083831405, 17700397171958035166, 18249110448117027038, 8906205380227326203, 4362400237726204205, 16281776889210602562, 4962687005987029339, 5046527547997136739, 15389940485215503504, 8078314735919109828, 5959378659908477764, 0, 5160, 18346837778669738664, 15130142357101091527, 6726588340010678615, 8394319278312203283, 15942424551308612685, 7629500615465222065, 14939877513325106589, 17048523965011794048, 2306293645521445312, 823113708878672797, 14981348226783328932, 7432878333905782051, 3482639998457803800, 632277917380007036, 18266437030920184246, 3366715262389109205, 5280275432441977334, 5379329043314533811, 13912213856326486056, 17217059915921675075, 15634373017412823086, 14981257187297131103, 16697350900700022325, 5239234081629986555, 3229291246709926782, 18373224696258292584, 6771862800272250893, 7666370275789511263, 12942227631865082960, 15190222347874856922, 2147483648, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [87, 8629850144821916384, 4475574334214635511, 15844375305567102825, 10178368558488980289, 366424541133389116, 14318718192085040201, 11141735015346329315, 14736248158977353058, 6659594400091594161, 9354501143254856958, 1788553586845505120, 13567541605223635136, 18116490434673131256, 3267515885574430559, 4026772730948844076, 2031101258349406169, 1067905233090125355, 3177657145644554672, 3126867087711378899, 2351734901108666112, 7401562071196444455, 11029998200473456200, 12823977733512090066, 9220325101017945081, 9541188526080901705, 9807406399356825925, 11614758863876097772, 7718195260684522704, 12447607757449687684, 2284861843754100216, 16982814561187843115, 0, 4128, 6496253015800789210, 18063315295058131399, 14099326864720264780, 16744359797696928029, 11669954633423859445, 10923938539628559259, 10579480970462933513, 17315553376669597828, 12114095292572219189, 16129781670858537825, 67936491912723144, 6285840300661422802, 14359460599290704174, 7597471307904508314, 8469569990667894210, 9117246600999250277, 14614928058075190380, 13738364908865630160, 1806905237893315697, 261412144627674040, 8380596589382515797, 3809925330596605534, 1983199361335541287, 6337901890572878101, 17063257729896061936, 12690697575318882146, 3846044480011221270, 10729939698274680623, 5297971463863936522, 8671284646676347574, 108, 14745280635380602265, 1030231790864474253, 8493304069558799424, 3813500112725093016, 1584024639278012914, 6691630066548896421, 12744785931761802081, 8312414042457270416, 15913285332885706950, 11904695260466451537, 4503780104272324718, 3020894344784966101, 8121142696445856470, 7323566571197968291, 15900985531249599446, 7156364108131320107, 15910943131140158025, 14526518136578598747, 6720684608059903461, 17378127155945101975, 8120421969064271148, 12903874735177520891, 4533560749542240026, 13603960728052470511, 5595478722910465584, 1530061232442071378, 8451873054224800759, 7908366039873426748, 17285432733773675712, 7133857220640768475, 4076807723615210075, 0, 4128, 6496253015800789210, 18063315295058131399, 14099326864720264780, 16744359797696928029, 11669954633423859445, 10923938539628559259, 10579480970462933513, 17315553376669597828, 12114095292572219189, 16129781670858537825, 67936491912723144, 6285840300661422802, 14359460599290704174, 7597471307904508314, 8469569990667894210, 9117246600999250277, 14614928058075190380, 13738364908865630160, 1806905237893315697, 261412144627674040, 8380596589382515797, 3809925330596605534, 1983199361335541287, 6337901890572878101, 17063257729896061936, 12690697575318882146, 3846044480011221270, 10729939698274680623, 5297971463863936522, 8671284646676347574, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 17468442170295488858, 9773381208787513234, 2185606873808106597, 5326701750299677540, 18331867594591263096, 548097224697282340, 10547562414019002308, 13272144351666153699, 15855067207807736351, 4370081121859711944, 2612761535881667398, 16433499902516242349, 5490313979471750512, 12242667433588409287, 13667932040054721093, 11397361705799260268, 13352179165506178583, 18130276598071715349, 5367905172204163759, 13899921222016942193, 16739429834098497391, 9456664549854782490, 18285262020229949627, 11267975946641671449, 4164320394230196430, 17698213099167806270, 5464680925773178239, 16672746771430202203, 17570877581179860050, 2661602147392096981, 17592358249594079251, 0, 1032, 13084260837127404333, 4018109146681745349, 14498381569327145056, 3778421823029569719, 1344624249217908323, 3634653398484528177, 1428985706412758663, 11382569756632997337, 13894906302086601399, 3911680161282028629, 11467762927868003365, 10098326072301516020, 16073214466625742345, 16150512194511843089, 11525294274796193451, 15902507139806774023, 13926886722650908730, 2974304378722638293, 5274544965980948277, 9984170014312577610, 639485734140932316, 15088403650698955530, 17189134684458608982, 6515320870350778492, 7902492290152572474, 17310456195349246143, 4070136787975548901, 6345872167795009033, 3095930865537762353, 4232664728858134772, 0, 11085857321233346183, 17340772818369048990, 4710612857210121909, 6383904020814938565, 2185295286363661452, 57911040231161987, 16587511410977976694, 2708167856204711091, 10934568936892706192, 16945176268586506094, 6648082856126081802, 13508616389857401321, 2042841450297716791, 14424400955124662023, 4566271445414618189, 6323391233814555017, 5903620650725668621, 10799633056255259898, 7254762119029478931, 8510983625183148698, 11995653210052429396, 8580571627687871547, 6611487504966808602, 4153539838331475868, 485956658090184855, 13092360131462553695, 16519639797422070758, 15931672450436655146, 1240279786436372570, 14570949492747980696, 1405895934075613917, 0, 1032, 13084260837127404333, 4018109146681745349, 14498381569327145056, 3778421823029569719, 1344624249217908323, 3634653398484528177, 1428985706412758663, 11382569756632997337, 13894906302086601399, 3911680161282028629, 11467762927868003365, 10098326072301516020, 16073214466625742345, 16150512194511843089, 11525294274796193451, 15902507139806774023, 13926886722650908730, 2974304378722638293, 5274544965980948277, 9984170014312577610, 639485734140932316, 15088403650698955530, 17189134684458608982, 6515320870350778492, 7902492290152572474, 17310456195349246143, 4070136787975548901, 6345872167795009033, 3095930865537762353, 4232664728858134772, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 17244797586245886456, 15751718828876603764, 11509908635527699125, 11475332140491226913, 17384989371947212455, 334761494745252139, 7616687658781298414, 14780080241553087954, 12346184924771259853, 16185631853241338171, 895339354972846288, 4068422042358699181, 17829363972116539489, 16616980036078363960, 11802237368737486290, 5517794271194351375, 1340602429246747412, 6137287375961878929, 9089335960846268476, 10715486062907500431, 9038952715608883929, 3376751855710232954, 9293572206177681748, 5274360121930626670, 10385953241879043200, 15812468027446779083, 17985531203042807174, 4527163876177139455, 1244842376420464745, 7071163393872573565, 10505779527452689750, 0, 1032, 15909096041365347974, 18432189660917429733, 2798890989547891271, 10768372030970716894, 5935807051329113911, 1259182408195029650, 16024750973514577255, 6103595041913569283, 914770550723164908, 5067028895751058275, 5242612139537538536, 13359135899043031769, 4430959127423856282, 16317056360529517539, 2634255659160911215, 15590656855559575839, 6832335878067392309, 6045109056629836176, 18146646330136390606, 6482705684632040588, 2770791364887326735, 7707774010999656594, 3401430074469265273, 3500862351024377705, 5135727797169111985, 14940852959892477883, 9633218853985087472, 16966092255533854383, 3065488485208441055, 15703076512693482766, 0, 7442777957161348517, 15511565770182079598, 17588127306488605836, 12156963648059548539, 9855001437726729603, 750212215289098948, 3057342424889339513, 12076679785316333126, 4754090667046207383, 5287048869294162247, 13665676832765504604, 7892998254318929425, 10986386945260945625, 650038937356756422, 1562289959612081521, 18390988039078367877, 10259188468824740395, 8732714546322097295, 7010052931953742806, 17653496644410780843, 12884831098778763497, 17079843757158488506, 5971369750353050420, 3223792838828500232, 6029903770259711111, 16004411386897649153, 5901432683519548685, 18030233803416436591, 18259374036374690916, 15125936605156360851, 1558963802307733462, 0, 1032, 15909096041365347974, 18432189660917429733, 2798890989547891271, 10768372030970716894, 5935807051329113911, 1259182408195029650, 16024750973514577255, 6103595041913569283, 914770550723164908, 5067028895751058275, 5242612139537538536, 13359135899043031769, 4430959127423856282, 16317056360529517539, 2634255659160911215, 15590656855559575839, 6832335878067392309, 6045109056629836176, 18146646330136390606, 6482705684632040588, 2770791364887326735, 7707774010999656594, 3401430074469265273, 3500862351024377705, 5135727797169111985, 14940852959892477883, 9633218853985087472, 16966092255533854383, 3065488485208441055, 15703076512693482766, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] }, last_program_row: RowIndex(12) }, program_info: ProgramInfo { program_hash: Word([385638883771950111, 14533042520471865290, 12416920551073560045, 6947485957721124704]), kernel: Kernel([]) }, stack_outputs: StackOutputs { elements: [1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, merkle_store_nodes: {Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571]): (Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350]), Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350])), Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484]): (Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693]), Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693])), Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781]): (Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874]), Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874])), Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171]): (Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361]), Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361])), Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815]): (Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305]), Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305])), Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689]): (Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195]), Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195])), Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362]): (Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063]), Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063])), Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848]): (Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661]), Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661])), Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352]): (Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829]), Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829])), Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444]): (Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223]), Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223])), Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386]): (Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388]), Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388])), Word([13190842942618341421, 17548956981569849952, 15418963848144418856, 730733050713174879]): (Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144]), Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144])), Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874]): (Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675]), Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675])), Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594]): (Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115]), Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115])), Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809]): (Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257]), Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257])), Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777]): (Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555]), Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555])), Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509]): (Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882]), Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882])), Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725]): (Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979]), Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979])), Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134]): (Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987]), Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987])), Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828]): (Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910]), Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910])), Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830]): (Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054]), Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054])), Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228]): (Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742]), Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742])), Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443]): (Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928]), Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928])), Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643]): (Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979]), Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979])), Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758]): (Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106]), Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106])), Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580]): (Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594]), Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594])), Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765]): (Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045]), Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045])), Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766]): (Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281]), Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281])), Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385]): (Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828]), Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828])), Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579]): (Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171]), Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171])), Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212]): (Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992]), Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992])), Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463]): (Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004]), Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004])), Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502]): (Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023]), Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023])), Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539]): (Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537]), Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537])), Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865]): (Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225]), Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225])), Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690]): (Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947]), Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947])), Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202]): (Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552]), Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552])), Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079]): (Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444]), Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444])), Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850]): (Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548]), Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548])), Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448]): (Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987]), Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987])), Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041]): (Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035]), Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035])), Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301]): (Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414]), Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414])), Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414]): (Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212]), Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212])), Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703]): (Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439]), Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439])), Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271]): (Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955]), Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955])), Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882]): (Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802]), Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802])), Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152]): (Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887]), Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887])), Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028]): (Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948]), Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948])), Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331]): (Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093]), Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093])), Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394]): (Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134]), Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134])), Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546]): (Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228]), Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228])), Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620]): (Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414]), Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414])), Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800]): (Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703]), Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703])), Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671]): (Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205]), Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205])), Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537]): (Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011]), Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011])), Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516]): (Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301]), Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301])), Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831]): (Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986]), Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986])), Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415]): (Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057]), Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057])), Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722]): (Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689]), Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689])), Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144]): (Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682]), Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682])), Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295]): (Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268]), Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268])), Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818]): (Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513]), Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513])), Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241]): (Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565]), Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565])), Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439]): (Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012]), Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012])), Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512]): (Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850]), Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850])), Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986]): (Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865]), Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865])), Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982]): (Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777]), Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777])), Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808]): (Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394]), Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394])), Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979]): (Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690]), Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690])), Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093]): (Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620]), Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620])), Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902]): (Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789]), Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789])), Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542]): (Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094]), Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094])), Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057]): (Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362]), Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362])), Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205]): (Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961]), Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961])), Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401]): (Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580]), Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580])), Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553]): (Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960]), Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960])), Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169]): (Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031]), Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031])), Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682]): (Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053]), Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053])), Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118]): (Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562]), Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562])), Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725]): (Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666]), Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666])), Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661]): (Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897]), Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897])), Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981]): (Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447]), Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447])), Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072]): (Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646]), Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646])), Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140]): (Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404]), Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404])), Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515]): (Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152]), Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152])), Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709]): (Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664]), Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664])), Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800]): (Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103]), Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103])), Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741]): (Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169]), Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169])), Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005]): (Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758]), Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758])), Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802]): (Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070]), Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070])), Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159]): (Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005]), Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005])), Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350]): (Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443]), Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443])), Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697]): (Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573]), Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573])), Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928]): (Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331]), Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331])), Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320]): (Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166]), Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166])), Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814]): (Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079]), Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079])), Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447]): (Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820]), Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820])), Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284]): (Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057]), Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057])), Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697]): (Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131]), Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131])), Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955]): (Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290]), Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290])), Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910]): (Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202]), Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202])), Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910]): (Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822]), Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822])), Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106]): (Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847]), Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847])), Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404]): (Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441]), Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441])), Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796]): (Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186]), Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186])), Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053]): (Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516]), Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516])), Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992]): (Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818]), Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818])), Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957]): (Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315]), Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315])), Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709]): (Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794]), Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794])), Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091]): (Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539]), Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539])), Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664]): (Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558]), Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558])), Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294]): (Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579]), Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579])), Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947]): (Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502]), Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502])), Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829]): (Word([0, 0, 0, 0]), Word([0, 0, 0, 0])), Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045]): (Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137]), Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137])), Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914]): (Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041]), Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041])), Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573]): (Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378]), Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378])), Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699]): (Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873]), Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873])), Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225]): (Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262]), Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262])), Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057]): (Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692]), Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692])), Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131]): (Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997]), Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997])), Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555]): (Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385]), Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385])), Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195]): (Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709]), Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709])), Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166]): (Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542]), Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542])), Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027]): (Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373]), Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373])), Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378]): (Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509]), Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509])), Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097]): (Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553]), Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553])), Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217]): (Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815]), Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815])), Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873]): (Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864]), Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864])), Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997]): (Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722]), Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722])), Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887]): (Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766]), Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766])), Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589]): (Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757]), Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757])), Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539]): (Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665]), Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665])), Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129]): (Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229]), Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229])), Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137]): (Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312]), Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312])), Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019]): (Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378]), Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378])), Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331]): (Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713]), Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713])), Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]): (Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980]), Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980])), Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325]): (Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546]), Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546])), Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170]): (Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822]), Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822])), Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054]): (Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295]), Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295])), Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925]): (Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848]), Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848])), Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909]): (Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796]), Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796])), Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540]): (Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170]), Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170])), Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214]): (Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448]), Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448])), Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317]): (Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294]), Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294])), Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757]): (Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416]), Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416])), Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378]): (Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091]), Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091])), Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263]): (Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463]), Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463])), Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666]): (Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361]), Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361])), Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174]): (Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992]), Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992])), Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470]): (Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401]), Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401])), Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665]): (Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957]), Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957])), Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262]): (Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144]), Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144])), Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229]): (Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284]), Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284])), Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134]): (Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325]), Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325])), Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855]): (Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765]), Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765])), Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115]): (Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814]), Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814])), Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441]): (Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831]), Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831])), Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977]): (Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446]), Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446])), Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880]): (Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005]), Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005])), Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789]): (Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995]), Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995])), Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000]): (Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267]), Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267])), Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998]): (Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982]), Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982])), Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995]): (Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539]), Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539])), Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507]): (Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512]), Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512])), Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305]): (Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118]), Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118])), Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219]): (Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009]), Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009])), Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416]): (Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089]), Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089])), Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980]): (Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445]), Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445])), Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063]): (Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140]), Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140])), Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713]): (Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159]), Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159])), Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031]): (Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809]), Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809])), Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932]): (Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037]), Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037])), Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094]): (Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925]), Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925])), Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315]): (Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386]), Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386])), Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446]): (Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721]), Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721])), Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742]): (Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981]), Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981])), Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661]): (Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072]), Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072])), Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979]): (Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671]), Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671])), Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361]): (Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269]), Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269])), Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558]): (Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571]), Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571])), Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290]): (Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902]), Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902])), Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987]): (Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741]), Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741])), Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902]): (Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515]), Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515])), Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497]): (Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028]), Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028])), Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948]): (Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709]), Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709])), Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009]): (Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725]), Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725])), Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387]): (Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317]), Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317])), Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159]): (Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808]), Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808])), Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394]): (Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699]), Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699])), Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312]): (Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000]), Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000])), Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987]): (Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821]), Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821])), Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046]): (Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909]), Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909])), Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565]): (Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028]), Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028])), Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269]): (Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352]), Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352])), Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847]): (Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271]), Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271])), Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513]): (Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800]), Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800])), Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054]): (Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394]), Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394])), Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004]): (Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977]), Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977])), Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675]): (Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800]), Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800])), Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692]): (Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159]), Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159])), Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909]): (Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932]), Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932])), Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814]): (Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697]), Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697])), Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186]): (Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387]), Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387])), Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445]): (Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470]), Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470])), Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966]): (Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507]), Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507])), Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548]): (Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253]), Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253])), Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897]): (Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783]), Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783])), Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208]): (Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054]), Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054])), Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268]): (Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661]), Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661])), Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388]): (Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643]), Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643])), Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257]): (Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174]), Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174])), Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960]): (Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241]), Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241])), Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721]): (Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046]), Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046])), Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822]): (Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217]), Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217])), Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253]): (Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697]), Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697])), Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054]): (Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019]), Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019])), Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821]): (Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432]), Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432])), Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864]): (Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105]), Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105])), Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373]): (Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855]), Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855])), Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646]): (Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830]), Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830])), Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460]): (Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208]), Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208])), Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033]): (Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214]), Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214])), Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105]): (Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129]), Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129])), Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281]): (Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909]), Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909])), Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028]): (Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027]), Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027])), Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012]): (Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054]), Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054])), Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562]): (Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589]), Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589])), Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037]): (Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097]), Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097])), Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355]): (Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460]), Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460])), Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223]): (Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355]), Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355])), Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089]): (Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306]), Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306])), Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035]): (Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219]), Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219])), Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432]): (Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297]), Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297])), Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693]): (Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263]), Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263])), Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794]): (Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484]), Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484])), Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552]): (Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941]), Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941])), Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267]): (Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814]), Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814])), Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992]): (Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415]), Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415])), Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941]): (Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966]), Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966])), Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822]): (Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320]), Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320])), Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306]): (Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902]), Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902])), Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820]): (Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880]), Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880])), Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361]): (Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725]), Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725])), Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005]): (Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914]), Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914])), Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783]): (Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781]), Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781])), Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011]): (Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033]), Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033])), Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297]): (Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910]), Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910])), Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070]): (Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134]), Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134])), Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144]): (Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331]), Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331])), Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023]): (Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497]), Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497])), Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103]): (Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540]), Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540])), Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961]): (Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998]), Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998])), Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414]): (Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]), Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]))}, trace_len_summary: TraceLenSummary { main_trace_len: 13, range_trace_len: 41, chiplets_trace_len: ChipletsLengths { hash_chiplet_len: 128, bitwise_chiplet_len: 0, memory_chiplet_len: 1, kernel_rom_len: 0 } } } +ExecutionTrace { main_trace: MainTrace { storage: Parts { core_rm: [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 9795023497998985336, 13300695072875785024, 10130173733677792318, 11939015773035265411, 0, 0, 0, 0, 0, 0, 1, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1032, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 2, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 8, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 3, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 4, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 1, 1, 1, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 5, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 6, 6, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 5, 0, 1, 1, 0, 1, 0, 1, 1032, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 7, 6, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 7, 0, 0, 0, 1, 0, 0, 0, 8, 5, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 8, 6, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 7, 0, 0, 0, 1, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 9, 6, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 7, 0, 0, 0, 0, 1, 1, 1, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 10, 6, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 5, 0, 0, 0, 0, 1, 1, 1, 9795023497998985336, 13300695072875785024, 10130173733677792318, 11939015773035265411, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 11, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 31, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 33, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 39, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 43, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 47, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 50, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 51, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 53, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 54, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 55, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 59, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 60, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 61, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 67, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 69, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 70, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 71, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 72, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 73, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 74, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 75, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 76, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 77, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 78, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 79, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 81, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 82, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 83, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 86, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 87, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 88, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 89, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 90, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 91, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 92, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 93, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 94, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 97, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 98, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 99, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 101, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 102, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 103, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 104, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 105, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 106, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 107, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 108, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 109, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 110, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 111, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 112, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 113, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 114, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 115, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 116, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 117, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 118, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 119, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 120, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 121, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 122, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 123, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 124, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 125, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 126, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 127, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0], chiplets_rm: [1, 1, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 9795023497998985336, 13300695072875785024, 10130173733677792318, 11939015773035265411, 0, 87, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 13813148053191742203, 9801149536421508036, 8323744943735804454, 9781218902110540179, 5842910582527751306, 6515775080041612554, 2207036983008389704, 7138588223420389995, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1032, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 11116382020814057190, 14732796941305378371, 13074361791711182490, 6715193688317415490, 1571558009365433839, 13285275197432594374, 15905141483335727027, 2507840277166973476, 0, 0, 1, 0, 0, 1, 1, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 0, 0, 0, 0, 0, 108, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 9795023497998985336, 13300695072875785024, 10130173733677792318, 11939015773035265411, 12109893904215917933, 11216622576129138242, 2033568431633301211, 6175855265335479925, 2993234814900659250, 17541474196881156701, 6380009076578808155, 7007738773696586556, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1032, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 11116382020814057190, 14732796941305378371, 13074361791711182490, 6715193688317415490, 1571558009365433839, 13285275197432594374, 15905141483335727027, 2507840277166973476, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1032, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 0, 15913981378790993016, 12701179462806902902, 9645342555817022514, 6889850077248808033, 678249829196625442, 8726676798253716750, 14136118088409135949, 1027279235140821190, 8048729929177993405, 2542525775606472849, 3283471062508934848, 18058280687405074483, 2, 0, 0, 0, 1, 0, 0, 0, 0, 11899090779839289087, 1701090513954162998, 6953639183117323837, 11460660778637092812, 8345945186928076892, 11308243255833047975, 5734666540714547293, 1546649737555419076, 14643837757854608147, 7477230882792828789, 2359592855656894189, 12732146754685591216, 2, 0, 0, 0, 1, 0, 0, 0, 0, 16283412161296764998, 17261112905912533997, 1498213616014501531, 7707889409925905689, 16090493533591377617, 525010687572874692, 5228788497345464933, 13051466527897639054, 3560924095387897187, 12551242480725370445, 4038828260160651477, 6132317990703151787, 2, 0, 0, 0, 1, 0, 14261694278902826987, 16097544111075686229, 16632169854204459773, 14265791174051766329, 14732671264513481238, 15642599276989292777, 7593738854072541043, 11440582168151819564, 18258483622390056257, 6851601084855956341, 10463349537167637967, 10032876585525342603, 825669147467031185, 16271217766495541082, 9021089524754424392, 2, 0, 0, 0, 1, 0, 16780109665356203593, 16025948514351396737, 4256182047405196535, 4919013996388780384, 6974015548720770018, 10189882052640604940, 12288632186238773648, 7055558833039165669, 9820743264545515107, 7353106531603230851, 5612808106478211181, 362487531847990854, 10259224130335842891, 2374318293393776907, 16208179153232019183, 2, 0, 0, 0, 1, 0, 9496969110446094198, 10424961628901078909, 7587726188775237019, 13423955604028434301, 12288543613568774022, 4068762405627465026, 7288480650179820504, 1035430088689333582, 2651098721515326755, 4524440782000877024, 3013038852551457145, 12536534023666437466, 6560028330562582937, 9090521726813489969, 17634755409309861791, 2, 0, 0, 0, 1, 0, 15761194215082968049, 15796684185970405493, 1294179585337070936, 5701860167148115542, 17707247215386403887, 18419960639673587986, 14570347312565937582, 8634142387233894354, 11938075017385927203, 8060480374868324599, 16699922976999064541, 14234489074154948378, 17210389744085299852, 17331527780947314617, 16356838976302290254, 2, 0, 0, 0, 1, 0, 6184336662619539433, 7106147576739595100, 18237994300618329820, 9768155666925548219, 226714884885574576, 11169479382209254075, 5756676929838789145, 29803495366482069, 13128905441940840949, 18304516631519674746, 3177693875357946498, 10624850715031233718, 16956738608020324589, 10558540052020438814, 7826502712354673600, 2, 0, 0, 0, 1, 0, 1980308537464408089, 6810023246846442283, 9400257804338494201, 11246932855318952856, 7504545710540897051, 5823677062954428984, 9151299935574592196, 15905322272715446259, 18174748553199601666, 9877077233183640995, 2431998410719122545, 3541292002384422941, 5416588529930333172, 15788517205879313917, 2490575598934209003, 2, 0, 0, 0, 1, 0, 17950140321155419078, 9014768943295123367, 10707122777228105884, 10701204914974985643, 15060806908759160804, 7011191650405807117, 13598159658926423040, 3947314552577424057, 12985682730462769834, 18264715466581442035, 7667189540353817157, 7685483800933651249, 16085167604591833455, 16105855167414075111, 16215395602017884846, 2, 0, 0, 0, 1, 0, 8676227747932036802, 0, 0, 11504729673400082663, 3659553513673892306, 10374352082945691939, 15819529278889203623, 18107940902385670152, 8889798095480337831, 12737345777792032790, 456604824069734238, 2859376131275373721, 8758251935142908528, 2364536875264708997, 2435873391009301907, 2, 0, 0, 0, 1, 0, 0, 0, 0, 16797630026773069829, 16954579754978210547, 4393671449525183699, 6245909065255485436, 8311309349844601638, 3305827896314343556, 1615477551160071258, 3897903986825909618, 13015230208471866351, 13839070994009764281, 2415598337053791919, 5526300544248852335, 2, 0, 0, 0, 1, 0, 0, 0, 0, 12827873667465929582, 15892701250663610383, 549489834728826775, 9425334953627649153, 15402634395731091512, 11814416271399500934, 14597718118926923662, 4726679541432826422, 342915941842538663, 11221492717904369823, 17188959961041335276, 13559932473868727168, 2, 0, 0, 0, 1, 0, 0, 0, 0, 8689096602925893779, 4096531352684607500, 8424481237826564505, 15238165026175259240, 10985176737527635898, 2672540837788784952, 6649439643634522762, 7581835251244605715, 17671970641549389116, 18069913154458602790, 749417941228438762, 6150863900366154379, 2, 0, 0, 0, 1, 0, 0, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 11116382020814057190, 14732796941305378371, 13074361791711182490, 6715193688317415490, 1571558009365433839, 13285275197432594374, 15905141483335727027, 2507840277166973476, 2, 0, 0, 0, 1, 0, 0, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 0, 0, 0, 0, 0, 108, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 12512288845269211131, 853499250082959838, 13488661663129764539, 8125050245190817108, 3804813068188359937, 3313483727945122453, 12360781197875022983, 12306355678569585549, 14131911740731702820, 4051317191743228419, 18012527566990830204, 10255515555502453711, 1, 0, 0, 0, 1, 0, 0, 0, 0, 13268666745610888359, 5035299923140309359, 9492710178938090874, 16432193728393177858, 488197519654209705, 16306861889432269511, 12965290967174006273, 5899276799385944982, 4732569325232601941, 17250390449616619232, 2263709671564173949, 16014366373996617459, 1, 0, 0, 0, 1, 0, 0, 0, 0, 6251349156658906743, 8609811827979294882, 16396123621276698425, 4191392625375252196, 13118130563168054808, 10137725945150597993, 17091661325003867912, 15987533992994607704, 16422379462831291528, 12094114857378650954, 1084226545221903173, 6915613376340340043, 1, 0, 0, 0, 1, 0, 1534645424544051783, 4642164202005224189, 13639350595321647774, 14997123658379691665, 5095591508188209815, 17378968424157853898, 3319587194701345303, 7912013546961175954, 13058442299138466556, 113820789366504723, 979480813836484063, 12810935507899622334, 10071317704529062824, 17157647224138114155, 86309787246248239, 1, 0, 0, 0, 1, 0, 2913198445711677774, 9888361099408058975, 6942011412713736468, 6203537965825290504, 14477641448356369216, 8203223455911494092, 6384931917509725098, 10942323986007690541, 2372505191155982696, 13505926961374950297, 9863815224566244166, 12000427914776781281, 9676867145055745792, 16197034225912806058, 14661960577890819530, 1, 0, 0, 0, 1, 0, 15190546416264078116, 7775818643073018412, 9071871860943081771, 1416093219274823693, 5963314482819748512, 17442313688172807287, 1561163009835858446, 7267981992016523791, 13647940476497044011, 3432681625158272448, 1993371153287576489, 14086944830164184302, 17901613865752995639, 9876439357546613309, 1905959172944565459, 1, 0, 0, 0, 1, 0, 16787762740302082173, 13687172702509280801, 13829601699493328726, 13077396723920915658, 6334600257668993247, 16005831570146470727, 6870535038357161642, 3318715655314199213, 1604329190047159158, 13627534697145261227, 9687118959345407025, 1168709924583816553, 13777237771639017487, 6657527270060440390, 2805827836820765534, 1, 0, 0, 0, 1, 0, 3605868392435965294, 253522748327669049, 11011264558059064878, 6160836649233708903, 12171046083408363106, 8043060876658338795, 9860685140977757959, 4159667182749534960, 9273137746535878130, 16329758115433750926, 6949713863289936704, 14729752357791305157, 13443252680326955644, 8704483663624610247, 13845644156795384523, 1, 0, 0, 0, 1, 0, 1381807822628776459, 6185989713666623112, 6906262917832007676, 12034839856630957225, 1124098930189483722, 10617691351745831328, 17046424117532723784, 18328837382080531957, 499124217804614118, 7054779445715304974, 14721592817235079691, 15438177461805878082, 4893763607985641131, 14735613271204743175, 11055989889840127175, 1, 0, 0, 0, 1, 0, 12865381359176879968, 2554523313877966954, 7294679159466444323, 4506042742239578122, 6099115752699339215, 15220891401986890192, 12223236740078007539, 12409048149390343723, 16157310078954948179, 5713143862578741194, 12176609611331176615, 1208131014354067353, 8416999318707249338, 4632186832415650928, 4787230416960148769, 1, 0, 0, 0, 1, 0, 8430676800162925096, 0, 0, 8496072762751336805, 16886443911130558975, 12033532278877703853, 15851236173354166236, 15013693898292177964, 8135782089737993532, 1771838547975961981, 4211538783056899457, 1087116229540095042, 13570948918462148235, 13789448633689060947, 15910710132207983081, 1, 0, 0, 0, 1, 0, 0, 0, 0, 7928740039385897882, 10727806439135124602, 7646638143768945898, 14819732602933823085, 9587178260979641455, 14797965785210665193, 16685257700649146157, 1815375165055766101, 9227997262307743106, 10732992718179136350, 10791645390406102219, 3748207455775523223, 1, 0, 0, 0, 1, 0, 0, 0, 0, 15502106930635125896, 14713985548484747994, 10270851360514545566, 7322520777221196131, 13829203811429967568, 3578695923684700475, 15476694481212406519, 17447568335080248836, 16980404531860824247, 16570689533324192389, 8333013671770279648, 8383746024118130204, 1, 0, 0, 0, 1, 0, 0, 0, 0, 17958915377109677965, 15689157688771292017, 1337195173853601995, 12055027230426124267, 11003189687841806082, 10219528601216730754, 5064732806791575544, 16072502552074795611, 7851615748612726715, 15271023857443749252, 13107834510030116795, 17189900208955315576, 1, 0, 0, 0, 1, 0, 0, 0, 0, 9795023497998985336, 13300695072875785024, 10130173733677792318, 11939015773035265411, 12109893904215917933, 11216622576129138242, 2033568431633301211, 6175855265335479925, 2993234814900659250, 17541474196881156701, 6380009076578808155, 7007738773696586556, 1, 0, 0, 0, 1, 0, 0, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 9795023497998985336, 13300695072875785024, 10130173733677792318, 11939015773035265411, 0, 87, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 647798198322186763, 6592792203074652875, 17476824078129141338, 17767912865459160960, 12302196565172406159, 7133118425001032114, 13036064078204647105, 12154160758539910974, 12910600937056884084, 6562813264032936877, 17375732645941164592, 10668415322419739982, 1, 0, 0, 0, 1, 0, 0, 0, 0, 17688107483147659424, 3826470524415365168, 15397518990548874541, 7384515665769464908, 11530227496484511911, 10894583914980996271, 11471481017983097595, 647782521607901735, 6043493769912162117, 15718422881208362819, 16775781916941621047, 3126686215251231764, 1, 0, 0, 0, 1, 0, 0, 0, 0, 17869525775473816866, 13995241216315274115, 14157490272424291288, 12595361644534565853, 12216357805740360097, 1694591003072000395, 3743605083914104716, 7861948909415027744, 13777320358159433695, 10689965220940509198, 4900308999419319661, 11865597697730630365, 1, 0, 0, 0, 1, 0, 10853190877700104359, 6532325916675391436, 17332182286650619204, 1356390314429927430, 680063998460740918, 8263520885737962336, 18031038291900560110, 7916313783579135045, 1390923500114638504, 7357257710265531874, 18050819232629601946, 3177304029089432776, 3356183043120314110, 4896437526344275110, 17783772191254049099, 1, 0, 0, 0, 1, 0, 13700841206357793383, 5242897844664901975, 6931875987485621525, 13535345953969129244, 2030741039344819106, 2762531947819167934, 1589867303015706387, 12511013938757434078, 8759705058299416073, 17894980373425490293, 119389077056921696, 1349552240585307632, 743126002153768243, 2283053310727276098, 4623381538665208128, 1, 0, 0, 0, 1, 0, 6666301890538843304, 15100184186909227104, 13104585709762494144, 16067212803475054780, 15532329799213457697, 8334881840944266358, 2517121414305531206, 9226292579245106006, 17087207871947927046, 11092098231878012627, 10970068856242050959, 11581725042784187604, 13304428174381080582, 15591901374250498087, 14932175652999057387, 1, 0, 0, 0, 1, 0, 5429713005191529599, 485169140917582212, 4576842161780004363, 12062213544561319942, 11418995341251578421, 17152905263785336993, 1631276317082485483, 3568887030966752039, 3361290037864726245, 15436522396033313024, 17085807233874391210, 8147970228355894659, 6261462177346527521, 6933857645565178124, 7551583744620273002, 1, 0, 0, 0, 1, 0, 6807448188965543153, 9507596951835777611, 11958721233767021404, 3380817682214556522, 16170609460104531156, 10111115936627491028, 3604487074555980458, 8451136074985746484, 5442720530348853678, 9471235153819067672, 10672876360944965833, 15381377407789231918, 4737142352428164538, 8819307315481053031, 3302024672420588861, 1, 0, 0, 0, 1, 0, 8272992415832567053, 10756755112993818184, 10057238749770162032, 11156441887212538418, 3098818062082866526, 4253492566197441506, 8767167317332381804, 17223395584715517067, 6083768282731854197, 15287591782061935966, 1749627974902211442, 11405958977712175628, 12451241949260942894, 5075882627538566638, 5802029065265737628, 1, 0, 0, 0, 1, 0, 115043481862425790, 8259507034822886871, 12751027772465443875, 14559366336196618760, 14638271998745396609, 16008945461034236, 3946239166811380672, 12563230741835717849, 12528039909892426334, 17476972384961842195, 14568804827433702794, 3163555765045496501, 9857342525699923921, 5170133709252280486, 6934457598776258250, 1, 0, 0, 0, 1, 0, 16607251464683034540, 0, 0, 16598287690982947812, 17624625052233494012, 18382683990989729838, 11627160828668855898, 2837237790382853743, 17608254328373195204, 8384927093614621388, 144360432842733232, 4955652552073033885, 2877948804182802216, 14754884514108307037, 8237817611365992649, 1, 0, 0, 0, 1, 0, 0, 0, 0, 14243997351069122112, 6885597843867247745, 5829165866197358838, 3828442679559769924, 5962955824096586186, 5722638855509675004, 3866341543198538266, 10395572289151695247, 11957833676204658018, 7226351981553525019, 13730521644769894866, 1730532664872069974, 1, 0, 0, 0, 1, 0, 0, 0, 0, 10057186991882797037, 13979535426176151003, 3368993333474359559, 15087545933098252019, 15471413093926581707, 13303729614330622172, 5722877545315066256, 8676274815465763770, 8482044564546020834, 5141673631152671885, 384165086974752860, 13639880556665716509, 1, 0, 0, 0, 1, 0, 0, 0, 0, 5245170599699700602, 10291681149902218321, 11746208067041323698, 11709563291311499632, 235501757784833854, 13623063482483079236, 4703846003811315010, 17004989925486193850, 7023073680354827593, 11626271086934648748, 14817075775725990184, 4763888723549665869, 1, 0, 0, 0, 1, 0, 0, 0, 0, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 13813148053191742203, 9801149536421508036, 8323744943735804454, 9781218902110540179, 5842910582527751306, 6515775080041612554, 2207036983008389704, 7138588223420389995, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 6, 4294967292, 0, 1, 5, 0, 0, 2147483648, 0, 1, 0, 1, 1, 65535, 16383, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], range_checker_cols: [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2188, 4375, 6562, 8749, 10936, 13123, 15310, 16039, 16282, 16363, 16372, 16381, 16382, 16383, 18570, 20757, 22944, 25131, 27318, 29505, 31692, 33879, 36066, 38253, 40440, 42627, 44814, 47001, 49188, 51375, 53562, 55749, 57936, 60123, 62310, 64497, 65226, 65469, 65496, 65523, 65532, 65535, 65535]], num_rows: 128 }, last_program_row: RowIndex(12) }, program_info: ProgramInfo { program_hash: Word([14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053]), kernel: Kernel([]) }, stack_outputs: StackOutputs { elements: [1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, precompile_requests: [], final_precompile_transcript: PrecompileTranscript { state: Word([0, 0, 0, 0]) }, trace_len_summary: TraceLenSummary { main_trace_len: 13, range_trace_len: 45, chiplets_trace_len: ChipletsLengths { hash_chiplet_len: 64, bitwise_chiplet_len: 0, memory_chiplet_len: 1, ace_chiplet_len: 0, kernel_rom_len: 0 } } } diff --git a/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_12.snap b/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_12.snap index 40691a79f7..0e6abdbd90 100644 --- a/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_12.snap +++ b/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_12.snap @@ -2,4 +2,4 @@ source: processor/src/trace/parallel/tests.rs expression: DeterministicTrace(&trace_from_fragments) --- -ExecutionTrace { main_trace: MainTrace { columns: ColMatrix { columns: [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255], [0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 7458506668679174706, 7458506668679174706, 7458506668679174706, 7458506668679174706, 7458506668679174706, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 18375473735916206629, 18375473735916206629, 18375473735916206629, 18375473735916206629, 18375473735916206629, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 2105717247508690050, 2105717247508690050, 2105717247508690050, 2105717247508690050, 2105717247508690050, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1679902783560062568, 1679902783560062568, 1679902783560062568, 1679902783560062568, 1679902783560062568, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 33, 33, 33, 1, 65, 97, 97, 97, 65, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [7458506668679174706, 1032, 8, 0, 7458506668679174706, 7458506668679174706, 1032, 8, 0, 7458506668679174706, 8038422000946611307, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111, 385638883771950111], [18375473735916206629, 0, 1, 1, 18375473735916206629, 18375473735916206629, 0, 65, 65, 18375473735916206629, 14346009158187546482, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290, 14533042520471865290], [2105717247508690050, 0, 0, 0, 2105717247508690050, 2105717247508690050, 0, 0, 0, 2105717247508690050, 2190566822905267077, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045, 12416920551073560045], [1679902783560062568, 0, 0, 0, 1679902783560062568, 1679902783560062568, 0, 0, 0, 1679902783560062568, 2591468219526413421, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704, 6947485957721124704], [8038422000946611307, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [14346009158187546482, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [2190566822905267077, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [2591468219526413421, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2], [3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2188, 4375, 6562, 8749, 10936, 13123, 15310, 17497, 19684, 21871, 24058, 26245, 28432, 30619, 32806, 34993, 37180, 39367, 41554, 43741, 45928, 48115, 50302, 52489, 54676, 56863, 59050, 61237, 63424, 64153, 64882, 65125, 65368, 65449, 65530, 65533, 65534, 65535, 65535], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [7458506668679174706, 17096349974747592886, 18361620591822500183, 16289398515402274208, 12841425204405288471, 15487398038599823036, 14276138499607098431, 10749365977722278245, 6523151203286366650, 4335325190849710619, 15614163639554121613, 12559670426893619349, 2624231249184618532, 172006848477927500, 14464825374273596237, 17032775430832607567, 5313985443683323356, 5926060660140296438, 17163852599398532090, 13307451342254896743, 6745543631073250405, 5541607425778637052, 17242934273716413404, 8175629301673337378, 9641946119039093964, 13376211201769313404, 3983555747063229007, 2734833199126280117, 726265693390881232, 14561475405601408308, 12499075216226282978, 385638883771950111, 1032, 10320, 13024110921086730221, 3587442816163675215, 512402747638547729, 9217956011885162917, 3925750957223009950, 8674177413178223320, 12846799727083908462, 9116601283268739756, 2958792353189815054, 1720195204565087693, 7696852080146622077, 2890877729556257606, 16676527939404087356, 223754558788184593, 4767414622778376421, 14072300156908432530, 16856861612825314654, 11910434229443384600, 15658716527747040980, 14322127566252286435, 4770460127206402609, 10805338145914832851, 1391598300875421210, 18211456042978337510, 11866022853402812888, 6438324596032750504, 13328288515202849800, 17331158106613184460, 18344276842462151560, 7458506668679174706, 7458506668679174706, 14091156936533878352, 9449073279161460587, 12931192181764701571, 984010488942368543, 9685532581221734183, 7253373568681004065, 3375237562644883775, 6753674160453463758, 3441205833090784550, 2852031204586017293, 17888529253300920997, 14261166963032608042, 7584983368183421126, 6933428701043454429, 6613788239612360156, 12188550669627194766, 11116051071552283912, 12942594340955341249, 15973329405569184071, 6599410081338642359, 9166275669564489461, 16205691190134424749, 10240544379350652389, 617488447888956772, 10444963251954281557, 1760171480459315772, 225922431704781657, 6781621337133548780, 6905620312272855934, 11742310966982885025, 8038422000946611307, 1032, 10320, 13024110921086730221, 3587442816163675215, 512402747638547729, 9217956011885162917, 3925750957223009950, 8674177413178223320, 12846799727083908462, 9116601283268739756, 2958792353189815054, 1720195204565087693, 7696852080146622077, 2890877729556257606, 16676527939404087356, 223754558788184593, 4767414622778376421, 14072300156908432530, 16856861612825314654, 11910434229443384600, 15658716527747040980, 14322127566252286435, 4770460127206402609, 10805338145914832851, 1391598300875421210, 18211456042978337510, 11866022853402812888, 6438324596032750504, 13328288515202849800, 17331158106613184460, 18344276842462151560, 7458506668679174706, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [18375473735916206629, 4928386710787932510, 1059957073285149997, 7414794499417747342, 8707706418338537128, 18233967745224015541, 14225356453364529209, 16969240713191698060, 2722387933855210372, 10882627342955990743, 8403803192675895448, 16245041381764943451, 3708333802929870625, 6959279407809842059, 13217946414061638961, 18053036458820754856, 14921461448469870468, 560525447297576809, 7018646217871183595, 13178251276894296346, 6921572661546485589, 15572457938054287524, 2649667358943828601, 7478653578860599304, 10687080159641340324, 2690283767645584259, 18436093682323240213, 7844418673662650289, 14896924519547367367, 5700869957895642798, 1468047895374295633, 14533042520471865290, 0, 8256, 1131208899036558480, 1667157010810320250, 2053960715201569301, 1526213270499333709, 69813565043892453, 14925652377538846871, 1380252317064967448, 9902934070223067140, 3786794161520721521, 664031068804619792, 8470323998416702977, 4965297830526000942, 9404280000999464502, 8244737495337250711, 4784363486033662704, 4680481291290566437, 15373555507761845373, 8780119261264514018, 729009684537575982, 18306419558979237700, 15407410920890065538, 2509966126115291236, 12709897403480972846, 11498596868429821859, 6606875518512322314, 13880694912200059110, 6972406840307481976, 14148490408465275064, 2917966740410115114, 18375473735916206629, 18375473735916206629, 11043817201346618265, 1121487758252150877, 11145191037714825824, 1213485180702191508, 7846971226962020365, 6910576852826920348, 16299106229207932049, 13494897806355030713, 14683406224909707924, 7225022863877466358, 8659258489615358612, 1007283657566761474, 3461275599657397285, 13991061905462032659, 7694544543570254942, 13915724103240909421, 3035711690563019728, 12166494415818485436, 8309121944568509175, 14938409169697365298, 8594201398583676528, 10975429338366528094, 12203611326855107051, 13805253251340915462, 17236773525845958123, 8285118005586313889, 4578896616328629575, 4956581778649408453, 2207149270543631094, 14846185326871759573, 14346009158187546482, 0, 8256, 1131208899036558480, 1667157010810320250, 2053960715201569301, 1526213270499333709, 69813565043892453, 14925652377538846871, 1380252317064967448, 9902934070223067140, 3786794161520721521, 664031068804619792, 8470323998416702977, 4965297830526000942, 9404280000999464502, 8244737495337250711, 4784363486033662704, 4680481291290566437, 15373555507761845373, 8780119261264514018, 729009684537575982, 18306419558979237700, 15407410920890065538, 2509966126115291236, 12709897403480972846, 11498596868429821859, 6606875518512322314, 13880694912200059110, 6972406840307481976, 14148490408465275064, 2917966740410115114, 18375473735916206629, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [2105717247508690050, 10107555422114249811, 10238372411792495411, 5045095827015758924, 712045908447132336, 5489587686936736744, 16325305247621291738, 3474647312056323841, 17923261380734419001, 6422147522697035080, 14808436219267178190, 498420322150313505, 13431378003732567637, 7624522606684096342, 16563220449590599184, 17295714046586140515, 670583892751407031, 2602239721821758274, 6195887607206027232, 2861627473244922884, 4750941303537176677, 9649080575881148937, 13116712088373847968, 6713440703831969386, 8417294471144249339, 1401889430288725516, 4371677581775699941, 4682611113744629451, 15268715163867613574, 18046680204045439410, 4916517868000584486, 12416920551073560045, 0, 2064, 18136552782870868471, 952274539956745973, 15933282259815262093, 9924516287334785738, 18064603646801610993, 5114527609957824263, 11816233963570869158, 17699527003452380450, 14533708946479200173, 17484213571014188868, 832814531422633701, 1508169308733590908, 8423043379628164525, 12595277727969636921, 14226276023010866965, 10485112285448962747, 1783527593060720204, 10145484005384627580, 7463752398658534839, 17345550819494003223, 4432309123412733588, 7086318781105575433, 8830891075082588619, 310185093236608634, 16683125300631590273, 7786799186167080425, 29465347809991832, 8090161351836983773, 8665315444141111469, 2105717247508690050, 2105717247508690050, 3724970573052107073, 8941582041334934334, 8312329417918475026, 1987590179830007973, 2110379688364488268, 2640821370997726846, 8705349523122969177, 17635305137043271645, 5321945504199945322, 14864981808156728804, 12170067272088757680, 9570740252338888760, 8752234911193229380, 7657051830321493279, 10054332690091372507, 9785276524271352823, 11645316320468991699, 16682105615873122608, 11466817788450225616, 11077840439234171924, 8390120315669274279, 15664297021877418193, 9890840092123213718, 14010940161066467221, 6608692618887145744, 7336759030812521166, 6773864172894681873, 14718016860648898221, 10620364686165750780, 13091258350263300328, 2190566822905267077, 0, 2064, 18136552782870868471, 952274539956745973, 15933282259815262093, 9924516287334785738, 18064603646801610993, 5114527609957824263, 11816233963570869158, 17699527003452380450, 14533708946479200173, 17484213571014188868, 832814531422633701, 1508169308733590908, 8423043379628164525, 12595277727969636921, 14226276023010866965, 10485112285448962747, 1783527593060720204, 10145484005384627580, 7463752398658534839, 17345550819494003223, 4432309123412733588, 7086318781105575433, 8830891075082588619, 310185093236608634, 16683125300631590273, 7786799186167080425, 29465347809991832, 8090161351836983773, 8665315444141111469, 2105717247508690050, 4294967292, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1679902783560062568, 6240831473992650349, 7295075507077524016, 1708983071443589586, 5101441454781013927, 1762085221214582981, 4624893715923722401, 5034791698378793493, 2426086071573235308, 5506620828865036918, 7907851684587935310, 191858132690363422, 12189827080513272685, 4161952004851845371, 3113047032182286095, 9384643295764542420, 16611260466052466604, 10297192864125327962, 8420396089584454313, 17843538048800435721, 49291998290789182, 15454664486445800726, 3574645404922812405, 11401680143523240515, 4109004423430966857, 16206235872347886942, 1597537279118331686, 11520518532281367191, 3135755890995221672, 15097801996593502346, 4266164594774171363, 6947485957721124704, 0, 2064, 9594118340025725004, 16218246678075491818, 11582919835122342747, 5661452934218108707, 3714647928422746674, 13689184893219719187, 1899963197709801965, 8313716591368695784, 17822645741084942000, 18354595702287703799, 12620512717427217848, 10145637708639089787, 1735222492513760332, 14681927838838900060, 9262747238997471758, 11498487923782501751, 8924101344488972446, 2592517964915386184, 4276681409258176044, 3764365715267793208, 3120204268813370353, 6019260256544801113, 2801984351776029768, 16979166255722313516, 2813750347113564525, 16588139065369475399, 12012198471360912693, 2492059183640657261, 16968938268466755316, 1679902783560062568, 1679902783560062568, 14885555914322696710, 11595861135030037790, 15790255405818319154, 1788244094476607025, 3713346340151405890, 10088532170345334842, 17854024334494248585, 12211195930325373909, 14810607828402585285, 6176927505545789216, 7340196426348852368, 4385801084072612889, 14434159451233581456, 16984288007453782663, 5968497068768213078, 13891165676869534375, 11051615708535243788, 18406940479749704351, 4657122466881791459, 11427117893432527856, 9342747858627858744, 4615623292891883658, 2986843800380659541, 3219777777177975421, 8998753509000282586, 14589941254121359798, 3914101860949270917, 12606215244329868526, 16670383938906392554, 9639583597360292920, 2591468219526413421, 0, 2064, 9594118340025725004, 16218246678075491818, 11582919835122342747, 5661452934218108707, 3714647928422746674, 13689184893219719187, 1899963197709801965, 8313716591368695784, 17822645741084942000, 18354595702287703799, 12620512717427217848, 10145637708639089787, 1735222492513760332, 14681927838838900060, 9262747238997471758, 11498487923782501751, 8924101344488972446, 2592517964915386184, 4276681409258176044, 3764365715267793208, 3120204268813370353, 6019260256544801113, 2801984351776029768, 16979166255722313516, 2813750347113564525, 16588139065369475399, 12012198471360912693, 2492059183640657261, 16968938268466755316, 1679902783560062568, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [8038422000946611307, 13055964544694368769, 7749914311668337250, 2490550827364591193, 4834428694324052171, 1237735850038716981, 8896240793576304991, 6582069168543167041, 3706649958322292721, 6839310826708053103, 12095513884410398346, 12922970210395916603, 12358523363220613934, 16454123186601925336, 4991814670781152799, 2040061269519504799, 17488717307568714132, 17317480533129930885, 2098096181527665460, 4697187904025813178, 1478747224857255407, 4468957360091397608, 17536692358706723977, 13559769323964866828, 10531481423547827694, 5398218750581689859, 8391144048742825188, 16471665752727725784, 3043860411079700945, 3316394317418127534, 7755478137750309004, 15345115023987982060, 0, 5160, 1190658701913535022, 9371121588404883743, 7133056533056999470, 7380100170229652082, 14719783382686670107, 4693530971176924881, 11125714198188567552, 2434816259070577714, 17927785478103501878, 834873962620943786, 1091858408197145201, 9293176204765248193, 11318806736621162148, 979530496520387452, 8328113718786640843, 15870139479256453021, 7754853849459016697, 2742936430580983415, 6806060556807781604, 5089080673677611112, 16430235900965466453, 309743103212430298, 15664803780047891222, 3113571524475220627, 17862871362988443440, 1231393200801541530, 15779352999894925288, 6026600320279882336, 6970552753544824994, 4949154992619464010, 0, 7045578468266939554, 7760605592330700907, 8360793687611805321, 738095676972904954, 15564477193367915463, 5876321119815014086, 17552573089477749612, 11411212736325006200, 13815587307529680030, 17156301712489415615, 17351081171119935003, 8966918709601352564, 3417326002908165374, 5362234606277969799, 6579629986598330856, 12247315276947966697, 18410067321498813805, 16182198715872613358, 11840483485843621799, 10053996112039279419, 8402815695409633837, 14225254012036856662, 269445170964238763, 7745973219325669511, 13587984894488746939, 8094627026199116369, 3994495212216710235, 9140718271797260749, 16931156974940547986, 14990750302990274425, 2224156252998910395, 0, 5160, 1190658701913535022, 9371121588404883743, 7133056533056999470, 7380100170229652082, 14719783382686670107, 4693530971176924881, 11125714198188567552, 2434816259070577714, 17927785478103501878, 834873962620943786, 1091858408197145201, 9293176204765248193, 11318806736621162148, 979530496520387452, 8328113718786640843, 15870139479256453021, 7754853849459016697, 2742936430580983415, 6806060556807781604, 5089080673677611112, 16430235900965466453, 309743103212430298, 15664803780047891222, 3113571524475220627, 17862871362988443440, 1231393200801541530, 15779352999894925288, 6026600320279882336, 6970552753544824994, 4949154992619464010, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [14346009158187546482, 2514419654263230233, 10868075426920088717, 14626639685450047092, 15824191413144451094, 3872785008711037698, 15159572856872914175, 13499848828490637487, 12504162360551599075, 6704874092885621909, 8482918267067478031, 11182299479692082524, 1644784474325024851, 10866220166037749110, 13011220300525187244, 5714286046111667701, 3271812982662883550, 4912758288798487759, 12958366352003970496, 11568317646859944473, 1188141313951948960, 12777681205968064182, 13771180111214880533, 3688955093092273987, 1949816493804567768, 12058362437595143266, 18379600813280833240, 11754259659339519197, 7370638446447886746, 2915034789487291427, 17553720084081617212, 15041334301981527295, 0, 4128, 1352424102745866255, 13301242752201603536, 5420135027930584396, 17078794493496835379, 4779811836607866048, 3650219859599657886, 13618468821889769363, 11429589192023659923, 8853101337885331080, 9650238821992519861, 14401087967309285252, 12035560952634921032, 15407186837043713393, 15711028160746246110, 5396976350889627712, 15903424027416555998, 11304777107657759509, 9857843669692965578, 12605480788735099613, 14618970056708743810, 8493993205782554647, 6059068631740368787, 18316971448227884023, 12499808993385025318, 4210674244211222629, 18405965507148502967, 173097048437312502, 15568437290332308327, 11532601739151124629, 10000279862191744493, 0, 14745280635380601617, 3718367898484243235, 9018263790739496394, 11183632545038441118, 11084602196898449287, 10533306301610546918, 1420887495241955081, 4459785951807836148, 12821108383646715262, 10486453955800644813, 1149237165662367781, 14820375481022552179, 16262631485420346362, 15566979183400849953, 16057390897683363413, 11254638356144199099, 15872210457308658069, 81952248385650954, 18028966990791016994, 6002088535876283975, 14457561209066214295, 12899353015952976468, 2384048206878222613, 11488447290357428274, 7532999527428712911, 63498412877849097, 17284768262212667433, 15648250834702978300, 8529394818161928928, 12738537911867917740, 15275140426936934232, 0, 4128, 1352424102745866255, 13301242752201603536, 5420135027930584396, 17078794493496835379, 4779811836607866048, 3650219859599657886, 13618468821889769363, 11429589192023659923, 8853101337885331080, 9650238821992519861, 14401087967309285252, 12035560952634921032, 15407186837043713393, 15711028160746246110, 5396976350889627712, 15903424027416555998, 11304777107657759509, 9857843669692965578, 12605480788735099613, 14618970056708743810, 8493993205782554647, 6059068631740368787, 18316971448227884023, 12499808993385025318, 4210674244211222629, 18405965507148502967, 173097048437312502, 15568437290332308327, 11532601739151124629, 10000279862191744493, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [2190566822905267077, 5404282949943047077, 5620556269036690141, 14491113445439742990, 3583407126333665201, 11553681770295205503, 1216093779061977398, 9009035935586042381, 10160118687758838044, 5189341129501661569, 552602416783565214, 13892332176168710533, 4210303372183975982, 9918111397467437847, 13191859809007430670, 12682554283327491677, 6159734265799796346, 3655472932705407889, 6138462302257325090, 9507551446430113809, 477055463074084789, 5562148904013569055, 16089614614433980121, 11132173538218883660, 2369773375363070297, 8734570802518415843, 13624820787911837119, 15026940072471861444, 10407697142160461181, 14258174989754257767, 11934701342627358954, 17583525004205959015, 0, 1032, 4798141223555508282, 12962488577647927717, 10133257770726709126, 332864556927106185, 12116126881643349994, 6604148216925166409, 101015634312276042, 15934992137290074922, 6112274855072540816, 17762248064501548615, 13166189948742588777, 270100349969833402, 13485211244653928073, 3502306881032295169, 13607663468974078519, 8883940618995723208, 10623667092532612652, 12293715092576816840, 10386976621364522928, 9128135834925108269, 15731443845270647366, 13373704167654916087, 13746187061551926812, 11684868053863796759, 3258729720361659960, 10434904637843727165, 7034851303745741351, 16133345873308301364, 5426492436527662130, 2980140658145787783, 0, 11085857321233345859, 6502498117283132750, 10381882708453841125, 13452669420839074331, 4680755747100261382, 2695613323752232712, 17146809849277743421, 9239864853466318604, 14768453813159795872, 18276894718067265811, 17257251339549225733, 5284904431001214307, 5764961239481152941, 10517783806308559735, 15410914971073808541, 3344855092587244940, 10472918269298152403, 12402503503713090948, 2754408248470837514, 15057664949131650205, 4187574032621547594, 5855521755089516239, 13990442832618678273, 14308234035637757543, 11933928216400818327, 15524863835262422966, 11531650814746237864, 7664866084994005813, 6402603575808426205, 15478402516028642985, 9020969347685648365, 0, 1032, 4798141223555508282, 12962488577647927717, 10133257770726709126, 332864556927106185, 12116126881643349994, 6604148216925166409, 101015634312276042, 15934992137290074922, 6112274855072540816, 17762248064501548615, 13166189948742588777, 270100349969833402, 13485211244653928073, 3502306881032295169, 13607663468974078519, 8883940618995723208, 10623667092532612652, 12293715092576816840, 10386976621364522928, 9128135834925108269, 15731443845270647366, 13373704167654916087, 13746187061551926812, 11684868053863796759, 3258729720361659960, 10434904637843727165, 7034851303745741351, 16133345873308301364, 5426492436527662130, 2980140658145787783, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [2591468219526413421, 8600073145915840029, 9972703476491052945, 7474968551123382164, 7181997692355145187, 15428345773987404117, 11743605500774065098, 11268864392770353056, 12211833414579612038, 15717209816757714363, 890156557088959300, 4859169418838628114, 17769229151585966679, 14412689958488784376, 3341988471057096642, 3129947071292798718, 17633680398960744148, 9040916820504033241, 5930774742161220001, 13876115104798876568, 6388325427377182963, 14330705119681412991, 15768069489925358116, 6157532873490141938, 2469680878449864864, 12328809527998355692, 16304509166225849524, 3168032149605842623, 935982989392333515, 1210836981232166821, 15698638297176561506, 17830733542807512157, 0, 1032, 11702782905971311743, 8115486282645452027, 16425371230714077552, 10333496212804492507, 1572943607289284437, 13244361396034453954, 12880029163967100393, 14716450796809578181, 2618965885956593171, 1606019581379521796, 12562170441304287563, 4599116799417823473, 4257071131168813417, 10446583017549019711, 3570388907037362614, 11170081717188072664, 17238997244398394333, 17231192964516960933, 8123337005847551087, 7060091366977384949, 5719725530909274667, 5057603743378325948, 13848013489728729143, 17729739340387068117, 367186060507240673, 1411195984452924204, 11088333491201093194, 16575090776691519559, 16147396598096989679, 14525300817521856881, 0, 7442777957161348409, 12950881678740459660, 6646706469455563416, 5900873935105415470, 17072140113884084441, 13172589932512713520, 5522401646053069342, 3133914205806983551, 13779823240426764791, 17224433130794138533, 14489298897463599319, 1940759318652413905, 7694480472126993559, 17366018125192157291, 16887976527497663730, 1916565854454348991, 2294268388330909452, 8983416234083684410, 11974102734257880906, 11534526793163396841, 10005306190103088231, 12997092893241557181, 2268817966601289631, 8051413784985211055, 5191686653404052624, 18373940558834700052, 4703711900874228713, 2364324903714729084, 11224300914395639224, 6723817418214557043, 2429828201690573781, 0, 1032, 11702782905971311743, 8115486282645452027, 16425371230714077552, 10333496212804492507, 1572943607289284437, 13244361396034453954, 12880029163967100393, 14716450796809578181, 2618965885956593171, 1606019581379521796, 12562170441304287563, 4599116799417823473, 4257071131168813417, 10446583017549019711, 3570388907037362614, 11170081717188072664, 17238997244398394333, 17231192964516960933, 8123337005847551087, 7060091366977384949, 5719725530909274667, 5057603743378325948, 13848013489728729143, 17729739340387068117, 367186060507240673, 1411195984452924204, 11088333491201093194, 16575090776691519559, 16147396598096989679, 14525300817521856881, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 10050771506480654697, 13420837528738763520, 8496521368864059734, 2484674105691110618, 14534130756197581682, 5302125583480436763, 17447925507451726835, 6158355997654729039, 2747272733640735637, 16008460117209203149, 7966664559987380274, 12228289745234304260, 5769015309045246106, 10117630725268935850, 1928165892714903315, 13757138220331554723, 3415891051222089939, 9614135373790971720, 15460760939838461118, 3083939397091390513, 5208743639505571028, 10512816629673800187, 1038453745979635965, 11152507394095411482, 16277833565401448399, 1857640599304385129, 15507736315414043252, 10006390466474490543, 14803299263866517418, 15066726409373257878, 5538305542985598681, 0, 5160, 18346837778669738664, 15130142357101091527, 6726588340010678615, 8394319278312203283, 15942424551308612685, 7629500615465222065, 14939877513325106589, 17048523965011794048, 2306293645521445312, 823113708878672797, 14981348226783328932, 7432878333905782051, 3482639998457803800, 632277917380007036, 18266437030920184246, 3366715262389109205, 5280275432441977334, 5379329043314533811, 13912213856326486056, 17217059915921675075, 15634373017412823086, 14981257187297131103, 16697350900700022325, 5239234081629986555, 3229291246709926782, 18373224696258292584, 6771862800272250893, 7666370275789511263, 12942227631865082960, 15190222347874856922, 0, 7045578468266940310, 11422404183367723688, 4734813192583045175, 16795465921267519808, 12362009349652409415, 3020519614827991855, 2942658800463567237, 18428726703177922018, 10231394582054281621, 8503976903131851970, 11539035678955040518, 6287740157380564628, 3273842793073629785, 15356197472622263350, 8793463497412363872, 15129820397597713369, 2881507314714938985, 10712615481926377093, 9279961334386063516, 4068525996563916658, 13774208723083831405, 17700397171958035166, 18249110448117027038, 8906205380227326203, 4362400237726204205, 16281776889210602562, 4962687005987029339, 5046527547997136739, 15389940485215503504, 8078314735919109828, 5959378659908477764, 0, 5160, 18346837778669738664, 15130142357101091527, 6726588340010678615, 8394319278312203283, 15942424551308612685, 7629500615465222065, 14939877513325106589, 17048523965011794048, 2306293645521445312, 823113708878672797, 14981348226783328932, 7432878333905782051, 3482639998457803800, 632277917380007036, 18266437030920184246, 3366715262389109205, 5280275432441977334, 5379329043314533811, 13912213856326486056, 17217059915921675075, 15634373017412823086, 14981257187297131103, 16697350900700022325, 5239234081629986555, 3229291246709926782, 18373224696258292584, 6771862800272250893, 7666370275789511263, 12942227631865082960, 15190222347874856922, 2147483648, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [87, 8629850144821916384, 4475574334214635511, 15844375305567102825, 10178368558488980289, 366424541133389116, 14318718192085040201, 11141735015346329315, 14736248158977353058, 6659594400091594161, 9354501143254856958, 1788553586845505120, 13567541605223635136, 18116490434673131256, 3267515885574430559, 4026772730948844076, 2031101258349406169, 1067905233090125355, 3177657145644554672, 3126867087711378899, 2351734901108666112, 7401562071196444455, 11029998200473456200, 12823977733512090066, 9220325101017945081, 9541188526080901705, 9807406399356825925, 11614758863876097772, 7718195260684522704, 12447607757449687684, 2284861843754100216, 16982814561187843115, 0, 4128, 6496253015800789210, 18063315295058131399, 14099326864720264780, 16744359797696928029, 11669954633423859445, 10923938539628559259, 10579480970462933513, 17315553376669597828, 12114095292572219189, 16129781670858537825, 67936491912723144, 6285840300661422802, 14359460599290704174, 7597471307904508314, 8469569990667894210, 9117246600999250277, 14614928058075190380, 13738364908865630160, 1806905237893315697, 261412144627674040, 8380596589382515797, 3809925330596605534, 1983199361335541287, 6337901890572878101, 17063257729896061936, 12690697575318882146, 3846044480011221270, 10729939698274680623, 5297971463863936522, 8671284646676347574, 108, 14745280635380602265, 1030231790864474253, 8493304069558799424, 3813500112725093016, 1584024639278012914, 6691630066548896421, 12744785931761802081, 8312414042457270416, 15913285332885706950, 11904695260466451537, 4503780104272324718, 3020894344784966101, 8121142696445856470, 7323566571197968291, 15900985531249599446, 7156364108131320107, 15910943131140158025, 14526518136578598747, 6720684608059903461, 17378127155945101975, 8120421969064271148, 12903874735177520891, 4533560749542240026, 13603960728052470511, 5595478722910465584, 1530061232442071378, 8451873054224800759, 7908366039873426748, 17285432733773675712, 7133857220640768475, 4076807723615210075, 0, 4128, 6496253015800789210, 18063315295058131399, 14099326864720264780, 16744359797696928029, 11669954633423859445, 10923938539628559259, 10579480970462933513, 17315553376669597828, 12114095292572219189, 16129781670858537825, 67936491912723144, 6285840300661422802, 14359460599290704174, 7597471307904508314, 8469569990667894210, 9117246600999250277, 14614928058075190380, 13738364908865630160, 1806905237893315697, 261412144627674040, 8380596589382515797, 3809925330596605534, 1983199361335541287, 6337901890572878101, 17063257729896061936, 12690697575318882146, 3846044480011221270, 10729939698274680623, 5297971463863936522, 8671284646676347574, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 17468442170295488858, 9773381208787513234, 2185606873808106597, 5326701750299677540, 18331867594591263096, 548097224697282340, 10547562414019002308, 13272144351666153699, 15855067207807736351, 4370081121859711944, 2612761535881667398, 16433499902516242349, 5490313979471750512, 12242667433588409287, 13667932040054721093, 11397361705799260268, 13352179165506178583, 18130276598071715349, 5367905172204163759, 13899921222016942193, 16739429834098497391, 9456664549854782490, 18285262020229949627, 11267975946641671449, 4164320394230196430, 17698213099167806270, 5464680925773178239, 16672746771430202203, 17570877581179860050, 2661602147392096981, 17592358249594079251, 0, 1032, 13084260837127404333, 4018109146681745349, 14498381569327145056, 3778421823029569719, 1344624249217908323, 3634653398484528177, 1428985706412758663, 11382569756632997337, 13894906302086601399, 3911680161282028629, 11467762927868003365, 10098326072301516020, 16073214466625742345, 16150512194511843089, 11525294274796193451, 15902507139806774023, 13926886722650908730, 2974304378722638293, 5274544965980948277, 9984170014312577610, 639485734140932316, 15088403650698955530, 17189134684458608982, 6515320870350778492, 7902492290152572474, 17310456195349246143, 4070136787975548901, 6345872167795009033, 3095930865537762353, 4232664728858134772, 0, 11085857321233346183, 17340772818369048990, 4710612857210121909, 6383904020814938565, 2185295286363661452, 57911040231161987, 16587511410977976694, 2708167856204711091, 10934568936892706192, 16945176268586506094, 6648082856126081802, 13508616389857401321, 2042841450297716791, 14424400955124662023, 4566271445414618189, 6323391233814555017, 5903620650725668621, 10799633056255259898, 7254762119029478931, 8510983625183148698, 11995653210052429396, 8580571627687871547, 6611487504966808602, 4153539838331475868, 485956658090184855, 13092360131462553695, 16519639797422070758, 15931672450436655146, 1240279786436372570, 14570949492747980696, 1405895934075613917, 0, 1032, 13084260837127404333, 4018109146681745349, 14498381569327145056, 3778421823029569719, 1344624249217908323, 3634653398484528177, 1428985706412758663, 11382569756632997337, 13894906302086601399, 3911680161282028629, 11467762927868003365, 10098326072301516020, 16073214466625742345, 16150512194511843089, 11525294274796193451, 15902507139806774023, 13926886722650908730, 2974304378722638293, 5274544965980948277, 9984170014312577610, 639485734140932316, 15088403650698955530, 17189134684458608982, 6515320870350778492, 7902492290152572474, 17310456195349246143, 4070136787975548901, 6345872167795009033, 3095930865537762353, 4232664728858134772, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 17244797586245886456, 15751718828876603764, 11509908635527699125, 11475332140491226913, 17384989371947212455, 334761494745252139, 7616687658781298414, 14780080241553087954, 12346184924771259853, 16185631853241338171, 895339354972846288, 4068422042358699181, 17829363972116539489, 16616980036078363960, 11802237368737486290, 5517794271194351375, 1340602429246747412, 6137287375961878929, 9089335960846268476, 10715486062907500431, 9038952715608883929, 3376751855710232954, 9293572206177681748, 5274360121930626670, 10385953241879043200, 15812468027446779083, 17985531203042807174, 4527163876177139455, 1244842376420464745, 7071163393872573565, 10505779527452689750, 0, 1032, 15909096041365347974, 18432189660917429733, 2798890989547891271, 10768372030970716894, 5935807051329113911, 1259182408195029650, 16024750973514577255, 6103595041913569283, 914770550723164908, 5067028895751058275, 5242612139537538536, 13359135899043031769, 4430959127423856282, 16317056360529517539, 2634255659160911215, 15590656855559575839, 6832335878067392309, 6045109056629836176, 18146646330136390606, 6482705684632040588, 2770791364887326735, 7707774010999656594, 3401430074469265273, 3500862351024377705, 5135727797169111985, 14940852959892477883, 9633218853985087472, 16966092255533854383, 3065488485208441055, 15703076512693482766, 0, 7442777957161348517, 15511565770182079598, 17588127306488605836, 12156963648059548539, 9855001437726729603, 750212215289098948, 3057342424889339513, 12076679785316333126, 4754090667046207383, 5287048869294162247, 13665676832765504604, 7892998254318929425, 10986386945260945625, 650038937356756422, 1562289959612081521, 18390988039078367877, 10259188468824740395, 8732714546322097295, 7010052931953742806, 17653496644410780843, 12884831098778763497, 17079843757158488506, 5971369750353050420, 3223792838828500232, 6029903770259711111, 16004411386897649153, 5901432683519548685, 18030233803416436591, 18259374036374690916, 15125936605156360851, 1558963802307733462, 0, 1032, 15909096041365347974, 18432189660917429733, 2798890989547891271, 10768372030970716894, 5935807051329113911, 1259182408195029650, 16024750973514577255, 6103595041913569283, 914770550723164908, 5067028895751058275, 5242612139537538536, 13359135899043031769, 4430959127423856282, 16317056360529517539, 2634255659160911215, 15590656855559575839, 6832335878067392309, 6045109056629836176, 18146646330136390606, 6482705684632040588, 2770791364887326735, 7707774010999656594, 3401430074469265273, 3500862351024377705, 5135727797169111985, 14940852959892477883, 9633218853985087472, 16966092255533854383, 3065488485208441055, 15703076512693482766, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] }, last_program_row: RowIndex(12) }, program_info: ProgramInfo { program_hash: Word([385638883771950111, 14533042520471865290, 12416920551073560045, 6947485957721124704]), kernel: Kernel([]) }, stack_outputs: StackOutputs { elements: [1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, merkle_store_nodes: {Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571]): (Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350]), Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350])), Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484]): (Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693]), Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693])), Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781]): (Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874]), Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874])), Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171]): (Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361]), Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361])), Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815]): (Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305]), Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305])), Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689]): (Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195]), Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195])), Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362]): (Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063]), Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063])), Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848]): (Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661]), Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661])), Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352]): (Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829]), Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829])), Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444]): (Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223]), Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223])), Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386]): (Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388]), Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388])), Word([13190842942618341421, 17548956981569849952, 15418963848144418856, 730733050713174879]): (Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144]), Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144])), Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874]): (Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675]), Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675])), Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594]): (Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115]), Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115])), Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809]): (Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257]), Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257])), Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777]): (Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555]), Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555])), Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509]): (Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882]), Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882])), Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725]): (Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979]), Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979])), Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134]): (Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987]), Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987])), Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828]): (Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910]), Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910])), Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830]): (Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054]), Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054])), Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228]): (Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742]), Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742])), Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443]): (Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928]), Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928])), Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643]): (Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979]), Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979])), Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758]): (Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106]), Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106])), Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580]): (Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594]), Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594])), Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765]): (Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045]), Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045])), Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766]): (Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281]), Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281])), Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385]): (Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828]), Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828])), Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579]): (Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171]), Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171])), Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212]): (Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992]), Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992])), Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463]): (Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004]), Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004])), Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502]): (Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023]), Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023])), Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539]): (Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537]), Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537])), Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865]): (Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225]), Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225])), Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690]): (Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947]), Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947])), Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202]): (Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552]), Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552])), Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079]): (Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444]), Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444])), Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850]): (Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548]), Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548])), Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448]): (Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987]), Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987])), Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041]): (Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035]), Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035])), Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301]): (Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414]), Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414])), Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414]): (Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212]), Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212])), Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703]): (Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439]), Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439])), Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271]): (Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955]), Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955])), Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882]): (Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802]), Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802])), Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152]): (Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887]), Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887])), Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028]): (Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948]), Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948])), Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331]): (Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093]), Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093])), Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394]): (Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134]), Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134])), Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546]): (Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228]), Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228])), Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620]): (Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414]), Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414])), Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800]): (Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703]), Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703])), Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671]): (Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205]), Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205])), Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537]): (Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011]), Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011])), Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516]): (Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301]), Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301])), Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831]): (Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986]), Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986])), Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415]): (Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057]), Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057])), Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722]): (Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689]), Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689])), Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144]): (Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682]), Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682])), Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295]): (Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268]), Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268])), Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818]): (Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513]), Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513])), Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241]): (Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565]), Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565])), Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439]): (Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012]), Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012])), Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512]): (Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850]), Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850])), Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986]): (Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865]), Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865])), Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982]): (Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777]), Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777])), Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808]): (Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394]), Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394])), Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979]): (Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690]), Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690])), Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093]): (Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620]), Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620])), Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902]): (Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789]), Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789])), Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542]): (Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094]), Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094])), Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057]): (Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362]), Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362])), Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205]): (Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961]), Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961])), Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401]): (Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580]), Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580])), Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553]): (Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960]), Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960])), Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169]): (Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031]), Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031])), Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682]): (Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053]), Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053])), Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118]): (Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562]), Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562])), Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725]): (Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666]), Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666])), Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661]): (Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897]), Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897])), Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981]): (Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447]), Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447])), Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072]): (Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646]), Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646])), Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140]): (Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404]), Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404])), Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515]): (Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152]), Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152])), Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709]): (Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664]), Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664])), Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800]): (Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103]), Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103])), Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741]): (Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169]), Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169])), Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005]): (Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758]), Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758])), Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802]): (Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070]), Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070])), Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159]): (Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005]), Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005])), Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350]): (Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443]), Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443])), Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697]): (Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573]), Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573])), Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928]): (Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331]), Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331])), Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320]): (Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166]), Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166])), Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814]): (Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079]), Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079])), Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447]): (Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820]), Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820])), Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284]): (Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057]), Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057])), Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697]): (Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131]), Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131])), Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955]): (Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290]), Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290])), Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910]): (Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202]), Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202])), Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910]): (Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822]), Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822])), Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106]): (Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847]), Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847])), Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404]): (Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441]), Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441])), Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796]): (Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186]), Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186])), Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053]): (Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516]), Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516])), Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992]): (Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818]), Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818])), Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957]): (Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315]), Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315])), Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709]): (Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794]), Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794])), Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091]): (Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539]), Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539])), Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664]): (Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558]), Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558])), Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294]): (Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579]), Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579])), Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947]): (Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502]), Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502])), Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829]): (Word([0, 0, 0, 0]), Word([0, 0, 0, 0])), Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045]): (Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137]), Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137])), Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914]): (Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041]), Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041])), Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573]): (Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378]), Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378])), Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699]): (Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873]), Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873])), Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225]): (Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262]), Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262])), Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057]): (Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692]), Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692])), Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131]): (Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997]), Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997])), Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555]): (Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385]), Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385])), Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195]): (Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709]), Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709])), Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166]): (Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542]), Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542])), Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027]): (Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373]), Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373])), Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378]): (Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509]), Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509])), Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097]): (Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553]), Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553])), Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217]): (Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815]), Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815])), Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873]): (Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864]), Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864])), Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997]): (Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722]), Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722])), Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887]): (Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766]), Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766])), Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589]): (Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757]), Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757])), Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539]): (Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665]), Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665])), Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129]): (Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229]), Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229])), Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137]): (Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312]), Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312])), Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019]): (Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378]), Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378])), Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331]): (Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713]), Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713])), Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]): (Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980]), Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980])), Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325]): (Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546]), Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546])), Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170]): (Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822]), Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822])), Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054]): (Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295]), Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295])), Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925]): (Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848]), Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848])), Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909]): (Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796]), Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796])), Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540]): (Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170]), Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170])), Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214]): (Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448]), Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448])), Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317]): (Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294]), Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294])), Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757]): (Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416]), Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416])), Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378]): (Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091]), Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091])), Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263]): (Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463]), Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463])), Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666]): (Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361]), Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361])), Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174]): (Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992]), Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992])), Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470]): (Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401]), Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401])), Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665]): (Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957]), Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957])), Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262]): (Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144]), Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144])), Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229]): (Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284]), Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284])), Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134]): (Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325]), Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325])), Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855]): (Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765]), Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765])), Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115]): (Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814]), Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814])), Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441]): (Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831]), Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831])), Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977]): (Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446]), Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446])), Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880]): (Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005]), Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005])), Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789]): (Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995]), Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995])), Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000]): (Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267]), Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267])), Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998]): (Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982]), Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982])), Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995]): (Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539]), Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539])), Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507]): (Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512]), Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512])), Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305]): (Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118]), Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118])), Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219]): (Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009]), Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009])), Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416]): (Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089]), Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089])), Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980]): (Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445]), Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445])), Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063]): (Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140]), Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140])), Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713]): (Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159]), Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159])), Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031]): (Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809]), Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809])), Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932]): (Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037]), Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037])), Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094]): (Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925]), Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925])), Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315]): (Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386]), Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386])), Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446]): (Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721]), Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721])), Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742]): (Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981]), Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981])), Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661]): (Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072]), Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072])), Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979]): (Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671]), Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671])), Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361]): (Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269]), Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269])), Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558]): (Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571]), Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571])), Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290]): (Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902]), Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902])), Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987]): (Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741]), Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741])), Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902]): (Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515]), Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515])), Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497]): (Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028]), Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028])), Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948]): (Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709]), Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709])), Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009]): (Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725]), Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725])), Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387]): (Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317]), Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317])), Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159]): (Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808]), Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808])), Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394]): (Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699]), Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699])), Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312]): (Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000]), Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000])), Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987]): (Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821]), Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821])), Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046]): (Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909]), Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909])), Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565]): (Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028]), Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028])), Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269]): (Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352]), Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352])), Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847]): (Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271]), Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271])), Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513]): (Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800]), Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800])), Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054]): (Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394]), Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394])), Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004]): (Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977]), Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977])), Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675]): (Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800]), Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800])), Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692]): (Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159]), Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159])), Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909]): (Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932]), Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932])), Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814]): (Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697]), Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697])), Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186]): (Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387]), Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387])), Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445]): (Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470]), Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470])), Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966]): (Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507]), Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507])), Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548]): (Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253]), Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253])), Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897]): (Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783]), Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783])), Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208]): (Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054]), Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054])), Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268]): (Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661]), Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661])), Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388]): (Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643]), Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643])), Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257]): (Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174]), Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174])), Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960]): (Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241]), Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241])), Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721]): (Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046]), Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046])), Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822]): (Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217]), Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217])), Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253]): (Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697]), Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697])), Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054]): (Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019]), Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019])), Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821]): (Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432]), Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432])), Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864]): (Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105]), Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105])), Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373]): (Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855]), Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855])), Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646]): (Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830]), Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830])), Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460]): (Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208]), Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208])), Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033]): (Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214]), Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214])), Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105]): (Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129]), Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129])), Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281]): (Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909]), Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909])), Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028]): (Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027]), Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027])), Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012]): (Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054]), Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054])), Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562]): (Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589]), Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589])), Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037]): (Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097]), Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097])), Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355]): (Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460]), Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460])), Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223]): (Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355]), Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355])), Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089]): (Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306]), Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306])), Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035]): (Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219]), Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219])), Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432]): (Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297]), Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297])), Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693]): (Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263]), Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263])), Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794]): (Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484]), Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484])), Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552]): (Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941]), Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941])), Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267]): (Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814]), Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814])), Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992]): (Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415]), Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415])), Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941]): (Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966]), Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966])), Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822]): (Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320]), Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320])), Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306]): (Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902]), Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902])), Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820]): (Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880]), Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880])), Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361]): (Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725]), Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725])), Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005]): (Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914]), Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914])), Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783]): (Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781]), Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781])), Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011]): (Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033]), Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033])), Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297]): (Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910]), Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910])), Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070]): (Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134]), Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134])), Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144]): (Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331]), Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331])), Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023]): (Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497]), Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497])), Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103]): (Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540]), Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540])), Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961]): (Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998]), Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998])), Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414]): (Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]), Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]))}, trace_len_summary: TraceLenSummary { main_trace_len: 13, range_trace_len: 41, chiplets_trace_len: ChipletsLengths { hash_chiplet_len: 128, bitwise_chiplet_len: 0, memory_chiplet_len: 1, kernel_rom_len: 0 } } } +ExecutionTrace { main_trace: MainTrace { storage: Parts { core_rm: [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 9795023497998985336, 13300695072875785024, 10130173733677792318, 11939015773035265411, 0, 0, 0, 0, 0, 0, 1, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1032, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 2, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 8, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 3, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 4, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 1, 1, 1, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 5, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 6, 6, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 5, 0, 1, 1, 0, 1, 0, 1, 1032, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 7, 6, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 7, 0, 0, 0, 1, 0, 0, 0, 8, 5, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 8, 6, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 7, 0, 0, 0, 1, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 9, 6, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 7, 0, 0, 0, 0, 1, 1, 1, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 10, 6, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 5, 0, 0, 0, 0, 1, 1, 1, 9795023497998985336, 13300695072875785024, 10130173733677792318, 11939015773035265411, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 11, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 31, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 33, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 39, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 43, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 47, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 50, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 51, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 53, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 54, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 55, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 59, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 60, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 61, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 67, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 69, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 70, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 71, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 72, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 73, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 74, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 75, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 76, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 77, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 78, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 79, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 81, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 82, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 83, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 86, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 87, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 88, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 89, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 90, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 91, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 92, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 93, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 94, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 97, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 98, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 99, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 101, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 102, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 103, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 104, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 105, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 106, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 107, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 108, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 109, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 110, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 111, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 112, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 113, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 114, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 115, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 116, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 117, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 118, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 119, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 120, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 121, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 122, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 123, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 124, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 125, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 126, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 127, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0], chiplets_rm: [1, 1, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 9795023497998985336, 13300695072875785024, 10130173733677792318, 11939015773035265411, 0, 87, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 13813148053191742203, 9801149536421508036, 8323744943735804454, 9781218902110540179, 5842910582527751306, 6515775080041612554, 2207036983008389704, 7138588223420389995, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1032, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 11116382020814057190, 14732796941305378371, 13074361791711182490, 6715193688317415490, 1571558009365433839, 13285275197432594374, 15905141483335727027, 2507840277166973476, 0, 0, 1, 0, 0, 1, 1, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 0, 0, 0, 0, 0, 108, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 9795023497998985336, 13300695072875785024, 10130173733677792318, 11939015773035265411, 12109893904215917933, 11216622576129138242, 2033568431633301211, 6175855265335479925, 2993234814900659250, 17541474196881156701, 6380009076578808155, 7007738773696586556, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1032, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 11116382020814057190, 14732796941305378371, 13074361791711182490, 6715193688317415490, 1571558009365433839, 13285275197432594374, 15905141483335727027, 2507840277166973476, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1032, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 0, 15913981378790993016, 12701179462806902902, 9645342555817022514, 6889850077248808033, 678249829196625442, 8726676798253716750, 14136118088409135949, 1027279235140821190, 8048729929177993405, 2542525775606472849, 3283471062508934848, 18058280687405074483, 2, 0, 0, 0, 1, 0, 0, 0, 0, 11899090779839289087, 1701090513954162998, 6953639183117323837, 11460660778637092812, 8345945186928076892, 11308243255833047975, 5734666540714547293, 1546649737555419076, 14643837757854608147, 7477230882792828789, 2359592855656894189, 12732146754685591216, 2, 0, 0, 0, 1, 0, 0, 0, 0, 16283412161296764998, 17261112905912533997, 1498213616014501531, 7707889409925905689, 16090493533591377617, 525010687572874692, 5228788497345464933, 13051466527897639054, 3560924095387897187, 12551242480725370445, 4038828260160651477, 6132317990703151787, 2, 0, 0, 0, 1, 0, 14261694278902826987, 16097544111075686229, 16632169854204459773, 14265791174051766329, 14732671264513481238, 15642599276989292777, 7593738854072541043, 11440582168151819564, 18258483622390056257, 6851601084855956341, 10463349537167637967, 10032876585525342603, 825669147467031185, 16271217766495541082, 9021089524754424392, 2, 0, 0, 0, 1, 0, 16780109665356203593, 16025948514351396737, 4256182047405196535, 4919013996388780384, 6974015548720770018, 10189882052640604940, 12288632186238773648, 7055558833039165669, 9820743264545515107, 7353106531603230851, 5612808106478211181, 362487531847990854, 10259224130335842891, 2374318293393776907, 16208179153232019183, 2, 0, 0, 0, 1, 0, 9496969110446094198, 10424961628901078909, 7587726188775237019, 13423955604028434301, 12288543613568774022, 4068762405627465026, 7288480650179820504, 1035430088689333582, 2651098721515326755, 4524440782000877024, 3013038852551457145, 12536534023666437466, 6560028330562582937, 9090521726813489969, 17634755409309861791, 2, 0, 0, 0, 1, 0, 15761194215082968049, 15796684185970405493, 1294179585337070936, 5701860167148115542, 17707247215386403887, 18419960639673587986, 14570347312565937582, 8634142387233894354, 11938075017385927203, 8060480374868324599, 16699922976999064541, 14234489074154948378, 17210389744085299852, 17331527780947314617, 16356838976302290254, 2, 0, 0, 0, 1, 0, 6184336662619539433, 7106147576739595100, 18237994300618329820, 9768155666925548219, 226714884885574576, 11169479382209254075, 5756676929838789145, 29803495366482069, 13128905441940840949, 18304516631519674746, 3177693875357946498, 10624850715031233718, 16956738608020324589, 10558540052020438814, 7826502712354673600, 2, 0, 0, 0, 1, 0, 1980308537464408089, 6810023246846442283, 9400257804338494201, 11246932855318952856, 7504545710540897051, 5823677062954428984, 9151299935574592196, 15905322272715446259, 18174748553199601666, 9877077233183640995, 2431998410719122545, 3541292002384422941, 5416588529930333172, 15788517205879313917, 2490575598934209003, 2, 0, 0, 0, 1, 0, 17950140321155419078, 9014768943295123367, 10707122777228105884, 10701204914974985643, 15060806908759160804, 7011191650405807117, 13598159658926423040, 3947314552577424057, 12985682730462769834, 18264715466581442035, 7667189540353817157, 7685483800933651249, 16085167604591833455, 16105855167414075111, 16215395602017884846, 2, 0, 0, 0, 1, 0, 8676227747932036802, 0, 0, 11504729673400082663, 3659553513673892306, 10374352082945691939, 15819529278889203623, 18107940902385670152, 8889798095480337831, 12737345777792032790, 456604824069734238, 2859376131275373721, 8758251935142908528, 2364536875264708997, 2435873391009301907, 2, 0, 0, 0, 1, 0, 0, 0, 0, 16797630026773069829, 16954579754978210547, 4393671449525183699, 6245909065255485436, 8311309349844601638, 3305827896314343556, 1615477551160071258, 3897903986825909618, 13015230208471866351, 13839070994009764281, 2415598337053791919, 5526300544248852335, 2, 0, 0, 0, 1, 0, 0, 0, 0, 12827873667465929582, 15892701250663610383, 549489834728826775, 9425334953627649153, 15402634395731091512, 11814416271399500934, 14597718118926923662, 4726679541432826422, 342915941842538663, 11221492717904369823, 17188959961041335276, 13559932473868727168, 2, 0, 0, 0, 1, 0, 0, 0, 0, 8689096602925893779, 4096531352684607500, 8424481237826564505, 15238165026175259240, 10985176737527635898, 2672540837788784952, 6649439643634522762, 7581835251244605715, 17671970641549389116, 18069913154458602790, 749417941228438762, 6150863900366154379, 2, 0, 0, 0, 1, 0, 0, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 11116382020814057190, 14732796941305378371, 13074361791711182490, 6715193688317415490, 1571558009365433839, 13285275197432594374, 15905141483335727027, 2507840277166973476, 2, 0, 0, 0, 1, 0, 0, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 0, 0, 0, 0, 0, 108, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 12512288845269211131, 853499250082959838, 13488661663129764539, 8125050245190817108, 3804813068188359937, 3313483727945122453, 12360781197875022983, 12306355678569585549, 14131911740731702820, 4051317191743228419, 18012527566990830204, 10255515555502453711, 1, 0, 0, 0, 1, 0, 0, 0, 0, 13268666745610888359, 5035299923140309359, 9492710178938090874, 16432193728393177858, 488197519654209705, 16306861889432269511, 12965290967174006273, 5899276799385944982, 4732569325232601941, 17250390449616619232, 2263709671564173949, 16014366373996617459, 1, 0, 0, 0, 1, 0, 0, 0, 0, 6251349156658906743, 8609811827979294882, 16396123621276698425, 4191392625375252196, 13118130563168054808, 10137725945150597993, 17091661325003867912, 15987533992994607704, 16422379462831291528, 12094114857378650954, 1084226545221903173, 6915613376340340043, 1, 0, 0, 0, 1, 0, 1534645424544051783, 4642164202005224189, 13639350595321647774, 14997123658379691665, 5095591508188209815, 17378968424157853898, 3319587194701345303, 7912013546961175954, 13058442299138466556, 113820789366504723, 979480813836484063, 12810935507899622334, 10071317704529062824, 17157647224138114155, 86309787246248239, 1, 0, 0, 0, 1, 0, 2913198445711677774, 9888361099408058975, 6942011412713736468, 6203537965825290504, 14477641448356369216, 8203223455911494092, 6384931917509725098, 10942323986007690541, 2372505191155982696, 13505926961374950297, 9863815224566244166, 12000427914776781281, 9676867145055745792, 16197034225912806058, 14661960577890819530, 1, 0, 0, 0, 1, 0, 15190546416264078116, 7775818643073018412, 9071871860943081771, 1416093219274823693, 5963314482819748512, 17442313688172807287, 1561163009835858446, 7267981992016523791, 13647940476497044011, 3432681625158272448, 1993371153287576489, 14086944830164184302, 17901613865752995639, 9876439357546613309, 1905959172944565459, 1, 0, 0, 0, 1, 0, 16787762740302082173, 13687172702509280801, 13829601699493328726, 13077396723920915658, 6334600257668993247, 16005831570146470727, 6870535038357161642, 3318715655314199213, 1604329190047159158, 13627534697145261227, 9687118959345407025, 1168709924583816553, 13777237771639017487, 6657527270060440390, 2805827836820765534, 1, 0, 0, 0, 1, 0, 3605868392435965294, 253522748327669049, 11011264558059064878, 6160836649233708903, 12171046083408363106, 8043060876658338795, 9860685140977757959, 4159667182749534960, 9273137746535878130, 16329758115433750926, 6949713863289936704, 14729752357791305157, 13443252680326955644, 8704483663624610247, 13845644156795384523, 1, 0, 0, 0, 1, 0, 1381807822628776459, 6185989713666623112, 6906262917832007676, 12034839856630957225, 1124098930189483722, 10617691351745831328, 17046424117532723784, 18328837382080531957, 499124217804614118, 7054779445715304974, 14721592817235079691, 15438177461805878082, 4893763607985641131, 14735613271204743175, 11055989889840127175, 1, 0, 0, 0, 1, 0, 12865381359176879968, 2554523313877966954, 7294679159466444323, 4506042742239578122, 6099115752699339215, 15220891401986890192, 12223236740078007539, 12409048149390343723, 16157310078954948179, 5713143862578741194, 12176609611331176615, 1208131014354067353, 8416999318707249338, 4632186832415650928, 4787230416960148769, 1, 0, 0, 0, 1, 0, 8430676800162925096, 0, 0, 8496072762751336805, 16886443911130558975, 12033532278877703853, 15851236173354166236, 15013693898292177964, 8135782089737993532, 1771838547975961981, 4211538783056899457, 1087116229540095042, 13570948918462148235, 13789448633689060947, 15910710132207983081, 1, 0, 0, 0, 1, 0, 0, 0, 0, 7928740039385897882, 10727806439135124602, 7646638143768945898, 14819732602933823085, 9587178260979641455, 14797965785210665193, 16685257700649146157, 1815375165055766101, 9227997262307743106, 10732992718179136350, 10791645390406102219, 3748207455775523223, 1, 0, 0, 0, 1, 0, 0, 0, 0, 15502106930635125896, 14713985548484747994, 10270851360514545566, 7322520777221196131, 13829203811429967568, 3578695923684700475, 15476694481212406519, 17447568335080248836, 16980404531860824247, 16570689533324192389, 8333013671770279648, 8383746024118130204, 1, 0, 0, 0, 1, 0, 0, 0, 0, 17958915377109677965, 15689157688771292017, 1337195173853601995, 12055027230426124267, 11003189687841806082, 10219528601216730754, 5064732806791575544, 16072502552074795611, 7851615748612726715, 15271023857443749252, 13107834510030116795, 17189900208955315576, 1, 0, 0, 0, 1, 0, 0, 0, 0, 9795023497998985336, 13300695072875785024, 10130173733677792318, 11939015773035265411, 12109893904215917933, 11216622576129138242, 2033568431633301211, 6175855265335479925, 2993234814900659250, 17541474196881156701, 6380009076578808155, 7007738773696586556, 1, 0, 0, 0, 1, 0, 0, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 9795023497998985336, 13300695072875785024, 10130173733677792318, 11939015773035265411, 0, 87, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 647798198322186763, 6592792203074652875, 17476824078129141338, 17767912865459160960, 12302196565172406159, 7133118425001032114, 13036064078204647105, 12154160758539910974, 12910600937056884084, 6562813264032936877, 17375732645941164592, 10668415322419739982, 1, 0, 0, 0, 1, 0, 0, 0, 0, 17688107483147659424, 3826470524415365168, 15397518990548874541, 7384515665769464908, 11530227496484511911, 10894583914980996271, 11471481017983097595, 647782521607901735, 6043493769912162117, 15718422881208362819, 16775781916941621047, 3126686215251231764, 1, 0, 0, 0, 1, 0, 0, 0, 0, 17869525775473816866, 13995241216315274115, 14157490272424291288, 12595361644534565853, 12216357805740360097, 1694591003072000395, 3743605083914104716, 7861948909415027744, 13777320358159433695, 10689965220940509198, 4900308999419319661, 11865597697730630365, 1, 0, 0, 0, 1, 0, 10853190877700104359, 6532325916675391436, 17332182286650619204, 1356390314429927430, 680063998460740918, 8263520885737962336, 18031038291900560110, 7916313783579135045, 1390923500114638504, 7357257710265531874, 18050819232629601946, 3177304029089432776, 3356183043120314110, 4896437526344275110, 17783772191254049099, 1, 0, 0, 0, 1, 0, 13700841206357793383, 5242897844664901975, 6931875987485621525, 13535345953969129244, 2030741039344819106, 2762531947819167934, 1589867303015706387, 12511013938757434078, 8759705058299416073, 17894980373425490293, 119389077056921696, 1349552240585307632, 743126002153768243, 2283053310727276098, 4623381538665208128, 1, 0, 0, 0, 1, 0, 6666301890538843304, 15100184186909227104, 13104585709762494144, 16067212803475054780, 15532329799213457697, 8334881840944266358, 2517121414305531206, 9226292579245106006, 17087207871947927046, 11092098231878012627, 10970068856242050959, 11581725042784187604, 13304428174381080582, 15591901374250498087, 14932175652999057387, 1, 0, 0, 0, 1, 0, 5429713005191529599, 485169140917582212, 4576842161780004363, 12062213544561319942, 11418995341251578421, 17152905263785336993, 1631276317082485483, 3568887030966752039, 3361290037864726245, 15436522396033313024, 17085807233874391210, 8147970228355894659, 6261462177346527521, 6933857645565178124, 7551583744620273002, 1, 0, 0, 0, 1, 0, 6807448188965543153, 9507596951835777611, 11958721233767021404, 3380817682214556522, 16170609460104531156, 10111115936627491028, 3604487074555980458, 8451136074985746484, 5442720530348853678, 9471235153819067672, 10672876360944965833, 15381377407789231918, 4737142352428164538, 8819307315481053031, 3302024672420588861, 1, 0, 0, 0, 1, 0, 8272992415832567053, 10756755112993818184, 10057238749770162032, 11156441887212538418, 3098818062082866526, 4253492566197441506, 8767167317332381804, 17223395584715517067, 6083768282731854197, 15287591782061935966, 1749627974902211442, 11405958977712175628, 12451241949260942894, 5075882627538566638, 5802029065265737628, 1, 0, 0, 0, 1, 0, 115043481862425790, 8259507034822886871, 12751027772465443875, 14559366336196618760, 14638271998745396609, 16008945461034236, 3946239166811380672, 12563230741835717849, 12528039909892426334, 17476972384961842195, 14568804827433702794, 3163555765045496501, 9857342525699923921, 5170133709252280486, 6934457598776258250, 1, 0, 0, 0, 1, 0, 16607251464683034540, 0, 0, 16598287690982947812, 17624625052233494012, 18382683990989729838, 11627160828668855898, 2837237790382853743, 17608254328373195204, 8384927093614621388, 144360432842733232, 4955652552073033885, 2877948804182802216, 14754884514108307037, 8237817611365992649, 1, 0, 0, 0, 1, 0, 0, 0, 0, 14243997351069122112, 6885597843867247745, 5829165866197358838, 3828442679559769924, 5962955824096586186, 5722638855509675004, 3866341543198538266, 10395572289151695247, 11957833676204658018, 7226351981553525019, 13730521644769894866, 1730532664872069974, 1, 0, 0, 0, 1, 0, 0, 0, 0, 10057186991882797037, 13979535426176151003, 3368993333474359559, 15087545933098252019, 15471413093926581707, 13303729614330622172, 5722877545315066256, 8676274815465763770, 8482044564546020834, 5141673631152671885, 384165086974752860, 13639880556665716509, 1, 0, 0, 0, 1, 0, 0, 0, 0, 5245170599699700602, 10291681149902218321, 11746208067041323698, 11709563291311499632, 235501757784833854, 13623063482483079236, 4703846003811315010, 17004989925486193850, 7023073680354827593, 11626271086934648748, 14817075775725990184, 4763888723549665869, 1, 0, 0, 0, 1, 0, 0, 0, 0, 14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053, 13813148053191742203, 9801149536421508036, 8323744943735804454, 9781218902110540179, 5842910582527751306, 6515775080041612554, 2207036983008389704, 7138588223420389995, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 6, 4294967292, 0, 1, 5, 0, 0, 2147483648, 0, 1, 0, 1, 1, 65535, 16383, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], range_checker_cols: [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2188, 4375, 6562, 8749, 10936, 13123, 15310, 16039, 16282, 16363, 16372, 16381, 16382, 16383, 18570, 20757, 22944, 25131, 27318, 29505, 31692, 33879, 36066, 38253, 40440, 42627, 44814, 47001, 49188, 51375, 53562, 55749, 57936, 60123, 62310, 64497, 65226, 65469, 65496, 65523, 65532, 65535, 65535]], num_rows: 128 }, last_program_row: RowIndex(12) }, program_info: ProgramInfo { program_hash: Word([14702774402853413141, 15069487866135976146, 6734468535935735084, 4533503067745498053]), kernel: Kernel([]) }, stack_outputs: StackOutputs { elements: [1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, precompile_requests: [], final_precompile_transcript: PrecompileTranscript { state: Word([0, 0, 0, 0]) }, trace_len_summary: TraceLenSummary { main_trace_len: 13, range_trace_len: 45, chiplets_trace_len: ChipletsLengths { hash_chiplet_len: 64, bitwise_chiplet_len: 0, memory_chiplet_len: 1, ace_chiplet_len: 0, kernel_rom_len: 0 } } } diff --git a/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_13.snap b/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_13.snap index 7effc433de..11ed9c2d2c 100644 --- a/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_13.snap +++ b/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_13.snap @@ -2,4 +2,4 @@ source: processor/src/trace/parallel/tests.rs expression: DeterministicTrace(&trace_from_fragments) --- -ExecutionTrace { main_trace: MainTrace { columns: ColMatrix { columns: [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 33, 33, 33, 1, 65, 97, 97, 97, 65, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [7458506668679174706, 1032, 8, 0, 7458506668679174706, 7458506668679174706, 1032, 8, 0, 7458506668679174706, 10762639943655126491, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706], [18375473735916206629, 0, 1, 1, 18375473735916206629, 18375473735916206629, 0, 65, 65, 18375473735916206629, 8123069549705052795, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571], [2105717247508690050, 0, 0, 0, 2105717247508690050, 2105717247508690050, 0, 0, 0, 2105717247508690050, 10333571018226702209, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072], [1679902783560062568, 0, 0, 0, 1679902783560062568, 1679902783560062568, 0, 0, 0, 1679902783560062568, 3763553361837852375, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968], [10762639943655126491, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [8123069549705052795, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [10333571018226702209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [3763553361837852375, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2], [3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2187, 4374, 6561, 8748, 10935, 13122, 15309, 17496, 19683, 21870, 24057, 26244, 28431, 30618, 32805, 34992, 37179, 39366, 41553, 43740, 45927, 48114, 50301, 52488, 54675, 56862, 59049, 61236, 63423, 64152, 64881, 65124, 65367, 65448, 65529, 65532, 65535, 65535], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [7458506668679174706, 17262866120583049312, 1604139919365911138, 5113851726573374470, 13536996102937200288, 5144547684530650448, 3655783001982481850, 17854454697671763355, 16371583576737997647, 15021252922727947001, 17129020395602960691, 12027296227437859344, 15768109424081379298, 5534448791232096558, 5035998873325494463, 58659117798024738, 1950987668385367835, 1047959670635367230, 7199802506274179843, 11627650263155381900, 4361064659696575038, 10347120495653094676, 14070050808875715623, 75544510591201674, 10341266954735171749, 16977730335508259685, 2978522689205632800, 8395315594913867980, 3061960129452262767, 5601779727658274094, 17491526265780712239, 15233389079858696706, 1032, 10320, 13024110921086730221, 3587442816163675215, 512402747638547729, 9217956011885162917, 3925750957223009950, 8674177413178223320, 12846799727083908462, 9116601283268739756, 2958792353189815054, 1720195204565087693, 7696852080146622077, 2890877729556257606, 16676527939404087356, 223754558788184593, 4767414622778376421, 14072300156908432530, 16856861612825314654, 11910434229443384600, 15658716527747040980, 14322127566252286435, 4770460127206402609, 10805338145914832851, 1391598300875421210, 18211456042978337510, 11866022853402812888, 6438324596032750504, 13328288515202849800, 17331158106613184460, 18344276842462151560, 7458506668679174706, 7458506668679174706, 14091156936533878324, 7375572182970693729, 14515360628218652783, 7553352677317462240, 10955938084877387415, 1034062223635325003, 16019914937455843830, 15206938952668638091, 4012447997079815331, 5665102116197551876, 3770800016172304546, 5393161755790695273, 11037954541995943116, 1538549641630821923, 82458381601698052, 11256540292329595942, 3662649950675088442, 9310380056949111902, 9078793057127894263, 12413466243433342378, 11963713252400458519, 17170011751313180080, 3131690541743081493, 1565661301057382940, 1661897422826290746, 14617639341020367486, 14014187841969039807, 6350121359078755518, 1074154985721744973, 8576960520729553430, 10762639943655126491, 1032, 10320, 13024110921086730221, 3587442816163675215, 512402747638547729, 9217956011885162917, 3925750957223009950, 8674177413178223320, 12846799727083908462, 9116601283268739756, 2958792353189815054, 1720195204565087693, 7696852080146622077, 2890877729556257606, 16676527939404087356, 223754558788184593, 4767414622778376421, 14072300156908432530, 16856861612825314654, 11910434229443384600, 15658716527747040980, 14322127566252286435, 4770460127206402609, 10805338145914832851, 1391598300875421210, 18211456042978337510, 11866022853402812888, 6438324596032750504, 13328288515202849800, 17331158106613184460, 18344276842462151560, 7458506668679174706, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [18375473735916206629, 6249454237774489531, 9157878094690374909, 6425669842054368493, 2701132623000331756, 17379641915532686294, 5560495940744274531, 11612441789282260948, 16999709768989875265, 6996700069669527727, 18218056048932681656, 17323420959416556496, 466802243942182139, 11973093936801453371, 9146724945876234312, 7489576767990881255, 17520081994390187724, 12872469591277262776, 16839284714279473816, 8284906559011073539, 2830433105177125840, 13008883457151437178, 7615615770295186136, 8044553197656770543, 10297444041327462885, 5697734349102267077, 10790124910810980155, 9679484750905502198, 13726494118104201951, 15750438276851199178, 7407323102906641682, 4869430190272581571, 0, 8256, 1131208899036558480, 1667157010810320250, 2053960715201569301, 1526213270499333709, 69813565043892453, 14925652377538846871, 1380252317064967448, 9902934070223067140, 3786794161520721521, 664031068804619792, 8470323998416702977, 4965297830526000942, 9404280000999464502, 8244737495337250711, 4784363486033662704, 4680481291290566437, 15373555507761845373, 8780119261264514018, 729009684537575982, 18306419558979237700, 15407410920890065538, 2509966126115291236, 12709897403480972846, 11498596868429821859, 6606875518512322314, 13880694912200059110, 6972406840307481976, 14148490408465275064, 2917966740410115114, 18375473735916206629, 18375473735916206629, 11043817201346618241, 11930265205656561266, 10224097019891343377, 748994844361267888, 16702335214860257337, 12190724893927857742, 15379261811913612411, 16916810907472200588, 3208814004368724195, 3855578449388338708, 14165119338755346303, 6632649140152805373, 2797795394808561009, 15650881762132647945, 17209782644178391817, 13783743867565375293, 10090924967376195547, 7343319863281531122, 3154891837622088858, 15555070991869858832, 3720214064901529690, 16228854173327781424, 14339877087618729700, 6737780555657097058, 10816148347772460352, 6888313430102783827, 11552248269785226165, 16919207520546831674, 859159578513939084, 3809060186754369406, 8123069549705052795, 0, 8256, 1131208899036558480, 1667157010810320250, 2053960715201569301, 1526213270499333709, 69813565043892453, 14925652377538846871, 1380252317064967448, 9902934070223067140, 3786794161520721521, 664031068804619792, 8470323998416702977, 4965297830526000942, 9404280000999464502, 8244737495337250711, 4784363486033662704, 4680481291290566437, 15373555507761845373, 8780119261264514018, 729009684537575982, 18306419558979237700, 15407410920890065538, 2509966126115291236, 12709897403480972846, 11498596868429821859, 6606875518512322314, 13880694912200059110, 6972406840307481976, 14148490408465275064, 2917966740410115114, 18375473735916206629, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [2105717247508690050, 6189083373333363630, 2656177146482477345, 1057347249925241992, 12877193726173516655, 12251509207411105210, 1152241254719451449, 9876796305008770402, 13886895990537049692, 5955094425987607481, 1554095718593181827, 13216497717183331409, 776902023022590964, 5811111240012717463, 4275189229324905850, 13670290926832689868, 5572024486552078020, 17065492216843752601, 3297004024924317076, 14424352157875397982, 17390634589199639220, 6197470634991589920, 4408358210817562027, 2934098723242191367, 1959730788177155769, 17690050280182053134, 3272945528020851774, 10688942373536545422, 2313436297690393057, 9701508002112089263, 1542465249691690504, 15500832090051527072, 0, 2064, 18136552782870868471, 952274539956745973, 15933282259815262093, 9924516287334785738, 18064603646801610993, 5114527609957824263, 11816233963570869158, 17699527003452380450, 14533708946479200173, 17484213571014188868, 832814531422633701, 1508169308733590908, 8423043379628164525, 12595277727969636921, 14226276023010866965, 10485112285448962747, 1783527593060720204, 10145484005384627580, 7463752398658534839, 17345550819494003223, 4432309123412733588, 7086318781105575433, 8830891075082588619, 310185093236608634, 16683125300631590273, 7786799186167080425, 29465347809991832, 8090161351836983773, 8665315444141111469, 2105717247508690050, 2105717247508690050, 3724970573052107061, 4114673899889075534, 9176940842530023940, 7547336479279255184, 11656391078860305642, 295623386594127504, 16942248732504945228, 13682452505450251602, 1932912055656971408, 2726480361376479149, 8421050872483387862, 15290165883438443901, 1096575918097796357, 18242297745273113718, 17017163620459148710, 4241087992417717505, 2254013451933557848, 3831151314405580129, 3571435480437187779, 3526382752987906743, 10913818845540317263, 2010650094200565990, 11538983127386740908, 2393120920072159035, 9645620379287089841, 14221268644167684727, 14318256705345657556, 2619120800729679292, 841980681719838180, 13388339383354858226, 10333571018226702209, 0, 2064, 18136552782870868471, 952274539956745973, 15933282259815262093, 9924516287334785738, 18064603646801610993, 5114527609957824263, 11816233963570869158, 17699527003452380450, 14533708946479200173, 17484213571014188868, 832814531422633701, 1508169308733590908, 8423043379628164525, 12595277727969636921, 14226276023010866965, 10485112285448962747, 1783527593060720204, 10145484005384627580, 7463752398658534839, 17345550819494003223, 4432309123412733588, 7086318781105575433, 8830891075082588619, 310185093236608634, 16683125300631590273, 7786799186167080425, 29465347809991832, 8090161351836983773, 8665315444141111469, 2105717247508690050, 7458506668679174706, 7458506668679174706, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1679902783560062568, 5453149304543877456, 9595010673478717796, 2952696768975672640, 8134038032300527981, 11332133599874182390, 9024753214576304672, 857162913496477952, 12013033971053205979, 4600756375093602184, 14082822594797913170, 8883202514107224654, 2439806288455133669, 5376354024916878032, 7594752061560203213, 5093440171701971002, 11786562020391663198, 1236915402111178740, 13738296853496739000, 7765385093473679298, 8013578318153954341, 11778596345025144994, 14965315602871180353, 15355585492520345027, 3683028660232663225, 6851384090147864767, 10508624984882018667, 1397413665818442288, 2862574062899872918, 292885921741812279, 12978790960819480190, 15232111199771387968, 0, 2064, 9594118340025725004, 16218246678075491818, 11582919835122342747, 5661452934218108707, 3714647928422746674, 13689184893219719187, 1899963197709801965, 8313716591368695784, 17822645741084942000, 18354595702287703799, 12620512717427217848, 10145637708639089787, 1735222492513760332, 14681927838838900060, 9262747238997471758, 11498487923782501751, 8924101344488972446, 2592517964915386184, 4276681409258176044, 3764365715267793208, 3120204268813370353, 6019260256544801113, 2801984351776029768, 16979166255722313516, 2813750347113564525, 16588139065369475399, 12012198471360912693, 2492059183640657261, 16968938268466755316, 1679902783560062568, 1679902783560062568, 14885555914322696706, 357898588148103340, 5295486817886607656, 12813840270094930087, 14997912950175773344, 3065571107994870550, 6045840981748218070, 6913190410219799142, 10694613226894070186, 13202643588773009520, 12618454603290221396, 4286869539192998442, 14688825675433502322, 6261505341338998374, 11526290763485067527, 13595735573859078719, 11176916463285615298, 18361875051234113789, 7745326199098368365, 16699599314531576118, 1870816068625375840, 15123892811152051673, 13015893667273525423, 9102343296676237120, 3339334071833702047, 15390057062148905453, 7122136282318587603, 9966134226732180184, 5538826350883883796, 9989685048829963204, 3763553361837852375, 0, 2064, 9594118340025725004, 16218246678075491818, 11582919835122342747, 5661452934218108707, 3714647928422746674, 13689184893219719187, 1899963197709801965, 8313716591368695784, 17822645741084942000, 18354595702287703799, 12620512717427217848, 10145637708639089787, 1735222492513760332, 14681927838838900060, 9262747238997471758, 11498487923782501751, 8924101344488972446, 2592517964915386184, 4276681409258176044, 3764365715267793208, 3120204268813370353, 6019260256544801113, 2801984351776029768, 16979166255722313516, 2813750347113564525, 16588139065369475399, 12012198471360912693, 2492059183640657261, 16968938268466755316, 1679902783560062568, 18375473735916206629, 18375473735916206629, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [10762639943655126491, 13388996836365281621, 18292910592958568240, 12237721921963192287, 8943209618246977520, 17924245204927493750, 8434099123041054143, 10575898537057061569, 7340771781180054840, 12844549286514316999, 12231131842570129507, 16875123239233429747, 3964564537195320111, 5715220285758953899, 12754036126848799562, 18436803950002947068, 1770169068010173560, 9424981723294470612, 17771283980301938781, 15212703043278891550, 16986576216468074674, 11657506507106753305, 12474701290169643873, 13224479227546334120, 2845122065365884365, 13589399096280778905, 4675637374086440016, 2796167990897236857, 3556539463682311357, 15865424937925414652, 3385987959754514103, 8819338964313765439, 0, 5160, 1190658701913535022, 9371121588404883743, 7133056533056999470, 7380100170229652082, 14719783382686670107, 4693530971176924881, 11125714198188567552, 2434816259070577714, 17927785478103501878, 834873962620943786, 1091858408197145201, 9293176204765248193, 11318806736621162148, 979530496520387452, 8328113718786640843, 15870139479256453021, 7754853849459016697, 2742936430580983415, 6806060556807781604, 5089080673677611112, 16430235900965466453, 309743103212430298, 15664803780047891222, 3113571524475220627, 17862871362988443440, 1231393200801541530, 15779352999894925288, 6026600320279882336, 6970552753544824994, 4949154992619464010, 0, 7045578468266939526, 7285583783616369700, 2341840897571774669, 7986574489568710564, 12566560672680462445, 16276641203995750872, 1484828875872057093, 1043080754823121706, 14953544298592652410, 1857761078137818000, 6862941658795962417, 7623278478713901054, 9161331715698713896, 2770593420692286823, 3760546371254144518, 9012199850736714078, 16164469939521445727, 3279768234486766882, 1877833914786208431, 6746861716770001362, 8593640503056413152, 8414605328494867260, 10458069463001905889, 16457099907011561259, 16703249241540341232, 12864763495673156246, 6953851240052973821, 11069840221589825139, 2743129109919723025, 8185888587159810481, 9760033137073938718, 0, 5160, 1190658701913535022, 9371121588404883743, 7133056533056999470, 7380100170229652082, 14719783382686670107, 4693530971176924881, 11125714198188567552, 2434816259070577714, 17927785478103501878, 834873962620943786, 1091858408197145201, 9293176204765248193, 11318806736621162148, 979530496520387452, 8328113718786640843, 15870139479256453021, 7754853849459016697, 2742936430580983415, 6806060556807781604, 5089080673677611112, 16430235900965466453, 309743103212430298, 15664803780047891222, 3113571524475220627, 17862871362988443440, 1231393200801541530, 15779352999894925288, 6026600320279882336, 6970552753544824994, 4949154992619464010, 2105717247508690050, 2105717247508690050, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [8123069549705052795, 5156554708236344275, 14240818815081743895, 9867313438556302162, 15795460020964061272, 4746638863317237450, 13819676251412656237, 4727422680796194490, 8335480078758159858, 9036771623022810541, 8351265204536669701, 9236720663990755838, 11452649604190176127, 17344644189632397547, 141238439626841910, 5940293383350715760, 13513881994175113234, 1766672227767985245, 5047254911149411718, 11537743148965787196, 11119902426374535999, 10562233986963391039, 5709991789928772648, 8741809910406193485, 8455014431114507154, 1111308100041845231, 4725453465222465298, 18262636953418597987, 3114326789966402908, 14795199298580283463, 1803230571695746105, 6301331656216941589, 0, 4128, 1352424102745866255, 13301242752201603536, 5420135027930584396, 17078794493496835379, 4779811836607866048, 3650219859599657886, 13618468821889769363, 11429589192023659923, 8853101337885331080, 9650238821992519861, 14401087967309285252, 12035560952634921032, 15407186837043713393, 15711028160746246110, 5396976350889627712, 15903424027416555998, 11304777107657759509, 9857843669692965578, 12605480788735099613, 14618970056708743810, 8493993205782554647, 6059068631740368787, 18316971448227884023, 12499808993385025318, 4210674244211222629, 18405965507148502967, 173097048437312502, 15568437290332308327, 11532601739151124629, 10000279862191744493, 0, 14745280635380601593, 17607190493438925163, 11648589526377348791, 6243809814482637102, 16161225923217405001, 4968707009078818352, 7850088573615079578, 16921347809582866242, 14652545103008190675, 3872738867357780593, 2726731287352881882, 192228728999281395, 7091916593754280269, 16410861698623401699, 1724516719793133637, 2030640503060349569, 8472956584581079805, 4062370463253756874, 17250202004686581488, 14985797666948203666, 16191245541264589205, 4308256905478940952, 7707331357694852335, 16083843991369764206, 2809575014506442646, 2531361488896305650, 4074765595145570620, 16198584180859672852, 2331298026793641183, 10607839477677695183, 18135156828501150556, 0, 4128, 1352424102745866255, 13301242752201603536, 5420135027930584396, 17078794493496835379, 4779811836607866048, 3650219859599657886, 13618468821889769363, 11429589192023659923, 8853101337885331080, 9650238821992519861, 14401087967309285252, 12035560952634921032, 15407186837043713393, 15711028160746246110, 5396976350889627712, 15903424027416555998, 11304777107657759509, 9857843669692965578, 12605480788735099613, 14618970056708743810, 8493993205782554647, 6059068631740368787, 18316971448227884023, 12499808993385025318, 4210674244211222629, 18405965507148502967, 173097048437312502, 15568437290332308327, 11532601739151124629, 10000279862191744493, 1679902783560062568, 1679902783560062568, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [10333571018226702209, 16014082921795859036, 12629006099543903781, 11629549595353476530, 12391817649960371746, 18215572691662216416, 9770277866850602303, 15952392766460324197, 15252935280552519544, 15112355243278003890, 11730975142866437995, 14381423242728406980, 10300190929163106289, 5789021531153320332, 9467399003606204480, 16325741572454755376, 8742203160529149671, 5901287082041632906, 6770325052904344921, 9452634477113688134, 3864284104719206717, 1425502383761932940, 2603361438916393613, 13866368315332604201, 9048180624295164267, 16476448149297980239, 2875474760261200724, 13145957222015138318, 10421862999996593301, 1295265690517985261, 16925389328505591881, 10498339818362385984, 0, 1032, 4798141223555508282, 12962488577647927717, 10133257770726709126, 332864556927106185, 12116126881643349994, 6604148216925166409, 101015634312276042, 15934992137290074922, 6112274855072540816, 17762248064501548615, 13166189948742588777, 270100349969833402, 13485211244653928073, 3502306881032295169, 13607663468974078519, 8883940618995723208, 10623667092532612652, 12293715092576816840, 10386976621364522928, 9128135834925108269, 15731443845270647366, 13373704167654916087, 13746187061551926812, 11684868053863796759, 3258729720361659960, 10434904637843727165, 7034851303745741351, 16133345873308301364, 5426492436527662130, 2980140658145787783, 0, 11085857321233345847, 2980560268975659509, 16677115946292689576, 6374023427586874052, 13803600456482333144, 17431196185821251777, 10464217353719819983, 6438571068779754291, 13603500087699002662, 16932213864431306166, 2730762088957911453, 12429723114079333001, 8118452627061731933, 8355576936208207930, 16312459584950423998, 13584079343885951211, 10089145279525513149, 11716103245047864025, 18203686573852208977, 4067749319688593665, 3265941627325086351, 5632283698331253382, 15760522752058781932, 12058385795435302938, 9091954158859286830, 6057235671332894001, 8049826081078855168, 8520182244182315667, 11739746407539790532, 15346229459908117188, 12074025836888921857, 0, 1032, 4798141223555508282, 12962488577647927717, 10133257770726709126, 332864556927106185, 12116126881643349994, 6604148216925166409, 101015634312276042, 15934992137290074922, 6112274855072540816, 17762248064501548615, 13166189948742588777, 270100349969833402, 13485211244653928073, 3502306881032295169, 13607663468974078519, 8883940618995723208, 10623667092532612652, 12293715092576816840, 10386976621364522928, 9128135834925108269, 15731443845270647366, 13373704167654916087, 13746187061551926812, 11684868053863796759, 3258729720361659960, 10434904637843727165, 7034851303745741351, 16133345873308301364, 5426492436527662130, 2980140658145787783, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [3763553361837852375, 7024708807018294243, 17577226387288678131, 13716375462026905857, 14482978747921062164, 17754397088096536098, 2341715857705720364, 3724235583902658756, 12360261201437984812, 730185504501270972, 15524246669712397578, 7810652382804679854, 5971697062339273781, 5708809062652245260, 16177446039571837537, 7755082824309561098, 1927394300565043315, 1165019439709787271, 6617008402134939344, 3603778144996964306, 176242085391797703, 909081700857492913, 17467207375025427139, 2699428799277364714, 13677833070933733895, 466181988870620953, 6186708066785434963, 15657067447011081019, 14062022826502957095, 761626268401747468, 4218839459301981158, 16913863751850228813, 0, 1032, 11702782905971311743, 8115486282645452027, 16425371230714077552, 10333496212804492507, 1572943607289284437, 13244361396034453954, 12880029163967100393, 14716450796809578181, 2618965885956593171, 1606019581379521796, 12562170441304287563, 4599116799417823473, 4257071131168813417, 10446583017549019711, 3570388907037362614, 11170081717188072664, 17238997244398394333, 17231192964516960933, 8123337005847551087, 7060091366977384949, 5719725530909274667, 5057603743378325948, 13848013489728729143, 17729739340387068117, 367186060507240673, 1411195984452924204, 11088333491201093194, 16575090776691519559, 16147396598096989679, 14525300817521856881, 0, 7442777957161348405, 9840729387235286710, 5900691155193699968, 4972370306575754106, 9622663477343810731, 8634190114258092107, 3115968329113702329, 407029562402079548, 8621676138210350854, 17169697721720642078, 13787761240489595746, 4665424646389854706, 15962032776378499122, 10283190965555694067, 13646278760603062560, 14461293318223306846, 15816981584402185692, 10710878099338717350, 8561420609988943751, 11090271778037546558, 17906181318089402198, 13930473893330665754, 1680786918385336269, 4346813073489505623, 588116911830026470, 1138114433189805556, 12813431130535659481, 17403245364016302552, 4250865385724499409, 2341302228431136742, 12052022490343773172, 0, 1032, 11702782905971311743, 8115486282645452027, 16425371230714077552, 10333496212804492507, 1572943607289284437, 13244361396034453954, 12880029163967100393, 14716450796809578181, 2618965885956593171, 1606019581379521796, 12562170441304287563, 4599116799417823473, 4257071131168813417, 10446583017549019711, 3570388907037362614, 11170081717188072664, 17238997244398394333, 17231192964516960933, 8123337005847551087, 7060091366977384949, 5719725530909274667, 5057603743378325948, 13848013489728729143, 17729739340387068117, 367186060507240673, 1411195984452924204, 11088333491201093194, 16575090776691519559, 16147396598096989679, 14525300817521856881, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 10217287652316111123, 13517781640136319575, 1661113771033030694, 16589784235244657737, 17095733862217014640, 12034870070859925254, 3362052720054026253, 14837478738765105779, 3912940502921138924, 4669997399462018425, 17270138094532924819, 1214102817436621233, 9054176820646026827, 14620454815482057063, 14379345126022103590, 1237842674755258205, 7292827283948466879, 7427352618130823166, 7062449106203043729, 4684102489113893021, 9822227459662699800, 8534835061687915045, 6887380873242738838, 14418031150463989616, 221488275360631569, 10086890380770548477, 6262776103179261925, 1645321375146597351, 16239201862143352504, 15053642145439578838, 2190556552135086015, 0, 5160, 18346837778669738664, 15130142357101091527, 6726588340010678615, 8394319278312203283, 15942424551308612685, 7629500615465222065, 14939877513325106589, 17048523965011794048, 2306293645521445312, 823113708878672797, 14981348226783328932, 7432878333905782051, 3482639998457803800, 632277917380007036, 18266437030920184246, 3366715262389109205, 5280275432441977334, 5379329043314533811, 13912213856326486056, 17217059915921675075, 15634373017412823086, 14981257187297131103, 16697350900700022325, 5239234081629986555, 3229291246709926782, 18373224696258292584, 6771862800272250893, 7666370275789511263, 12942227631865082960, 15190222347874856922, 0, 7045578468266940254, 4295968767249300726, 5119947407811220060, 9698255539411717765, 12731464969523549591, 10964642791546394204, 7030591121083126444, 7491881549557152759, 8712880758165105101, 17597004205156968556, 3440400661109297059, 18367279145997928908, 7289973069099595657, 16259498994873975520, 16637999468821149367, 13016124245267804117, 3041300342890742581, 15830253523429142702, 4124978113326913000, 18280219261996495240, 13678174604107677296, 11027937708781352184, 9524461836107268283, 7086746505450311592, 7319928310078430930, 11146341134166142886, 14000752730312100679, 8776837767210836349, 7842835560601620329, 9613994929417659617, 12679002698944454251, 0, 5160, 18346837778669738664, 15130142357101091527, 6726588340010678615, 8394319278312203283, 15942424551308612685, 7629500615465222065, 14939877513325106589, 17048523965011794048, 2306293645521445312, 823113708878672797, 14981348226783328932, 7432878333905782051, 3482639998457803800, 632277917380007036, 18266437030920184246, 3366715262389109205, 5280275432441977334, 5379329043314533811, 13912213856326486056, 17217059915921675075, 15634373017412823086, 14981257187297131103, 16697350900700022325, 5239234081629986555, 3229291246709926782, 18373224696258292584, 6771862800272250893, 7666370275789511263, 12942227631865082960, 15190222347874856922, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [87, 9950917671808473405, 3554228101202979253, 9306806947978771582, 4401882774217375917, 15315969540976862758, 16886025621791162858, 10861900348873787927, 5957397384759471696, 13244465343946802573, 6540213681196691440, 11070522019866408102, 3801445557467335639, 12532452847683566938, 11669769547992992357, 12808908716587726858, 17995649345722530812, 698204761262232508, 6333121561150411801, 4032763150397248777, 14008259259755136035, 6979651972374810449, 7911828305365051593, 3932176613876828948, 7810471060559602612, 10015863907140938459, 8849830318071758779, 7592172000473889159, 5876504027679413408, 17878067193823269498, 15447825779474026874, 5053260159826664462, 0, 4128, 6496253015800789210, 18063315295058131399, 14099326864720264780, 16744359797696928029, 11669954633423859445, 10923938539628559259, 10579480970462933513, 17315553376669597828, 12114095292572219189, 16129781670858537825, 67936491912723144, 6285840300661422802, 14359460599290704174, 7597471307904508314, 8469569990667894210, 9117246600999250277, 14614928058075190380, 13738364908865630160, 1806905237893315697, 261412144627674040, 8380596589382515797, 3809925330596605534, 1983199361335541287, 6337901890572878101, 17063257729896061936, 12690697575318882146, 3846044480011221270, 10729939698274680623, 5297971463863936522, 8671284646676347574, 104, 14745280635380602217, 1277989312750492883, 17882043915102295645, 8402260971363137004, 11464571068891742851, 15059523259116208792, 4259151281546711306, 12299499890598148513, 16319371075448400987, 8885641423428293370, 16309893991999277564, 2619218791994734454, 17151450962136165028, 17614551442000447874, 17230858587654278062, 19705201673078532, 2732075625107327721, 6566262129896944024, 689808164767473390, 11564905194821649437, 14876340024025687860, 10936017910631925277, 10540913652282428134, 10843077561784740363, 5250262515785863526, 8273371701363724667, 16366540385334083230, 9631977100618497396, 18413271307798397411, 1499758295592994876, 14053004056904301616, 0, 4128, 6496253015800789210, 18063315295058131399, 14099326864720264780, 16744359797696928029, 11669954633423859445, 10923938539628559259, 10579480970462933513, 17315553376669597828, 12114095292572219189, 16129781670858537825, 67936491912723144, 6285840300661422802, 14359460599290704174, 7597471307904508314, 8469569990667894210, 9117246600999250277, 14614928058075190380, 13738364908865630160, 1806905237893315697, 261412144627674040, 8380596589382515797, 3809925330596605534, 1983199361335541287, 6337901890572878101, 17063257729896061936, 12690697575318882146, 3846044480011221270, 10729939698274680623, 5297971463863936522, 8671284646676347574, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 13549970121514602677, 473829894064878094, 13789183496966727565, 1955350239938339874, 7201082322234349663, 9016022097577899196, 6529222281750641224, 17689702079462878790, 10156549575434042429, 7248885352501816322, 12178683397221723524, 6850524170552426967, 8689264751605527455, 1407059625629950522, 9144161729371790458, 3267820578940859361, 10961895042020971306, 15803107242779899332, 13169126454128015246, 6297730490781618091, 16325028460633105625, 1221092837168607222, 8986628150783184058, 17306851421758051833, 15205710348050472951, 2733211805524420436, 13936580861462477484, 16716871354996632672, 2773281916155934536, 9099902973067746305, 12285155954580341409, 0, 1032, 13084260837127404333, 4018109146681745349, 14498381569327145056, 3778421823029569719, 1344624249217908323, 3634653398484528177, 1428985706412758663, 11382569756632997337, 13894906302086601399, 3911680161282028629, 11467762927868003365, 10098326072301516020, 16073214466625742345, 16150512194511843089, 11525294274796193451, 15902507139806774023, 13926886722650908730, 2974304378722638293, 5274544965980948277, 9984170014312577610, 639485734140932316, 15088403650698955530, 17189134684458608982, 6515320870350778492, 7902492290152572474, 17310456195349246143, 4070136787975548901, 6345872167795009033, 3095930865537762353, 4232664728858134772, 0, 11085857321233346159, 750403697714635224, 15867156494024459966, 7866397620702682136, 5793298599059911546, 5158478207966654343, 16510537027687425322, 4650635265747757214, 2676532104357997308, 10285794245095273390, 13247727332705294758, 17671377272587403594, 8030571597136649189, 1289802346192453208, 14103228039950804909, 4124512422853870088, 3056884801892714758, 4767720916160432521, 3187398915591767652, 16919717526667459899, 18271533057078737338, 4118950315111493430, 5321954010838991352, 4375178466595687599, 13452922166654240382, 18416629007910574933, 663957419786385993, 3920191287070292962, 1103793272511562248, 4364510604874202960, 18207465128223513961, 0, 1032, 13084260837127404333, 4018109146681745349, 14498381569327145056, 3778421823029569719, 1344624249217908323, 3634653398484528177, 1428985706412758663, 11382569756632997337, 13894906302086601399, 3911680161282028629, 11467762927868003365, 10098326072301516020, 16073214466625742345, 16150512194511843089, 11525294274796193451, 15902507139806774023, 13926886722650908730, 2974304378722638293, 5274544965980948277, 9984170014312577610, 639485734140932316, 15088403650698955530, 17189134684458608982, 6515320870350778492, 7902492290152572474, 17310456195349246143, 4070136787975548901, 6345872167795009033, 3095930865537762353, 4232664728858134772, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 16457115416797113563, 16239155032122797832, 14849238236368251159, 9108419460474808576, 1033211373414661409, 14502772570466296089, 4038467972202515368, 1460799694261663366, 12439775236546072843, 16427603058194514665, 14959440030310041613, 3845590175102547346, 1301757407011623611, 17501633393315606025, 11009053095286438923, 3009367688589025768, 6965916889756314709, 4517155861865643415, 15896658462307045811, 9681943962122261504, 9968758826692797274, 5829992311401516243, 15782779420328542209, 11631298814075616775, 12222681008501641705, 12020699456941818376, 16842897778485981781, 4735042970479906379, 3151070592229922496, 3062023609160919321, 9514569903823065872, 0, 1032, 15909096041365347974, 18432189660917429733, 2798890989547891271, 10768372030970716894, 5935807051329113911, 1259182408195029650, 16024750973514577255, 6103595041913569283, 914770550723164908, 5067028895751058275, 5242612139537538536, 13359135899043031769, 4430959127423856282, 16317056360529517539, 2634255659160911215, 15590656855559575839, 6832335878067392309, 6045109056629836176, 18146646330136390606, 6482705684632040588, 2770791364887326735, 7707774010999656594, 3401430074469265273, 3500862351024377705, 5135727797169111985, 14940852959892477883, 9633218853985087472, 16966092255533854383, 3065488485208441055, 15703076512693482766, 0, 7442777957161348509, 3036215591853057143, 16090863638087042910, 3963133567703228598, 17908349476423851244, 7001924323395444874, 17338586306104572036, 14119937534703630749, 4242994035168829398, 2363031437222084351, 3255777517629291140, 124459613086078350, 13938492907317794048, 4899661652548582019, 1296301487511431772, 14599398842157535330, 4565191284080628584, 9612849067002171183, 10046653166326882870, 1539793980828004113, 15261415128186745093, 15065597191535528607, 16001910338161660328, 12471346680264155869, 6112064272743521679, 16130747048670899171, 1508047113079150807, 8501241071240823019, 9778047403489538902, 4539108168956164212, 12867780329443177182, 0, 1032, 15909096041365347974, 18432189660917429733, 2798890989547891271, 10768372030970716894, 5935807051329113911, 1259182408195029650, 16024750973514577255, 6103595041913569283, 914770550723164908, 5067028895751058275, 5242612139537538536, 13359135899043031769, 4430959127423856282, 16317056360529517539, 2634255659160911215, 15590656855559575839, 6832335878067392309, 6045109056629836176, 18146646330136390606, 6482705684632040588, 2770791364887326735, 7707774010999656594, 3401430074469265273, 3500862351024377705, 5135727797169111985, 14940852959892477883, 9633218853985087472, 16966092255533854383, 3065488485208441055, 15703076512693482766, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] }, last_program_row: RowIndex(12) }, program_info: ProgramInfo { program_hash: Word([15233389079858696706, 4869430190272581571, 15500832090051527072, 15232111199771387968]), kernel: Kernel([Word([7458506668679174706, 18375473735916206629, 2105717247508690050, 1679902783560062568])]) }, stack_outputs: StackOutputs { elements: [1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, merkle_store_nodes: {Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571]): (Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350]), Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350])), Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484]): (Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693]), Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693])), Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781]): (Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874]), Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874])), Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171]): (Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361]), Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361])), Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815]): (Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305]), Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305])), Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689]): (Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195]), Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195])), Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362]): (Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063]), Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063])), Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848]): (Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661]), Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661])), Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352]): (Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829]), Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829])), Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444]): (Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223]), Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223])), Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386]): (Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388]), Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388])), Word([13190842942618341421, 17548956981569849952, 15418963848144418856, 730733050713174879]): (Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144]), Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144])), Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874]): (Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675]), Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675])), Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594]): (Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115]), Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115])), Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809]): (Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257]), Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257])), Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777]): (Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555]), Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555])), Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509]): (Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882]), Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882])), Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725]): (Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979]), Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979])), Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134]): (Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987]), Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987])), Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828]): (Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910]), Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910])), Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830]): (Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054]), Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054])), Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228]): (Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742]), Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742])), Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443]): (Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928]), Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928])), Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643]): (Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979]), Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979])), Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758]): (Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106]), Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106])), Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580]): (Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594]), Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594])), Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765]): (Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045]), Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045])), Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766]): (Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281]), Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281])), Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385]): (Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828]), Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828])), Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579]): (Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171]), Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171])), Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212]): (Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992]), Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992])), Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463]): (Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004]), Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004])), Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502]): (Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023]), Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023])), Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539]): (Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537]), Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537])), Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865]): (Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225]), Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225])), Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690]): (Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947]), Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947])), Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202]): (Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552]), Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552])), Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079]): (Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444]), Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444])), Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850]): (Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548]), Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548])), Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448]): (Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987]), Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987])), Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041]): (Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035]), Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035])), Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301]): (Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414]), Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414])), Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414]): (Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212]), Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212])), Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703]): (Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439]), Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439])), Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271]): (Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955]), Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955])), Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882]): (Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802]), Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802])), Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152]): (Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887]), Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887])), Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028]): (Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948]), Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948])), Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331]): (Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093]), Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093])), Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394]): (Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134]), Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134])), Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546]): (Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228]), Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228])), Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620]): (Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414]), Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414])), Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800]): (Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703]), Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703])), Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671]): (Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205]), Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205])), Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537]): (Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011]), Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011])), Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516]): (Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301]), Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301])), Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831]): (Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986]), Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986])), Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415]): (Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057]), Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057])), Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722]): (Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689]), Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689])), Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144]): (Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682]), Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682])), Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295]): (Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268]), Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268])), Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818]): (Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513]), Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513])), Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241]): (Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565]), Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565])), Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439]): (Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012]), Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012])), Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512]): (Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850]), Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850])), Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986]): (Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865]), Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865])), Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982]): (Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777]), Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777])), Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808]): (Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394]), Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394])), Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979]): (Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690]), Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690])), Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093]): (Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620]), Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620])), Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902]): (Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789]), Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789])), Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542]): (Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094]), Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094])), Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057]): (Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362]), Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362])), Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205]): (Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961]), Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961])), Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401]): (Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580]), Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580])), Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553]): (Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960]), Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960])), Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169]): (Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031]), Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031])), Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682]): (Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053]), Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053])), Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118]): (Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562]), Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562])), Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725]): (Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666]), Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666])), Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661]): (Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897]), Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897])), Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981]): (Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447]), Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447])), Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072]): (Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646]), Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646])), Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140]): (Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404]), Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404])), Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515]): (Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152]), Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152])), Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709]): (Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664]), Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664])), Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800]): (Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103]), Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103])), Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741]): (Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169]), Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169])), Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005]): (Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758]), Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758])), Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802]): (Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070]), Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070])), Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159]): (Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005]), Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005])), Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350]): (Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443]), Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443])), Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697]): (Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573]), Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573])), Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928]): (Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331]), Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331])), Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320]): (Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166]), Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166])), Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814]): (Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079]), Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079])), Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447]): (Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820]), Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820])), Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284]): (Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057]), Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057])), Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697]): (Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131]), Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131])), Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955]): (Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290]), Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290])), Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910]): (Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202]), Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202])), Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910]): (Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822]), Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822])), Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106]): (Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847]), Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847])), Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404]): (Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441]), Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441])), Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796]): (Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186]), Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186])), Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053]): (Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516]), Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516])), Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992]): (Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818]), Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818])), Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957]): (Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315]), Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315])), Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709]): (Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794]), Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794])), Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091]): (Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539]), Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539])), Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664]): (Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558]), Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558])), Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294]): (Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579]), Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579])), Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947]): (Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502]), Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502])), Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829]): (Word([0, 0, 0, 0]), Word([0, 0, 0, 0])), Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045]): (Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137]), Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137])), Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914]): (Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041]), Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041])), Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573]): (Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378]), Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378])), Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699]): (Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873]), Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873])), Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225]): (Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262]), Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262])), Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057]): (Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692]), Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692])), Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131]): (Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997]), Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997])), Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555]): (Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385]), Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385])), Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195]): (Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709]), Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709])), Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166]): (Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542]), Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542])), Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027]): (Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373]), Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373])), Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378]): (Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509]), Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509])), Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097]): (Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553]), Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553])), Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217]): (Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815]), Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815])), Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873]): (Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864]), Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864])), Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997]): (Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722]), Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722])), Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887]): (Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766]), Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766])), Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589]): (Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757]), Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757])), Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539]): (Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665]), Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665])), Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129]): (Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229]), Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229])), Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137]): (Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312]), Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312])), Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019]): (Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378]), Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378])), Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331]): (Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713]), Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713])), Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]): (Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980]), Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980])), Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325]): (Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546]), Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546])), Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170]): (Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822]), Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822])), Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054]): (Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295]), Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295])), Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925]): (Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848]), Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848])), Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909]): (Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796]), Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796])), Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540]): (Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170]), Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170])), Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214]): (Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448]), Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448])), Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317]): (Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294]), Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294])), Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757]): (Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416]), Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416])), Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378]): (Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091]), Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091])), Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263]): (Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463]), Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463])), Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666]): (Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361]), Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361])), Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174]): (Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992]), Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992])), Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470]): (Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401]), Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401])), Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665]): (Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957]), Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957])), Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262]): (Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144]), Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144])), Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229]): (Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284]), Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284])), Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134]): (Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325]), Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325])), Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855]): (Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765]), Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765])), Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115]): (Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814]), Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814])), Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441]): (Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831]), Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831])), Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977]): (Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446]), Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446])), Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880]): (Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005]), Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005])), Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789]): (Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995]), Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995])), Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000]): (Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267]), Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267])), Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998]): (Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982]), Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982])), Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995]): (Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539]), Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539])), Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507]): (Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512]), Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512])), Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305]): (Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118]), Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118])), Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219]): (Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009]), Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009])), Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416]): (Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089]), Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089])), Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980]): (Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445]), Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445])), Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063]): (Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140]), Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140])), Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713]): (Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159]), Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159])), Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031]): (Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809]), Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809])), Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932]): (Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037]), Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037])), Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094]): (Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925]), Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925])), Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315]): (Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386]), Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386])), Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446]): (Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721]), Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721])), Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742]): (Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981]), Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981])), Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661]): (Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072]), Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072])), Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979]): (Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671]), Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671])), Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361]): (Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269]), Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269])), Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558]): (Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571]), Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571])), Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290]): (Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902]), Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902])), Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987]): (Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741]), Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741])), Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902]): (Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515]), Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515])), Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497]): (Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028]), Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028])), Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948]): (Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709]), Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709])), Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009]): (Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725]), Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725])), Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387]): (Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317]), Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317])), Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159]): (Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808]), Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808])), Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394]): (Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699]), Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699])), Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312]): (Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000]), Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000])), Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987]): (Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821]), Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821])), Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046]): (Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909]), Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909])), Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565]): (Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028]), Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028])), Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269]): (Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352]), Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352])), Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847]): (Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271]), Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271])), Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513]): (Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800]), Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800])), Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054]): (Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394]), Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394])), Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004]): (Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977]), Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977])), Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675]): (Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800]), Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800])), Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692]): (Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159]), Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159])), Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909]): (Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932]), Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932])), Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814]): (Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697]), Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697])), Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186]): (Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387]), Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387])), Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445]): (Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470]), Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470])), Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966]): (Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507]), Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507])), Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548]): (Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253]), Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253])), Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897]): (Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783]), Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783])), Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208]): (Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054]), Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054])), Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268]): (Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661]), Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661])), Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388]): (Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643]), Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643])), Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257]): (Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174]), Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174])), Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960]): (Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241]), Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241])), Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721]): (Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046]), Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046])), Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822]): (Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217]), Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217])), Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253]): (Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697]), Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697])), Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054]): (Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019]), Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019])), Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821]): (Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432]), Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432])), Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864]): (Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105]), Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105])), Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373]): (Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855]), Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855])), Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646]): (Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830]), Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830])), Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460]): (Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208]), Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208])), Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033]): (Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214]), Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214])), Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105]): (Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129]), Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129])), Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281]): (Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909]), Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909])), Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028]): (Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027]), Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027])), Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012]): (Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054]), Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054])), Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562]): (Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589]), Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589])), Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037]): (Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097]), Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097])), Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355]): (Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460]), Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460])), Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223]): (Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355]), Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355])), Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089]): (Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306]), Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306])), Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035]): (Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219]), Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219])), Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432]): (Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297]), Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297])), Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693]): (Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263]), Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263])), Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794]): (Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484]), Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484])), Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552]): (Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941]), Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941])), Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267]): (Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814]), Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814])), Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992]): (Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415]), Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415])), Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941]): (Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966]), Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966])), Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822]): (Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320]), Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320])), Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306]): (Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902]), Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902])), Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820]): (Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880]), Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880])), Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361]): (Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725]), Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725])), Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005]): (Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914]), Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914])), Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783]): (Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781]), Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781])), Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011]): (Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033]), Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033])), Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297]): (Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910]), Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910])), Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070]): (Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134]), Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134])), Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144]): (Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331]), Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331])), Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023]): (Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497]), Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497])), Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103]): (Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540]), Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540])), Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961]): (Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998]), Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998])), Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414]): (Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]), Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]))}, trace_len_summary: TraceLenSummary { main_trace_len: 13, range_trace_len: 39, chiplets_trace_len: ChipletsLengths { hash_chiplet_len: 128, bitwise_chiplet_len: 0, memory_chiplet_len: 0, kernel_rom_len: 2 } } } +ExecutionTrace { main_trace: MainTrace { storage: Parts { core_rm: [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 2899453830169817055, 16816598283634567027, 3068995836555945716, 12171400876639430472, 0, 0, 0, 0, 0, 0, 1, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1032, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 2, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 8, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 3, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 4, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 1, 1, 1, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 5, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 6, 0, 0, 0, 0, 0, 5, 0, 1, 1, 0, 1, 0, 1, 1032, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 7, 0, 0, 0, 0, 0, 7, 0, 0, 0, 1, 0, 0, 0, 8, 5, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 8, 0, 0, 0, 0, 0, 7, 0, 0, 0, 1, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 9, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 1, 1, 1, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 10, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 1, 1, 1, 2899453830169817055, 16816598283634567027, 3068995836555945716, 12171400876639430472, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 11, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 31, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 33, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 39, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 43, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 47, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 50, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 51, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 53, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 54, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 55, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 59, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 60, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 61, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 67, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 69, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 70, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 71, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 72, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 73, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 74, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 75, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 76, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 77, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 78, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 79, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 81, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 82, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 83, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 86, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 87, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 88, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 89, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 90, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 91, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 92, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 93, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 94, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 97, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 98, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 99, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 101, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 102, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 103, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 104, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 105, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 106, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 107, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 108, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 109, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 110, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 111, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 112, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 113, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 114, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 115, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 116, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 117, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 118, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 119, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 120, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 121, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 122, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 123, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 124, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 125, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 126, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 127, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0], chiplets_rm: [1, 1, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 2899453830169817055, 16816598283634567027, 3068995836555945716, 12171400876639430472, 0, 87, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 18295472245208082500, 5861891236755868697, 15427470125368014171, 5623455816162216176, 11335643519415282023, 11551270937114235273, 11863835819310119404, 14266241634618616211, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1032, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 11116382020814057190, 14732796941305378371, 13074361791711182490, 6715193688317415490, 1571558009365433839, 13285275197432594374, 15905141483335727027, 2507840277166973476, 0, 0, 1, 0, 0, 1, 1, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 0, 0, 0, 0, 0, 104, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 2899453830169817055, 16816598283634567027, 3068995836555945716, 12171400876639430472, 3302920651539558582, 2392789792202575031, 11898680931385242334, 3118702462093730513, 6675709269000188192, 6602703777719207165, 6265915402349571564, 2890093557727619615, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1032, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 11116382020814057190, 14732796941305378371, 13074361791711182490, 6715193688317415490, 1571558009365433839, 13285275197432594374, 15905141483335727027, 2507840277166973476, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1032, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 0, 15913981378790993016, 12701179462806902902, 9645342555817022514, 6889850077248808033, 678249829196625442, 8726676798253716750, 14136118088409135949, 1027279235140821190, 8048729929177993405, 2542525775606472849, 3283471062508934848, 18058280687405074483, 2, 0, 0, 0, 1, 0, 0, 0, 0, 11899090779839289087, 1701090513954162998, 6953639183117323837, 11460660778637092812, 8345945186928076892, 11308243255833047975, 5734666540714547293, 1546649737555419076, 14643837757854608147, 7477230882792828789, 2359592855656894189, 12732146754685591216, 2, 0, 0, 0, 1, 0, 0, 0, 0, 16283412161296764998, 17261112905912533997, 1498213616014501531, 7707889409925905689, 16090493533591377617, 525010687572874692, 5228788497345464933, 13051466527897639054, 3560924095387897187, 12551242480725370445, 4038828260160651477, 6132317990703151787, 2, 0, 0, 0, 1, 0, 14261694278902826987, 16097544111075686229, 16632169854204459773, 14265791174051766329, 14732671264513481238, 15642599276989292777, 7593738854072541043, 11440582168151819564, 18258483622390056257, 6851601084855956341, 10463349537167637967, 10032876585525342603, 825669147467031185, 16271217766495541082, 9021089524754424392, 2, 0, 0, 0, 1, 0, 16780109665356203593, 16025948514351396737, 4256182047405196535, 4919013996388780384, 6974015548720770018, 10189882052640604940, 12288632186238773648, 7055558833039165669, 9820743264545515107, 7353106531603230851, 5612808106478211181, 362487531847990854, 10259224130335842891, 2374318293393776907, 16208179153232019183, 2, 0, 0, 0, 1, 0, 9496969110446094198, 10424961628901078909, 7587726188775237019, 13423955604028434301, 12288543613568774022, 4068762405627465026, 7288480650179820504, 1035430088689333582, 2651098721515326755, 4524440782000877024, 3013038852551457145, 12536534023666437466, 6560028330562582937, 9090521726813489969, 17634755409309861791, 2, 0, 0, 0, 1, 0, 15761194215082968049, 15796684185970405493, 1294179585337070936, 5701860167148115542, 17707247215386403887, 18419960639673587986, 14570347312565937582, 8634142387233894354, 11938075017385927203, 8060480374868324599, 16699922976999064541, 14234489074154948378, 17210389744085299852, 17331527780947314617, 16356838976302290254, 2, 0, 0, 0, 1, 0, 6184336662619539433, 7106147576739595100, 18237994300618329820, 9768155666925548219, 226714884885574576, 11169479382209254075, 5756676929838789145, 29803495366482069, 13128905441940840949, 18304516631519674746, 3177693875357946498, 10624850715031233718, 16956738608020324589, 10558540052020438814, 7826502712354673600, 2, 0, 0, 0, 1, 0, 1980308537464408089, 6810023246846442283, 9400257804338494201, 11246932855318952856, 7504545710540897051, 5823677062954428984, 9151299935574592196, 15905322272715446259, 18174748553199601666, 9877077233183640995, 2431998410719122545, 3541292002384422941, 5416588529930333172, 15788517205879313917, 2490575598934209003, 2, 0, 0, 0, 1, 0, 17950140321155419078, 9014768943295123367, 10707122777228105884, 10701204914974985643, 15060806908759160804, 7011191650405807117, 13598159658926423040, 3947314552577424057, 12985682730462769834, 18264715466581442035, 7667189540353817157, 7685483800933651249, 16085167604591833455, 16105855167414075111, 16215395602017884846, 2, 0, 0, 0, 1, 0, 8676227747932036802, 0, 0, 11504729673400082663, 3659553513673892306, 10374352082945691939, 15819529278889203623, 18107940902385670152, 8889798095480337831, 12737345777792032790, 456604824069734238, 2859376131275373721, 8758251935142908528, 2364536875264708997, 2435873391009301907, 2, 0, 0, 0, 1, 0, 0, 0, 0, 16797630026773069829, 16954579754978210547, 4393671449525183699, 6245909065255485436, 8311309349844601638, 3305827896314343556, 1615477551160071258, 3897903986825909618, 13015230208471866351, 13839070994009764281, 2415598337053791919, 5526300544248852335, 2, 0, 0, 0, 1, 0, 0, 0, 0, 12827873667465929582, 15892701250663610383, 549489834728826775, 9425334953627649153, 15402634395731091512, 11814416271399500934, 14597718118926923662, 4726679541432826422, 342915941842538663, 11221492717904369823, 17188959961041335276, 13559932473868727168, 2, 0, 0, 0, 1, 0, 0, 0, 0, 8689096602925893779, 4096531352684607500, 8424481237826564505, 15238165026175259240, 10985176737527635898, 2672540837788784952, 6649439643634522762, 7581835251244605715, 17671970641549389116, 18069913154458602790, 749417941228438762, 6150863900366154379, 2, 0, 0, 0, 1, 0, 0, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 11116382020814057190, 14732796941305378371, 13074361791711182490, 6715193688317415490, 1571558009365433839, 13285275197432594374, 15905141483335727027, 2507840277166973476, 2, 0, 0, 0, 1, 0, 0, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 0, 0, 0, 0, 0, 104, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 8045445736281483033, 11250386210932698181, 8447328201766628152, 527413860513422548, 2685530738566346168, 6831208533457089257, 18437518609042158966, 9278656209339918204, 4985219875437159245, 11102677601257469434, 16507477945842790035, 1824439754798293960, 1, 0, 0, 0, 1, 0, 0, 0, 0, 13956548861570575417, 9763011176116608502, 4674794667694672124, 15480945315513057131, 1720127490715987209, 8831144276914012491, 250532683106813113, 18120264276823504303, 7075953940225467814, 5209117550659913714, 16837262421580091230, 11776861544437613654, 1, 0, 0, 0, 1, 0, 0, 0, 0, 11512288827914447463, 17480311708360681553, 1580648391454313983, 3096307188042936924, 1465975368055000312, 1362735000009130378, 9465263839861379226, 14989718516974665241, 6566304943303044120, 2566111340353544025, 11325114382049196546, 15312957863351292707, 1, 0, 0, 0, 1, 0, 14277010279095994320, 16421135900115366688, 8672081456162485113, 3315051758368515759, 16767795201975506841, 15745773069630130456, 10428682341827527559, 1609230777320982945, 8538451532688083939, 3309529438878958210, 2752224770668803053, 4030118788308868253, 9432517950422109187, 16655292287441213846, 3022134227219891882, 1, 0, 0, 0, 1, 0, 12527609013750224641, 4064424364292504784, 12759359572746242099, 17498386834554682438, 9899399543530128857, 13823203783008011183, 4789373231313821943, 2275698290172824909, 14631083886626574849, 6083693282888760833, 17878128073269252636, 9098606451540172932, 4868784239831205121, 2796426330015583824, 10989039359288278884, 1, 0, 0, 0, 1, 0, 11227322858093773958, 1256671723465513282, 4658091495748016755, 14665531030768273966, 5299487590341247604, 3822486110676485203, 2504794437525571246, 16499336243305873535, 10440692312118465582, 8016916182618053860, 11635644660770389253, 4003332628141212645, 8214607993079575395, 7207010966340578848, 10940185796204185824, 1, 0, 0, 0, 1, 0, 12668058855470446370, 5255019430616758101, 14462744774902056824, 4113277495358115867, 1662113282866907292, 6585130578479449998, 17149676088405916342, 10457761600032190139, 3327323833077679847, 8197592365883421679, 7425424839480263678, 13938948244809494455, 16228892676090661713, 1504971017217144480, 8182776272628891435, 1, 0, 0, 0, 1, 0, 6914860967029724068, 10806403396787496173, 3848579298848325229, 13805102062857951563, 16229844626955596217, 13935582109846251306, 8572389593169145834, 17576620671980411587, 10572618363726686694, 4850773447466262928, 15638373093776703034, 7910188832488865399, 15531097057290072206, 4889338479662679107, 10949924992689136363, 1, 0, 0, 0, 1, 0, 4330865582496855032, 8473297999555512458, 7242240654409420037, 10299128364456298062, 14941042471610818695, 7565852759213474271, 3702504147651721524, 207598518842942194, 6753564273898291164, 11919043583188527726, 2096230895461827816, 9814026405907874850, 17772509140662880385, 15771358593260243554, 6654163437055992392, 1, 0, 0, 0, 1, 0, 14424762448455122149, 9431772018868236879, 584341294112809445, 4918781353216964245, 2337856752823889422, 16060522829040602978, 1539091624536270714, 3206058370812795090, 10870942617842401040, 8606083879706978586, 4344150548445731150, 380060561426657383, 2730766720879432427, 14498706802584030890, 7769509436274319865, 1, 0, 0, 0, 1, 0, 4147902545389306045, 0, 0, 16093847529947137599, 5589254378675598674, 14560311910293184412, 2592280228933147027, 10554718058272358421, 1080024418599256897, 646685994271806030, 5548578222066968465, 13466005348915411989, 1280314003050779809, 11336903746061502338, 9170512654829817344, 1, 0, 0, 0, 1, 0, 0, 0, 0, 4018352536943676596, 1718970205214835807, 16103902027304323769, 7153843611717905198, 7564037379049998274, 6261812460083581507, 17412746410051240602, 11497751499239916990, 9826997558611816650, 2818155236871917143, 1303564367886020260, 8520201627654591972, 1, 0, 0, 0, 1, 0, 0, 0, 0, 7399548230295413142, 15817399793431362137, 11111223990289672490, 14277270972042777124, 9762507146447503800, 5775448381623517643, 9705617515238056177, 10499143968321217911, 13713380413483444727, 2803285551461817904, 3117235683594903662, 8848529162601814389, 1, 0, 0, 0, 1, 0, 0, 0, 0, 41605777382338142, 13705243190620087435, 8813156438606599548, 3668196738148877897, 8870883218370515482, 1311045307375281156, 891925000095841393, 18305520102948210690, 3095238878624340898, 8925726914230878692, 11158112996086314015, 16463229027226752316, 1, 0, 0, 0, 1, 0, 0, 0, 0, 2899453830169817055, 16816598283634567027, 3068995836555945716, 12171400876639430472, 3302920651539558582, 2392789792202575031, 11898680931385242334, 3118702462093730513, 6675709269000188192, 6602703777719207165, 6265915402349571564, 2890093557727619615, 1, 0, 0, 0, 1, 0, 0, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 2899453830169817055, 16816598283634567027, 3068995836555945716, 12171400876639430472, 0, 87, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 3856634821061399044, 17111039960895529319, 4566799539362193550, 16844085186824886612, 3355565787613486613, 17176810829821093448, 1352137470786356802, 17998789203926124900, 16786513982140394745, 18361321143200586840, 13282415620666686464, 8228901733828007087, 1, 0, 0, 0, 1, 0, 0, 0, 0, 7778838127124972351, 10159506934852280087, 12722539778584946047, 2132149890053205639, 18102156639692354752, 8649394742436479221, 4276590013765363445, 12997989410109585404, 9529430557140348691, 7606828505864121076, 17598459768503654580, 7777709650181082785, 1, 0, 0, 0, 1, 0, 0, 0, 0, 8194007358744550661, 306611979519524457, 10528705374691960700, 319508112022086105, 10482736583082303606, 10309893049243492470, 12917037695721108312, 6248886070590142047, 6486447845183860200, 17251231915071761348, 16404214944354933870, 13204576128129345952, 1, 0, 0, 0, 1, 0, 8699431654038775343, 37936723307283666, 8146588049311051327, 4530941775236136548, 16738435301601374688, 11359785745622903572, 15791382447019722900, 13379247305879358010, 13936169968399350974, 3508629571016445401, 5950565638198879243, 3988632325321614173, 14773776822077474877, 3784342517219646416, 16429780078047820450, 1, 0, 0, 0, 1, 0, 3424975013671552621, 14815277144979047633, 8209627855274846837, 8295342049297215958, 15269992241592835077, 6438591265885629379, 13730717627697535913, 7787232003492715877, 9621206971434531853, 11223875126467095457, 6436756480486800604, 5377264485189635000, 5482319143373695788, 12350937431324290559, 6389531569788570962, 1, 0, 0, 0, 1, 0, 4990332689225356878, 13089030850077380376, 2471524608045276896, 17139358263655017093, 18165060065290469256, 9446121688110358951, 977359788342611310, 16707128933418187061, 16621781274459601592, 7539458736435553900, 13565999334907596759, 1167963651906558177, 801268771425181312, 6228026786881094671, 1048304545096961231, 1, 0, 0, 0, 1, 0, 9535941747246118180, 6758632961600419030, 13740260214376027515, 1405920164415583051, 14920069431652436384, 17439962485710135044, 417887867370226026, 16088228384974311599, 3710261815002798848, 137273432282796342, 5851059442771612226, 15136621875351529272, 15702932139541150313, 8779333934582463234, 9538098266673672038, 1, 0, 0, 0, 1, 0, 8185802697182936648, 17682692702261395783, 2219736463483295590, 10757593865239447517, 1468754948270208383, 13746393160610271679, 6189648269704333551, 6527095477330083457, 289679669419955019, 9046656083049426920, 3573808134852581123, 16538711805104705524, 17122129810962376462, 2926585958971102942, 10107422984112301769, 1, 0, 0, 0, 1, 0, 12705492336505225259, 715424026399539381, 2549298692279483128, 1219968445867773701, 12911638424059178129, 5048199682718381540, 1535097268869899419, 17260972721034176516, 15413356179839910737, 13476986835056197648, 7470895530577539713, 8398414302064166980, 16518486341402545799, 70008875869363926, 10307933594111103714, 1, 0, 0, 0, 1, 0, 450024681039430413, 17110346123676092707, 503623504778112596, 1520822994009218024, 3997469258016952350, 18365130032920199069, 7964473389350786015, 9071675461601628413, 4719657860691726363, 2082610983791917873, 13643709933077212296, 16696777778525571691, 5937099920759461106, 17798517164851075633, 7519473231185213307, 1, 0, 0, 0, 1, 0, 17931731304193244959, 0, 0, 11156145431451224746, 9448001553779471302, 11663814486624427477, 8105139713546092506, 996052311483623897, 18356245393792640289, 11128269591471854109, 3650549423833220560, 10102060878284432657, 6999065210900455588, 9632395034475899386, 10920626017129534091, 1, 0, 0, 0, 1, 0, 0, 0, 0, 17063798001278894185, 2357038714604006367, 10530018908095235062, 8857952782846291740, 17150424826448967994, 8501298665346388356, 15857100073185553560, 2606143849991065668, 1709380969765926542, 7242804148613591485, 10415598312293556776, 3315485625242432418, 1, 0, 0, 0, 1, 0, 0, 0, 0, 6980956723582544769, 17736580895885199098, 10473837116748539797, 5495612785159148096, 8023377746099375924, 15245498074053387423, 15841461147440760970, 14724882291190243897, 13636145514567347966, 11793730383025693858, 9279036588745121360, 3956126734745245173, 1, 0, 0, 0, 1, 0, 0, 0, 0, 14149948942544104911, 13474931984659215558, 7610362789910399421, 10137886774563078569, 110488320743199774, 6631727638469492070, 9820426758070632911, 11785623090416681374, 2883529595690350478, 8282658300559339579, 1247473541961741200, 12265308465311135280, 1, 0, 0, 0, 1, 0, 0, 0, 0, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 18295472245208082500, 5861891236755868697, 15427470125368014171, 5623455816162216176, 11335643519415282023, 11551270937114235273, 11863835819310119404, 14266241634618616211, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], range_checker_cols: [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2187, 4374, 6561, 8748, 10935, 13122, 15309, 17496, 19683, 21870, 24057, 26244, 28431, 30618, 32805, 34992, 37179, 39366, 41553, 43740, 45927, 48114, 50301, 52488, 54675, 56862, 59049, 61236, 63423, 64152, 64881, 65124, 65367, 65448, 65529, 65532, 65535, 65535]], num_rows: 128 }, last_program_row: RowIndex(12) }, program_info: ProgramInfo { program_hash: Word([8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090]), kernel: Kernel([Word([13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008])]) }, stack_outputs: StackOutputs { elements: [1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, precompile_requests: [], final_precompile_transcript: PrecompileTranscript { state: Word([0, 0, 0, 0]) }, trace_len_summary: TraceLenSummary { main_trace_len: 13, range_trace_len: 39, chiplets_trace_len: ChipletsLengths { hash_chiplet_len: 64, bitwise_chiplet_len: 0, memory_chiplet_len: 0, ace_chiplet_len: 0, kernel_rom_len: 1 } } } diff --git a/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_14.snap b/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_14.snap index 7effc433de..11ed9c2d2c 100644 --- a/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_14.snap +++ b/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_14.snap @@ -2,4 +2,4 @@ source: processor/src/trace/parallel/tests.rs expression: DeterministicTrace(&trace_from_fragments) --- -ExecutionTrace { main_trace: MainTrace { columns: ColMatrix { columns: [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 33, 33, 33, 1, 65, 97, 97, 97, 65, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [7458506668679174706, 1032, 8, 0, 7458506668679174706, 7458506668679174706, 1032, 8, 0, 7458506668679174706, 10762639943655126491, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706, 15233389079858696706], [18375473735916206629, 0, 1, 1, 18375473735916206629, 18375473735916206629, 0, 65, 65, 18375473735916206629, 8123069549705052795, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571, 4869430190272581571], [2105717247508690050, 0, 0, 0, 2105717247508690050, 2105717247508690050, 0, 0, 0, 2105717247508690050, 10333571018226702209, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072, 15500832090051527072], [1679902783560062568, 0, 0, 0, 1679902783560062568, 1679902783560062568, 0, 0, 0, 1679902783560062568, 3763553361837852375, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968, 15232111199771387968], [10762639943655126491, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [8123069549705052795, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [10333571018226702209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [3763553361837852375, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2], [3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2187, 4374, 6561, 8748, 10935, 13122, 15309, 17496, 19683, 21870, 24057, 26244, 28431, 30618, 32805, 34992, 37179, 39366, 41553, 43740, 45927, 48114, 50301, 52488, 54675, 56862, 59049, 61236, 63423, 64152, 64881, 65124, 65367, 65448, 65529, 65532, 65535, 65535], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [7458506668679174706, 17262866120583049312, 1604139919365911138, 5113851726573374470, 13536996102937200288, 5144547684530650448, 3655783001982481850, 17854454697671763355, 16371583576737997647, 15021252922727947001, 17129020395602960691, 12027296227437859344, 15768109424081379298, 5534448791232096558, 5035998873325494463, 58659117798024738, 1950987668385367835, 1047959670635367230, 7199802506274179843, 11627650263155381900, 4361064659696575038, 10347120495653094676, 14070050808875715623, 75544510591201674, 10341266954735171749, 16977730335508259685, 2978522689205632800, 8395315594913867980, 3061960129452262767, 5601779727658274094, 17491526265780712239, 15233389079858696706, 1032, 10320, 13024110921086730221, 3587442816163675215, 512402747638547729, 9217956011885162917, 3925750957223009950, 8674177413178223320, 12846799727083908462, 9116601283268739756, 2958792353189815054, 1720195204565087693, 7696852080146622077, 2890877729556257606, 16676527939404087356, 223754558788184593, 4767414622778376421, 14072300156908432530, 16856861612825314654, 11910434229443384600, 15658716527747040980, 14322127566252286435, 4770460127206402609, 10805338145914832851, 1391598300875421210, 18211456042978337510, 11866022853402812888, 6438324596032750504, 13328288515202849800, 17331158106613184460, 18344276842462151560, 7458506668679174706, 7458506668679174706, 14091156936533878324, 7375572182970693729, 14515360628218652783, 7553352677317462240, 10955938084877387415, 1034062223635325003, 16019914937455843830, 15206938952668638091, 4012447997079815331, 5665102116197551876, 3770800016172304546, 5393161755790695273, 11037954541995943116, 1538549641630821923, 82458381601698052, 11256540292329595942, 3662649950675088442, 9310380056949111902, 9078793057127894263, 12413466243433342378, 11963713252400458519, 17170011751313180080, 3131690541743081493, 1565661301057382940, 1661897422826290746, 14617639341020367486, 14014187841969039807, 6350121359078755518, 1074154985721744973, 8576960520729553430, 10762639943655126491, 1032, 10320, 13024110921086730221, 3587442816163675215, 512402747638547729, 9217956011885162917, 3925750957223009950, 8674177413178223320, 12846799727083908462, 9116601283268739756, 2958792353189815054, 1720195204565087693, 7696852080146622077, 2890877729556257606, 16676527939404087356, 223754558788184593, 4767414622778376421, 14072300156908432530, 16856861612825314654, 11910434229443384600, 15658716527747040980, 14322127566252286435, 4770460127206402609, 10805338145914832851, 1391598300875421210, 18211456042978337510, 11866022853402812888, 6438324596032750504, 13328288515202849800, 17331158106613184460, 18344276842462151560, 7458506668679174706, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [18375473735916206629, 6249454237774489531, 9157878094690374909, 6425669842054368493, 2701132623000331756, 17379641915532686294, 5560495940744274531, 11612441789282260948, 16999709768989875265, 6996700069669527727, 18218056048932681656, 17323420959416556496, 466802243942182139, 11973093936801453371, 9146724945876234312, 7489576767990881255, 17520081994390187724, 12872469591277262776, 16839284714279473816, 8284906559011073539, 2830433105177125840, 13008883457151437178, 7615615770295186136, 8044553197656770543, 10297444041327462885, 5697734349102267077, 10790124910810980155, 9679484750905502198, 13726494118104201951, 15750438276851199178, 7407323102906641682, 4869430190272581571, 0, 8256, 1131208899036558480, 1667157010810320250, 2053960715201569301, 1526213270499333709, 69813565043892453, 14925652377538846871, 1380252317064967448, 9902934070223067140, 3786794161520721521, 664031068804619792, 8470323998416702977, 4965297830526000942, 9404280000999464502, 8244737495337250711, 4784363486033662704, 4680481291290566437, 15373555507761845373, 8780119261264514018, 729009684537575982, 18306419558979237700, 15407410920890065538, 2509966126115291236, 12709897403480972846, 11498596868429821859, 6606875518512322314, 13880694912200059110, 6972406840307481976, 14148490408465275064, 2917966740410115114, 18375473735916206629, 18375473735916206629, 11043817201346618241, 11930265205656561266, 10224097019891343377, 748994844361267888, 16702335214860257337, 12190724893927857742, 15379261811913612411, 16916810907472200588, 3208814004368724195, 3855578449388338708, 14165119338755346303, 6632649140152805373, 2797795394808561009, 15650881762132647945, 17209782644178391817, 13783743867565375293, 10090924967376195547, 7343319863281531122, 3154891837622088858, 15555070991869858832, 3720214064901529690, 16228854173327781424, 14339877087618729700, 6737780555657097058, 10816148347772460352, 6888313430102783827, 11552248269785226165, 16919207520546831674, 859159578513939084, 3809060186754369406, 8123069549705052795, 0, 8256, 1131208899036558480, 1667157010810320250, 2053960715201569301, 1526213270499333709, 69813565043892453, 14925652377538846871, 1380252317064967448, 9902934070223067140, 3786794161520721521, 664031068804619792, 8470323998416702977, 4965297830526000942, 9404280000999464502, 8244737495337250711, 4784363486033662704, 4680481291290566437, 15373555507761845373, 8780119261264514018, 729009684537575982, 18306419558979237700, 15407410920890065538, 2509966126115291236, 12709897403480972846, 11498596868429821859, 6606875518512322314, 13880694912200059110, 6972406840307481976, 14148490408465275064, 2917966740410115114, 18375473735916206629, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [2105717247508690050, 6189083373333363630, 2656177146482477345, 1057347249925241992, 12877193726173516655, 12251509207411105210, 1152241254719451449, 9876796305008770402, 13886895990537049692, 5955094425987607481, 1554095718593181827, 13216497717183331409, 776902023022590964, 5811111240012717463, 4275189229324905850, 13670290926832689868, 5572024486552078020, 17065492216843752601, 3297004024924317076, 14424352157875397982, 17390634589199639220, 6197470634991589920, 4408358210817562027, 2934098723242191367, 1959730788177155769, 17690050280182053134, 3272945528020851774, 10688942373536545422, 2313436297690393057, 9701508002112089263, 1542465249691690504, 15500832090051527072, 0, 2064, 18136552782870868471, 952274539956745973, 15933282259815262093, 9924516287334785738, 18064603646801610993, 5114527609957824263, 11816233963570869158, 17699527003452380450, 14533708946479200173, 17484213571014188868, 832814531422633701, 1508169308733590908, 8423043379628164525, 12595277727969636921, 14226276023010866965, 10485112285448962747, 1783527593060720204, 10145484005384627580, 7463752398658534839, 17345550819494003223, 4432309123412733588, 7086318781105575433, 8830891075082588619, 310185093236608634, 16683125300631590273, 7786799186167080425, 29465347809991832, 8090161351836983773, 8665315444141111469, 2105717247508690050, 2105717247508690050, 3724970573052107061, 4114673899889075534, 9176940842530023940, 7547336479279255184, 11656391078860305642, 295623386594127504, 16942248732504945228, 13682452505450251602, 1932912055656971408, 2726480361376479149, 8421050872483387862, 15290165883438443901, 1096575918097796357, 18242297745273113718, 17017163620459148710, 4241087992417717505, 2254013451933557848, 3831151314405580129, 3571435480437187779, 3526382752987906743, 10913818845540317263, 2010650094200565990, 11538983127386740908, 2393120920072159035, 9645620379287089841, 14221268644167684727, 14318256705345657556, 2619120800729679292, 841980681719838180, 13388339383354858226, 10333571018226702209, 0, 2064, 18136552782870868471, 952274539956745973, 15933282259815262093, 9924516287334785738, 18064603646801610993, 5114527609957824263, 11816233963570869158, 17699527003452380450, 14533708946479200173, 17484213571014188868, 832814531422633701, 1508169308733590908, 8423043379628164525, 12595277727969636921, 14226276023010866965, 10485112285448962747, 1783527593060720204, 10145484005384627580, 7463752398658534839, 17345550819494003223, 4432309123412733588, 7086318781105575433, 8830891075082588619, 310185093236608634, 16683125300631590273, 7786799186167080425, 29465347809991832, 8090161351836983773, 8665315444141111469, 2105717247508690050, 7458506668679174706, 7458506668679174706, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1679902783560062568, 5453149304543877456, 9595010673478717796, 2952696768975672640, 8134038032300527981, 11332133599874182390, 9024753214576304672, 857162913496477952, 12013033971053205979, 4600756375093602184, 14082822594797913170, 8883202514107224654, 2439806288455133669, 5376354024916878032, 7594752061560203213, 5093440171701971002, 11786562020391663198, 1236915402111178740, 13738296853496739000, 7765385093473679298, 8013578318153954341, 11778596345025144994, 14965315602871180353, 15355585492520345027, 3683028660232663225, 6851384090147864767, 10508624984882018667, 1397413665818442288, 2862574062899872918, 292885921741812279, 12978790960819480190, 15232111199771387968, 0, 2064, 9594118340025725004, 16218246678075491818, 11582919835122342747, 5661452934218108707, 3714647928422746674, 13689184893219719187, 1899963197709801965, 8313716591368695784, 17822645741084942000, 18354595702287703799, 12620512717427217848, 10145637708639089787, 1735222492513760332, 14681927838838900060, 9262747238997471758, 11498487923782501751, 8924101344488972446, 2592517964915386184, 4276681409258176044, 3764365715267793208, 3120204268813370353, 6019260256544801113, 2801984351776029768, 16979166255722313516, 2813750347113564525, 16588139065369475399, 12012198471360912693, 2492059183640657261, 16968938268466755316, 1679902783560062568, 1679902783560062568, 14885555914322696706, 357898588148103340, 5295486817886607656, 12813840270094930087, 14997912950175773344, 3065571107994870550, 6045840981748218070, 6913190410219799142, 10694613226894070186, 13202643588773009520, 12618454603290221396, 4286869539192998442, 14688825675433502322, 6261505341338998374, 11526290763485067527, 13595735573859078719, 11176916463285615298, 18361875051234113789, 7745326199098368365, 16699599314531576118, 1870816068625375840, 15123892811152051673, 13015893667273525423, 9102343296676237120, 3339334071833702047, 15390057062148905453, 7122136282318587603, 9966134226732180184, 5538826350883883796, 9989685048829963204, 3763553361837852375, 0, 2064, 9594118340025725004, 16218246678075491818, 11582919835122342747, 5661452934218108707, 3714647928422746674, 13689184893219719187, 1899963197709801965, 8313716591368695784, 17822645741084942000, 18354595702287703799, 12620512717427217848, 10145637708639089787, 1735222492513760332, 14681927838838900060, 9262747238997471758, 11498487923782501751, 8924101344488972446, 2592517964915386184, 4276681409258176044, 3764365715267793208, 3120204268813370353, 6019260256544801113, 2801984351776029768, 16979166255722313516, 2813750347113564525, 16588139065369475399, 12012198471360912693, 2492059183640657261, 16968938268466755316, 1679902783560062568, 18375473735916206629, 18375473735916206629, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [10762639943655126491, 13388996836365281621, 18292910592958568240, 12237721921963192287, 8943209618246977520, 17924245204927493750, 8434099123041054143, 10575898537057061569, 7340771781180054840, 12844549286514316999, 12231131842570129507, 16875123239233429747, 3964564537195320111, 5715220285758953899, 12754036126848799562, 18436803950002947068, 1770169068010173560, 9424981723294470612, 17771283980301938781, 15212703043278891550, 16986576216468074674, 11657506507106753305, 12474701290169643873, 13224479227546334120, 2845122065365884365, 13589399096280778905, 4675637374086440016, 2796167990897236857, 3556539463682311357, 15865424937925414652, 3385987959754514103, 8819338964313765439, 0, 5160, 1190658701913535022, 9371121588404883743, 7133056533056999470, 7380100170229652082, 14719783382686670107, 4693530971176924881, 11125714198188567552, 2434816259070577714, 17927785478103501878, 834873962620943786, 1091858408197145201, 9293176204765248193, 11318806736621162148, 979530496520387452, 8328113718786640843, 15870139479256453021, 7754853849459016697, 2742936430580983415, 6806060556807781604, 5089080673677611112, 16430235900965466453, 309743103212430298, 15664803780047891222, 3113571524475220627, 17862871362988443440, 1231393200801541530, 15779352999894925288, 6026600320279882336, 6970552753544824994, 4949154992619464010, 0, 7045578468266939526, 7285583783616369700, 2341840897571774669, 7986574489568710564, 12566560672680462445, 16276641203995750872, 1484828875872057093, 1043080754823121706, 14953544298592652410, 1857761078137818000, 6862941658795962417, 7623278478713901054, 9161331715698713896, 2770593420692286823, 3760546371254144518, 9012199850736714078, 16164469939521445727, 3279768234486766882, 1877833914786208431, 6746861716770001362, 8593640503056413152, 8414605328494867260, 10458069463001905889, 16457099907011561259, 16703249241540341232, 12864763495673156246, 6953851240052973821, 11069840221589825139, 2743129109919723025, 8185888587159810481, 9760033137073938718, 0, 5160, 1190658701913535022, 9371121588404883743, 7133056533056999470, 7380100170229652082, 14719783382686670107, 4693530971176924881, 11125714198188567552, 2434816259070577714, 17927785478103501878, 834873962620943786, 1091858408197145201, 9293176204765248193, 11318806736621162148, 979530496520387452, 8328113718786640843, 15870139479256453021, 7754853849459016697, 2742936430580983415, 6806060556807781604, 5089080673677611112, 16430235900965466453, 309743103212430298, 15664803780047891222, 3113571524475220627, 17862871362988443440, 1231393200801541530, 15779352999894925288, 6026600320279882336, 6970552753544824994, 4949154992619464010, 2105717247508690050, 2105717247508690050, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [8123069549705052795, 5156554708236344275, 14240818815081743895, 9867313438556302162, 15795460020964061272, 4746638863317237450, 13819676251412656237, 4727422680796194490, 8335480078758159858, 9036771623022810541, 8351265204536669701, 9236720663990755838, 11452649604190176127, 17344644189632397547, 141238439626841910, 5940293383350715760, 13513881994175113234, 1766672227767985245, 5047254911149411718, 11537743148965787196, 11119902426374535999, 10562233986963391039, 5709991789928772648, 8741809910406193485, 8455014431114507154, 1111308100041845231, 4725453465222465298, 18262636953418597987, 3114326789966402908, 14795199298580283463, 1803230571695746105, 6301331656216941589, 0, 4128, 1352424102745866255, 13301242752201603536, 5420135027930584396, 17078794493496835379, 4779811836607866048, 3650219859599657886, 13618468821889769363, 11429589192023659923, 8853101337885331080, 9650238821992519861, 14401087967309285252, 12035560952634921032, 15407186837043713393, 15711028160746246110, 5396976350889627712, 15903424027416555998, 11304777107657759509, 9857843669692965578, 12605480788735099613, 14618970056708743810, 8493993205782554647, 6059068631740368787, 18316971448227884023, 12499808993385025318, 4210674244211222629, 18405965507148502967, 173097048437312502, 15568437290332308327, 11532601739151124629, 10000279862191744493, 0, 14745280635380601593, 17607190493438925163, 11648589526377348791, 6243809814482637102, 16161225923217405001, 4968707009078818352, 7850088573615079578, 16921347809582866242, 14652545103008190675, 3872738867357780593, 2726731287352881882, 192228728999281395, 7091916593754280269, 16410861698623401699, 1724516719793133637, 2030640503060349569, 8472956584581079805, 4062370463253756874, 17250202004686581488, 14985797666948203666, 16191245541264589205, 4308256905478940952, 7707331357694852335, 16083843991369764206, 2809575014506442646, 2531361488896305650, 4074765595145570620, 16198584180859672852, 2331298026793641183, 10607839477677695183, 18135156828501150556, 0, 4128, 1352424102745866255, 13301242752201603536, 5420135027930584396, 17078794493496835379, 4779811836607866048, 3650219859599657886, 13618468821889769363, 11429589192023659923, 8853101337885331080, 9650238821992519861, 14401087967309285252, 12035560952634921032, 15407186837043713393, 15711028160746246110, 5396976350889627712, 15903424027416555998, 11304777107657759509, 9857843669692965578, 12605480788735099613, 14618970056708743810, 8493993205782554647, 6059068631740368787, 18316971448227884023, 12499808993385025318, 4210674244211222629, 18405965507148502967, 173097048437312502, 15568437290332308327, 11532601739151124629, 10000279862191744493, 1679902783560062568, 1679902783560062568, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [10333571018226702209, 16014082921795859036, 12629006099543903781, 11629549595353476530, 12391817649960371746, 18215572691662216416, 9770277866850602303, 15952392766460324197, 15252935280552519544, 15112355243278003890, 11730975142866437995, 14381423242728406980, 10300190929163106289, 5789021531153320332, 9467399003606204480, 16325741572454755376, 8742203160529149671, 5901287082041632906, 6770325052904344921, 9452634477113688134, 3864284104719206717, 1425502383761932940, 2603361438916393613, 13866368315332604201, 9048180624295164267, 16476448149297980239, 2875474760261200724, 13145957222015138318, 10421862999996593301, 1295265690517985261, 16925389328505591881, 10498339818362385984, 0, 1032, 4798141223555508282, 12962488577647927717, 10133257770726709126, 332864556927106185, 12116126881643349994, 6604148216925166409, 101015634312276042, 15934992137290074922, 6112274855072540816, 17762248064501548615, 13166189948742588777, 270100349969833402, 13485211244653928073, 3502306881032295169, 13607663468974078519, 8883940618995723208, 10623667092532612652, 12293715092576816840, 10386976621364522928, 9128135834925108269, 15731443845270647366, 13373704167654916087, 13746187061551926812, 11684868053863796759, 3258729720361659960, 10434904637843727165, 7034851303745741351, 16133345873308301364, 5426492436527662130, 2980140658145787783, 0, 11085857321233345847, 2980560268975659509, 16677115946292689576, 6374023427586874052, 13803600456482333144, 17431196185821251777, 10464217353719819983, 6438571068779754291, 13603500087699002662, 16932213864431306166, 2730762088957911453, 12429723114079333001, 8118452627061731933, 8355576936208207930, 16312459584950423998, 13584079343885951211, 10089145279525513149, 11716103245047864025, 18203686573852208977, 4067749319688593665, 3265941627325086351, 5632283698331253382, 15760522752058781932, 12058385795435302938, 9091954158859286830, 6057235671332894001, 8049826081078855168, 8520182244182315667, 11739746407539790532, 15346229459908117188, 12074025836888921857, 0, 1032, 4798141223555508282, 12962488577647927717, 10133257770726709126, 332864556927106185, 12116126881643349994, 6604148216925166409, 101015634312276042, 15934992137290074922, 6112274855072540816, 17762248064501548615, 13166189948742588777, 270100349969833402, 13485211244653928073, 3502306881032295169, 13607663468974078519, 8883940618995723208, 10623667092532612652, 12293715092576816840, 10386976621364522928, 9128135834925108269, 15731443845270647366, 13373704167654916087, 13746187061551926812, 11684868053863796759, 3258729720361659960, 10434904637843727165, 7034851303745741351, 16133345873308301364, 5426492436527662130, 2980140658145787783, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [3763553361837852375, 7024708807018294243, 17577226387288678131, 13716375462026905857, 14482978747921062164, 17754397088096536098, 2341715857705720364, 3724235583902658756, 12360261201437984812, 730185504501270972, 15524246669712397578, 7810652382804679854, 5971697062339273781, 5708809062652245260, 16177446039571837537, 7755082824309561098, 1927394300565043315, 1165019439709787271, 6617008402134939344, 3603778144996964306, 176242085391797703, 909081700857492913, 17467207375025427139, 2699428799277364714, 13677833070933733895, 466181988870620953, 6186708066785434963, 15657067447011081019, 14062022826502957095, 761626268401747468, 4218839459301981158, 16913863751850228813, 0, 1032, 11702782905971311743, 8115486282645452027, 16425371230714077552, 10333496212804492507, 1572943607289284437, 13244361396034453954, 12880029163967100393, 14716450796809578181, 2618965885956593171, 1606019581379521796, 12562170441304287563, 4599116799417823473, 4257071131168813417, 10446583017549019711, 3570388907037362614, 11170081717188072664, 17238997244398394333, 17231192964516960933, 8123337005847551087, 7060091366977384949, 5719725530909274667, 5057603743378325948, 13848013489728729143, 17729739340387068117, 367186060507240673, 1411195984452924204, 11088333491201093194, 16575090776691519559, 16147396598096989679, 14525300817521856881, 0, 7442777957161348405, 9840729387235286710, 5900691155193699968, 4972370306575754106, 9622663477343810731, 8634190114258092107, 3115968329113702329, 407029562402079548, 8621676138210350854, 17169697721720642078, 13787761240489595746, 4665424646389854706, 15962032776378499122, 10283190965555694067, 13646278760603062560, 14461293318223306846, 15816981584402185692, 10710878099338717350, 8561420609988943751, 11090271778037546558, 17906181318089402198, 13930473893330665754, 1680786918385336269, 4346813073489505623, 588116911830026470, 1138114433189805556, 12813431130535659481, 17403245364016302552, 4250865385724499409, 2341302228431136742, 12052022490343773172, 0, 1032, 11702782905971311743, 8115486282645452027, 16425371230714077552, 10333496212804492507, 1572943607289284437, 13244361396034453954, 12880029163967100393, 14716450796809578181, 2618965885956593171, 1606019581379521796, 12562170441304287563, 4599116799417823473, 4257071131168813417, 10446583017549019711, 3570388907037362614, 11170081717188072664, 17238997244398394333, 17231192964516960933, 8123337005847551087, 7060091366977384949, 5719725530909274667, 5057603743378325948, 13848013489728729143, 17729739340387068117, 367186060507240673, 1411195984452924204, 11088333491201093194, 16575090776691519559, 16147396598096989679, 14525300817521856881, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 10217287652316111123, 13517781640136319575, 1661113771033030694, 16589784235244657737, 17095733862217014640, 12034870070859925254, 3362052720054026253, 14837478738765105779, 3912940502921138924, 4669997399462018425, 17270138094532924819, 1214102817436621233, 9054176820646026827, 14620454815482057063, 14379345126022103590, 1237842674755258205, 7292827283948466879, 7427352618130823166, 7062449106203043729, 4684102489113893021, 9822227459662699800, 8534835061687915045, 6887380873242738838, 14418031150463989616, 221488275360631569, 10086890380770548477, 6262776103179261925, 1645321375146597351, 16239201862143352504, 15053642145439578838, 2190556552135086015, 0, 5160, 18346837778669738664, 15130142357101091527, 6726588340010678615, 8394319278312203283, 15942424551308612685, 7629500615465222065, 14939877513325106589, 17048523965011794048, 2306293645521445312, 823113708878672797, 14981348226783328932, 7432878333905782051, 3482639998457803800, 632277917380007036, 18266437030920184246, 3366715262389109205, 5280275432441977334, 5379329043314533811, 13912213856326486056, 17217059915921675075, 15634373017412823086, 14981257187297131103, 16697350900700022325, 5239234081629986555, 3229291246709926782, 18373224696258292584, 6771862800272250893, 7666370275789511263, 12942227631865082960, 15190222347874856922, 0, 7045578468266940254, 4295968767249300726, 5119947407811220060, 9698255539411717765, 12731464969523549591, 10964642791546394204, 7030591121083126444, 7491881549557152759, 8712880758165105101, 17597004205156968556, 3440400661109297059, 18367279145997928908, 7289973069099595657, 16259498994873975520, 16637999468821149367, 13016124245267804117, 3041300342890742581, 15830253523429142702, 4124978113326913000, 18280219261996495240, 13678174604107677296, 11027937708781352184, 9524461836107268283, 7086746505450311592, 7319928310078430930, 11146341134166142886, 14000752730312100679, 8776837767210836349, 7842835560601620329, 9613994929417659617, 12679002698944454251, 0, 5160, 18346837778669738664, 15130142357101091527, 6726588340010678615, 8394319278312203283, 15942424551308612685, 7629500615465222065, 14939877513325106589, 17048523965011794048, 2306293645521445312, 823113708878672797, 14981348226783328932, 7432878333905782051, 3482639998457803800, 632277917380007036, 18266437030920184246, 3366715262389109205, 5280275432441977334, 5379329043314533811, 13912213856326486056, 17217059915921675075, 15634373017412823086, 14981257187297131103, 16697350900700022325, 5239234081629986555, 3229291246709926782, 18373224696258292584, 6771862800272250893, 7666370275789511263, 12942227631865082960, 15190222347874856922, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [87, 9950917671808473405, 3554228101202979253, 9306806947978771582, 4401882774217375917, 15315969540976862758, 16886025621791162858, 10861900348873787927, 5957397384759471696, 13244465343946802573, 6540213681196691440, 11070522019866408102, 3801445557467335639, 12532452847683566938, 11669769547992992357, 12808908716587726858, 17995649345722530812, 698204761262232508, 6333121561150411801, 4032763150397248777, 14008259259755136035, 6979651972374810449, 7911828305365051593, 3932176613876828948, 7810471060559602612, 10015863907140938459, 8849830318071758779, 7592172000473889159, 5876504027679413408, 17878067193823269498, 15447825779474026874, 5053260159826664462, 0, 4128, 6496253015800789210, 18063315295058131399, 14099326864720264780, 16744359797696928029, 11669954633423859445, 10923938539628559259, 10579480970462933513, 17315553376669597828, 12114095292572219189, 16129781670858537825, 67936491912723144, 6285840300661422802, 14359460599290704174, 7597471307904508314, 8469569990667894210, 9117246600999250277, 14614928058075190380, 13738364908865630160, 1806905237893315697, 261412144627674040, 8380596589382515797, 3809925330596605534, 1983199361335541287, 6337901890572878101, 17063257729896061936, 12690697575318882146, 3846044480011221270, 10729939698274680623, 5297971463863936522, 8671284646676347574, 104, 14745280635380602217, 1277989312750492883, 17882043915102295645, 8402260971363137004, 11464571068891742851, 15059523259116208792, 4259151281546711306, 12299499890598148513, 16319371075448400987, 8885641423428293370, 16309893991999277564, 2619218791994734454, 17151450962136165028, 17614551442000447874, 17230858587654278062, 19705201673078532, 2732075625107327721, 6566262129896944024, 689808164767473390, 11564905194821649437, 14876340024025687860, 10936017910631925277, 10540913652282428134, 10843077561784740363, 5250262515785863526, 8273371701363724667, 16366540385334083230, 9631977100618497396, 18413271307798397411, 1499758295592994876, 14053004056904301616, 0, 4128, 6496253015800789210, 18063315295058131399, 14099326864720264780, 16744359797696928029, 11669954633423859445, 10923938539628559259, 10579480970462933513, 17315553376669597828, 12114095292572219189, 16129781670858537825, 67936491912723144, 6285840300661422802, 14359460599290704174, 7597471307904508314, 8469569990667894210, 9117246600999250277, 14614928058075190380, 13738364908865630160, 1806905237893315697, 261412144627674040, 8380596589382515797, 3809925330596605534, 1983199361335541287, 6337901890572878101, 17063257729896061936, 12690697575318882146, 3846044480011221270, 10729939698274680623, 5297971463863936522, 8671284646676347574, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 13549970121514602677, 473829894064878094, 13789183496966727565, 1955350239938339874, 7201082322234349663, 9016022097577899196, 6529222281750641224, 17689702079462878790, 10156549575434042429, 7248885352501816322, 12178683397221723524, 6850524170552426967, 8689264751605527455, 1407059625629950522, 9144161729371790458, 3267820578940859361, 10961895042020971306, 15803107242779899332, 13169126454128015246, 6297730490781618091, 16325028460633105625, 1221092837168607222, 8986628150783184058, 17306851421758051833, 15205710348050472951, 2733211805524420436, 13936580861462477484, 16716871354996632672, 2773281916155934536, 9099902973067746305, 12285155954580341409, 0, 1032, 13084260837127404333, 4018109146681745349, 14498381569327145056, 3778421823029569719, 1344624249217908323, 3634653398484528177, 1428985706412758663, 11382569756632997337, 13894906302086601399, 3911680161282028629, 11467762927868003365, 10098326072301516020, 16073214466625742345, 16150512194511843089, 11525294274796193451, 15902507139806774023, 13926886722650908730, 2974304378722638293, 5274544965980948277, 9984170014312577610, 639485734140932316, 15088403650698955530, 17189134684458608982, 6515320870350778492, 7902492290152572474, 17310456195349246143, 4070136787975548901, 6345872167795009033, 3095930865537762353, 4232664728858134772, 0, 11085857321233346159, 750403697714635224, 15867156494024459966, 7866397620702682136, 5793298599059911546, 5158478207966654343, 16510537027687425322, 4650635265747757214, 2676532104357997308, 10285794245095273390, 13247727332705294758, 17671377272587403594, 8030571597136649189, 1289802346192453208, 14103228039950804909, 4124512422853870088, 3056884801892714758, 4767720916160432521, 3187398915591767652, 16919717526667459899, 18271533057078737338, 4118950315111493430, 5321954010838991352, 4375178466595687599, 13452922166654240382, 18416629007910574933, 663957419786385993, 3920191287070292962, 1103793272511562248, 4364510604874202960, 18207465128223513961, 0, 1032, 13084260837127404333, 4018109146681745349, 14498381569327145056, 3778421823029569719, 1344624249217908323, 3634653398484528177, 1428985706412758663, 11382569756632997337, 13894906302086601399, 3911680161282028629, 11467762927868003365, 10098326072301516020, 16073214466625742345, 16150512194511843089, 11525294274796193451, 15902507139806774023, 13926886722650908730, 2974304378722638293, 5274544965980948277, 9984170014312577610, 639485734140932316, 15088403650698955530, 17189134684458608982, 6515320870350778492, 7902492290152572474, 17310456195349246143, 4070136787975548901, 6345872167795009033, 3095930865537762353, 4232664728858134772, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 16457115416797113563, 16239155032122797832, 14849238236368251159, 9108419460474808576, 1033211373414661409, 14502772570466296089, 4038467972202515368, 1460799694261663366, 12439775236546072843, 16427603058194514665, 14959440030310041613, 3845590175102547346, 1301757407011623611, 17501633393315606025, 11009053095286438923, 3009367688589025768, 6965916889756314709, 4517155861865643415, 15896658462307045811, 9681943962122261504, 9968758826692797274, 5829992311401516243, 15782779420328542209, 11631298814075616775, 12222681008501641705, 12020699456941818376, 16842897778485981781, 4735042970479906379, 3151070592229922496, 3062023609160919321, 9514569903823065872, 0, 1032, 15909096041365347974, 18432189660917429733, 2798890989547891271, 10768372030970716894, 5935807051329113911, 1259182408195029650, 16024750973514577255, 6103595041913569283, 914770550723164908, 5067028895751058275, 5242612139537538536, 13359135899043031769, 4430959127423856282, 16317056360529517539, 2634255659160911215, 15590656855559575839, 6832335878067392309, 6045109056629836176, 18146646330136390606, 6482705684632040588, 2770791364887326735, 7707774010999656594, 3401430074469265273, 3500862351024377705, 5135727797169111985, 14940852959892477883, 9633218853985087472, 16966092255533854383, 3065488485208441055, 15703076512693482766, 0, 7442777957161348509, 3036215591853057143, 16090863638087042910, 3963133567703228598, 17908349476423851244, 7001924323395444874, 17338586306104572036, 14119937534703630749, 4242994035168829398, 2363031437222084351, 3255777517629291140, 124459613086078350, 13938492907317794048, 4899661652548582019, 1296301487511431772, 14599398842157535330, 4565191284080628584, 9612849067002171183, 10046653166326882870, 1539793980828004113, 15261415128186745093, 15065597191535528607, 16001910338161660328, 12471346680264155869, 6112064272743521679, 16130747048670899171, 1508047113079150807, 8501241071240823019, 9778047403489538902, 4539108168956164212, 12867780329443177182, 0, 1032, 15909096041365347974, 18432189660917429733, 2798890989547891271, 10768372030970716894, 5935807051329113911, 1259182408195029650, 16024750973514577255, 6103595041913569283, 914770550723164908, 5067028895751058275, 5242612139537538536, 13359135899043031769, 4430959127423856282, 16317056360529517539, 2634255659160911215, 15590656855559575839, 6832335878067392309, 6045109056629836176, 18146646330136390606, 6482705684632040588, 2770791364887326735, 7707774010999656594, 3401430074469265273, 3500862351024377705, 5135727797169111985, 14940852959892477883, 9633218853985087472, 16966092255533854383, 3065488485208441055, 15703076512693482766, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] }, last_program_row: RowIndex(12) }, program_info: ProgramInfo { program_hash: Word([15233389079858696706, 4869430190272581571, 15500832090051527072, 15232111199771387968]), kernel: Kernel([Word([7458506668679174706, 18375473735916206629, 2105717247508690050, 1679902783560062568])]) }, stack_outputs: StackOutputs { elements: [1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, merkle_store_nodes: {Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571]): (Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350]), Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350])), Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484]): (Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693]), Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693])), Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781]): (Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874]), Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874])), Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171]): (Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361]), Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361])), Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815]): (Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305]), Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305])), Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689]): (Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195]), Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195])), Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362]): (Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063]), Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063])), Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848]): (Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661]), Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661])), Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352]): (Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829]), Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829])), Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444]): (Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223]), Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223])), Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386]): (Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388]), Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388])), Word([13190842942618341421, 17548956981569849952, 15418963848144418856, 730733050713174879]): (Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144]), Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144])), Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874]): (Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675]), Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675])), Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594]): (Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115]), Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115])), Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809]): (Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257]), Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257])), Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777]): (Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555]), Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555])), Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509]): (Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882]), Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882])), Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725]): (Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979]), Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979])), Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134]): (Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987]), Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987])), Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828]): (Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910]), Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910])), Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830]): (Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054]), Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054])), Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228]): (Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742]), Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742])), Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443]): (Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928]), Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928])), Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643]): (Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979]), Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979])), Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758]): (Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106]), Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106])), Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580]): (Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594]), Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594])), Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765]): (Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045]), Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045])), Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766]): (Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281]), Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281])), Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385]): (Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828]), Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828])), Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579]): (Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171]), Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171])), Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212]): (Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992]), Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992])), Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463]): (Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004]), Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004])), Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502]): (Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023]), Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023])), Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539]): (Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537]), Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537])), Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865]): (Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225]), Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225])), Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690]): (Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947]), Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947])), Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202]): (Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552]), Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552])), Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079]): (Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444]), Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444])), Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850]): (Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548]), Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548])), Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448]): (Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987]), Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987])), Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041]): (Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035]), Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035])), Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301]): (Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414]), Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414])), Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414]): (Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212]), Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212])), Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703]): (Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439]), Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439])), Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271]): (Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955]), Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955])), Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882]): (Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802]), Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802])), Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152]): (Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887]), Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887])), Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028]): (Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948]), Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948])), Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331]): (Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093]), Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093])), Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394]): (Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134]), Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134])), Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546]): (Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228]), Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228])), Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620]): (Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414]), Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414])), Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800]): (Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703]), Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703])), Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671]): (Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205]), Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205])), Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537]): (Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011]), Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011])), Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516]): (Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301]), Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301])), Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831]): (Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986]), Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986])), Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415]): (Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057]), Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057])), Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722]): (Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689]), Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689])), Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144]): (Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682]), Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682])), Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295]): (Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268]), Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268])), Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818]): (Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513]), Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513])), Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241]): (Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565]), Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565])), Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439]): (Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012]), Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012])), Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512]): (Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850]), Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850])), Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986]): (Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865]), Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865])), Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982]): (Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777]), Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777])), Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808]): (Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394]), Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394])), Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979]): (Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690]), Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690])), Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093]): (Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620]), Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620])), Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902]): (Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789]), Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789])), Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542]): (Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094]), Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094])), Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057]): (Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362]), Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362])), Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205]): (Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961]), Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961])), Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401]): (Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580]), Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580])), Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553]): (Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960]), Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960])), Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169]): (Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031]), Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031])), Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682]): (Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053]), Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053])), Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118]): (Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562]), Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562])), Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725]): (Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666]), Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666])), Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661]): (Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897]), Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897])), Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981]): (Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447]), Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447])), Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072]): (Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646]), Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646])), Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140]): (Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404]), Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404])), Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515]): (Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152]), Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152])), Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709]): (Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664]), Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664])), Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800]): (Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103]), Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103])), Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741]): (Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169]), Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169])), Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005]): (Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758]), Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758])), Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802]): (Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070]), Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070])), Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159]): (Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005]), Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005])), Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350]): (Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443]), Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443])), Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697]): (Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573]), Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573])), Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928]): (Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331]), Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331])), Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320]): (Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166]), Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166])), Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814]): (Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079]), Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079])), Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447]): (Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820]), Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820])), Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284]): (Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057]), Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057])), Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697]): (Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131]), Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131])), Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955]): (Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290]), Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290])), Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910]): (Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202]), Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202])), Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910]): (Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822]), Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822])), Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106]): (Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847]), Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847])), Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404]): (Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441]), Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441])), Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796]): (Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186]), Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186])), Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053]): (Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516]), Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516])), Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992]): (Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818]), Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818])), Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957]): (Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315]), Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315])), Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709]): (Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794]), Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794])), Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091]): (Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539]), Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539])), Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664]): (Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558]), Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558])), Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294]): (Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579]), Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579])), Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947]): (Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502]), Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502])), Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829]): (Word([0, 0, 0, 0]), Word([0, 0, 0, 0])), Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045]): (Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137]), Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137])), Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914]): (Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041]), Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041])), Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573]): (Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378]), Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378])), Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699]): (Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873]), Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873])), Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225]): (Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262]), Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262])), Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057]): (Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692]), Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692])), Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131]): (Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997]), Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997])), Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555]): (Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385]), Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385])), Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195]): (Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709]), Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709])), Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166]): (Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542]), Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542])), Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027]): (Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373]), Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373])), Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378]): (Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509]), Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509])), Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097]): (Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553]), Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553])), Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217]): (Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815]), Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815])), Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873]): (Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864]), Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864])), Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997]): (Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722]), Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722])), Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887]): (Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766]), Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766])), Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589]): (Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757]), Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757])), Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539]): (Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665]), Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665])), Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129]): (Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229]), Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229])), Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137]): (Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312]), Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312])), Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019]): (Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378]), Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378])), Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331]): (Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713]), Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713])), Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]): (Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980]), Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980])), Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325]): (Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546]), Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546])), Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170]): (Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822]), Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822])), Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054]): (Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295]), Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295])), Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925]): (Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848]), Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848])), Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909]): (Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796]), Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796])), Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540]): (Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170]), Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170])), Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214]): (Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448]), Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448])), Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317]): (Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294]), Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294])), Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757]): (Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416]), Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416])), Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378]): (Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091]), Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091])), Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263]): (Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463]), Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463])), Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666]): (Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361]), Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361])), Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174]): (Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992]), Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992])), Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470]): (Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401]), Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401])), Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665]): (Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957]), Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957])), Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262]): (Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144]), Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144])), Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229]): (Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284]), Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284])), Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134]): (Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325]), Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325])), Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855]): (Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765]), Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765])), Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115]): (Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814]), Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814])), Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441]): (Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831]), Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831])), Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977]): (Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446]), Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446])), Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880]): (Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005]), Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005])), Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789]): (Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995]), Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995])), Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000]): (Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267]), Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267])), Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998]): (Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982]), Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982])), Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995]): (Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539]), Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539])), Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507]): (Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512]), Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512])), Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305]): (Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118]), Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118])), Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219]): (Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009]), Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009])), Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416]): (Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089]), Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089])), Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980]): (Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445]), Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445])), Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063]): (Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140]), Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140])), Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713]): (Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159]), Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159])), Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031]): (Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809]), Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809])), Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932]): (Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037]), Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037])), Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094]): (Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925]), Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925])), Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315]): (Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386]), Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386])), Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446]): (Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721]), Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721])), Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742]): (Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981]), Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981])), Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661]): (Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072]), Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072])), Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979]): (Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671]), Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671])), Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361]): (Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269]), Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269])), Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558]): (Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571]), Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571])), Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290]): (Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902]), Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902])), Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987]): (Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741]), Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741])), Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902]): (Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515]), Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515])), Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497]): (Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028]), Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028])), Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948]): (Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709]), Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709])), Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009]): (Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725]), Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725])), Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387]): (Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317]), Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317])), Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159]): (Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808]), Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808])), Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394]): (Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699]), Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699])), Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312]): (Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000]), Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000])), Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987]): (Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821]), Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821])), Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046]): (Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909]), Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909])), Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565]): (Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028]), Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028])), Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269]): (Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352]), Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352])), Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847]): (Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271]), Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271])), Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513]): (Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800]), Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800])), Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054]): (Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394]), Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394])), Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004]): (Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977]), Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977])), Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675]): (Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800]), Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800])), Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692]): (Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159]), Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159])), Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909]): (Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932]), Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932])), Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814]): (Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697]), Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697])), Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186]): (Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387]), Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387])), Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445]): (Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470]), Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470])), Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966]): (Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507]), Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507])), Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548]): (Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253]), Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253])), Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897]): (Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783]), Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783])), Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208]): (Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054]), Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054])), Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268]): (Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661]), Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661])), Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388]): (Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643]), Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643])), Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257]): (Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174]), Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174])), Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960]): (Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241]), Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241])), Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721]): (Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046]), Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046])), Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822]): (Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217]), Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217])), Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253]): (Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697]), Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697])), Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054]): (Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019]), Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019])), Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821]): (Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432]), Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432])), Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864]): (Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105]), Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105])), Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373]): (Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855]), Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855])), Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646]): (Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830]), Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830])), Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460]): (Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208]), Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208])), Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033]): (Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214]), Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214])), Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105]): (Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129]), Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129])), Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281]): (Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909]), Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909])), Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028]): (Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027]), Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027])), Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012]): (Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054]), Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054])), Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562]): (Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589]), Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589])), Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037]): (Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097]), Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097])), Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355]): (Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460]), Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460])), Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223]): (Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355]), Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355])), Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089]): (Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306]), Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306])), Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035]): (Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219]), Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219])), Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432]): (Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297]), Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297])), Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693]): (Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263]), Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263])), Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794]): (Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484]), Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484])), Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552]): (Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941]), Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941])), Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267]): (Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814]), Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814])), Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992]): (Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415]), Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415])), Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941]): (Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966]), Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966])), Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822]): (Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320]), Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320])), Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306]): (Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902]), Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902])), Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820]): (Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880]), Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880])), Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361]): (Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725]), Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725])), Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005]): (Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914]), Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914])), Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783]): (Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781]), Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781])), Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011]): (Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033]), Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033])), Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297]): (Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910]), Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910])), Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070]): (Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134]), Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134])), Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144]): (Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331]), Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331])), Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023]): (Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497]), Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497])), Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103]): (Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540]), Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540])), Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961]): (Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998]), Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998])), Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414]): (Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]), Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]))}, trace_len_summary: TraceLenSummary { main_trace_len: 13, range_trace_len: 39, chiplets_trace_len: ChipletsLengths { hash_chiplet_len: 128, bitwise_chiplet_len: 0, memory_chiplet_len: 0, kernel_rom_len: 2 } } } +ExecutionTrace { main_trace: MainTrace { storage: Parts { core_rm: [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 2899453830169817055, 16816598283634567027, 3068995836555945716, 12171400876639430472, 0, 0, 0, 0, 0, 0, 1, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1032, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 2, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 8, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 3, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 4, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 1, 1, 1, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 5, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 6, 0, 0, 0, 0, 0, 5, 0, 1, 1, 0, 1, 0, 1, 1032, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 7, 0, 0, 0, 0, 0, 7, 0, 0, 0, 1, 0, 0, 0, 8, 5, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 8, 0, 0, 0, 0, 0, 7, 0, 0, 0, 1, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 9, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 1, 1, 1, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 10, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 1, 1, 1, 2899453830169817055, 16816598283634567027, 3068995836555945716, 12171400876639430472, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 11, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 31, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 33, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 39, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 43, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 47, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 50, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 51, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 53, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 54, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 55, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 59, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 60, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 61, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 67, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 69, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 70, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 71, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 72, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 73, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 74, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 75, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 76, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 77, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 78, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 79, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 81, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 82, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 83, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 86, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 87, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 88, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 89, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 90, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 91, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 92, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 93, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 94, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 97, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 98, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 99, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 101, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 102, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 103, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 104, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 105, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 106, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 107, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 108, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 109, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 110, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 111, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 112, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 113, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 114, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 115, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 116, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 117, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 118, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 119, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 120, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 121, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 122, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 123, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 124, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 125, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 126, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 127, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0], chiplets_rm: [1, 1, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 2899453830169817055, 16816598283634567027, 3068995836555945716, 12171400876639430472, 0, 87, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 18295472245208082500, 5861891236755868697, 15427470125368014171, 5623455816162216176, 11335643519415282023, 11551270937114235273, 11863835819310119404, 14266241634618616211, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1032, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 11116382020814057190, 14732796941305378371, 13074361791711182490, 6715193688317415490, 1571558009365433839, 13285275197432594374, 15905141483335727027, 2507840277166973476, 0, 0, 1, 0, 0, 1, 1, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 0, 0, 0, 0, 0, 104, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 2899453830169817055, 16816598283634567027, 3068995836555945716, 12171400876639430472, 3302920651539558582, 2392789792202575031, 11898680931385242334, 3118702462093730513, 6675709269000188192, 6602703777719207165, 6265915402349571564, 2890093557727619615, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1032, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 11116382020814057190, 14732796941305378371, 13074361791711182490, 6715193688317415490, 1571558009365433839, 13285275197432594374, 15905141483335727027, 2507840277166973476, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1032, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 0, 15913981378790993016, 12701179462806902902, 9645342555817022514, 6889850077248808033, 678249829196625442, 8726676798253716750, 14136118088409135949, 1027279235140821190, 8048729929177993405, 2542525775606472849, 3283471062508934848, 18058280687405074483, 2, 0, 0, 0, 1, 0, 0, 0, 0, 11899090779839289087, 1701090513954162998, 6953639183117323837, 11460660778637092812, 8345945186928076892, 11308243255833047975, 5734666540714547293, 1546649737555419076, 14643837757854608147, 7477230882792828789, 2359592855656894189, 12732146754685591216, 2, 0, 0, 0, 1, 0, 0, 0, 0, 16283412161296764998, 17261112905912533997, 1498213616014501531, 7707889409925905689, 16090493533591377617, 525010687572874692, 5228788497345464933, 13051466527897639054, 3560924095387897187, 12551242480725370445, 4038828260160651477, 6132317990703151787, 2, 0, 0, 0, 1, 0, 14261694278902826987, 16097544111075686229, 16632169854204459773, 14265791174051766329, 14732671264513481238, 15642599276989292777, 7593738854072541043, 11440582168151819564, 18258483622390056257, 6851601084855956341, 10463349537167637967, 10032876585525342603, 825669147467031185, 16271217766495541082, 9021089524754424392, 2, 0, 0, 0, 1, 0, 16780109665356203593, 16025948514351396737, 4256182047405196535, 4919013996388780384, 6974015548720770018, 10189882052640604940, 12288632186238773648, 7055558833039165669, 9820743264545515107, 7353106531603230851, 5612808106478211181, 362487531847990854, 10259224130335842891, 2374318293393776907, 16208179153232019183, 2, 0, 0, 0, 1, 0, 9496969110446094198, 10424961628901078909, 7587726188775237019, 13423955604028434301, 12288543613568774022, 4068762405627465026, 7288480650179820504, 1035430088689333582, 2651098721515326755, 4524440782000877024, 3013038852551457145, 12536534023666437466, 6560028330562582937, 9090521726813489969, 17634755409309861791, 2, 0, 0, 0, 1, 0, 15761194215082968049, 15796684185970405493, 1294179585337070936, 5701860167148115542, 17707247215386403887, 18419960639673587986, 14570347312565937582, 8634142387233894354, 11938075017385927203, 8060480374868324599, 16699922976999064541, 14234489074154948378, 17210389744085299852, 17331527780947314617, 16356838976302290254, 2, 0, 0, 0, 1, 0, 6184336662619539433, 7106147576739595100, 18237994300618329820, 9768155666925548219, 226714884885574576, 11169479382209254075, 5756676929838789145, 29803495366482069, 13128905441940840949, 18304516631519674746, 3177693875357946498, 10624850715031233718, 16956738608020324589, 10558540052020438814, 7826502712354673600, 2, 0, 0, 0, 1, 0, 1980308537464408089, 6810023246846442283, 9400257804338494201, 11246932855318952856, 7504545710540897051, 5823677062954428984, 9151299935574592196, 15905322272715446259, 18174748553199601666, 9877077233183640995, 2431998410719122545, 3541292002384422941, 5416588529930333172, 15788517205879313917, 2490575598934209003, 2, 0, 0, 0, 1, 0, 17950140321155419078, 9014768943295123367, 10707122777228105884, 10701204914974985643, 15060806908759160804, 7011191650405807117, 13598159658926423040, 3947314552577424057, 12985682730462769834, 18264715466581442035, 7667189540353817157, 7685483800933651249, 16085167604591833455, 16105855167414075111, 16215395602017884846, 2, 0, 0, 0, 1, 0, 8676227747932036802, 0, 0, 11504729673400082663, 3659553513673892306, 10374352082945691939, 15819529278889203623, 18107940902385670152, 8889798095480337831, 12737345777792032790, 456604824069734238, 2859376131275373721, 8758251935142908528, 2364536875264708997, 2435873391009301907, 2, 0, 0, 0, 1, 0, 0, 0, 0, 16797630026773069829, 16954579754978210547, 4393671449525183699, 6245909065255485436, 8311309349844601638, 3305827896314343556, 1615477551160071258, 3897903986825909618, 13015230208471866351, 13839070994009764281, 2415598337053791919, 5526300544248852335, 2, 0, 0, 0, 1, 0, 0, 0, 0, 12827873667465929582, 15892701250663610383, 549489834728826775, 9425334953627649153, 15402634395731091512, 11814416271399500934, 14597718118926923662, 4726679541432826422, 342915941842538663, 11221492717904369823, 17188959961041335276, 13559932473868727168, 2, 0, 0, 0, 1, 0, 0, 0, 0, 8689096602925893779, 4096531352684607500, 8424481237826564505, 15238165026175259240, 10985176737527635898, 2672540837788784952, 6649439643634522762, 7581835251244605715, 17671970641549389116, 18069913154458602790, 749417941228438762, 6150863900366154379, 2, 0, 0, 0, 1, 0, 0, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 11116382020814057190, 14732796941305378371, 13074361791711182490, 6715193688317415490, 1571558009365433839, 13285275197432594374, 15905141483335727027, 2507840277166973476, 2, 0, 0, 0, 1, 0, 0, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 0, 0, 0, 0, 0, 104, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 8045445736281483033, 11250386210932698181, 8447328201766628152, 527413860513422548, 2685530738566346168, 6831208533457089257, 18437518609042158966, 9278656209339918204, 4985219875437159245, 11102677601257469434, 16507477945842790035, 1824439754798293960, 1, 0, 0, 0, 1, 0, 0, 0, 0, 13956548861570575417, 9763011176116608502, 4674794667694672124, 15480945315513057131, 1720127490715987209, 8831144276914012491, 250532683106813113, 18120264276823504303, 7075953940225467814, 5209117550659913714, 16837262421580091230, 11776861544437613654, 1, 0, 0, 0, 1, 0, 0, 0, 0, 11512288827914447463, 17480311708360681553, 1580648391454313983, 3096307188042936924, 1465975368055000312, 1362735000009130378, 9465263839861379226, 14989718516974665241, 6566304943303044120, 2566111340353544025, 11325114382049196546, 15312957863351292707, 1, 0, 0, 0, 1, 0, 14277010279095994320, 16421135900115366688, 8672081456162485113, 3315051758368515759, 16767795201975506841, 15745773069630130456, 10428682341827527559, 1609230777320982945, 8538451532688083939, 3309529438878958210, 2752224770668803053, 4030118788308868253, 9432517950422109187, 16655292287441213846, 3022134227219891882, 1, 0, 0, 0, 1, 0, 12527609013750224641, 4064424364292504784, 12759359572746242099, 17498386834554682438, 9899399543530128857, 13823203783008011183, 4789373231313821943, 2275698290172824909, 14631083886626574849, 6083693282888760833, 17878128073269252636, 9098606451540172932, 4868784239831205121, 2796426330015583824, 10989039359288278884, 1, 0, 0, 0, 1, 0, 11227322858093773958, 1256671723465513282, 4658091495748016755, 14665531030768273966, 5299487590341247604, 3822486110676485203, 2504794437525571246, 16499336243305873535, 10440692312118465582, 8016916182618053860, 11635644660770389253, 4003332628141212645, 8214607993079575395, 7207010966340578848, 10940185796204185824, 1, 0, 0, 0, 1, 0, 12668058855470446370, 5255019430616758101, 14462744774902056824, 4113277495358115867, 1662113282866907292, 6585130578479449998, 17149676088405916342, 10457761600032190139, 3327323833077679847, 8197592365883421679, 7425424839480263678, 13938948244809494455, 16228892676090661713, 1504971017217144480, 8182776272628891435, 1, 0, 0, 0, 1, 0, 6914860967029724068, 10806403396787496173, 3848579298848325229, 13805102062857951563, 16229844626955596217, 13935582109846251306, 8572389593169145834, 17576620671980411587, 10572618363726686694, 4850773447466262928, 15638373093776703034, 7910188832488865399, 15531097057290072206, 4889338479662679107, 10949924992689136363, 1, 0, 0, 0, 1, 0, 4330865582496855032, 8473297999555512458, 7242240654409420037, 10299128364456298062, 14941042471610818695, 7565852759213474271, 3702504147651721524, 207598518842942194, 6753564273898291164, 11919043583188527726, 2096230895461827816, 9814026405907874850, 17772509140662880385, 15771358593260243554, 6654163437055992392, 1, 0, 0, 0, 1, 0, 14424762448455122149, 9431772018868236879, 584341294112809445, 4918781353216964245, 2337856752823889422, 16060522829040602978, 1539091624536270714, 3206058370812795090, 10870942617842401040, 8606083879706978586, 4344150548445731150, 380060561426657383, 2730766720879432427, 14498706802584030890, 7769509436274319865, 1, 0, 0, 0, 1, 0, 4147902545389306045, 0, 0, 16093847529947137599, 5589254378675598674, 14560311910293184412, 2592280228933147027, 10554718058272358421, 1080024418599256897, 646685994271806030, 5548578222066968465, 13466005348915411989, 1280314003050779809, 11336903746061502338, 9170512654829817344, 1, 0, 0, 0, 1, 0, 0, 0, 0, 4018352536943676596, 1718970205214835807, 16103902027304323769, 7153843611717905198, 7564037379049998274, 6261812460083581507, 17412746410051240602, 11497751499239916990, 9826997558611816650, 2818155236871917143, 1303564367886020260, 8520201627654591972, 1, 0, 0, 0, 1, 0, 0, 0, 0, 7399548230295413142, 15817399793431362137, 11111223990289672490, 14277270972042777124, 9762507146447503800, 5775448381623517643, 9705617515238056177, 10499143968321217911, 13713380413483444727, 2803285551461817904, 3117235683594903662, 8848529162601814389, 1, 0, 0, 0, 1, 0, 0, 0, 0, 41605777382338142, 13705243190620087435, 8813156438606599548, 3668196738148877897, 8870883218370515482, 1311045307375281156, 891925000095841393, 18305520102948210690, 3095238878624340898, 8925726914230878692, 11158112996086314015, 16463229027226752316, 1, 0, 0, 0, 1, 0, 0, 0, 0, 2899453830169817055, 16816598283634567027, 3068995836555945716, 12171400876639430472, 3302920651539558582, 2392789792202575031, 11898680931385242334, 3118702462093730513, 6675709269000188192, 6602703777719207165, 6265915402349571564, 2890093557727619615, 1, 0, 0, 0, 1, 0, 0, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 2899453830169817055, 16816598283634567027, 3068995836555945716, 12171400876639430472, 0, 87, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 3856634821061399044, 17111039960895529319, 4566799539362193550, 16844085186824886612, 3355565787613486613, 17176810829821093448, 1352137470786356802, 17998789203926124900, 16786513982140394745, 18361321143200586840, 13282415620666686464, 8228901733828007087, 1, 0, 0, 0, 1, 0, 0, 0, 0, 7778838127124972351, 10159506934852280087, 12722539778584946047, 2132149890053205639, 18102156639692354752, 8649394742436479221, 4276590013765363445, 12997989410109585404, 9529430557140348691, 7606828505864121076, 17598459768503654580, 7777709650181082785, 1, 0, 0, 0, 1, 0, 0, 0, 0, 8194007358744550661, 306611979519524457, 10528705374691960700, 319508112022086105, 10482736583082303606, 10309893049243492470, 12917037695721108312, 6248886070590142047, 6486447845183860200, 17251231915071761348, 16404214944354933870, 13204576128129345952, 1, 0, 0, 0, 1, 0, 8699431654038775343, 37936723307283666, 8146588049311051327, 4530941775236136548, 16738435301601374688, 11359785745622903572, 15791382447019722900, 13379247305879358010, 13936169968399350974, 3508629571016445401, 5950565638198879243, 3988632325321614173, 14773776822077474877, 3784342517219646416, 16429780078047820450, 1, 0, 0, 0, 1, 0, 3424975013671552621, 14815277144979047633, 8209627855274846837, 8295342049297215958, 15269992241592835077, 6438591265885629379, 13730717627697535913, 7787232003492715877, 9621206971434531853, 11223875126467095457, 6436756480486800604, 5377264485189635000, 5482319143373695788, 12350937431324290559, 6389531569788570962, 1, 0, 0, 0, 1, 0, 4990332689225356878, 13089030850077380376, 2471524608045276896, 17139358263655017093, 18165060065290469256, 9446121688110358951, 977359788342611310, 16707128933418187061, 16621781274459601592, 7539458736435553900, 13565999334907596759, 1167963651906558177, 801268771425181312, 6228026786881094671, 1048304545096961231, 1, 0, 0, 0, 1, 0, 9535941747246118180, 6758632961600419030, 13740260214376027515, 1405920164415583051, 14920069431652436384, 17439962485710135044, 417887867370226026, 16088228384974311599, 3710261815002798848, 137273432282796342, 5851059442771612226, 15136621875351529272, 15702932139541150313, 8779333934582463234, 9538098266673672038, 1, 0, 0, 0, 1, 0, 8185802697182936648, 17682692702261395783, 2219736463483295590, 10757593865239447517, 1468754948270208383, 13746393160610271679, 6189648269704333551, 6527095477330083457, 289679669419955019, 9046656083049426920, 3573808134852581123, 16538711805104705524, 17122129810962376462, 2926585958971102942, 10107422984112301769, 1, 0, 0, 0, 1, 0, 12705492336505225259, 715424026399539381, 2549298692279483128, 1219968445867773701, 12911638424059178129, 5048199682718381540, 1535097268869899419, 17260972721034176516, 15413356179839910737, 13476986835056197648, 7470895530577539713, 8398414302064166980, 16518486341402545799, 70008875869363926, 10307933594111103714, 1, 0, 0, 0, 1, 0, 450024681039430413, 17110346123676092707, 503623504778112596, 1520822994009218024, 3997469258016952350, 18365130032920199069, 7964473389350786015, 9071675461601628413, 4719657860691726363, 2082610983791917873, 13643709933077212296, 16696777778525571691, 5937099920759461106, 17798517164851075633, 7519473231185213307, 1, 0, 0, 0, 1, 0, 17931731304193244959, 0, 0, 11156145431451224746, 9448001553779471302, 11663814486624427477, 8105139713546092506, 996052311483623897, 18356245393792640289, 11128269591471854109, 3650549423833220560, 10102060878284432657, 6999065210900455588, 9632395034475899386, 10920626017129534091, 1, 0, 0, 0, 1, 0, 0, 0, 0, 17063798001278894185, 2357038714604006367, 10530018908095235062, 8857952782846291740, 17150424826448967994, 8501298665346388356, 15857100073185553560, 2606143849991065668, 1709380969765926542, 7242804148613591485, 10415598312293556776, 3315485625242432418, 1, 0, 0, 0, 1, 0, 0, 0, 0, 6980956723582544769, 17736580895885199098, 10473837116748539797, 5495612785159148096, 8023377746099375924, 15245498074053387423, 15841461147440760970, 14724882291190243897, 13636145514567347966, 11793730383025693858, 9279036588745121360, 3956126734745245173, 1, 0, 0, 0, 1, 0, 0, 0, 0, 14149948942544104911, 13474931984659215558, 7610362789910399421, 10137886774563078569, 110488320743199774, 6631727638469492070, 9820426758070632911, 11785623090416681374, 2883529595690350478, 8282658300559339579, 1247473541961741200, 12265308465311135280, 1, 0, 0, 0, 1, 0, 0, 0, 0, 8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090, 18295472245208082500, 5861891236755868697, 15427470125368014171, 5623455816162216176, 11335643519415282023, 11551270937114235273, 11863835819310119404, 14266241634618616211, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], range_checker_cols: [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2187, 4374, 6561, 8748, 10935, 13122, 15309, 17496, 19683, 21870, 24057, 26244, 28431, 30618, 32805, 34992, 37179, 39366, 41553, 43740, 45927, 48114, 50301, 52488, 54675, 56862, 59049, 61236, 63423, 64152, 64881, 65124, 65367, 65448, 65529, 65532, 65535, 65535]], num_rows: 128 }, last_program_row: RowIndex(12) }, program_info: ProgramInfo { program_hash: Word([8390006645619712562, 1693808462939001829, 16098741705486284700, 15555841994343850090]), kernel: Kernel([Word([13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008])]) }, stack_outputs: StackOutputs { elements: [1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, precompile_requests: [], final_precompile_transcript: PrecompileTranscript { state: Word([0, 0, 0, 0]) }, trace_len_summary: TraceLenSummary { main_trace_len: 13, range_trace_len: 39, chiplets_trace_len: ChipletsLengths { hash_chiplet_len: 64, bitwise_chiplet_len: 0, memory_chiplet_len: 0, ace_chiplet_len: 0, kernel_rom_len: 1 } } } diff --git a/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_15.snap b/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_15.snap index a5f0d94b28..db50a4f102 100644 --- a/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_15.snap +++ b/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_15.snap @@ -2,4 +2,4 @@ source: processor/src/trace/parallel/tests.rs expression: DeterministicTrace(&trace_from_fragments) --- -ExecutionTrace { main_trace: MainTrace { columns: ColMatrix { columns: [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 33, 33, 33, 33, 1, 65, 65, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [11182969138190702361, 11656, 91, 0, 0, 11182969138190702361, 41, 0, 11006573531383828351, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010], [1109628455053940361, 42, 1, 1, 1, 1109628455053940361, 0, 1, 10983413158656624898, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331], [13928676565061410159, 0, 0, 0, 0, 13928676565061410159, 0, 0, 4869282124135316831, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319], [297470094449022674, 0, 0, 0, 0, 297470094449022674, 0, 0, 5899798166361732461, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694], [11006573531383828351, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [10983413158656624898, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [4869282124135316831, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [5899798166361732461, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 2, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 2, 42, 42, 42, 42, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2], [2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [3, 3, 3, 3, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3], [0, 0, 0, 0, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [16, 16, 16, 16, 17, 17, 17, 17, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16], [0, 0, 0, 0, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2187, 4374, 6561, 8748, 10935, 13122, 15309, 17496, 19683, 21870, 24057, 26244, 28431, 30618, 32805, 34992, 37179, 39366, 41553, 43740, 45927, 48114, 50301, 52488, 54675, 56862, 59049, 61236, 63423, 64152, 64881, 65124, 65367, 65448, 65529, 65532, 65535, 65535], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [11182969138190702361, 16344194729581826754, 15045917672181612303, 3672327111134984977, 11902001817992340801, 97480563262877602, 1831626543952762702, 12062163654685913941, 1451330498122947575, 1742063333427513989, 2331114102915733339, 8550984974115591347, 8960841496031156142, 13720918668577423004, 5779906183691085674, 3198599991840782485, 13728843979899181292, 7239115491427587826, 12128894594351473931, 15480692841914867508, 8817470180767843173, 10548371713427919789, 10315264763691724912, 1023167627240586914, 3818953450339058320, 14941570263133670432, 12615841091071546269, 15435370781163068976, 15373572920503822367, 11769995123877236600, 3762647969008011219, 8269653645296248010, 11656, 117148, 6714198787893475936, 5262284953624879131, 6828048997998717653, 14647846255598321281, 12213957512096072087, 15486993862206988880, 9916068016290756984, 12311676223031039230, 6798558233575208094, 6061515485015027193, 9178825932447902299, 16451694760407086053, 9245574117575493602, 6706571375738621744, 5707941763645196550, 13553995817865937844, 18312867062271325792, 11246612591729350508, 8806896510487478352, 16014621579841168337, 6332183310159529150, 2444726075814550534, 13415483499482541228, 16602291456530418215, 3069389264726801426, 4940323642218861897, 3979217445866956620, 6693606464693965975, 9525288177353527302, 11182969138190702361, 41, 410, 8488924048752676071, 5473488137200086909, 16124688533662466636, 4527044298581192722, 16887055178922689595, 5249711198271717177, 15470787238396171217, 5632634005697013617, 7337408598993184022, 11147561538212402733, 9710911023591971572, 8752830793140649116, 11546140485006286209, 10738951369466640003, 2139663271495255306, 6135983205453599776, 17538856881976830392, 2031516987289365197, 17199894398730562705, 4010699482290892787, 3922552954514582360, 7369439734883755459, 108303794773646012, 14521269346803535153, 14515762120928230173, 13893962684375637966, 13610167819530098127, 11215445033353754262, 8081237365032914784, 11006573531383828351, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1109628455053940361, 12119768350776285319, 8184561966951183876, 12431805880114311043, 2986356007899077631, 2836244341662188919, 146796491816379180, 8696360259937422388, 13878284404078727054, 7667548888861073206, 9741377056638459459, 11905155073870025459, 9736056580211703764, 17352787150580200349, 5883496260565631343, 9594088066979877926, 9297041447863221537, 6214639496702145664, 2461170076272033096, 17112913798212225634, 1035954869286151888, 2140568550425483844, 10584986198873793665, 12555736327846716176, 12072441430913369009, 13906015856663078107, 14389918991418187594, 2676571742010508284, 5150637797762075635, 11237118474907085960, 11752652705714102353, 997682303299740331, 42, 93752, 18084035356118526352, 8386870944408484201, 18056918720989013854, 11520229540186073721, 5668756658695595711, 14109792997657353922, 12303762929371991135, 14460911410586037148, 12418445481638740107, 16455507557982986163, 18172284878038222122, 6352198309363971688, 9198509167958908347, 1068046269761257463, 16102483860755268671, 1544674922431042375, 9868836391822552540, 7915117918356788325, 6533551228799195237, 3992189811639127908, 9511948951280762358, 13039263708530965818, 708611914251242147, 4206064101444952505, 17714998603219848343, 13074430791784659712, 14102459334756352921, 13661835471193379756, 3038016940647586670, 1109628455053940361, 0, 328, 7132218559010351790, 2687466917280430353, 14170238607512888511, 5453168895411602323, 8679138582261878552, 10871515559850126217, 7649138216344653830, 12086029516113687059, 14609582285822867389, 7271583017513514692, 3821121937809044409, 3833100151978191712, 5702916883024911354, 3579138882391492892, 14347405124134927123, 9277341930384005575, 2993137622300793545, 13370802209879109056, 13653108884642243926, 8702782587703766612, 12945832125614510830, 15167316901472929028, 4608694219239856197, 4443739924303229750, 8611475648437961511, 1575864515244779062, 10900065459953722709, 9162692523043045302, 17462008412377898139, 10983413158656624898, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [13928676565061410159, 5375705730949115787, 1314981229280595867, 1393532256400242982, 13433705342207763738, 12880831435259048250, 10699055768478348083, 2470044642731141974, 13732313223959877570, 2078090264025450769, 3845297826200108779, 15581584642080412492, 11359623335937034504, 14549946302435322871, 17424758021352066268, 15472130290487345321, 13048555428151627244, 13747770174448213841, 9164669383091055648, 3250455247796114093, 10799815877710934765, 9086202890994770785, 12116339825079888992, 1619117325320043308, 16898959203497269575, 15756045849228969140, 6190024525131486611, 6215657966742979785, 17671950935398765622, 15303512720733905693, 10727837149375754730, 12907160815575155319, 0, 23564, 4199576522683349447, 16513391592299529611, 11415640949254272304, 16138036929710694921, 9992494271122179933, 3020772293084222765, 15625472986208536177, 12149624601412828429, 10735117276139490774, 13332197512776217968, 13474689739491604605, 13815225937039366706, 706573335075180235, 4097091053989040149, 693823183101411164, 5341110475237803180, 4368449439175744649, 7740607367180462177, 13389502447794973829, 6721164191334334250, 6997451158266748059, 9767862146044075473, 4778055569341029558, 10088175016132507812, 3285997397792070136, 10914182999248450193, 14473951691792990803, 8827937223658185560, 9698676695870635420, 13928676565061410159, 0, 82, 18152833202936203138, 10305147718805144715, 13246631902503555591, 18142351346900318359, 11971140429919100117, 6903484634638418138, 3098698980745497723, 3068992673894668202, 9164459936648953977, 11194864417357882388, 12005359455571366116, 12356306486226268709, 10059737158050223658, 17119982236602677307, 4225663824996553892, 17852936504841763737, 5778553506856942969, 9045001363359345866, 18423338781077887809, 2711240319770097821, 8346149567490270428, 9594540064387516595, 1859863665658604717, 16919987197409252682, 7809934763889573038, 12492597695329698922, 18341122838405415754, 11967784234256998242, 10761804868734649587, 4869282124135316831, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [297470094449022674, 13535968261560526699, 10051713503687926694, 5258910437097366761, 14031537229609682064, 18190284629542346231, 4346004165604875907, 15375947702712472554, 4019409425675168575, 2064296209102051574, 17718639079388526425, 16642022229570326204, 1618478323171655450, 5998884876319667302, 6872649224968331273, 13753905356607269997, 7559241041198219519, 8363779881416372286, 2105649450986611656, 11644599807961994770, 12949568200151355456, 4366812189797744262, 9669235379242805159, 18184433440084438609, 13914998044815764482, 11325806379320193213, 1586181560816232196, 5920020313630770955, 8020025137186066841, 13419225700498867773, 13671651770198504476, 18024383338294781694, 0, 23396, 7560057297276955988, 7451013195867945919, 7468487593070852196, 5578183109591783882, 15747662796636990589, 2066701485189878406, 17025371161980089605, 4391959764977446152, 4985867595251695917, 6710066216774366729, 6241000701339836952, 4718440141936325382, 4986060230214018536, 5748634601882563491, 10896228304766504283, 6457499153671182820, 12270042173384394159, 11711065129605555908, 15065279868519608165, 17856220227797901726, 8953039722587792244, 16994104539161729445, 14670768895096516686, 14803898243742553487, 2327203233976270205, 17449705512918939747, 8253253226048886083, 11671578295265948239, 14297456315487806992, 297470094449022674, 0, 82, 302695496926486902, 16415403596737407938, 12969246825596557956, 15965643470182086386, 14881573336337548597, 2868629484750761697, 7317402970608805914, 2570537868338555591, 6697005353407257884, 5717939852331496040, 9408357527608003903, 8011884131194179594, 15942512744234440774, 9052662470595673790, 11913271961595885333, 15508051727969296111, 6269710669185644103, 12322255659000247132, 810875278274469351, 3499523055983644139, 9453749819048496107, 598273005722510655, 12338854942180141395, 2829445891916136836, 12653867244112536729, 4648827005364006908, 3153753366153954420, 12197142511433562971, 13557680898519201450, 5899798166361732461, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [11006573531383828351, 92579048505362891, 10772660272533654046, 3331697170176629084, 602109730184155310, 16230148280330706633, 6302091831624975391, 14001078336639287767, 14888577262766439787, 12258632680483319887, 7641862043593808385, 4740702640077452126, 8494032654039797119, 8314420015254970480, 18294822284401514132, 15552480182219334239, 908821363395967579, 18258193129875665644, 4226365574585037317, 3638253471537757569, 17581484848263912285, 6286301305761091621, 4777175749672661669, 10658559677463134471, 1417442037893012894, 7857622794514614671, 1052908464763109826, 4925127753504389599, 4274762298296320367, 7383511416371792464, 17305170235876004791, 2200823396264285425, 0, 58574, 18280076181055982575, 3965010120048981150, 1623299660155787797, 11930292174601709627, 17275008438838615802, 5756406115988630048, 17841510847136093686, 6729021181420822547, 1709787776185889305, 2022739540363098314, 5157634830695555269, 17099057016182449505, 4092740078069974091, 9582547144648304801, 4715310719341519129, 1597700055042697404, 480964694484615271, 56280064407246395, 10536769335197150641, 16099710145374622840, 3473101726323291593, 3295906456874767760, 716460020344690975, 10580825486552151036, 4976836170739997781, 16652319776094256449, 12319687016213027555, 13490282225851742651, 3371801902832234206, 3795543859124105201, 0, 205, 13622702382434675698, 8941567408770445183, 2168342371250989865, 17553704974699598306, 12818882650622055705, 16478401302589696546, 10652219805906948351, 13167156861512034068, 260666911081589986, 1428764500637505382, 2190433219200603887, 11999917547751101526, 2751093334206085539, 9318931023569054874, 16297727142514657495, 11875658036026604145, 5829323963705819601, 407792022339954638, 5684565403642367050, 13995368600016681288, 2845800306757116207, 5216498913603536417, 2411940295743487842, 2014066638340124975, 5258230180909223265, 17089893338044941808, 1124366766375746940, 9116801986360376826, 6650575029061305823, 4025036448660092914, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [10983413158656624898, 11859595567907759997, 10088766553729725414, 12574093635772317570, 5470069473511751658, 9645793732101008923, 1476556243604239385, 17933040757673393353, 7118521641278947238, 7588084371428510216, 12191494749556797391, 8228232126921631746, 15226641263820888277, 4239012011479875368, 14018593041447406970, 3541695062587160892, 11116896887234129281, 3929539690735302143, 11203930352796078636, 8751959587369085991, 12655249523595546680, 16379258612200834026, 9984807922535170831, 9638171237357393134, 12191893464144837018, 4677785078090407332, 8064604530099592479, 10076433135196495423, 544627542347870852, 11879905738846635842, 5683487714952213815, 8088984326603898052, 0, 46876, 15125170292333450443, 7072657932567702059, 10475291980250876467, 14632109792663117375, 18379882203306053694, 10250239327737538260, 11537033439839832588, 15180883293806522386, 18285674122603938406, 16116176887352657770, 15068074760365493774, 10507624248254584461, 7669544778380245671, 16424767991328560142, 16771797144770177609, 4105927596877687309, 7519344916607985067, 16277772212475505196, 1322695487397776109, 8302446182097155523, 14744324883381489574, 16338446684875281086, 5703860549203085948, 14077533030564871132, 12287193162084105824, 2535384450001991464, 13089916287630526229, 1568845385281768860, 982340402770608276, 12910581729787565904, 0, 164, 6093021124582015914, 375332441348258328, 16597900739273350797, 16788616498952461620, 10323894478242846558, 3730474644926313294, 17377183878976452334, 12746711269593150718, 13699107349734059694, 421533440407219618, 15109303318896079214, 17746438429032263850, 13224617406323308041, 5646455969610140563, 12626985742338481481, 14497665384991648640, 13894375308737560134, 3268393834564630675, 13312171511942754529, 611321250913478210, 12048873764879264902, 5334026694118161468, 14360341460112568406, 17654490467796517057, 1299716947845207044, 7609683397541157642, 14709808073905360012, 11742139955633481423, 13522070698443062110, 12847434483856017691, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [4869282124135316831, 10293244464294212936, 8691876854061179148, 2952350747126730564, 7968203687716298290, 6747517476428823928, 16731591574836256879, 12286682322909052293, 5699380547329532508, 8774011841981167612, 10988677337017809219, 6257583805205658612, 8595550098696265772, 17321901905145630028, 3295089823193122164, 6581488060195755410, 6329516418872359771, 7640632346113799527, 10454000694343684461, 15867346750604392587, 5805413556949044653, 9247297947852762648, 13748015074908171216, 13312272456227001370, 5054807356361880835, 1012271632864570722, 11252467974344770686, 492886975717156403, 2629112354487966090, 10128035487146424848, 18233951381382816412, 1751709948898726303, 0, 11782, 6055246182589913733, 15015595405278911690, 2209046468675768902, 16429197663637467330, 15810134098389081544, 9588791733994120847, 18370261572729563296, 7006788971063612777, 7962515674056117045, 15223121510830934757, 15872454912771340895, 1486059252283823706, 3912605942422700262, 4173681472723400357, 2922691200579275072, 7112424425452913463, 17213377378328786151, 6274713241106982122, 15112974401160243995, 17175975930045398893, 5467280291812001242, 5238070817263862176, 17584445990298638069, 171514605620090783, 4267926381848052110, 9011064139813451706, 17044511642202081265, 17370313250110904770, 13397257034080852565, 17596568325206204932, 0, 41, 9617260353707541367, 9187825164453421957, 17649953659489375797, 6396310504287885774, 17019569090864760371, 870218876784769460, 17213560015461715510, 16812494438448165271, 15885717661613279263, 2958950328581697287, 14311601477626423214, 12599125587081655507, 12078599565132475515, 3332808335850364509, 374688056722968094, 5591521890390007231, 9584980789501913045, 4066644474875437132, 17728945623551220217, 1158050506628066296, 3730734784735709807, 10671987699715228843, 3173999018565335463, 14949604462817069254, 11653871972148380806, 312408327658285690, 8531928004921347162, 98858158429688394, 6167334615107562354, 1234843923022284190, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [5899798166361732461, 2163003956713638315, 5989289390391757114, 15670015339098587014, 12708827926449341197, 10159927950043513901, 15395056832871965886, 17405960500607097380, 9229756563573051371, 1186079292937331145, 13463816706671585562, 10107168241231917326, 8534001612601599401, 12790948878158723266, 12619661555644649350, 11614101867080583800, 11255619179741810030, 10501448523390229441, 16971746085380600175, 7173352752193758542, 9960833320626690499, 3507659370538431093, 6846598866105961944, 2557094292829749679, 11416743759689580593, 12182449258645699464, 11951277814213817673, 10567677969346318078, 13884819925875295975, 1926379571595510347, 5918588896905128530, 3405979658670756574, 0, 11698, 8146055133796963630, 4724864404296433607, 10453305271538430204, 17141108237620938331, 16113292978122689735, 14630852758047225712, 16936235645680974811, 640959767495035790, 11162248672474783185, 10618808740372936561, 12973220127719589473, 13223353016814262874, 17652411276563186968, 10141330567980253051, 1770876161367154023, 12442058685904907795, 12986633647641209886, 5384244903407669612, 14778499304685795812, 8054814913234770610, 8358166993767322841, 11933451322373121057, 17795028935448509068, 11142588879850986282, 873880226830208445, 11017896854604878841, 6896812394605202475, 2024842447089060639, 16625734836325714912, 12512094004962322130, 0, 41, 12529483521877137515, 4671467226762388980, 13873740979092621907, 12847173262736205772, 2640423636460273022, 8374058502362870155, 7630996533587302384, 3556075572123538464, 8078558398785937163, 5856098383496092000, 7999607615804135893, 15509992149354799776, 13785560116650003734, 8358196300413379173, 10412508239405514928, 7840142081125036731, 18075062342410207477, 18173191150607640442, 2133036585496843963, 8931901040624025193, 9454731621283026961, 5837806564591410604, 5850596656185029719, 296117354535505751, 8985195681813998404, 1975947551471322175, 12041110943945791333, 11648250496545232642, 7830634726555216225, 5266777994490151623, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 11627839282500592134, 3407397722647202213, 13644814392425193274, 9689174787852538317, 15759480978611340324, 10073546228149283602, 8090878949578096073, 1502926046713635634, 7624167193861818791, 10274257988202953339, 4186763142475177793, 6025425965090069083, 8194342163688078130, 13163397875087894329, 5161390927343581791, 10103251159424454395, 575959985319833606, 13175926157437524595, 8928028362497258488, 8665485641724560922, 15570929820685955587, 6150675652390666890, 6384512333148749163, 35921027791486524, 3229184449291625000, 7414754653220847914, 11347301099028602515, 8368586536930615942, 10138228048917253579, 344980745193352015, 5644431973654019812, 0, 58574, 12761879591277148733, 3794756304714494565, 10919382803049057886, 13927811434585922718, 8315847055470475708, 10095847089706649983, 41153506376499461, 5529807447506440005, 72892344713547594, 18362204307013225363, 527610602670466995, 14772158556567070690, 9538491437159792328, 1580498045195806896, 8297535568256810268, 13797917351588149895, 1651894826575892086, 13380716913143325871, 2655893075036451977, 3750342908258071259, 18231595474498119868, 18163310674975357977, 2371603174180061555, 6433509503768865899, 5002589281792664271, 10946433388588585987, 9256382872640968643, 6570002101874463971, 3849537215181896567, 5735281858523620986, 0, 205, 7876112718273244024, 1276143811675585923, 9993912342918529935, 16999254614849428545, 8194747920293058753, 11171758628037424552, 8208119826419095432, 5568149314099479773, 17551537772960996556, 12651683228606533001, 13584145944854843210, 12212300608708011466, 18102951610480561318, 14720258372954226591, 15448472262117068008, 10575290756167155008, 11997391634424499349, 9879556170680135793, 12373753045781314057, 9529470285212177396, 10620662102176580756, 10199402949196411787, 9825825353570660203, 18337390924518345383, 15945306792731206141, 10537181099344133724, 5505106000120813030, 14774803975376978777, 14575654492591748955, 8207377881872409730, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [87, 1844206616423154361, 7941852203687681180, 2987825311454433607, 185071303888742221, 16140725249773135932, 13486449309893009073, 13471170357015645210, 11073859438158044651, 16507211018434913458, 4066228076398875428, 16536071023746429034, 10818247459046542341, 4392853051950044706, 12116759677655250999, 17293580330275603290, 2376540144284705519, 8057038266027202789, 15097730100005395027, 3583575859544955648, 11146351406925299070, 13473187462927502829, 8056538798141691018, 13509558775822115028, 6797301950091310335, 8773981691004278165, 4751058192101309365, 10661116978196100999, 15345629614104209519, 1689963602473071179, 12869561156624962469, 12554030503530361323, 0, 46876, 4789346784708035796, 9438751512570250357, 447952077691938652, 6351356675900770483, 4868676530510485341, 3192437812250556397, 11511034416225137032, 15380266628173325649, 10700144984876703355, 12230522212327928379, 15526804358639727019, 6410705682507666807, 15728916292645010880, 13992590038292222154, 1916422775943772979, 8280685582260709248, 12515254706968408232, 4845996266408136556, 15172713941042952680, 2233761585242005099, 13227100893355110663, 3914062371738178895, 7843298541359739176, 8386193964610423744, 8614894336467293783, 8834991867772635266, 14221135810103683560, 11406071542091908609, 571586377235018247, 3013510715159483905, 0, 164, 14482187202392982684, 17682350329754313417, 66214439016909251, 7504629639084879386, 11708178258767948919, 188011405648496761, 10242982970375452289, 16510140404231294235, 13381084464566932690, 9239012175869487665, 9339694231140180875, 9917181315244873380, 17448534469581521177, 4965043893766771965, 13305445405772227224, 6963375374275021656, 4554518835153561582, 1694446457415578298, 4604616361036784646, 11439774970058559661, 10784225701912607868, 17782855612978839775, 13368223431578003475, 18100595786373494652, 12753204151452870283, 17504098334052422651, 12896535568794110034, 7402084190222773115, 598469278842686486, 5912604878679295331, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 11371898088219304696, 4199208231896291776, 6349271639347163621, 5568595648257864309, 10224931331962954075, 8046167029187450402, 6585148777263545478, 3706462809677116963, 12578093594063946501, 11334181120248394313, 4953509182438845792, 4130560513564095433, 6665409895959715593, 12872180446847298231, 11452171012153290342, 5729159829892489539, 5675564903335979949, 14158677720471443076, 12300968791182495713, 13879671978791253311, 14820104759072107152, 17585955671327967478, 6737505022417937354, 17454985371239394211, 15749874646256262769, 10017226585432634212, 8893160827421013787, 11893931769684808775, 16471875099240353401, 9975926385796085953, 11231727832144176264, 0, 11782, 6351111885067026894, 14086295994708840477, 3142920623105062021, 4317195510637014184, 16341148873550430347, 8014762585425506108, 12977978004680762325, 15318810920503136316, 9472517513827583818, 211962335804367550, 14931353145911604525, 9340212215573419915, 5244269534978718672, 1584128384101705476, 4460891295949496863, 14654598206063183317, 13555452196222133132, 17680908597379218579, 13178742765486355260, 3964993209073179108, 4213917162333386044, 2639949635019592417, 3300803743280888923, 12914222891103397086, 13436383826829479040, 7004576641630317963, 12080155723705641895, 6767987840126452263, 14392317091133450653, 7390177608867021213, 0, 41, 3800418813655617572, 14503408479575576010, 10553169970007645345, 4946745422622378051, 7127828976000219721, 2687285609278369395, 16630221959750548176, 1114885198959805561, 3895092647933222339, 9831397389014117600, 12816842684293233323, 1779119880742935864, 17663607747965229138, 5382558247959552902, 11972955750871888364, 16616426694032134438, 9711126273890628516, 376576173107709408, 12451218545182255865, 14301764572821220192, 13209253693600827240, 5745169166190656073, 12916752429524642864, 14463770325561420619, 7870235520772452232, 13278341252249613603, 5432056100901092307, 8994645443800925562, 5908996313982662075, 1494658977663487041, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 17530820119034444668, 15233230393479930649, 15702789941308523576, 8819781861782654629, 7112644758334533508, 2549387492966523460, 15838339720324898846, 10242380937000070843, 1124701407395854549, 5706112669062280829, 17015988684670402201, 12671109438456697877, 15652595419009785355, 10753966634497852319, 3622124053041186910, 2063695485301676711, 17845322355197915738, 9894091605930112348, 10822348040176532279, 9689802115657313068, 6759722828145755337, 9479044480226984785, 7845909286502989649, 560081323074218824, 16017591174163981005, 1196237303718990885, 6783304352365897531, 5064625229425039166, 12661189034561966549, 11511655067934063768, 11479359825177848513, 0, 11698, 2084118884093035279, 16979859941949546961, 1454299506056429821, 9658643065222637557, 11605485146349749283, 13057696629474024230, 16650374201325163722, 7457309320444728046, 1243843599995756274, 17176177262691414244, 14152683925184093692, 198845790532099135, 442435874165139119, 1462611314767788334, 3462067515008653152, 4141759445261917472, 12323330957750482072, 14922731139272985797, 10387565380055278256, 9531386257124273696, 9539285450074189441, 3691450672437772660, 12463184698711878632, 4858502687517999226, 12256855995572753726, 9245347314341240247, 7569214225554358494, 1017686422583121037, 10327407591150878848, 15025446886891081073, 0, 41, 13092032916490151270, 2856458557507854671, 14059661153766146178, 1724041303048776424, 7119687853704366589, 3699246950542313036, 8338994289155538949, 7732171807197958061, 10653644351656999339, 15262849800927670044, 6132373490633371091, 16473831322001214578, 12928938600331453669, 6959935525856744214, 17173069020016176920, 6747622983845354522, 2484033613426731933, 9879916419081378373, 4275250202523893223, 5995505684018086986, 16115855409799741127, 2490003355474156145, 10034475279304353355, 7223217715426381376, 10334063888823214988, 2139000562522371457, 18314119367638727156, 15311716904301189063, 894706229073498557, 1570146104298050273, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] }, last_program_row: RowIndex(10) }, program_info: ProgramInfo { program_hash: Word([8269653645296248010, 997682303299740331, 12907160815575155319, 18024383338294781694]), kernel: Kernel([]) }, stack_outputs: StackOutputs { elements: [2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, merkle_store_nodes: {Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571]): (Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350]), Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350])), Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484]): (Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693]), Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693])), Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781]): (Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874]), Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874])), Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171]): (Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361]), Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361])), Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815]): (Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305]), Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305])), Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689]): (Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195]), Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195])), Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362]): (Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063]), Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063])), Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848]): (Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661]), Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661])), Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352]): (Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829]), Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829])), Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444]): (Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223]), Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223])), Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386]): (Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388]), Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388])), Word([13190842942618341421, 17548956981569849952, 15418963848144418856, 730733050713174879]): (Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144]), Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144])), Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874]): (Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675]), Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675])), Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594]): (Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115]), Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115])), Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809]): (Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257]), Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257])), Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777]): (Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555]), Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555])), Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509]): (Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882]), Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882])), Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725]): (Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979]), Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979])), Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134]): (Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987]), Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987])), Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828]): (Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910]), Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910])), Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830]): (Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054]), Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054])), Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228]): (Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742]), Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742])), Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443]): (Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928]), Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928])), Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643]): (Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979]), Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979])), Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758]): (Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106]), Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106])), Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580]): (Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594]), Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594])), Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765]): (Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045]), Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045])), Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766]): (Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281]), Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281])), Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385]): (Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828]), Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828])), Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579]): (Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171]), Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171])), Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212]): (Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992]), Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992])), Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463]): (Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004]), Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004])), Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502]): (Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023]), Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023])), Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539]): (Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537]), Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537])), Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865]): (Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225]), Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225])), Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690]): (Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947]), Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947])), Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202]): (Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552]), Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552])), Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079]): (Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444]), Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444])), Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850]): (Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548]), Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548])), Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448]): (Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987]), Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987])), Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041]): (Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035]), Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035])), Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301]): (Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414]), Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414])), Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414]): (Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212]), Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212])), Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703]): (Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439]), Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439])), Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271]): (Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955]), Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955])), Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882]): (Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802]), Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802])), Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152]): (Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887]), Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887])), Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028]): (Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948]), Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948])), Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331]): (Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093]), Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093])), Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394]): (Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134]), Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134])), Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546]): (Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228]), Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228])), Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620]): (Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414]), Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414])), Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800]): (Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703]), Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703])), Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671]): (Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205]), Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205])), Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537]): (Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011]), Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011])), Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516]): (Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301]), Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301])), Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831]): (Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986]), Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986])), Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415]): (Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057]), Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057])), Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722]): (Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689]), Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689])), Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144]): (Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682]), Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682])), Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295]): (Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268]), Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268])), Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818]): (Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513]), Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513])), Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241]): (Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565]), Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565])), Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439]): (Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012]), Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012])), Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512]): (Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850]), Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850])), Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986]): (Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865]), Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865])), Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982]): (Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777]), Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777])), Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808]): (Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394]), Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394])), Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979]): (Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690]), Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690])), Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093]): (Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620]), Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620])), Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902]): (Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789]), Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789])), Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542]): (Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094]), Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094])), Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057]): (Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362]), Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362])), Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205]): (Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961]), Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961])), Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401]): (Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580]), Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580])), Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553]): (Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960]), Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960])), Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169]): (Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031]), Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031])), Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682]): (Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053]), Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053])), Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118]): (Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562]), Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562])), Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725]): (Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666]), Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666])), Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661]): (Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897]), Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897])), Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981]): (Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447]), Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447])), Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072]): (Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646]), Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646])), Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140]): (Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404]), Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404])), Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515]): (Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152]), Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152])), Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709]): (Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664]), Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664])), Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800]): (Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103]), Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103])), Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741]): (Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169]), Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169])), Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005]): (Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758]), Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758])), Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802]): (Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070]), Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070])), Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159]): (Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005]), Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005])), Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350]): (Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443]), Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443])), Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697]): (Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573]), Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573])), Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928]): (Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331]), Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331])), Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320]): (Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166]), Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166])), Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814]): (Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079]), Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079])), Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447]): (Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820]), Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820])), Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284]): (Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057]), Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057])), Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697]): (Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131]), Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131])), Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955]): (Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290]), Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290])), Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910]): (Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202]), Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202])), Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910]): (Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822]), Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822])), Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106]): (Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847]), Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847])), Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404]): (Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441]), Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441])), Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796]): (Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186]), Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186])), Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053]): (Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516]), Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516])), Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992]): (Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818]), Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818])), Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957]): (Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315]), Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315])), Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709]): (Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794]), Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794])), Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091]): (Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539]), Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539])), Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664]): (Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558]), Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558])), Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294]): (Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579]), Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579])), Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947]): (Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502]), Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502])), Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829]): (Word([0, 0, 0, 0]), Word([0, 0, 0, 0])), Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045]): (Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137]), Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137])), Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914]): (Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041]), Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041])), Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573]): (Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378]), Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378])), Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699]): (Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873]), Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873])), Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225]): (Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262]), Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262])), Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057]): (Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692]), Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692])), Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131]): (Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997]), Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997])), Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555]): (Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385]), Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385])), Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195]): (Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709]), Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709])), Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166]): (Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542]), Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542])), Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027]): (Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373]), Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373])), Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378]): (Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509]), Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509])), Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097]): (Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553]), Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553])), Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217]): (Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815]), Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815])), Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873]): (Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864]), Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864])), Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997]): (Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722]), Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722])), Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887]): (Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766]), Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766])), Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589]): (Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757]), Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757])), Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539]): (Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665]), Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665])), Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129]): (Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229]), Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229])), Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137]): (Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312]), Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312])), Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019]): (Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378]), Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378])), Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331]): (Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713]), Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713])), Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]): (Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980]), Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980])), Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325]): (Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546]), Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546])), Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170]): (Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822]), Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822])), Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054]): (Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295]), Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295])), Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925]): (Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848]), Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848])), Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909]): (Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796]), Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796])), Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540]): (Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170]), Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170])), Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214]): (Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448]), Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448])), Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317]): (Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294]), Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294])), Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757]): (Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416]), Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416])), Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378]): (Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091]), Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091])), Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263]): (Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463]), Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463])), Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666]): (Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361]), Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361])), Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174]): (Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992]), Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992])), Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470]): (Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401]), Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401])), Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665]): (Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957]), Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957])), Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262]): (Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144]), Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144])), Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229]): (Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284]), Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284])), Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134]): (Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325]), Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325])), Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855]): (Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765]), Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765])), Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115]): (Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814]), Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814])), Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441]): (Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831]), Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831])), Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977]): (Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446]), Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446])), Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880]): (Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005]), Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005])), Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789]): (Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995]), Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995])), Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000]): (Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267]), Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267])), Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998]): (Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982]), Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982])), Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995]): (Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539]), Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539])), Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507]): (Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512]), Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512])), Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305]): (Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118]), Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118])), Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219]): (Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009]), Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009])), Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416]): (Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089]), Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089])), Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980]): (Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445]), Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445])), Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063]): (Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140]), Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140])), Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713]): (Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159]), Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159])), Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031]): (Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809]), Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809])), Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932]): (Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037]), Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037])), Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094]): (Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925]), Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925])), Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315]): (Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386]), Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386])), Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446]): (Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721]), Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721])), Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742]): (Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981]), Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981])), Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661]): (Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072]), Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072])), Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979]): (Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671]), Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671])), Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361]): (Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269]), Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269])), Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558]): (Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571]), Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571])), Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290]): (Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902]), Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902])), Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987]): (Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741]), Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741])), Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902]): (Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515]), Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515])), Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497]): (Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028]), Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028])), Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948]): (Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709]), Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709])), Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009]): (Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725]), Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725])), Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387]): (Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317]), Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317])), Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159]): (Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808]), Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808])), Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394]): (Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699]), Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699])), Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312]): (Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000]), Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000])), Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987]): (Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821]), Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821])), Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046]): (Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909]), Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909])), Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565]): (Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028]), Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028])), Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269]): (Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352]), Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352])), Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847]): (Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271]), Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271])), Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513]): (Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800]), Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800])), Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054]): (Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394]), Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394])), Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004]): (Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977]), Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977])), Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675]): (Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800]), Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800])), Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692]): (Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159]), Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159])), Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909]): (Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932]), Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932])), Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814]): (Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697]), Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697])), Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186]): (Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387]), Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387])), Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445]): (Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470]), Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470])), Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966]): (Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507]), Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507])), Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548]): (Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253]), Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253])), Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897]): (Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783]), Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783])), Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208]): (Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054]), Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054])), Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268]): (Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661]), Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661])), Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388]): (Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643]), Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643])), Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257]): (Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174]), Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174])), Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960]): (Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241]), Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241])), Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721]): (Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046]), Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046])), Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822]): (Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217]), Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217])), Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253]): (Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697]), Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697])), Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054]): (Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019]), Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019])), Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821]): (Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432]), Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432])), Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864]): (Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105]), Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105])), Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373]): (Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855]), Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855])), Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646]): (Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830]), Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830])), Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460]): (Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208]), Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208])), Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033]): (Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214]), Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214])), Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105]): (Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129]), Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129])), Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281]): (Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909]), Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909])), Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028]): (Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027]), Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027])), Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012]): (Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054]), Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054])), Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562]): (Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589]), Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589])), Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037]): (Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097]), Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097])), Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355]): (Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460]), Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460])), Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223]): (Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355]), Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355])), Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089]): (Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306]), Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306])), Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035]): (Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219]), Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219])), Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432]): (Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297]), Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297])), Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693]): (Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263]), Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263])), Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794]): (Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484]), Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484])), Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552]): (Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941]), Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941])), Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267]): (Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814]), Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814])), Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992]): (Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415]), Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415])), Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941]): (Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966]), Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966])), Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822]): (Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320]), Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320])), Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306]): (Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902]), Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902])), Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820]): (Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880]), Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880])), Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361]): (Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725]), Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725])), Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005]): (Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914]), Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914])), Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783]): (Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781]), Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781])), Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011]): (Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033]), Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033])), Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297]): (Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910]), Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910])), Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070]): (Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134]), Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134])), Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144]): (Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331]), Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331])), Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023]): (Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497]), Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497])), Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103]): (Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540]), Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540])), Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961]): (Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998]), Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998])), Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414]): (Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]), Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]))}, trace_len_summary: TraceLenSummary { main_trace_len: 11, range_trace_len: 39, chiplets_trace_len: ChipletsLengths { hash_chiplet_len: 96, bitwise_chiplet_len: 0, memory_chiplet_len: 0, kernel_rom_len: 0 } } } +ExecutionTrace { main_trace: MainTrace { storage: Parts { core_rm: [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 8296916230783913551, 16462332824047406715, 6884552431231699198, 12264801256605292690, 7532528701100807439, 10480547126759850066, 6097728641437901141, 17248496754222975198, 0, 0, 0, 0, 0, 0, 1, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 11656, 42, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 1, 1, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 2, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 91, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 3, 0, 0, 0, 0, 0, 3, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 4, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 0, 42, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 3, 1, 5, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 1, 1, 1, 8296916230783913551, 16462332824047406715, 6884552431231699198, 12264801256605292690, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 42, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 3, 1, 6, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 41, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 42, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 3, 1, 7, 0, 0, 0, 0, 0, 5, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 42, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 3, 1, 8, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 1, 1, 1, 7532528701100807439, 10480547126759850066, 6097728641437901141, 17248496754222975198, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 9, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 31, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 33, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 39, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 43, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 47, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 50, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 51, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 53, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 54, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 55, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 59, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 60, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 61, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 67, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 69, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 70, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 71, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 72, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 73, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 74, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 75, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 76, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 77, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 78, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 79, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 81, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 82, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 83, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 86, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 87, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 88, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 89, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 90, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 91, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 92, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 93, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 94, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 97, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 98, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 99, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 101, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 102, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 103, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 104, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 105, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 106, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 107, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 108, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 109, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 110, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 111, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 112, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 113, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 114, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 115, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 116, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 117, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 118, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 119, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 120, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 121, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 122, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 123, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 124, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 125, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 126, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 127, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0], chiplets_rm: [1, 1, 0, 0, 8296916230783913551, 16462332824047406715, 6884552431231699198, 12264801256605292690, 7532528701100807439, 10480547126759850066, 6097728641437901141, 17248496754222975198, 0, 87, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 8400310461204590462, 9108169057237353573, 17636133504178290964, 17406877359165992528, 1012686194999500095, 3119571665051516884, 6045109140346221273, 8023007352945590267, 0, 0, 1, 0, 0, 1, 1, 0, 0, 11656, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 8296916230783913551, 16462332824047406715, 6884552431231699198, 12264801256605292690, 18213254076385477335, 9294418641045383238, 8055320100535498720, 11030019888906999906, 1874843776400824061, 12942276814728926620, 15585255994602274508, 16203157087401046215, 0, 0, 1, 0, 0, 1, 1, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 7532528701100807439, 10480547126759850066, 6097728641437901141, 17248496754222975198, 12342802819241620905, 7554371666290801318, 8718773026382250605, 15984482998549000918, 15460443374009848343, 1087146607978023558, 7531163901062156801, 4426949494427873777, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 11621565010787354140, 1949391780818670486, 7327781180606137861, 2419787217529136215, 13249250205018233525, 10029758640146777270, 5716716695107147273, 10829954014693503473, 7405851154679558693, 2030135877513774489, 10401768244118899621, 7992444660002654486, 1, 0, 0, 0, 1, 0, 0, 0, 0, 9190577937819620371, 12978309842325015235, 10477013461463931935, 4855391316239312738, 10519745218266697287, 18375374895419140100, 876067972673449756, 17915370314859305010, 17877705855294641231, 120652674332571204, 3378556434908723888, 17649391022523856338, 1, 0, 0, 0, 1, 0, 0, 0, 0, 15052947986857015373, 3007680259418135415, 3197694984858038551, 6563270153864719814, 6889631464391242687, 12614331779225506253, 8884325160266334095, 15067359903282619456, 6045216153329131722, 7293213550537411486, 18377064823051127268, 14733223614830533518, 1, 0, 0, 0, 1, 0, 1248924765333967865, 15568788993061722932, 4037714036443683170, 2584579945446987950, 3496704858534018972, 10965787981110521559, 9000006360952503550, 8377181923806419223, 18078834148678517323, 13751832434934340803, 15306332964801742551, 828627458527105190, 2519953652271814816, 5563221586835004955, 16428502736240336605, 1, 0, 0, 0, 1, 0, 161503374172189975, 7180975586994120588, 13070121377098205312, 9655464535561865455, 4169214041423852321, 5771090309048429384, 6993654059550252564, 14478380452460405826, 12150434000885474539, 18399347099839405992, 88779829066683150, 4428174353386180423, 7547120791432137516, 11951584238447172023, 8804182506418522715, 1, 0, 0, 0, 1, 0, 1859011259345361207, 13205265558511858864, 16229683663108620000, 17688418164436772208, 12658415008146819428, 6291208835901171779, 3297271436089179933, 12943628284217684119, 11639259038601904106, 10502234848011596680, 13946225273525543944, 11318468498957948083, 13851055481982014034, 5765565570506082255, 10777382518726251007, 1, 0, 0, 0, 1, 0, 1023422172081481959, 14540338366569412926, 10271517463444484758, 8863158288377959817, 9066561794313536160, 10161961919995709177, 2094278659773331823, 4371761587112760854, 10972685992181286814, 5641963675353630718, 15569415989710829261, 4258403342016907208, 4740804749082440837, 1594229550076307598, 5045104152796606559, 1, 0, 0, 0, 1, 0, 12053626300860885956, 13987509258486900924, 17286360383804666298, 8301538772707939488, 7700154594411825373, 14332053735409157564, 6894934729579673545, 5430665485920789830, 10553406992561403551, 11528229548578861261, 3294597468571627674, 2903493961726666462, 10560076388764518443, 3749651622493296975, 18114127684252877364, 1, 0, 0, 0, 1, 0, 12240592655856206466, 6264740020775290721, 859763567572081467, 8842953438422484122, 14329981889510246939, 3582542183068105786, 6023391989510151456, 2953193964713672141, 12396149302348639250, 13882467375549577428, 3586988377712407519, 7213506509798642482, 13435456572406932891, 9645941250097564536, 2781650568775738364, 1, 0, 0, 0, 1, 0, 15637532899188291351, 12683652363890573925, 2704597975013858668, 17832955104866332736, 6815586591600943723, 13755349213265671492, 8924117914024270326, 3329964149511691453, 11039495891702065838, 15670789219464690273, 11281671746346947225, 10492374165392519994, 11439270560757451470, 7337394676363778206, 2272256910055258613, 1, 0, 0, 0, 1, 0, 3130343892077994054, 0, 0, 1136320813223337744, 11438337112810950654, 16692992611178972868, 9482499518540692367, 5451078715157933845, 18403012202839423090, 13340398881404871439, 16853681425214524760, 5540259513623809808, 7754241405876268140, 15538673406175044580, 15705643278636475771, 1, 0, 0, 0, 1, 0, 0, 0, 0, 6593967995490198369, 546795078589070868, 8093299549277945163, 1445098694824947603, 16968796337604054074, 7105604958885889972, 12829574433066656016, 10962264142076089650, 6970346774265824779, 5668604568559492205, 15930738860655806958, 14403244990983785091, 1, 0, 0, 0, 1, 0, 0, 0, 0, 7770193319703938593, 6228225228483877842, 5315425894230577486, 8012448033829391087, 5395398520381640698, 8770911350053719042, 14827874098479004474, 11024999006644848903, 13791657658989935762, 17830220104295996918, 2090812709146185278, 8577173283657139529, 1, 0, 0, 0, 1, 0, 0, 0, 0, 17471481800618265475, 1930822204634793148, 12769804899579893379, 13068810900387198296, 10732524945348487200, 1519317270498249877, 12604995971822921101, 14107509487727911757, 8257552923782319555, 12034059115493819529, 4343039820825149431, 395799121324568963, 1, 0, 0, 0, 1, 0, 0, 0, 0, 7532528701100807439, 10480547126759850066, 6097728641437901141, 17248496754222975198, 12342802819241620905, 7554371666290801318, 8718773026382250605, 15984482998549000918, 15460443374009848343, 1087146607978023558, 7531163901062156801, 4426949494427873777, 1, 0, 0, 0, 1, 0, 0, 0, 0, 11656, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 8259689913693129242, 3400892600405308205, 17378179173256779268, 5060920854688287001, 9687195410980644248, 6313248141024338188, 2582093590609427596, 3953695074988874383, 11971751964106597008, 9907486161844974200, 17989903003960359463, 13336380866068769777, 1, 0, 0, 0, 1, 0, 0, 0, 0, 12279731404675001026, 6278812133505380138, 6233201299601221057, 2388727383803081265, 12084036741190483661, 2317300697897833956, 9759443477696867671, 10883057071610381859, 3944615791382572320, 4072273145811045884, 17852897021998211163, 9684438072608016253, 1, 0, 0, 0, 1, 0, 0, 0, 0, 3651584995004100725, 6423803920838032987, 14027200390009907647, 6592032860050067711, 2594447921553931384, 18306574626058358562, 4512185877168969647, 11342492757671323084, 15957751677575885720, 5761823199659062393, 6846407586191335849, 9817376758188911585, 1, 0, 0, 0, 1, 0, 18183126545069935350, 12563248011457733820, 8356966014032630063, 12041609793392315665, 5281186701877768352, 5541580267076219602, 11576047020972388374, 6661568194349527666, 15437143780340457719, 10754987180927492954, 4211835751645452119, 10566966891469040816, 690793516206281144, 3247962926818069970, 9036036859539968974, 1, 0, 0, 0, 1, 0, 15893445344909186288, 5778049594265975833, 1423581989082731508, 5458007776595562807, 2498425571573111469, 16059466580364398666, 8902716392494711213, 14882573357788460188, 3225597659422237250, 3128065202613218656, 16995684508107895104, 12196793732604029414, 17723663615896720413, 9829416315291197871, 580745865383399340, 1, 0, 0, 0, 1, 0, 13902067347991440733, 5984630683069450754, 12729386174124645267, 13785662250538369696, 272255205933159866, 735616656951483055, 12424664074133983590, 5026981889191825136, 5767485772665833989, 15651669603605283176, 7414308024158917695, 15811954123421478742, 13258769136679205830, 3664463833800174816, 15497592431183820173, 1, 0, 0, 0, 1, 0, 11156605567826983932, 3639316624646464570, 5042698793479444923, 8630374421727305636, 17027951314675117661, 2801906069577385610, 18065291493111457552, 18067767546753643362, 5248148594352695009, 7578134041089558055, 18445498855455618598, 7189106720666328053, 6562930842885656592, 6844922721754111014, 780716667496251522, 1, 0, 0, 0, 1, 0, 11860885490747304346, 12272615266561732125, 10423884872730116228, 13929733142214397431, 2117615618497875527, 5203222542820499724, 4538429948347629507, 6877693664463852318, 18109062185597913481, 10147653053574341319, 10079670109614966266, 12064951107563936135, 1152998120279634164, 12844815835032732057, 12896711460106342356, 1, 0, 0, 0, 1, 0, 3078919787028426439, 15265543379215102231, 570695753264939069, 459110976220447167, 2176716793919417092, 14863591412045443847, 14252826520731507004, 15860274927896899753, 10390267100193539166, 17043032359848981742, 818991875743271755, 16275785202399117535, 8465017515346473513, 2777064625189300576, 13072175816967000886, 1, 0, 0, 0, 1, 0, 3442153457185747577, 2606206929260007126, 2317686975478948049, 15948992202505097484, 5942181083636438599, 15457210791918859006, 887605399554676434, 12986387963278623196, 10075175986843357851, 4859683927561004597, 6555547085880890919, 8280537903442447606, 16640962983997717683, 2248822201261309400, 13163090516020988950, 1, 0, 0, 0, 1, 0, 7196986181046756683, 0, 0, 16549653703171386973, 11518702294444124172, 1109770523953150302, 11415315369035533823, 5890935665450471727, 2253657843173273901, 13858462521885404044, 9125187176834287629, 14925311787915179675, 9356310136195018005, 14965392043314054082, 18423301843359275387, 1, 0, 0, 0, 1, 0, 0, 0, 0, 7040940919216905671, 6187741949018394442, 10532732827118411505, 13505135286384426969, 917467356231706545, 9047752258933341547, 2335143583534705649, 18052717581435745313, 9355624911805935499, 7190586108559742607, 2304843099991312546, 16303126242918615541, 1, 0, 0, 0, 1, 0, 0, 0, 0, 15603840856162477962, 3504063088563989096, 6361775464868278813, 17698044987168049155, 8418309402148081318, 15988177746184666422, 4270534912200806378, 12370149697383197906, 8363034440938926080, 17941258791536373709, 11011611614519090457, 10702921331067290122, 1, 0, 0, 0, 1, 0, 0, 0, 0, 8416267285503610972, 15089551497492948945, 5363802036407642792, 10347532956075658842, 17181858623993805271, 15855824450153307212, 7743632312226714799, 1845073853648620670, 2000026205350826313, 18037231946791138113, 14309912549728703012, 13253445327127715869, 1, 0, 0, 0, 1, 0, 0, 0, 0, 8296916230783913551, 16462332824047406715, 6884552431231699198, 12264801256605292690, 18213254076385477335, 9294418641045383238, 8055320100535498720, 11030019888906999906, 1874843776400824061, 12942276814728926620, 15585255994602274508, 16203157087401046215, 1, 0, 0, 0, 1, 0, 0, 0, 0, 8296916230783913551, 16462332824047406715, 6884552431231699198, 12264801256605292690, 7532528701100807439, 10480547126759850066, 6097728641437901141, 17248496754222975198, 0, 87, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 10686862901019340628, 15711583786595019806, 9378042936835126164, 11939142602264935891, 13605517752371930016, 2544863311362262665, 6880055194706872138, 2404926559643725443, 11298729247352625131, 13639273524510051487, 3031605320954281704, 2952677760580202523, 1, 0, 0, 0, 1, 0, 0, 0, 0, 6949406075980976859, 9142069989509656801, 14676622013796942288, 5295633173573979080, 14862684288436559050, 7708888152496129562, 8667911075542880817, 14424367369474907891, 14303094264982903091, 9838552210955819611, 15088013178433258027, 5833102420062152227, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1932675776657481842, 14290498569500988181, 11741991701671402436, 3934903733189518965, 10047440752038846171, 14938209139342513571, 7659889883493126262, 2134579895120260539, 7819147353957995986, 17861588317805920712, 11020859927535923500, 15623868602690334525, 1, 0, 0, 0, 1, 0, 6264451320029412065, 5315770291001895612, 3923979823614336294, 15496957568148800678, 4856878698798286165, 18427152961697133322, 13172977369565732662, 8634756726478972696, 17549357918509499997, 7356106617646839123, 16192566970100663376, 4904526601366015673, 11478334329288517717, 607398074844683832, 9609971183005491570, 1, 0, 0, 0, 1, 0, 18264070764381924889, 7558994944201947568, 16698567473332535936, 4066201321205995431, 14552036519561423602, 5620710451624899086, 14969463994437329823, 11938508228196027882, 9200118839118887577, 6855444937813269923, 13901427726318773655, 3507966654472722962, 13139165600809348467, 3547085602937656739, 11244050388029555026, 1, 0, 0, 0, 1, 0, 8312328144036608043, 17972686765781519170, 10784039031850599726, 14134435301654782468, 13131877571979284929, 8266221982529104091, 159405248778538274, 5778967389144576888, 6057984302796584762, 11714059928473413141, 11763232719990709154, 7978933720497313146, 16635094485101159936, 18327609188632861057, 11071183167122824035, 1, 0, 0, 0, 1, 0, 10287810620841180003, 4548089904338037398, 6876519236022884332, 192351967064940869, 13616941784242570400, 7032108910940453446, 13625250436816808378, 17491100122417306359, 2292049730346364666, 2733535393252649149, 17750397792987890641, 6346476747248545150, 3575465615474366120, 18213303372206038112, 2518621101786158931, 1, 0, 0, 0, 1, 0, 842637389045220237, 14003171518185218367, 14997648696661468292, 13477259760240789253, 7438659305055821970, 7828458451594639328, 1805142843426507273, 3804729079035423760, 5684604326361654696, 17218885460122549497, 974371611540683935, 16762750120460661174, 739710162320190732, 3363948547922989023, 4267260670759647913, 1, 0, 0, 0, 1, 0, 10264158766070300923, 6050974414693797250, 847386589526447339, 3548106904874618124, 9289172558104066787, 8226909131216769737, 16380713199877477068, 4410762367217395758, 12555768451623030884, 10357980275595284555, 10303991993655092221, 4060030248038493229, 11216725884924445657, 10194932652661424405, 17494422570060569743, 1, 0, 0, 0, 1, 0, 522514578171525652, 3717501858890221638, 16025700499781393088, 15033579247524264929, 1744414008664189122, 6807378681147180078, 16955668219975052585, 18323017022834713256, 6662618285165080179, 12762215046608848013, 17134633855452090590, 6353725621416552612, 4449259194945598867, 8877290555352616803, 13666098560811114332, 1, 0, 0, 0, 1, 0, 3232143389630708424, 0, 0, 9014593992030055460, 10869121640834977224, 1905700011211118876, 955944440419378960, 265206078841667899, 13713964984862746492, 9702435518807270681, 12343078651970579400, 18227529633908655074, 9709048888339027683, 15154974039676851951, 16388400023664675593, 1, 0, 0, 0, 1, 0, 0, 0, 0, 12342730708987043912, 13274159397630057441, 12697978258400128397, 368152630932848211, 6555819701154221199, 97417680512067538, 2018507387878521400, 1529782995014995301, 13636792419679998309, 6197980968820055410, 737644335551408580, 9956102600220791675, 1, 0, 0, 0, 1, 0, 0, 0, 0, 14179025343931559433, 1175312715506728066, 11255361077722267605, 9822732455439796133, 13335036252549184126, 17127037879360292568, 16600677125340288437, 11659800847392950623, 12605660248276552114, 14805446144065764307, 14804045017754446897, 13192632014186378484, 1, 0, 0, 0, 1, 0, 0, 0, 0, 12383461936126681247, 745215043874424896, 4540981537676651137, 16486351305638014506, 10972364256824969372, 5647748125744546841, 5620391031839475969, 17973620544670757805, 1344519641939806437, 11395404185290209616, 4498705163534372313, 3336623779264323323, 1, 0, 0, 0, 1, 0, 0, 0, 0, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 8400310461204590462, 9108169057237353573, 17636133504178290964, 17406877359165992528, 1012686194999500095, 3119571665051516884, 6045109140346221273, 8023007352945590267, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], range_checker_cols: [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2187, 4374, 6561, 8748, 10935, 13122, 15309, 17496, 19683, 21870, 24057, 26244, 28431, 30618, 32805, 34992, 37179, 39366, 41553, 43740, 45927, 48114, 50301, 52488, 54675, 56862, 59049, 61236, 63423, 64152, 64881, 65124, 65367, 65448, 65529, 65532, 65535, 65535]], num_rows: 128 }, last_program_row: RowIndex(10) }, program_info: ProgramInfo { program_hash: Word([11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518]), kernel: Kernel([]) }, stack_outputs: StackOutputs { elements: [2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, precompile_requests: [], final_precompile_transcript: PrecompileTranscript { state: Word([0, 0, 0, 0]) }, trace_len_summary: TraceLenSummary { main_trace_len: 11, range_trace_len: 39, chiplets_trace_len: ChipletsLengths { hash_chiplet_len: 64, bitwise_chiplet_len: 0, memory_chiplet_len: 0, ace_chiplet_len: 0, kernel_rom_len: 0 } } } diff --git a/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_16.snap b/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_16.snap index a5f0d94b28..db50a4f102 100644 --- a/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_16.snap +++ b/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_16.snap @@ -2,4 +2,4 @@ source: processor/src/trace/parallel/tests.rs expression: DeterministicTrace(&trace_from_fragments) --- -ExecutionTrace { main_trace: MainTrace { columns: ColMatrix { columns: [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 33, 33, 33, 33, 1, 65, 65, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [11182969138190702361, 11656, 91, 0, 0, 11182969138190702361, 41, 0, 11006573531383828351, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010], [1109628455053940361, 42, 1, 1, 1, 1109628455053940361, 0, 1, 10983413158656624898, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331], [13928676565061410159, 0, 0, 0, 0, 13928676565061410159, 0, 0, 4869282124135316831, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319], [297470094449022674, 0, 0, 0, 0, 297470094449022674, 0, 0, 5899798166361732461, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694], [11006573531383828351, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [10983413158656624898, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [4869282124135316831, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [5899798166361732461, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 2, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 2, 42, 42, 42, 42, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2], [2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [3, 3, 3, 3, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3], [0, 0, 0, 0, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [16, 16, 16, 16, 17, 17, 17, 17, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16], [0, 0, 0, 0, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2187, 4374, 6561, 8748, 10935, 13122, 15309, 17496, 19683, 21870, 24057, 26244, 28431, 30618, 32805, 34992, 37179, 39366, 41553, 43740, 45927, 48114, 50301, 52488, 54675, 56862, 59049, 61236, 63423, 64152, 64881, 65124, 65367, 65448, 65529, 65532, 65535, 65535], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [11182969138190702361, 16344194729581826754, 15045917672181612303, 3672327111134984977, 11902001817992340801, 97480563262877602, 1831626543952762702, 12062163654685913941, 1451330498122947575, 1742063333427513989, 2331114102915733339, 8550984974115591347, 8960841496031156142, 13720918668577423004, 5779906183691085674, 3198599991840782485, 13728843979899181292, 7239115491427587826, 12128894594351473931, 15480692841914867508, 8817470180767843173, 10548371713427919789, 10315264763691724912, 1023167627240586914, 3818953450339058320, 14941570263133670432, 12615841091071546269, 15435370781163068976, 15373572920503822367, 11769995123877236600, 3762647969008011219, 8269653645296248010, 11656, 117148, 6714198787893475936, 5262284953624879131, 6828048997998717653, 14647846255598321281, 12213957512096072087, 15486993862206988880, 9916068016290756984, 12311676223031039230, 6798558233575208094, 6061515485015027193, 9178825932447902299, 16451694760407086053, 9245574117575493602, 6706571375738621744, 5707941763645196550, 13553995817865937844, 18312867062271325792, 11246612591729350508, 8806896510487478352, 16014621579841168337, 6332183310159529150, 2444726075814550534, 13415483499482541228, 16602291456530418215, 3069389264726801426, 4940323642218861897, 3979217445866956620, 6693606464693965975, 9525288177353527302, 11182969138190702361, 41, 410, 8488924048752676071, 5473488137200086909, 16124688533662466636, 4527044298581192722, 16887055178922689595, 5249711198271717177, 15470787238396171217, 5632634005697013617, 7337408598993184022, 11147561538212402733, 9710911023591971572, 8752830793140649116, 11546140485006286209, 10738951369466640003, 2139663271495255306, 6135983205453599776, 17538856881976830392, 2031516987289365197, 17199894398730562705, 4010699482290892787, 3922552954514582360, 7369439734883755459, 108303794773646012, 14521269346803535153, 14515762120928230173, 13893962684375637966, 13610167819530098127, 11215445033353754262, 8081237365032914784, 11006573531383828351, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1109628455053940361, 12119768350776285319, 8184561966951183876, 12431805880114311043, 2986356007899077631, 2836244341662188919, 146796491816379180, 8696360259937422388, 13878284404078727054, 7667548888861073206, 9741377056638459459, 11905155073870025459, 9736056580211703764, 17352787150580200349, 5883496260565631343, 9594088066979877926, 9297041447863221537, 6214639496702145664, 2461170076272033096, 17112913798212225634, 1035954869286151888, 2140568550425483844, 10584986198873793665, 12555736327846716176, 12072441430913369009, 13906015856663078107, 14389918991418187594, 2676571742010508284, 5150637797762075635, 11237118474907085960, 11752652705714102353, 997682303299740331, 42, 93752, 18084035356118526352, 8386870944408484201, 18056918720989013854, 11520229540186073721, 5668756658695595711, 14109792997657353922, 12303762929371991135, 14460911410586037148, 12418445481638740107, 16455507557982986163, 18172284878038222122, 6352198309363971688, 9198509167958908347, 1068046269761257463, 16102483860755268671, 1544674922431042375, 9868836391822552540, 7915117918356788325, 6533551228799195237, 3992189811639127908, 9511948951280762358, 13039263708530965818, 708611914251242147, 4206064101444952505, 17714998603219848343, 13074430791784659712, 14102459334756352921, 13661835471193379756, 3038016940647586670, 1109628455053940361, 0, 328, 7132218559010351790, 2687466917280430353, 14170238607512888511, 5453168895411602323, 8679138582261878552, 10871515559850126217, 7649138216344653830, 12086029516113687059, 14609582285822867389, 7271583017513514692, 3821121937809044409, 3833100151978191712, 5702916883024911354, 3579138882391492892, 14347405124134927123, 9277341930384005575, 2993137622300793545, 13370802209879109056, 13653108884642243926, 8702782587703766612, 12945832125614510830, 15167316901472929028, 4608694219239856197, 4443739924303229750, 8611475648437961511, 1575864515244779062, 10900065459953722709, 9162692523043045302, 17462008412377898139, 10983413158656624898, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [13928676565061410159, 5375705730949115787, 1314981229280595867, 1393532256400242982, 13433705342207763738, 12880831435259048250, 10699055768478348083, 2470044642731141974, 13732313223959877570, 2078090264025450769, 3845297826200108779, 15581584642080412492, 11359623335937034504, 14549946302435322871, 17424758021352066268, 15472130290487345321, 13048555428151627244, 13747770174448213841, 9164669383091055648, 3250455247796114093, 10799815877710934765, 9086202890994770785, 12116339825079888992, 1619117325320043308, 16898959203497269575, 15756045849228969140, 6190024525131486611, 6215657966742979785, 17671950935398765622, 15303512720733905693, 10727837149375754730, 12907160815575155319, 0, 23564, 4199576522683349447, 16513391592299529611, 11415640949254272304, 16138036929710694921, 9992494271122179933, 3020772293084222765, 15625472986208536177, 12149624601412828429, 10735117276139490774, 13332197512776217968, 13474689739491604605, 13815225937039366706, 706573335075180235, 4097091053989040149, 693823183101411164, 5341110475237803180, 4368449439175744649, 7740607367180462177, 13389502447794973829, 6721164191334334250, 6997451158266748059, 9767862146044075473, 4778055569341029558, 10088175016132507812, 3285997397792070136, 10914182999248450193, 14473951691792990803, 8827937223658185560, 9698676695870635420, 13928676565061410159, 0, 82, 18152833202936203138, 10305147718805144715, 13246631902503555591, 18142351346900318359, 11971140429919100117, 6903484634638418138, 3098698980745497723, 3068992673894668202, 9164459936648953977, 11194864417357882388, 12005359455571366116, 12356306486226268709, 10059737158050223658, 17119982236602677307, 4225663824996553892, 17852936504841763737, 5778553506856942969, 9045001363359345866, 18423338781077887809, 2711240319770097821, 8346149567490270428, 9594540064387516595, 1859863665658604717, 16919987197409252682, 7809934763889573038, 12492597695329698922, 18341122838405415754, 11967784234256998242, 10761804868734649587, 4869282124135316831, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [297470094449022674, 13535968261560526699, 10051713503687926694, 5258910437097366761, 14031537229609682064, 18190284629542346231, 4346004165604875907, 15375947702712472554, 4019409425675168575, 2064296209102051574, 17718639079388526425, 16642022229570326204, 1618478323171655450, 5998884876319667302, 6872649224968331273, 13753905356607269997, 7559241041198219519, 8363779881416372286, 2105649450986611656, 11644599807961994770, 12949568200151355456, 4366812189797744262, 9669235379242805159, 18184433440084438609, 13914998044815764482, 11325806379320193213, 1586181560816232196, 5920020313630770955, 8020025137186066841, 13419225700498867773, 13671651770198504476, 18024383338294781694, 0, 23396, 7560057297276955988, 7451013195867945919, 7468487593070852196, 5578183109591783882, 15747662796636990589, 2066701485189878406, 17025371161980089605, 4391959764977446152, 4985867595251695917, 6710066216774366729, 6241000701339836952, 4718440141936325382, 4986060230214018536, 5748634601882563491, 10896228304766504283, 6457499153671182820, 12270042173384394159, 11711065129605555908, 15065279868519608165, 17856220227797901726, 8953039722587792244, 16994104539161729445, 14670768895096516686, 14803898243742553487, 2327203233976270205, 17449705512918939747, 8253253226048886083, 11671578295265948239, 14297456315487806992, 297470094449022674, 0, 82, 302695496926486902, 16415403596737407938, 12969246825596557956, 15965643470182086386, 14881573336337548597, 2868629484750761697, 7317402970608805914, 2570537868338555591, 6697005353407257884, 5717939852331496040, 9408357527608003903, 8011884131194179594, 15942512744234440774, 9052662470595673790, 11913271961595885333, 15508051727969296111, 6269710669185644103, 12322255659000247132, 810875278274469351, 3499523055983644139, 9453749819048496107, 598273005722510655, 12338854942180141395, 2829445891916136836, 12653867244112536729, 4648827005364006908, 3153753366153954420, 12197142511433562971, 13557680898519201450, 5899798166361732461, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [11006573531383828351, 92579048505362891, 10772660272533654046, 3331697170176629084, 602109730184155310, 16230148280330706633, 6302091831624975391, 14001078336639287767, 14888577262766439787, 12258632680483319887, 7641862043593808385, 4740702640077452126, 8494032654039797119, 8314420015254970480, 18294822284401514132, 15552480182219334239, 908821363395967579, 18258193129875665644, 4226365574585037317, 3638253471537757569, 17581484848263912285, 6286301305761091621, 4777175749672661669, 10658559677463134471, 1417442037893012894, 7857622794514614671, 1052908464763109826, 4925127753504389599, 4274762298296320367, 7383511416371792464, 17305170235876004791, 2200823396264285425, 0, 58574, 18280076181055982575, 3965010120048981150, 1623299660155787797, 11930292174601709627, 17275008438838615802, 5756406115988630048, 17841510847136093686, 6729021181420822547, 1709787776185889305, 2022739540363098314, 5157634830695555269, 17099057016182449505, 4092740078069974091, 9582547144648304801, 4715310719341519129, 1597700055042697404, 480964694484615271, 56280064407246395, 10536769335197150641, 16099710145374622840, 3473101726323291593, 3295906456874767760, 716460020344690975, 10580825486552151036, 4976836170739997781, 16652319776094256449, 12319687016213027555, 13490282225851742651, 3371801902832234206, 3795543859124105201, 0, 205, 13622702382434675698, 8941567408770445183, 2168342371250989865, 17553704974699598306, 12818882650622055705, 16478401302589696546, 10652219805906948351, 13167156861512034068, 260666911081589986, 1428764500637505382, 2190433219200603887, 11999917547751101526, 2751093334206085539, 9318931023569054874, 16297727142514657495, 11875658036026604145, 5829323963705819601, 407792022339954638, 5684565403642367050, 13995368600016681288, 2845800306757116207, 5216498913603536417, 2411940295743487842, 2014066638340124975, 5258230180909223265, 17089893338044941808, 1124366766375746940, 9116801986360376826, 6650575029061305823, 4025036448660092914, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [10983413158656624898, 11859595567907759997, 10088766553729725414, 12574093635772317570, 5470069473511751658, 9645793732101008923, 1476556243604239385, 17933040757673393353, 7118521641278947238, 7588084371428510216, 12191494749556797391, 8228232126921631746, 15226641263820888277, 4239012011479875368, 14018593041447406970, 3541695062587160892, 11116896887234129281, 3929539690735302143, 11203930352796078636, 8751959587369085991, 12655249523595546680, 16379258612200834026, 9984807922535170831, 9638171237357393134, 12191893464144837018, 4677785078090407332, 8064604530099592479, 10076433135196495423, 544627542347870852, 11879905738846635842, 5683487714952213815, 8088984326603898052, 0, 46876, 15125170292333450443, 7072657932567702059, 10475291980250876467, 14632109792663117375, 18379882203306053694, 10250239327737538260, 11537033439839832588, 15180883293806522386, 18285674122603938406, 16116176887352657770, 15068074760365493774, 10507624248254584461, 7669544778380245671, 16424767991328560142, 16771797144770177609, 4105927596877687309, 7519344916607985067, 16277772212475505196, 1322695487397776109, 8302446182097155523, 14744324883381489574, 16338446684875281086, 5703860549203085948, 14077533030564871132, 12287193162084105824, 2535384450001991464, 13089916287630526229, 1568845385281768860, 982340402770608276, 12910581729787565904, 0, 164, 6093021124582015914, 375332441348258328, 16597900739273350797, 16788616498952461620, 10323894478242846558, 3730474644926313294, 17377183878976452334, 12746711269593150718, 13699107349734059694, 421533440407219618, 15109303318896079214, 17746438429032263850, 13224617406323308041, 5646455969610140563, 12626985742338481481, 14497665384991648640, 13894375308737560134, 3268393834564630675, 13312171511942754529, 611321250913478210, 12048873764879264902, 5334026694118161468, 14360341460112568406, 17654490467796517057, 1299716947845207044, 7609683397541157642, 14709808073905360012, 11742139955633481423, 13522070698443062110, 12847434483856017691, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [4869282124135316831, 10293244464294212936, 8691876854061179148, 2952350747126730564, 7968203687716298290, 6747517476428823928, 16731591574836256879, 12286682322909052293, 5699380547329532508, 8774011841981167612, 10988677337017809219, 6257583805205658612, 8595550098696265772, 17321901905145630028, 3295089823193122164, 6581488060195755410, 6329516418872359771, 7640632346113799527, 10454000694343684461, 15867346750604392587, 5805413556949044653, 9247297947852762648, 13748015074908171216, 13312272456227001370, 5054807356361880835, 1012271632864570722, 11252467974344770686, 492886975717156403, 2629112354487966090, 10128035487146424848, 18233951381382816412, 1751709948898726303, 0, 11782, 6055246182589913733, 15015595405278911690, 2209046468675768902, 16429197663637467330, 15810134098389081544, 9588791733994120847, 18370261572729563296, 7006788971063612777, 7962515674056117045, 15223121510830934757, 15872454912771340895, 1486059252283823706, 3912605942422700262, 4173681472723400357, 2922691200579275072, 7112424425452913463, 17213377378328786151, 6274713241106982122, 15112974401160243995, 17175975930045398893, 5467280291812001242, 5238070817263862176, 17584445990298638069, 171514605620090783, 4267926381848052110, 9011064139813451706, 17044511642202081265, 17370313250110904770, 13397257034080852565, 17596568325206204932, 0, 41, 9617260353707541367, 9187825164453421957, 17649953659489375797, 6396310504287885774, 17019569090864760371, 870218876784769460, 17213560015461715510, 16812494438448165271, 15885717661613279263, 2958950328581697287, 14311601477626423214, 12599125587081655507, 12078599565132475515, 3332808335850364509, 374688056722968094, 5591521890390007231, 9584980789501913045, 4066644474875437132, 17728945623551220217, 1158050506628066296, 3730734784735709807, 10671987699715228843, 3173999018565335463, 14949604462817069254, 11653871972148380806, 312408327658285690, 8531928004921347162, 98858158429688394, 6167334615107562354, 1234843923022284190, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [5899798166361732461, 2163003956713638315, 5989289390391757114, 15670015339098587014, 12708827926449341197, 10159927950043513901, 15395056832871965886, 17405960500607097380, 9229756563573051371, 1186079292937331145, 13463816706671585562, 10107168241231917326, 8534001612601599401, 12790948878158723266, 12619661555644649350, 11614101867080583800, 11255619179741810030, 10501448523390229441, 16971746085380600175, 7173352752193758542, 9960833320626690499, 3507659370538431093, 6846598866105961944, 2557094292829749679, 11416743759689580593, 12182449258645699464, 11951277814213817673, 10567677969346318078, 13884819925875295975, 1926379571595510347, 5918588896905128530, 3405979658670756574, 0, 11698, 8146055133796963630, 4724864404296433607, 10453305271538430204, 17141108237620938331, 16113292978122689735, 14630852758047225712, 16936235645680974811, 640959767495035790, 11162248672474783185, 10618808740372936561, 12973220127719589473, 13223353016814262874, 17652411276563186968, 10141330567980253051, 1770876161367154023, 12442058685904907795, 12986633647641209886, 5384244903407669612, 14778499304685795812, 8054814913234770610, 8358166993767322841, 11933451322373121057, 17795028935448509068, 11142588879850986282, 873880226830208445, 11017896854604878841, 6896812394605202475, 2024842447089060639, 16625734836325714912, 12512094004962322130, 0, 41, 12529483521877137515, 4671467226762388980, 13873740979092621907, 12847173262736205772, 2640423636460273022, 8374058502362870155, 7630996533587302384, 3556075572123538464, 8078558398785937163, 5856098383496092000, 7999607615804135893, 15509992149354799776, 13785560116650003734, 8358196300413379173, 10412508239405514928, 7840142081125036731, 18075062342410207477, 18173191150607640442, 2133036585496843963, 8931901040624025193, 9454731621283026961, 5837806564591410604, 5850596656185029719, 296117354535505751, 8985195681813998404, 1975947551471322175, 12041110943945791333, 11648250496545232642, 7830634726555216225, 5266777994490151623, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 11627839282500592134, 3407397722647202213, 13644814392425193274, 9689174787852538317, 15759480978611340324, 10073546228149283602, 8090878949578096073, 1502926046713635634, 7624167193861818791, 10274257988202953339, 4186763142475177793, 6025425965090069083, 8194342163688078130, 13163397875087894329, 5161390927343581791, 10103251159424454395, 575959985319833606, 13175926157437524595, 8928028362497258488, 8665485641724560922, 15570929820685955587, 6150675652390666890, 6384512333148749163, 35921027791486524, 3229184449291625000, 7414754653220847914, 11347301099028602515, 8368586536930615942, 10138228048917253579, 344980745193352015, 5644431973654019812, 0, 58574, 12761879591277148733, 3794756304714494565, 10919382803049057886, 13927811434585922718, 8315847055470475708, 10095847089706649983, 41153506376499461, 5529807447506440005, 72892344713547594, 18362204307013225363, 527610602670466995, 14772158556567070690, 9538491437159792328, 1580498045195806896, 8297535568256810268, 13797917351588149895, 1651894826575892086, 13380716913143325871, 2655893075036451977, 3750342908258071259, 18231595474498119868, 18163310674975357977, 2371603174180061555, 6433509503768865899, 5002589281792664271, 10946433388588585987, 9256382872640968643, 6570002101874463971, 3849537215181896567, 5735281858523620986, 0, 205, 7876112718273244024, 1276143811675585923, 9993912342918529935, 16999254614849428545, 8194747920293058753, 11171758628037424552, 8208119826419095432, 5568149314099479773, 17551537772960996556, 12651683228606533001, 13584145944854843210, 12212300608708011466, 18102951610480561318, 14720258372954226591, 15448472262117068008, 10575290756167155008, 11997391634424499349, 9879556170680135793, 12373753045781314057, 9529470285212177396, 10620662102176580756, 10199402949196411787, 9825825353570660203, 18337390924518345383, 15945306792731206141, 10537181099344133724, 5505106000120813030, 14774803975376978777, 14575654492591748955, 8207377881872409730, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [87, 1844206616423154361, 7941852203687681180, 2987825311454433607, 185071303888742221, 16140725249773135932, 13486449309893009073, 13471170357015645210, 11073859438158044651, 16507211018434913458, 4066228076398875428, 16536071023746429034, 10818247459046542341, 4392853051950044706, 12116759677655250999, 17293580330275603290, 2376540144284705519, 8057038266027202789, 15097730100005395027, 3583575859544955648, 11146351406925299070, 13473187462927502829, 8056538798141691018, 13509558775822115028, 6797301950091310335, 8773981691004278165, 4751058192101309365, 10661116978196100999, 15345629614104209519, 1689963602473071179, 12869561156624962469, 12554030503530361323, 0, 46876, 4789346784708035796, 9438751512570250357, 447952077691938652, 6351356675900770483, 4868676530510485341, 3192437812250556397, 11511034416225137032, 15380266628173325649, 10700144984876703355, 12230522212327928379, 15526804358639727019, 6410705682507666807, 15728916292645010880, 13992590038292222154, 1916422775943772979, 8280685582260709248, 12515254706968408232, 4845996266408136556, 15172713941042952680, 2233761585242005099, 13227100893355110663, 3914062371738178895, 7843298541359739176, 8386193964610423744, 8614894336467293783, 8834991867772635266, 14221135810103683560, 11406071542091908609, 571586377235018247, 3013510715159483905, 0, 164, 14482187202392982684, 17682350329754313417, 66214439016909251, 7504629639084879386, 11708178258767948919, 188011405648496761, 10242982970375452289, 16510140404231294235, 13381084464566932690, 9239012175869487665, 9339694231140180875, 9917181315244873380, 17448534469581521177, 4965043893766771965, 13305445405772227224, 6963375374275021656, 4554518835153561582, 1694446457415578298, 4604616361036784646, 11439774970058559661, 10784225701912607868, 17782855612978839775, 13368223431578003475, 18100595786373494652, 12753204151452870283, 17504098334052422651, 12896535568794110034, 7402084190222773115, 598469278842686486, 5912604878679295331, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 11371898088219304696, 4199208231896291776, 6349271639347163621, 5568595648257864309, 10224931331962954075, 8046167029187450402, 6585148777263545478, 3706462809677116963, 12578093594063946501, 11334181120248394313, 4953509182438845792, 4130560513564095433, 6665409895959715593, 12872180446847298231, 11452171012153290342, 5729159829892489539, 5675564903335979949, 14158677720471443076, 12300968791182495713, 13879671978791253311, 14820104759072107152, 17585955671327967478, 6737505022417937354, 17454985371239394211, 15749874646256262769, 10017226585432634212, 8893160827421013787, 11893931769684808775, 16471875099240353401, 9975926385796085953, 11231727832144176264, 0, 11782, 6351111885067026894, 14086295994708840477, 3142920623105062021, 4317195510637014184, 16341148873550430347, 8014762585425506108, 12977978004680762325, 15318810920503136316, 9472517513827583818, 211962335804367550, 14931353145911604525, 9340212215573419915, 5244269534978718672, 1584128384101705476, 4460891295949496863, 14654598206063183317, 13555452196222133132, 17680908597379218579, 13178742765486355260, 3964993209073179108, 4213917162333386044, 2639949635019592417, 3300803743280888923, 12914222891103397086, 13436383826829479040, 7004576641630317963, 12080155723705641895, 6767987840126452263, 14392317091133450653, 7390177608867021213, 0, 41, 3800418813655617572, 14503408479575576010, 10553169970007645345, 4946745422622378051, 7127828976000219721, 2687285609278369395, 16630221959750548176, 1114885198959805561, 3895092647933222339, 9831397389014117600, 12816842684293233323, 1779119880742935864, 17663607747965229138, 5382558247959552902, 11972955750871888364, 16616426694032134438, 9711126273890628516, 376576173107709408, 12451218545182255865, 14301764572821220192, 13209253693600827240, 5745169166190656073, 12916752429524642864, 14463770325561420619, 7870235520772452232, 13278341252249613603, 5432056100901092307, 8994645443800925562, 5908996313982662075, 1494658977663487041, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 17530820119034444668, 15233230393479930649, 15702789941308523576, 8819781861782654629, 7112644758334533508, 2549387492966523460, 15838339720324898846, 10242380937000070843, 1124701407395854549, 5706112669062280829, 17015988684670402201, 12671109438456697877, 15652595419009785355, 10753966634497852319, 3622124053041186910, 2063695485301676711, 17845322355197915738, 9894091605930112348, 10822348040176532279, 9689802115657313068, 6759722828145755337, 9479044480226984785, 7845909286502989649, 560081323074218824, 16017591174163981005, 1196237303718990885, 6783304352365897531, 5064625229425039166, 12661189034561966549, 11511655067934063768, 11479359825177848513, 0, 11698, 2084118884093035279, 16979859941949546961, 1454299506056429821, 9658643065222637557, 11605485146349749283, 13057696629474024230, 16650374201325163722, 7457309320444728046, 1243843599995756274, 17176177262691414244, 14152683925184093692, 198845790532099135, 442435874165139119, 1462611314767788334, 3462067515008653152, 4141759445261917472, 12323330957750482072, 14922731139272985797, 10387565380055278256, 9531386257124273696, 9539285450074189441, 3691450672437772660, 12463184698711878632, 4858502687517999226, 12256855995572753726, 9245347314341240247, 7569214225554358494, 1017686422583121037, 10327407591150878848, 15025446886891081073, 0, 41, 13092032916490151270, 2856458557507854671, 14059661153766146178, 1724041303048776424, 7119687853704366589, 3699246950542313036, 8338994289155538949, 7732171807197958061, 10653644351656999339, 15262849800927670044, 6132373490633371091, 16473831322001214578, 12928938600331453669, 6959935525856744214, 17173069020016176920, 6747622983845354522, 2484033613426731933, 9879916419081378373, 4275250202523893223, 5995505684018086986, 16115855409799741127, 2490003355474156145, 10034475279304353355, 7223217715426381376, 10334063888823214988, 2139000562522371457, 18314119367638727156, 15311716904301189063, 894706229073498557, 1570146104298050273, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] }, last_program_row: RowIndex(10) }, program_info: ProgramInfo { program_hash: Word([8269653645296248010, 997682303299740331, 12907160815575155319, 18024383338294781694]), kernel: Kernel([]) }, stack_outputs: StackOutputs { elements: [2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, merkle_store_nodes: {Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571]): (Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350]), Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350])), Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484]): (Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693]), Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693])), Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781]): (Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874]), Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874])), Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171]): (Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361]), Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361])), Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815]): (Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305]), Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305])), Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689]): (Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195]), Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195])), Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362]): (Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063]), Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063])), Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848]): (Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661]), Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661])), Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352]): (Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829]), Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829])), Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444]): (Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223]), Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223])), Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386]): (Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388]), Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388])), Word([13190842942618341421, 17548956981569849952, 15418963848144418856, 730733050713174879]): (Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144]), Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144])), Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874]): (Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675]), Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675])), Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594]): (Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115]), Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115])), Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809]): (Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257]), Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257])), Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777]): (Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555]), Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555])), Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509]): (Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882]), Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882])), Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725]): (Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979]), Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979])), Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134]): (Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987]), Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987])), Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828]): (Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910]), Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910])), Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830]): (Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054]), Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054])), Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228]): (Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742]), Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742])), Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443]): (Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928]), Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928])), Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643]): (Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979]), Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979])), Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758]): (Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106]), Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106])), Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580]): (Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594]), Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594])), Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765]): (Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045]), Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045])), Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766]): (Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281]), Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281])), Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385]): (Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828]), Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828])), Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579]): (Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171]), Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171])), Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212]): (Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992]), Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992])), Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463]): (Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004]), Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004])), Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502]): (Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023]), Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023])), Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539]): (Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537]), Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537])), Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865]): (Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225]), Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225])), Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690]): (Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947]), Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947])), Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202]): (Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552]), Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552])), Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079]): (Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444]), Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444])), Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850]): (Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548]), Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548])), Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448]): (Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987]), Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987])), Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041]): (Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035]), Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035])), Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301]): (Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414]), Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414])), Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414]): (Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212]), Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212])), Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703]): (Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439]), Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439])), Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271]): (Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955]), Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955])), Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882]): (Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802]), Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802])), Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152]): (Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887]), Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887])), Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028]): (Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948]), Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948])), Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331]): (Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093]), Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093])), Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394]): (Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134]), Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134])), Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546]): (Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228]), Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228])), Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620]): (Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414]), Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414])), Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800]): (Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703]), Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703])), Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671]): (Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205]), Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205])), Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537]): (Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011]), Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011])), Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516]): (Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301]), Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301])), Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831]): (Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986]), Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986])), Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415]): (Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057]), Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057])), Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722]): (Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689]), Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689])), Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144]): (Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682]), Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682])), Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295]): (Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268]), Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268])), Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818]): (Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513]), Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513])), Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241]): (Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565]), Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565])), Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439]): (Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012]), Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012])), Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512]): (Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850]), Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850])), Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986]): (Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865]), Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865])), Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982]): (Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777]), Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777])), Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808]): (Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394]), Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394])), Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979]): (Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690]), Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690])), Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093]): (Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620]), Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620])), Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902]): (Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789]), Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789])), Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542]): (Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094]), Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094])), Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057]): (Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362]), Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362])), Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205]): (Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961]), Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961])), Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401]): (Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580]), Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580])), Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553]): (Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960]), Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960])), Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169]): (Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031]), Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031])), Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682]): (Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053]), Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053])), Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118]): (Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562]), Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562])), Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725]): (Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666]), Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666])), Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661]): (Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897]), Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897])), Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981]): (Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447]), Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447])), Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072]): (Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646]), Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646])), Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140]): (Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404]), Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404])), Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515]): (Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152]), Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152])), Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709]): (Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664]), Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664])), Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800]): (Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103]), Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103])), Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741]): (Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169]), Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169])), Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005]): (Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758]), Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758])), Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802]): (Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070]), Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070])), Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159]): (Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005]), Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005])), Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350]): (Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443]), Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443])), Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697]): (Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573]), Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573])), Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928]): (Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331]), Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331])), Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320]): (Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166]), Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166])), Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814]): (Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079]), Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079])), Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447]): (Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820]), Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820])), Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284]): (Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057]), Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057])), Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697]): (Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131]), Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131])), Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955]): (Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290]), Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290])), Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910]): (Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202]), Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202])), Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910]): (Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822]), Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822])), Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106]): (Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847]), Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847])), Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404]): (Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441]), Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441])), Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796]): (Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186]), Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186])), Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053]): (Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516]), Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516])), Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992]): (Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818]), Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818])), Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957]): (Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315]), Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315])), Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709]): (Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794]), Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794])), Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091]): (Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539]), Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539])), Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664]): (Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558]), Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558])), Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294]): (Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579]), Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579])), Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947]): (Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502]), Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502])), Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829]): (Word([0, 0, 0, 0]), Word([0, 0, 0, 0])), Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045]): (Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137]), Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137])), Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914]): (Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041]), Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041])), Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573]): (Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378]), Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378])), Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699]): (Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873]), Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873])), Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225]): (Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262]), Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262])), Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057]): (Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692]), Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692])), Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131]): (Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997]), Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997])), Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555]): (Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385]), Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385])), Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195]): (Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709]), Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709])), Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166]): (Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542]), Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542])), Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027]): (Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373]), Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373])), Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378]): (Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509]), Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509])), Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097]): (Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553]), Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553])), Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217]): (Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815]), Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815])), Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873]): (Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864]), Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864])), Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997]): (Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722]), Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722])), Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887]): (Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766]), Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766])), Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589]): (Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757]), Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757])), Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539]): (Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665]), Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665])), Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129]): (Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229]), Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229])), Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137]): (Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312]), Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312])), Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019]): (Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378]), Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378])), Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331]): (Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713]), Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713])), Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]): (Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980]), Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980])), Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325]): (Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546]), Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546])), Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170]): (Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822]), Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822])), Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054]): (Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295]), Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295])), Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925]): (Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848]), Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848])), Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909]): (Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796]), Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796])), Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540]): (Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170]), Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170])), Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214]): (Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448]), Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448])), Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317]): (Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294]), Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294])), Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757]): (Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416]), Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416])), Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378]): (Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091]), Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091])), Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263]): (Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463]), Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463])), Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666]): (Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361]), Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361])), Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174]): (Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992]), Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992])), Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470]): (Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401]), Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401])), Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665]): (Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957]), Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957])), Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262]): (Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144]), Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144])), Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229]): (Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284]), Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284])), Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134]): (Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325]), Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325])), Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855]): (Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765]), Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765])), Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115]): (Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814]), Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814])), Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441]): (Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831]), Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831])), Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977]): (Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446]), Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446])), Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880]): (Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005]), Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005])), Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789]): (Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995]), Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995])), Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000]): (Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267]), Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267])), Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998]): (Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982]), Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982])), Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995]): (Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539]), Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539])), Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507]): (Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512]), Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512])), Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305]): (Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118]), Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118])), Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219]): (Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009]), Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009])), Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416]): (Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089]), Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089])), Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980]): (Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445]), Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445])), Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063]): (Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140]), Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140])), Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713]): (Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159]), Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159])), Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031]): (Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809]), Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809])), Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932]): (Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037]), Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037])), Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094]): (Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925]), Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925])), Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315]): (Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386]), Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386])), Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446]): (Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721]), Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721])), Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742]): (Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981]), Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981])), Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661]): (Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072]), Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072])), Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979]): (Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671]), Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671])), Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361]): (Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269]), Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269])), Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558]): (Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571]), Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571])), Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290]): (Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902]), Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902])), Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987]): (Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741]), Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741])), Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902]): (Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515]), Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515])), Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497]): (Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028]), Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028])), Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948]): (Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709]), Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709])), Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009]): (Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725]), Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725])), Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387]): (Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317]), Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317])), Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159]): (Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808]), Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808])), Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394]): (Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699]), Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699])), Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312]): (Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000]), Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000])), Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987]): (Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821]), Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821])), Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046]): (Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909]), Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909])), Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565]): (Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028]), Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028])), Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269]): (Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352]), Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352])), Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847]): (Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271]), Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271])), Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513]): (Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800]), Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800])), Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054]): (Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394]), Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394])), Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004]): (Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977]), Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977])), Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675]): (Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800]), Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800])), Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692]): (Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159]), Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159])), Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909]): (Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932]), Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932])), Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814]): (Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697]), Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697])), Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186]): (Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387]), Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387])), Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445]): (Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470]), Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470])), Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966]): (Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507]), Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507])), Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548]): (Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253]), Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253])), Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897]): (Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783]), Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783])), Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208]): (Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054]), Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054])), Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268]): (Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661]), Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661])), Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388]): (Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643]), Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643])), Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257]): (Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174]), Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174])), Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960]): (Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241]), Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241])), Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721]): (Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046]), Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046])), Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822]): (Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217]), Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217])), Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253]): (Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697]), Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697])), Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054]): (Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019]), Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019])), Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821]): (Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432]), Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432])), Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864]): (Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105]), Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105])), Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373]): (Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855]), Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855])), Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646]): (Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830]), Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830])), Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460]): (Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208]), Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208])), Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033]): (Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214]), Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214])), Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105]): (Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129]), Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129])), Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281]): (Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909]), Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909])), Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028]): (Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027]), Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027])), Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012]): (Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054]), Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054])), Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562]): (Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589]), Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589])), Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037]): (Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097]), Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097])), Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355]): (Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460]), Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460])), Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223]): (Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355]), Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355])), Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089]): (Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306]), Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306])), Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035]): (Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219]), Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219])), Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432]): (Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297]), Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297])), Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693]): (Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263]), Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263])), Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794]): (Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484]), Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484])), Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552]): (Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941]), Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941])), Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267]): (Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814]), Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814])), Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992]): (Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415]), Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415])), Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941]): (Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966]), Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966])), Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822]): (Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320]), Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320])), Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306]): (Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902]), Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902])), Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820]): (Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880]), Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880])), Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361]): (Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725]), Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725])), Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005]): (Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914]), Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914])), Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783]): (Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781]), Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781])), Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011]): (Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033]), Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033])), Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297]): (Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910]), Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910])), Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070]): (Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134]), Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134])), Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144]): (Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331]), Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331])), Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023]): (Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497]), Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497])), Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103]): (Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540]), Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540])), Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961]): (Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998]), Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998])), Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414]): (Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]), Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]))}, trace_len_summary: TraceLenSummary { main_trace_len: 11, range_trace_len: 39, chiplets_trace_len: ChipletsLengths { hash_chiplet_len: 96, bitwise_chiplet_len: 0, memory_chiplet_len: 0, kernel_rom_len: 0 } } } +ExecutionTrace { main_trace: MainTrace { storage: Parts { core_rm: [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 8296916230783913551, 16462332824047406715, 6884552431231699198, 12264801256605292690, 7532528701100807439, 10480547126759850066, 6097728641437901141, 17248496754222975198, 0, 0, 0, 0, 0, 0, 1, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 11656, 42, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 1, 1, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 2, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 91, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 3, 0, 0, 0, 0, 0, 3, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 4, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 0, 42, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 3, 1, 5, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 1, 1, 1, 8296916230783913551, 16462332824047406715, 6884552431231699198, 12264801256605292690, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 42, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 3, 1, 6, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 41, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 42, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 3, 1, 7, 0, 0, 0, 0, 0, 5, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 42, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 3, 1, 8, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 1, 1, 1, 7532528701100807439, 10480547126759850066, 6097728641437901141, 17248496754222975198, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 9, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 31, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 33, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 39, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 43, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 47, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 50, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 51, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 53, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 54, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 55, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 59, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 60, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 61, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 67, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 69, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 70, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 71, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 72, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 73, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 74, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 75, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 76, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 77, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 78, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 79, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 81, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 82, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 83, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 86, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 87, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 88, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 89, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 90, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 91, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 92, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 93, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 94, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 97, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 98, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 99, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 101, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 102, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 103, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 104, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 105, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 106, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 107, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 108, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 109, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 110, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 111, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 112, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 113, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 114, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 115, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 116, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 117, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 118, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 119, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 120, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 121, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 122, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 123, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 124, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 125, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 126, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 127, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0], chiplets_rm: [1, 1, 0, 0, 8296916230783913551, 16462332824047406715, 6884552431231699198, 12264801256605292690, 7532528701100807439, 10480547126759850066, 6097728641437901141, 17248496754222975198, 0, 87, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 8400310461204590462, 9108169057237353573, 17636133504178290964, 17406877359165992528, 1012686194999500095, 3119571665051516884, 6045109140346221273, 8023007352945590267, 0, 0, 1, 0, 0, 1, 1, 0, 0, 11656, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 8296916230783913551, 16462332824047406715, 6884552431231699198, 12264801256605292690, 18213254076385477335, 9294418641045383238, 8055320100535498720, 11030019888906999906, 1874843776400824061, 12942276814728926620, 15585255994602274508, 16203157087401046215, 0, 0, 1, 0, 0, 1, 1, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 7532528701100807439, 10480547126759850066, 6097728641437901141, 17248496754222975198, 12342802819241620905, 7554371666290801318, 8718773026382250605, 15984482998549000918, 15460443374009848343, 1087146607978023558, 7531163901062156801, 4426949494427873777, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 11621565010787354140, 1949391780818670486, 7327781180606137861, 2419787217529136215, 13249250205018233525, 10029758640146777270, 5716716695107147273, 10829954014693503473, 7405851154679558693, 2030135877513774489, 10401768244118899621, 7992444660002654486, 1, 0, 0, 0, 1, 0, 0, 0, 0, 9190577937819620371, 12978309842325015235, 10477013461463931935, 4855391316239312738, 10519745218266697287, 18375374895419140100, 876067972673449756, 17915370314859305010, 17877705855294641231, 120652674332571204, 3378556434908723888, 17649391022523856338, 1, 0, 0, 0, 1, 0, 0, 0, 0, 15052947986857015373, 3007680259418135415, 3197694984858038551, 6563270153864719814, 6889631464391242687, 12614331779225506253, 8884325160266334095, 15067359903282619456, 6045216153329131722, 7293213550537411486, 18377064823051127268, 14733223614830533518, 1, 0, 0, 0, 1, 0, 1248924765333967865, 15568788993061722932, 4037714036443683170, 2584579945446987950, 3496704858534018972, 10965787981110521559, 9000006360952503550, 8377181923806419223, 18078834148678517323, 13751832434934340803, 15306332964801742551, 828627458527105190, 2519953652271814816, 5563221586835004955, 16428502736240336605, 1, 0, 0, 0, 1, 0, 161503374172189975, 7180975586994120588, 13070121377098205312, 9655464535561865455, 4169214041423852321, 5771090309048429384, 6993654059550252564, 14478380452460405826, 12150434000885474539, 18399347099839405992, 88779829066683150, 4428174353386180423, 7547120791432137516, 11951584238447172023, 8804182506418522715, 1, 0, 0, 0, 1, 0, 1859011259345361207, 13205265558511858864, 16229683663108620000, 17688418164436772208, 12658415008146819428, 6291208835901171779, 3297271436089179933, 12943628284217684119, 11639259038601904106, 10502234848011596680, 13946225273525543944, 11318468498957948083, 13851055481982014034, 5765565570506082255, 10777382518726251007, 1, 0, 0, 0, 1, 0, 1023422172081481959, 14540338366569412926, 10271517463444484758, 8863158288377959817, 9066561794313536160, 10161961919995709177, 2094278659773331823, 4371761587112760854, 10972685992181286814, 5641963675353630718, 15569415989710829261, 4258403342016907208, 4740804749082440837, 1594229550076307598, 5045104152796606559, 1, 0, 0, 0, 1, 0, 12053626300860885956, 13987509258486900924, 17286360383804666298, 8301538772707939488, 7700154594411825373, 14332053735409157564, 6894934729579673545, 5430665485920789830, 10553406992561403551, 11528229548578861261, 3294597468571627674, 2903493961726666462, 10560076388764518443, 3749651622493296975, 18114127684252877364, 1, 0, 0, 0, 1, 0, 12240592655856206466, 6264740020775290721, 859763567572081467, 8842953438422484122, 14329981889510246939, 3582542183068105786, 6023391989510151456, 2953193964713672141, 12396149302348639250, 13882467375549577428, 3586988377712407519, 7213506509798642482, 13435456572406932891, 9645941250097564536, 2781650568775738364, 1, 0, 0, 0, 1, 0, 15637532899188291351, 12683652363890573925, 2704597975013858668, 17832955104866332736, 6815586591600943723, 13755349213265671492, 8924117914024270326, 3329964149511691453, 11039495891702065838, 15670789219464690273, 11281671746346947225, 10492374165392519994, 11439270560757451470, 7337394676363778206, 2272256910055258613, 1, 0, 0, 0, 1, 0, 3130343892077994054, 0, 0, 1136320813223337744, 11438337112810950654, 16692992611178972868, 9482499518540692367, 5451078715157933845, 18403012202839423090, 13340398881404871439, 16853681425214524760, 5540259513623809808, 7754241405876268140, 15538673406175044580, 15705643278636475771, 1, 0, 0, 0, 1, 0, 0, 0, 0, 6593967995490198369, 546795078589070868, 8093299549277945163, 1445098694824947603, 16968796337604054074, 7105604958885889972, 12829574433066656016, 10962264142076089650, 6970346774265824779, 5668604568559492205, 15930738860655806958, 14403244990983785091, 1, 0, 0, 0, 1, 0, 0, 0, 0, 7770193319703938593, 6228225228483877842, 5315425894230577486, 8012448033829391087, 5395398520381640698, 8770911350053719042, 14827874098479004474, 11024999006644848903, 13791657658989935762, 17830220104295996918, 2090812709146185278, 8577173283657139529, 1, 0, 0, 0, 1, 0, 0, 0, 0, 17471481800618265475, 1930822204634793148, 12769804899579893379, 13068810900387198296, 10732524945348487200, 1519317270498249877, 12604995971822921101, 14107509487727911757, 8257552923782319555, 12034059115493819529, 4343039820825149431, 395799121324568963, 1, 0, 0, 0, 1, 0, 0, 0, 0, 7532528701100807439, 10480547126759850066, 6097728641437901141, 17248496754222975198, 12342802819241620905, 7554371666290801318, 8718773026382250605, 15984482998549000918, 15460443374009848343, 1087146607978023558, 7531163901062156801, 4426949494427873777, 1, 0, 0, 0, 1, 0, 0, 0, 0, 11656, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 8259689913693129242, 3400892600405308205, 17378179173256779268, 5060920854688287001, 9687195410980644248, 6313248141024338188, 2582093590609427596, 3953695074988874383, 11971751964106597008, 9907486161844974200, 17989903003960359463, 13336380866068769777, 1, 0, 0, 0, 1, 0, 0, 0, 0, 12279731404675001026, 6278812133505380138, 6233201299601221057, 2388727383803081265, 12084036741190483661, 2317300697897833956, 9759443477696867671, 10883057071610381859, 3944615791382572320, 4072273145811045884, 17852897021998211163, 9684438072608016253, 1, 0, 0, 0, 1, 0, 0, 0, 0, 3651584995004100725, 6423803920838032987, 14027200390009907647, 6592032860050067711, 2594447921553931384, 18306574626058358562, 4512185877168969647, 11342492757671323084, 15957751677575885720, 5761823199659062393, 6846407586191335849, 9817376758188911585, 1, 0, 0, 0, 1, 0, 18183126545069935350, 12563248011457733820, 8356966014032630063, 12041609793392315665, 5281186701877768352, 5541580267076219602, 11576047020972388374, 6661568194349527666, 15437143780340457719, 10754987180927492954, 4211835751645452119, 10566966891469040816, 690793516206281144, 3247962926818069970, 9036036859539968974, 1, 0, 0, 0, 1, 0, 15893445344909186288, 5778049594265975833, 1423581989082731508, 5458007776595562807, 2498425571573111469, 16059466580364398666, 8902716392494711213, 14882573357788460188, 3225597659422237250, 3128065202613218656, 16995684508107895104, 12196793732604029414, 17723663615896720413, 9829416315291197871, 580745865383399340, 1, 0, 0, 0, 1, 0, 13902067347991440733, 5984630683069450754, 12729386174124645267, 13785662250538369696, 272255205933159866, 735616656951483055, 12424664074133983590, 5026981889191825136, 5767485772665833989, 15651669603605283176, 7414308024158917695, 15811954123421478742, 13258769136679205830, 3664463833800174816, 15497592431183820173, 1, 0, 0, 0, 1, 0, 11156605567826983932, 3639316624646464570, 5042698793479444923, 8630374421727305636, 17027951314675117661, 2801906069577385610, 18065291493111457552, 18067767546753643362, 5248148594352695009, 7578134041089558055, 18445498855455618598, 7189106720666328053, 6562930842885656592, 6844922721754111014, 780716667496251522, 1, 0, 0, 0, 1, 0, 11860885490747304346, 12272615266561732125, 10423884872730116228, 13929733142214397431, 2117615618497875527, 5203222542820499724, 4538429948347629507, 6877693664463852318, 18109062185597913481, 10147653053574341319, 10079670109614966266, 12064951107563936135, 1152998120279634164, 12844815835032732057, 12896711460106342356, 1, 0, 0, 0, 1, 0, 3078919787028426439, 15265543379215102231, 570695753264939069, 459110976220447167, 2176716793919417092, 14863591412045443847, 14252826520731507004, 15860274927896899753, 10390267100193539166, 17043032359848981742, 818991875743271755, 16275785202399117535, 8465017515346473513, 2777064625189300576, 13072175816967000886, 1, 0, 0, 0, 1, 0, 3442153457185747577, 2606206929260007126, 2317686975478948049, 15948992202505097484, 5942181083636438599, 15457210791918859006, 887605399554676434, 12986387963278623196, 10075175986843357851, 4859683927561004597, 6555547085880890919, 8280537903442447606, 16640962983997717683, 2248822201261309400, 13163090516020988950, 1, 0, 0, 0, 1, 0, 7196986181046756683, 0, 0, 16549653703171386973, 11518702294444124172, 1109770523953150302, 11415315369035533823, 5890935665450471727, 2253657843173273901, 13858462521885404044, 9125187176834287629, 14925311787915179675, 9356310136195018005, 14965392043314054082, 18423301843359275387, 1, 0, 0, 0, 1, 0, 0, 0, 0, 7040940919216905671, 6187741949018394442, 10532732827118411505, 13505135286384426969, 917467356231706545, 9047752258933341547, 2335143583534705649, 18052717581435745313, 9355624911805935499, 7190586108559742607, 2304843099991312546, 16303126242918615541, 1, 0, 0, 0, 1, 0, 0, 0, 0, 15603840856162477962, 3504063088563989096, 6361775464868278813, 17698044987168049155, 8418309402148081318, 15988177746184666422, 4270534912200806378, 12370149697383197906, 8363034440938926080, 17941258791536373709, 11011611614519090457, 10702921331067290122, 1, 0, 0, 0, 1, 0, 0, 0, 0, 8416267285503610972, 15089551497492948945, 5363802036407642792, 10347532956075658842, 17181858623993805271, 15855824450153307212, 7743632312226714799, 1845073853648620670, 2000026205350826313, 18037231946791138113, 14309912549728703012, 13253445327127715869, 1, 0, 0, 0, 1, 0, 0, 0, 0, 8296916230783913551, 16462332824047406715, 6884552431231699198, 12264801256605292690, 18213254076385477335, 9294418641045383238, 8055320100535498720, 11030019888906999906, 1874843776400824061, 12942276814728926620, 15585255994602274508, 16203157087401046215, 1, 0, 0, 0, 1, 0, 0, 0, 0, 8296916230783913551, 16462332824047406715, 6884552431231699198, 12264801256605292690, 7532528701100807439, 10480547126759850066, 6097728641437901141, 17248496754222975198, 0, 87, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 10686862901019340628, 15711583786595019806, 9378042936835126164, 11939142602264935891, 13605517752371930016, 2544863311362262665, 6880055194706872138, 2404926559643725443, 11298729247352625131, 13639273524510051487, 3031605320954281704, 2952677760580202523, 1, 0, 0, 0, 1, 0, 0, 0, 0, 6949406075980976859, 9142069989509656801, 14676622013796942288, 5295633173573979080, 14862684288436559050, 7708888152496129562, 8667911075542880817, 14424367369474907891, 14303094264982903091, 9838552210955819611, 15088013178433258027, 5833102420062152227, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1932675776657481842, 14290498569500988181, 11741991701671402436, 3934903733189518965, 10047440752038846171, 14938209139342513571, 7659889883493126262, 2134579895120260539, 7819147353957995986, 17861588317805920712, 11020859927535923500, 15623868602690334525, 1, 0, 0, 0, 1, 0, 6264451320029412065, 5315770291001895612, 3923979823614336294, 15496957568148800678, 4856878698798286165, 18427152961697133322, 13172977369565732662, 8634756726478972696, 17549357918509499997, 7356106617646839123, 16192566970100663376, 4904526601366015673, 11478334329288517717, 607398074844683832, 9609971183005491570, 1, 0, 0, 0, 1, 0, 18264070764381924889, 7558994944201947568, 16698567473332535936, 4066201321205995431, 14552036519561423602, 5620710451624899086, 14969463994437329823, 11938508228196027882, 9200118839118887577, 6855444937813269923, 13901427726318773655, 3507966654472722962, 13139165600809348467, 3547085602937656739, 11244050388029555026, 1, 0, 0, 0, 1, 0, 8312328144036608043, 17972686765781519170, 10784039031850599726, 14134435301654782468, 13131877571979284929, 8266221982529104091, 159405248778538274, 5778967389144576888, 6057984302796584762, 11714059928473413141, 11763232719990709154, 7978933720497313146, 16635094485101159936, 18327609188632861057, 11071183167122824035, 1, 0, 0, 0, 1, 0, 10287810620841180003, 4548089904338037398, 6876519236022884332, 192351967064940869, 13616941784242570400, 7032108910940453446, 13625250436816808378, 17491100122417306359, 2292049730346364666, 2733535393252649149, 17750397792987890641, 6346476747248545150, 3575465615474366120, 18213303372206038112, 2518621101786158931, 1, 0, 0, 0, 1, 0, 842637389045220237, 14003171518185218367, 14997648696661468292, 13477259760240789253, 7438659305055821970, 7828458451594639328, 1805142843426507273, 3804729079035423760, 5684604326361654696, 17218885460122549497, 974371611540683935, 16762750120460661174, 739710162320190732, 3363948547922989023, 4267260670759647913, 1, 0, 0, 0, 1, 0, 10264158766070300923, 6050974414693797250, 847386589526447339, 3548106904874618124, 9289172558104066787, 8226909131216769737, 16380713199877477068, 4410762367217395758, 12555768451623030884, 10357980275595284555, 10303991993655092221, 4060030248038493229, 11216725884924445657, 10194932652661424405, 17494422570060569743, 1, 0, 0, 0, 1, 0, 522514578171525652, 3717501858890221638, 16025700499781393088, 15033579247524264929, 1744414008664189122, 6807378681147180078, 16955668219975052585, 18323017022834713256, 6662618285165080179, 12762215046608848013, 17134633855452090590, 6353725621416552612, 4449259194945598867, 8877290555352616803, 13666098560811114332, 1, 0, 0, 0, 1, 0, 3232143389630708424, 0, 0, 9014593992030055460, 10869121640834977224, 1905700011211118876, 955944440419378960, 265206078841667899, 13713964984862746492, 9702435518807270681, 12343078651970579400, 18227529633908655074, 9709048888339027683, 15154974039676851951, 16388400023664675593, 1, 0, 0, 0, 1, 0, 0, 0, 0, 12342730708987043912, 13274159397630057441, 12697978258400128397, 368152630932848211, 6555819701154221199, 97417680512067538, 2018507387878521400, 1529782995014995301, 13636792419679998309, 6197980968820055410, 737644335551408580, 9956102600220791675, 1, 0, 0, 0, 1, 0, 0, 0, 0, 14179025343931559433, 1175312715506728066, 11255361077722267605, 9822732455439796133, 13335036252549184126, 17127037879360292568, 16600677125340288437, 11659800847392950623, 12605660248276552114, 14805446144065764307, 14804045017754446897, 13192632014186378484, 1, 0, 0, 0, 1, 0, 0, 0, 0, 12383461936126681247, 745215043874424896, 4540981537676651137, 16486351305638014506, 10972364256824969372, 5647748125744546841, 5620391031839475969, 17973620544670757805, 1344519641939806437, 11395404185290209616, 4498705163534372313, 3336623779264323323, 1, 0, 0, 0, 1, 0, 0, 0, 0, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 8400310461204590462, 9108169057237353573, 17636133504178290964, 17406877359165992528, 1012686194999500095, 3119571665051516884, 6045109140346221273, 8023007352945590267, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], range_checker_cols: [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2187, 4374, 6561, 8748, 10935, 13122, 15309, 17496, 19683, 21870, 24057, 26244, 28431, 30618, 32805, 34992, 37179, 39366, 41553, 43740, 45927, 48114, 50301, 52488, 54675, 56862, 59049, 61236, 63423, 64152, 64881, 65124, 65367, 65448, 65529, 65532, 65535, 65535]], num_rows: 128 }, last_program_row: RowIndex(10) }, program_info: ProgramInfo { program_hash: Word([11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518]), kernel: Kernel([]) }, stack_outputs: StackOutputs { elements: [2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, precompile_requests: [], final_precompile_transcript: PrecompileTranscript { state: Word([0, 0, 0, 0]) }, trace_len_summary: TraceLenSummary { main_trace_len: 11, range_trace_len: 39, chiplets_trace_len: ChipletsLengths { hash_chiplet_len: 64, bitwise_chiplet_len: 0, memory_chiplet_len: 0, ace_chiplet_len: 0, kernel_rom_len: 0 } } } diff --git a/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_17.snap b/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_17.snap index a5f0d94b28..db50a4f102 100644 --- a/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_17.snap +++ b/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_17.snap @@ -2,4 +2,4 @@ source: processor/src/trace/parallel/tests.rs expression: DeterministicTrace(&trace_from_fragments) --- -ExecutionTrace { main_trace: MainTrace { columns: ColMatrix { columns: [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 33, 33, 33, 33, 1, 65, 65, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [11182969138190702361, 11656, 91, 0, 0, 11182969138190702361, 41, 0, 11006573531383828351, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010], [1109628455053940361, 42, 1, 1, 1, 1109628455053940361, 0, 1, 10983413158656624898, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331], [13928676565061410159, 0, 0, 0, 0, 13928676565061410159, 0, 0, 4869282124135316831, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319], [297470094449022674, 0, 0, 0, 0, 297470094449022674, 0, 0, 5899798166361732461, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694], [11006573531383828351, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [10983413158656624898, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [4869282124135316831, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [5899798166361732461, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 2, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 2, 42, 42, 42, 42, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2], [2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [3, 3, 3, 3, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3], [0, 0, 0, 0, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [16, 16, 16, 16, 17, 17, 17, 17, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16], [0, 0, 0, 0, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2187, 4374, 6561, 8748, 10935, 13122, 15309, 17496, 19683, 21870, 24057, 26244, 28431, 30618, 32805, 34992, 37179, 39366, 41553, 43740, 45927, 48114, 50301, 52488, 54675, 56862, 59049, 61236, 63423, 64152, 64881, 65124, 65367, 65448, 65529, 65532, 65535, 65535], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [11182969138190702361, 16344194729581826754, 15045917672181612303, 3672327111134984977, 11902001817992340801, 97480563262877602, 1831626543952762702, 12062163654685913941, 1451330498122947575, 1742063333427513989, 2331114102915733339, 8550984974115591347, 8960841496031156142, 13720918668577423004, 5779906183691085674, 3198599991840782485, 13728843979899181292, 7239115491427587826, 12128894594351473931, 15480692841914867508, 8817470180767843173, 10548371713427919789, 10315264763691724912, 1023167627240586914, 3818953450339058320, 14941570263133670432, 12615841091071546269, 15435370781163068976, 15373572920503822367, 11769995123877236600, 3762647969008011219, 8269653645296248010, 11656, 117148, 6714198787893475936, 5262284953624879131, 6828048997998717653, 14647846255598321281, 12213957512096072087, 15486993862206988880, 9916068016290756984, 12311676223031039230, 6798558233575208094, 6061515485015027193, 9178825932447902299, 16451694760407086053, 9245574117575493602, 6706571375738621744, 5707941763645196550, 13553995817865937844, 18312867062271325792, 11246612591729350508, 8806896510487478352, 16014621579841168337, 6332183310159529150, 2444726075814550534, 13415483499482541228, 16602291456530418215, 3069389264726801426, 4940323642218861897, 3979217445866956620, 6693606464693965975, 9525288177353527302, 11182969138190702361, 41, 410, 8488924048752676071, 5473488137200086909, 16124688533662466636, 4527044298581192722, 16887055178922689595, 5249711198271717177, 15470787238396171217, 5632634005697013617, 7337408598993184022, 11147561538212402733, 9710911023591971572, 8752830793140649116, 11546140485006286209, 10738951369466640003, 2139663271495255306, 6135983205453599776, 17538856881976830392, 2031516987289365197, 17199894398730562705, 4010699482290892787, 3922552954514582360, 7369439734883755459, 108303794773646012, 14521269346803535153, 14515762120928230173, 13893962684375637966, 13610167819530098127, 11215445033353754262, 8081237365032914784, 11006573531383828351, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1109628455053940361, 12119768350776285319, 8184561966951183876, 12431805880114311043, 2986356007899077631, 2836244341662188919, 146796491816379180, 8696360259937422388, 13878284404078727054, 7667548888861073206, 9741377056638459459, 11905155073870025459, 9736056580211703764, 17352787150580200349, 5883496260565631343, 9594088066979877926, 9297041447863221537, 6214639496702145664, 2461170076272033096, 17112913798212225634, 1035954869286151888, 2140568550425483844, 10584986198873793665, 12555736327846716176, 12072441430913369009, 13906015856663078107, 14389918991418187594, 2676571742010508284, 5150637797762075635, 11237118474907085960, 11752652705714102353, 997682303299740331, 42, 93752, 18084035356118526352, 8386870944408484201, 18056918720989013854, 11520229540186073721, 5668756658695595711, 14109792997657353922, 12303762929371991135, 14460911410586037148, 12418445481638740107, 16455507557982986163, 18172284878038222122, 6352198309363971688, 9198509167958908347, 1068046269761257463, 16102483860755268671, 1544674922431042375, 9868836391822552540, 7915117918356788325, 6533551228799195237, 3992189811639127908, 9511948951280762358, 13039263708530965818, 708611914251242147, 4206064101444952505, 17714998603219848343, 13074430791784659712, 14102459334756352921, 13661835471193379756, 3038016940647586670, 1109628455053940361, 0, 328, 7132218559010351790, 2687466917280430353, 14170238607512888511, 5453168895411602323, 8679138582261878552, 10871515559850126217, 7649138216344653830, 12086029516113687059, 14609582285822867389, 7271583017513514692, 3821121937809044409, 3833100151978191712, 5702916883024911354, 3579138882391492892, 14347405124134927123, 9277341930384005575, 2993137622300793545, 13370802209879109056, 13653108884642243926, 8702782587703766612, 12945832125614510830, 15167316901472929028, 4608694219239856197, 4443739924303229750, 8611475648437961511, 1575864515244779062, 10900065459953722709, 9162692523043045302, 17462008412377898139, 10983413158656624898, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [13928676565061410159, 5375705730949115787, 1314981229280595867, 1393532256400242982, 13433705342207763738, 12880831435259048250, 10699055768478348083, 2470044642731141974, 13732313223959877570, 2078090264025450769, 3845297826200108779, 15581584642080412492, 11359623335937034504, 14549946302435322871, 17424758021352066268, 15472130290487345321, 13048555428151627244, 13747770174448213841, 9164669383091055648, 3250455247796114093, 10799815877710934765, 9086202890994770785, 12116339825079888992, 1619117325320043308, 16898959203497269575, 15756045849228969140, 6190024525131486611, 6215657966742979785, 17671950935398765622, 15303512720733905693, 10727837149375754730, 12907160815575155319, 0, 23564, 4199576522683349447, 16513391592299529611, 11415640949254272304, 16138036929710694921, 9992494271122179933, 3020772293084222765, 15625472986208536177, 12149624601412828429, 10735117276139490774, 13332197512776217968, 13474689739491604605, 13815225937039366706, 706573335075180235, 4097091053989040149, 693823183101411164, 5341110475237803180, 4368449439175744649, 7740607367180462177, 13389502447794973829, 6721164191334334250, 6997451158266748059, 9767862146044075473, 4778055569341029558, 10088175016132507812, 3285997397792070136, 10914182999248450193, 14473951691792990803, 8827937223658185560, 9698676695870635420, 13928676565061410159, 0, 82, 18152833202936203138, 10305147718805144715, 13246631902503555591, 18142351346900318359, 11971140429919100117, 6903484634638418138, 3098698980745497723, 3068992673894668202, 9164459936648953977, 11194864417357882388, 12005359455571366116, 12356306486226268709, 10059737158050223658, 17119982236602677307, 4225663824996553892, 17852936504841763737, 5778553506856942969, 9045001363359345866, 18423338781077887809, 2711240319770097821, 8346149567490270428, 9594540064387516595, 1859863665658604717, 16919987197409252682, 7809934763889573038, 12492597695329698922, 18341122838405415754, 11967784234256998242, 10761804868734649587, 4869282124135316831, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [297470094449022674, 13535968261560526699, 10051713503687926694, 5258910437097366761, 14031537229609682064, 18190284629542346231, 4346004165604875907, 15375947702712472554, 4019409425675168575, 2064296209102051574, 17718639079388526425, 16642022229570326204, 1618478323171655450, 5998884876319667302, 6872649224968331273, 13753905356607269997, 7559241041198219519, 8363779881416372286, 2105649450986611656, 11644599807961994770, 12949568200151355456, 4366812189797744262, 9669235379242805159, 18184433440084438609, 13914998044815764482, 11325806379320193213, 1586181560816232196, 5920020313630770955, 8020025137186066841, 13419225700498867773, 13671651770198504476, 18024383338294781694, 0, 23396, 7560057297276955988, 7451013195867945919, 7468487593070852196, 5578183109591783882, 15747662796636990589, 2066701485189878406, 17025371161980089605, 4391959764977446152, 4985867595251695917, 6710066216774366729, 6241000701339836952, 4718440141936325382, 4986060230214018536, 5748634601882563491, 10896228304766504283, 6457499153671182820, 12270042173384394159, 11711065129605555908, 15065279868519608165, 17856220227797901726, 8953039722587792244, 16994104539161729445, 14670768895096516686, 14803898243742553487, 2327203233976270205, 17449705512918939747, 8253253226048886083, 11671578295265948239, 14297456315487806992, 297470094449022674, 0, 82, 302695496926486902, 16415403596737407938, 12969246825596557956, 15965643470182086386, 14881573336337548597, 2868629484750761697, 7317402970608805914, 2570537868338555591, 6697005353407257884, 5717939852331496040, 9408357527608003903, 8011884131194179594, 15942512744234440774, 9052662470595673790, 11913271961595885333, 15508051727969296111, 6269710669185644103, 12322255659000247132, 810875278274469351, 3499523055983644139, 9453749819048496107, 598273005722510655, 12338854942180141395, 2829445891916136836, 12653867244112536729, 4648827005364006908, 3153753366153954420, 12197142511433562971, 13557680898519201450, 5899798166361732461, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [11006573531383828351, 92579048505362891, 10772660272533654046, 3331697170176629084, 602109730184155310, 16230148280330706633, 6302091831624975391, 14001078336639287767, 14888577262766439787, 12258632680483319887, 7641862043593808385, 4740702640077452126, 8494032654039797119, 8314420015254970480, 18294822284401514132, 15552480182219334239, 908821363395967579, 18258193129875665644, 4226365574585037317, 3638253471537757569, 17581484848263912285, 6286301305761091621, 4777175749672661669, 10658559677463134471, 1417442037893012894, 7857622794514614671, 1052908464763109826, 4925127753504389599, 4274762298296320367, 7383511416371792464, 17305170235876004791, 2200823396264285425, 0, 58574, 18280076181055982575, 3965010120048981150, 1623299660155787797, 11930292174601709627, 17275008438838615802, 5756406115988630048, 17841510847136093686, 6729021181420822547, 1709787776185889305, 2022739540363098314, 5157634830695555269, 17099057016182449505, 4092740078069974091, 9582547144648304801, 4715310719341519129, 1597700055042697404, 480964694484615271, 56280064407246395, 10536769335197150641, 16099710145374622840, 3473101726323291593, 3295906456874767760, 716460020344690975, 10580825486552151036, 4976836170739997781, 16652319776094256449, 12319687016213027555, 13490282225851742651, 3371801902832234206, 3795543859124105201, 0, 205, 13622702382434675698, 8941567408770445183, 2168342371250989865, 17553704974699598306, 12818882650622055705, 16478401302589696546, 10652219805906948351, 13167156861512034068, 260666911081589986, 1428764500637505382, 2190433219200603887, 11999917547751101526, 2751093334206085539, 9318931023569054874, 16297727142514657495, 11875658036026604145, 5829323963705819601, 407792022339954638, 5684565403642367050, 13995368600016681288, 2845800306757116207, 5216498913603536417, 2411940295743487842, 2014066638340124975, 5258230180909223265, 17089893338044941808, 1124366766375746940, 9116801986360376826, 6650575029061305823, 4025036448660092914, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [10983413158656624898, 11859595567907759997, 10088766553729725414, 12574093635772317570, 5470069473511751658, 9645793732101008923, 1476556243604239385, 17933040757673393353, 7118521641278947238, 7588084371428510216, 12191494749556797391, 8228232126921631746, 15226641263820888277, 4239012011479875368, 14018593041447406970, 3541695062587160892, 11116896887234129281, 3929539690735302143, 11203930352796078636, 8751959587369085991, 12655249523595546680, 16379258612200834026, 9984807922535170831, 9638171237357393134, 12191893464144837018, 4677785078090407332, 8064604530099592479, 10076433135196495423, 544627542347870852, 11879905738846635842, 5683487714952213815, 8088984326603898052, 0, 46876, 15125170292333450443, 7072657932567702059, 10475291980250876467, 14632109792663117375, 18379882203306053694, 10250239327737538260, 11537033439839832588, 15180883293806522386, 18285674122603938406, 16116176887352657770, 15068074760365493774, 10507624248254584461, 7669544778380245671, 16424767991328560142, 16771797144770177609, 4105927596877687309, 7519344916607985067, 16277772212475505196, 1322695487397776109, 8302446182097155523, 14744324883381489574, 16338446684875281086, 5703860549203085948, 14077533030564871132, 12287193162084105824, 2535384450001991464, 13089916287630526229, 1568845385281768860, 982340402770608276, 12910581729787565904, 0, 164, 6093021124582015914, 375332441348258328, 16597900739273350797, 16788616498952461620, 10323894478242846558, 3730474644926313294, 17377183878976452334, 12746711269593150718, 13699107349734059694, 421533440407219618, 15109303318896079214, 17746438429032263850, 13224617406323308041, 5646455969610140563, 12626985742338481481, 14497665384991648640, 13894375308737560134, 3268393834564630675, 13312171511942754529, 611321250913478210, 12048873764879264902, 5334026694118161468, 14360341460112568406, 17654490467796517057, 1299716947845207044, 7609683397541157642, 14709808073905360012, 11742139955633481423, 13522070698443062110, 12847434483856017691, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [4869282124135316831, 10293244464294212936, 8691876854061179148, 2952350747126730564, 7968203687716298290, 6747517476428823928, 16731591574836256879, 12286682322909052293, 5699380547329532508, 8774011841981167612, 10988677337017809219, 6257583805205658612, 8595550098696265772, 17321901905145630028, 3295089823193122164, 6581488060195755410, 6329516418872359771, 7640632346113799527, 10454000694343684461, 15867346750604392587, 5805413556949044653, 9247297947852762648, 13748015074908171216, 13312272456227001370, 5054807356361880835, 1012271632864570722, 11252467974344770686, 492886975717156403, 2629112354487966090, 10128035487146424848, 18233951381382816412, 1751709948898726303, 0, 11782, 6055246182589913733, 15015595405278911690, 2209046468675768902, 16429197663637467330, 15810134098389081544, 9588791733994120847, 18370261572729563296, 7006788971063612777, 7962515674056117045, 15223121510830934757, 15872454912771340895, 1486059252283823706, 3912605942422700262, 4173681472723400357, 2922691200579275072, 7112424425452913463, 17213377378328786151, 6274713241106982122, 15112974401160243995, 17175975930045398893, 5467280291812001242, 5238070817263862176, 17584445990298638069, 171514605620090783, 4267926381848052110, 9011064139813451706, 17044511642202081265, 17370313250110904770, 13397257034080852565, 17596568325206204932, 0, 41, 9617260353707541367, 9187825164453421957, 17649953659489375797, 6396310504287885774, 17019569090864760371, 870218876784769460, 17213560015461715510, 16812494438448165271, 15885717661613279263, 2958950328581697287, 14311601477626423214, 12599125587081655507, 12078599565132475515, 3332808335850364509, 374688056722968094, 5591521890390007231, 9584980789501913045, 4066644474875437132, 17728945623551220217, 1158050506628066296, 3730734784735709807, 10671987699715228843, 3173999018565335463, 14949604462817069254, 11653871972148380806, 312408327658285690, 8531928004921347162, 98858158429688394, 6167334615107562354, 1234843923022284190, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [5899798166361732461, 2163003956713638315, 5989289390391757114, 15670015339098587014, 12708827926449341197, 10159927950043513901, 15395056832871965886, 17405960500607097380, 9229756563573051371, 1186079292937331145, 13463816706671585562, 10107168241231917326, 8534001612601599401, 12790948878158723266, 12619661555644649350, 11614101867080583800, 11255619179741810030, 10501448523390229441, 16971746085380600175, 7173352752193758542, 9960833320626690499, 3507659370538431093, 6846598866105961944, 2557094292829749679, 11416743759689580593, 12182449258645699464, 11951277814213817673, 10567677969346318078, 13884819925875295975, 1926379571595510347, 5918588896905128530, 3405979658670756574, 0, 11698, 8146055133796963630, 4724864404296433607, 10453305271538430204, 17141108237620938331, 16113292978122689735, 14630852758047225712, 16936235645680974811, 640959767495035790, 11162248672474783185, 10618808740372936561, 12973220127719589473, 13223353016814262874, 17652411276563186968, 10141330567980253051, 1770876161367154023, 12442058685904907795, 12986633647641209886, 5384244903407669612, 14778499304685795812, 8054814913234770610, 8358166993767322841, 11933451322373121057, 17795028935448509068, 11142588879850986282, 873880226830208445, 11017896854604878841, 6896812394605202475, 2024842447089060639, 16625734836325714912, 12512094004962322130, 0, 41, 12529483521877137515, 4671467226762388980, 13873740979092621907, 12847173262736205772, 2640423636460273022, 8374058502362870155, 7630996533587302384, 3556075572123538464, 8078558398785937163, 5856098383496092000, 7999607615804135893, 15509992149354799776, 13785560116650003734, 8358196300413379173, 10412508239405514928, 7840142081125036731, 18075062342410207477, 18173191150607640442, 2133036585496843963, 8931901040624025193, 9454731621283026961, 5837806564591410604, 5850596656185029719, 296117354535505751, 8985195681813998404, 1975947551471322175, 12041110943945791333, 11648250496545232642, 7830634726555216225, 5266777994490151623, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 11627839282500592134, 3407397722647202213, 13644814392425193274, 9689174787852538317, 15759480978611340324, 10073546228149283602, 8090878949578096073, 1502926046713635634, 7624167193861818791, 10274257988202953339, 4186763142475177793, 6025425965090069083, 8194342163688078130, 13163397875087894329, 5161390927343581791, 10103251159424454395, 575959985319833606, 13175926157437524595, 8928028362497258488, 8665485641724560922, 15570929820685955587, 6150675652390666890, 6384512333148749163, 35921027791486524, 3229184449291625000, 7414754653220847914, 11347301099028602515, 8368586536930615942, 10138228048917253579, 344980745193352015, 5644431973654019812, 0, 58574, 12761879591277148733, 3794756304714494565, 10919382803049057886, 13927811434585922718, 8315847055470475708, 10095847089706649983, 41153506376499461, 5529807447506440005, 72892344713547594, 18362204307013225363, 527610602670466995, 14772158556567070690, 9538491437159792328, 1580498045195806896, 8297535568256810268, 13797917351588149895, 1651894826575892086, 13380716913143325871, 2655893075036451977, 3750342908258071259, 18231595474498119868, 18163310674975357977, 2371603174180061555, 6433509503768865899, 5002589281792664271, 10946433388588585987, 9256382872640968643, 6570002101874463971, 3849537215181896567, 5735281858523620986, 0, 205, 7876112718273244024, 1276143811675585923, 9993912342918529935, 16999254614849428545, 8194747920293058753, 11171758628037424552, 8208119826419095432, 5568149314099479773, 17551537772960996556, 12651683228606533001, 13584145944854843210, 12212300608708011466, 18102951610480561318, 14720258372954226591, 15448472262117068008, 10575290756167155008, 11997391634424499349, 9879556170680135793, 12373753045781314057, 9529470285212177396, 10620662102176580756, 10199402949196411787, 9825825353570660203, 18337390924518345383, 15945306792731206141, 10537181099344133724, 5505106000120813030, 14774803975376978777, 14575654492591748955, 8207377881872409730, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [87, 1844206616423154361, 7941852203687681180, 2987825311454433607, 185071303888742221, 16140725249773135932, 13486449309893009073, 13471170357015645210, 11073859438158044651, 16507211018434913458, 4066228076398875428, 16536071023746429034, 10818247459046542341, 4392853051950044706, 12116759677655250999, 17293580330275603290, 2376540144284705519, 8057038266027202789, 15097730100005395027, 3583575859544955648, 11146351406925299070, 13473187462927502829, 8056538798141691018, 13509558775822115028, 6797301950091310335, 8773981691004278165, 4751058192101309365, 10661116978196100999, 15345629614104209519, 1689963602473071179, 12869561156624962469, 12554030503530361323, 0, 46876, 4789346784708035796, 9438751512570250357, 447952077691938652, 6351356675900770483, 4868676530510485341, 3192437812250556397, 11511034416225137032, 15380266628173325649, 10700144984876703355, 12230522212327928379, 15526804358639727019, 6410705682507666807, 15728916292645010880, 13992590038292222154, 1916422775943772979, 8280685582260709248, 12515254706968408232, 4845996266408136556, 15172713941042952680, 2233761585242005099, 13227100893355110663, 3914062371738178895, 7843298541359739176, 8386193964610423744, 8614894336467293783, 8834991867772635266, 14221135810103683560, 11406071542091908609, 571586377235018247, 3013510715159483905, 0, 164, 14482187202392982684, 17682350329754313417, 66214439016909251, 7504629639084879386, 11708178258767948919, 188011405648496761, 10242982970375452289, 16510140404231294235, 13381084464566932690, 9239012175869487665, 9339694231140180875, 9917181315244873380, 17448534469581521177, 4965043893766771965, 13305445405772227224, 6963375374275021656, 4554518835153561582, 1694446457415578298, 4604616361036784646, 11439774970058559661, 10784225701912607868, 17782855612978839775, 13368223431578003475, 18100595786373494652, 12753204151452870283, 17504098334052422651, 12896535568794110034, 7402084190222773115, 598469278842686486, 5912604878679295331, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 11371898088219304696, 4199208231896291776, 6349271639347163621, 5568595648257864309, 10224931331962954075, 8046167029187450402, 6585148777263545478, 3706462809677116963, 12578093594063946501, 11334181120248394313, 4953509182438845792, 4130560513564095433, 6665409895959715593, 12872180446847298231, 11452171012153290342, 5729159829892489539, 5675564903335979949, 14158677720471443076, 12300968791182495713, 13879671978791253311, 14820104759072107152, 17585955671327967478, 6737505022417937354, 17454985371239394211, 15749874646256262769, 10017226585432634212, 8893160827421013787, 11893931769684808775, 16471875099240353401, 9975926385796085953, 11231727832144176264, 0, 11782, 6351111885067026894, 14086295994708840477, 3142920623105062021, 4317195510637014184, 16341148873550430347, 8014762585425506108, 12977978004680762325, 15318810920503136316, 9472517513827583818, 211962335804367550, 14931353145911604525, 9340212215573419915, 5244269534978718672, 1584128384101705476, 4460891295949496863, 14654598206063183317, 13555452196222133132, 17680908597379218579, 13178742765486355260, 3964993209073179108, 4213917162333386044, 2639949635019592417, 3300803743280888923, 12914222891103397086, 13436383826829479040, 7004576641630317963, 12080155723705641895, 6767987840126452263, 14392317091133450653, 7390177608867021213, 0, 41, 3800418813655617572, 14503408479575576010, 10553169970007645345, 4946745422622378051, 7127828976000219721, 2687285609278369395, 16630221959750548176, 1114885198959805561, 3895092647933222339, 9831397389014117600, 12816842684293233323, 1779119880742935864, 17663607747965229138, 5382558247959552902, 11972955750871888364, 16616426694032134438, 9711126273890628516, 376576173107709408, 12451218545182255865, 14301764572821220192, 13209253693600827240, 5745169166190656073, 12916752429524642864, 14463770325561420619, 7870235520772452232, 13278341252249613603, 5432056100901092307, 8994645443800925562, 5908996313982662075, 1494658977663487041, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 17530820119034444668, 15233230393479930649, 15702789941308523576, 8819781861782654629, 7112644758334533508, 2549387492966523460, 15838339720324898846, 10242380937000070843, 1124701407395854549, 5706112669062280829, 17015988684670402201, 12671109438456697877, 15652595419009785355, 10753966634497852319, 3622124053041186910, 2063695485301676711, 17845322355197915738, 9894091605930112348, 10822348040176532279, 9689802115657313068, 6759722828145755337, 9479044480226984785, 7845909286502989649, 560081323074218824, 16017591174163981005, 1196237303718990885, 6783304352365897531, 5064625229425039166, 12661189034561966549, 11511655067934063768, 11479359825177848513, 0, 11698, 2084118884093035279, 16979859941949546961, 1454299506056429821, 9658643065222637557, 11605485146349749283, 13057696629474024230, 16650374201325163722, 7457309320444728046, 1243843599995756274, 17176177262691414244, 14152683925184093692, 198845790532099135, 442435874165139119, 1462611314767788334, 3462067515008653152, 4141759445261917472, 12323330957750482072, 14922731139272985797, 10387565380055278256, 9531386257124273696, 9539285450074189441, 3691450672437772660, 12463184698711878632, 4858502687517999226, 12256855995572753726, 9245347314341240247, 7569214225554358494, 1017686422583121037, 10327407591150878848, 15025446886891081073, 0, 41, 13092032916490151270, 2856458557507854671, 14059661153766146178, 1724041303048776424, 7119687853704366589, 3699246950542313036, 8338994289155538949, 7732171807197958061, 10653644351656999339, 15262849800927670044, 6132373490633371091, 16473831322001214578, 12928938600331453669, 6959935525856744214, 17173069020016176920, 6747622983845354522, 2484033613426731933, 9879916419081378373, 4275250202523893223, 5995505684018086986, 16115855409799741127, 2490003355474156145, 10034475279304353355, 7223217715426381376, 10334063888823214988, 2139000562522371457, 18314119367638727156, 15311716904301189063, 894706229073498557, 1570146104298050273, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] }, last_program_row: RowIndex(10) }, program_info: ProgramInfo { program_hash: Word([8269653645296248010, 997682303299740331, 12907160815575155319, 18024383338294781694]), kernel: Kernel([]) }, stack_outputs: StackOutputs { elements: [2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, merkle_store_nodes: {Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571]): (Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350]), Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350])), Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484]): (Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693]), Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693])), Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781]): (Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874]), Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874])), Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171]): (Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361]), Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361])), Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815]): (Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305]), Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305])), Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689]): (Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195]), Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195])), Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362]): (Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063]), Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063])), Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848]): (Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661]), Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661])), Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352]): (Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829]), Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829])), Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444]): (Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223]), Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223])), Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386]): (Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388]), Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388])), Word([13190842942618341421, 17548956981569849952, 15418963848144418856, 730733050713174879]): (Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144]), Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144])), Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874]): (Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675]), Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675])), Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594]): (Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115]), Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115])), Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809]): (Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257]), Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257])), Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777]): (Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555]), Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555])), Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509]): (Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882]), Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882])), Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725]): (Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979]), Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979])), Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134]): (Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987]), Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987])), Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828]): (Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910]), Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910])), Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830]): (Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054]), Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054])), Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228]): (Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742]), Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742])), Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443]): (Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928]), Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928])), Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643]): (Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979]), Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979])), Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758]): (Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106]), Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106])), Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580]): (Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594]), Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594])), Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765]): (Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045]), Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045])), Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766]): (Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281]), Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281])), Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385]): (Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828]), Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828])), Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579]): (Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171]), Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171])), Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212]): (Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992]), Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992])), Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463]): (Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004]), Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004])), Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502]): (Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023]), Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023])), Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539]): (Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537]), Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537])), Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865]): (Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225]), Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225])), Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690]): (Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947]), Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947])), Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202]): (Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552]), Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552])), Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079]): (Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444]), Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444])), Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850]): (Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548]), Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548])), Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448]): (Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987]), Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987])), Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041]): (Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035]), Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035])), Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301]): (Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414]), Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414])), Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414]): (Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212]), Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212])), Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703]): (Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439]), Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439])), Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271]): (Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955]), Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955])), Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882]): (Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802]), Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802])), Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152]): (Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887]), Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887])), Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028]): (Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948]), Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948])), Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331]): (Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093]), Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093])), Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394]): (Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134]), Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134])), Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546]): (Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228]), Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228])), Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620]): (Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414]), Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414])), Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800]): (Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703]), Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703])), Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671]): (Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205]), Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205])), Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537]): (Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011]), Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011])), Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516]): (Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301]), Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301])), Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831]): (Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986]), Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986])), Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415]): (Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057]), Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057])), Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722]): (Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689]), Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689])), Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144]): (Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682]), Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682])), Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295]): (Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268]), Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268])), Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818]): (Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513]), Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513])), Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241]): (Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565]), Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565])), Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439]): (Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012]), Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012])), Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512]): (Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850]), Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850])), Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986]): (Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865]), Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865])), Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982]): (Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777]), Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777])), Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808]): (Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394]), Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394])), Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979]): (Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690]), Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690])), Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093]): (Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620]), Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620])), Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902]): (Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789]), Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789])), Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542]): (Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094]), Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094])), Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057]): (Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362]), Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362])), Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205]): (Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961]), Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961])), Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401]): (Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580]), Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580])), Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553]): (Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960]), Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960])), Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169]): (Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031]), Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031])), Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682]): (Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053]), Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053])), Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118]): (Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562]), Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562])), Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725]): (Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666]), Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666])), Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661]): (Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897]), Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897])), Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981]): (Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447]), Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447])), Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072]): (Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646]), Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646])), Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140]): (Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404]), Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404])), Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515]): (Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152]), Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152])), Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709]): (Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664]), Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664])), Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800]): (Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103]), Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103])), Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741]): (Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169]), Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169])), Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005]): (Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758]), Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758])), Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802]): (Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070]), Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070])), Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159]): (Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005]), Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005])), Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350]): (Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443]), Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443])), Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697]): (Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573]), Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573])), Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928]): (Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331]), Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331])), Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320]): (Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166]), Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166])), Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814]): (Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079]), Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079])), Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447]): (Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820]), Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820])), Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284]): (Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057]), Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057])), Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697]): (Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131]), Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131])), Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955]): (Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290]), Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290])), Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910]): (Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202]), Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202])), Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910]): (Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822]), Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822])), Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106]): (Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847]), Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847])), Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404]): (Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441]), Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441])), Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796]): (Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186]), Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186])), Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053]): (Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516]), Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516])), Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992]): (Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818]), Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818])), Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957]): (Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315]), Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315])), Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709]): (Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794]), Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794])), Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091]): (Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539]), Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539])), Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664]): (Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558]), Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558])), Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294]): (Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579]), Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579])), Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947]): (Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502]), Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502])), Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829]): (Word([0, 0, 0, 0]), Word([0, 0, 0, 0])), Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045]): (Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137]), Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137])), Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914]): (Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041]), Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041])), Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573]): (Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378]), Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378])), Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699]): (Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873]), Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873])), Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225]): (Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262]), Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262])), Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057]): (Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692]), Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692])), Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131]): (Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997]), Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997])), Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555]): (Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385]), Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385])), Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195]): (Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709]), Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709])), Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166]): (Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542]), Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542])), Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027]): (Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373]), Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373])), Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378]): (Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509]), Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509])), Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097]): (Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553]), Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553])), Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217]): (Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815]), Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815])), Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873]): (Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864]), Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864])), Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997]): (Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722]), Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722])), Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887]): (Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766]), Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766])), Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589]): (Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757]), Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757])), Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539]): (Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665]), Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665])), Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129]): (Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229]), Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229])), Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137]): (Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312]), Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312])), Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019]): (Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378]), Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378])), Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331]): (Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713]), Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713])), Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]): (Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980]), Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980])), Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325]): (Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546]), Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546])), Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170]): (Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822]), Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822])), Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054]): (Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295]), Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295])), Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925]): (Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848]), Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848])), Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909]): (Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796]), Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796])), Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540]): (Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170]), Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170])), Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214]): (Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448]), Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448])), Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317]): (Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294]), Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294])), Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757]): (Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416]), Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416])), Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378]): (Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091]), Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091])), Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263]): (Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463]), Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463])), Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666]): (Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361]), Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361])), Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174]): (Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992]), Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992])), Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470]): (Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401]), Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401])), Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665]): (Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957]), Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957])), Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262]): (Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144]), Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144])), Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229]): (Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284]), Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284])), Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134]): (Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325]), Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325])), Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855]): (Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765]), Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765])), Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115]): (Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814]), Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814])), Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441]): (Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831]), Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831])), Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977]): (Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446]), Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446])), Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880]): (Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005]), Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005])), Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789]): (Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995]), Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995])), Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000]): (Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267]), Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267])), Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998]): (Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982]), Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982])), Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995]): (Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539]), Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539])), Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507]): (Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512]), Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512])), Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305]): (Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118]), Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118])), Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219]): (Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009]), Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009])), Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416]): (Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089]), Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089])), Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980]): (Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445]), Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445])), Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063]): (Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140]), Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140])), Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713]): (Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159]), Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159])), Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031]): (Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809]), Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809])), Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932]): (Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037]), Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037])), Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094]): (Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925]), Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925])), Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315]): (Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386]), Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386])), Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446]): (Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721]), Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721])), Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742]): (Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981]), Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981])), Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661]): (Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072]), Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072])), Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979]): (Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671]), Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671])), Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361]): (Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269]), Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269])), Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558]): (Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571]), Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571])), Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290]): (Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902]), Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902])), Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987]): (Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741]), Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741])), Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902]): (Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515]), Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515])), Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497]): (Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028]), Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028])), Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948]): (Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709]), Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709])), Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009]): (Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725]), Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725])), Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387]): (Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317]), Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317])), Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159]): (Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808]), Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808])), Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394]): (Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699]), Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699])), Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312]): (Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000]), Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000])), Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987]): (Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821]), Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821])), Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046]): (Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909]), Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909])), Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565]): (Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028]), Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028])), Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269]): (Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352]), Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352])), Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847]): (Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271]), Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271])), Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513]): (Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800]), Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800])), Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054]): (Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394]), Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394])), Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004]): (Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977]), Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977])), Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675]): (Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800]), Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800])), Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692]): (Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159]), Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159])), Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909]): (Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932]), Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932])), Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814]): (Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697]), Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697])), Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186]): (Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387]), Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387])), Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445]): (Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470]), Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470])), Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966]): (Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507]), Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507])), Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548]): (Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253]), Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253])), Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897]): (Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783]), Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783])), Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208]): (Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054]), Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054])), Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268]): (Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661]), Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661])), Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388]): (Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643]), Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643])), Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257]): (Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174]), Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174])), Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960]): (Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241]), Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241])), Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721]): (Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046]), Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046])), Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822]): (Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217]), Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217])), Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253]): (Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697]), Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697])), Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054]): (Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019]), Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019])), Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821]): (Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432]), Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432])), Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864]): (Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105]), Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105])), Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373]): (Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855]), Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855])), Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646]): (Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830]), Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830])), Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460]): (Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208]), Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208])), Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033]): (Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214]), Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214])), Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105]): (Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129]), Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129])), Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281]): (Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909]), Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909])), Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028]): (Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027]), Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027])), Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012]): (Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054]), Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054])), Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562]): (Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589]), Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589])), Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037]): (Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097]), Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097])), Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355]): (Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460]), Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460])), Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223]): (Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355]), Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355])), Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089]): (Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306]), Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306])), Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035]): (Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219]), Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219])), Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432]): (Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297]), Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297])), Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693]): (Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263]), Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263])), Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794]): (Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484]), Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484])), Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552]): (Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941]), Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941])), Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267]): (Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814]), Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814])), Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992]): (Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415]), Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415])), Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941]): (Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966]), Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966])), Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822]): (Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320]), Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320])), Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306]): (Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902]), Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902])), Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820]): (Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880]), Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880])), Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361]): (Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725]), Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725])), Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005]): (Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914]), Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914])), Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783]): (Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781]), Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781])), Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011]): (Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033]), Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033])), Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297]): (Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910]), Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910])), Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070]): (Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134]), Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134])), Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144]): (Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331]), Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331])), Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023]): (Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497]), Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497])), Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103]): (Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540]), Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540])), Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961]): (Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998]), Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998])), Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414]): (Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]), Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]))}, trace_len_summary: TraceLenSummary { main_trace_len: 11, range_trace_len: 39, chiplets_trace_len: ChipletsLengths { hash_chiplet_len: 96, bitwise_chiplet_len: 0, memory_chiplet_len: 0, kernel_rom_len: 0 } } } +ExecutionTrace { main_trace: MainTrace { storage: Parts { core_rm: [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 8296916230783913551, 16462332824047406715, 6884552431231699198, 12264801256605292690, 7532528701100807439, 10480547126759850066, 6097728641437901141, 17248496754222975198, 0, 0, 0, 0, 0, 0, 1, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 11656, 42, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 1, 1, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 2, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 91, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 3, 0, 0, 0, 0, 0, 3, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 4, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 0, 42, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 3, 1, 5, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 1, 1, 1, 8296916230783913551, 16462332824047406715, 6884552431231699198, 12264801256605292690, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 42, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 3, 1, 6, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 41, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 42, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 3, 1, 7, 0, 0, 0, 0, 0, 5, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 42, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 3, 1, 8, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 1, 1, 1, 7532528701100807439, 10480547126759850066, 6097728641437901141, 17248496754222975198, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 9, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 31, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 33, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 39, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 43, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 47, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 50, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 51, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 53, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 54, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 55, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 59, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 60, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 61, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 67, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 69, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 70, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 71, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 72, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 73, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 74, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 75, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 76, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 77, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 78, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 79, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 81, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 82, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 83, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 86, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 87, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 88, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 89, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 90, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 91, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 92, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 93, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 94, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 97, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 98, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 99, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 101, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 102, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 103, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 104, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 105, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 106, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 107, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 108, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 109, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 110, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 111, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 112, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 113, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 114, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 115, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 116, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 117, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 118, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 119, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 120, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 121, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 122, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 123, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 124, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 125, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 126, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 127, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0], chiplets_rm: [1, 1, 0, 0, 8296916230783913551, 16462332824047406715, 6884552431231699198, 12264801256605292690, 7532528701100807439, 10480547126759850066, 6097728641437901141, 17248496754222975198, 0, 87, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 8400310461204590462, 9108169057237353573, 17636133504178290964, 17406877359165992528, 1012686194999500095, 3119571665051516884, 6045109140346221273, 8023007352945590267, 0, 0, 1, 0, 0, 1, 1, 0, 0, 11656, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 8296916230783913551, 16462332824047406715, 6884552431231699198, 12264801256605292690, 18213254076385477335, 9294418641045383238, 8055320100535498720, 11030019888906999906, 1874843776400824061, 12942276814728926620, 15585255994602274508, 16203157087401046215, 0, 0, 1, 0, 0, 1, 1, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 7532528701100807439, 10480547126759850066, 6097728641437901141, 17248496754222975198, 12342802819241620905, 7554371666290801318, 8718773026382250605, 15984482998549000918, 15460443374009848343, 1087146607978023558, 7531163901062156801, 4426949494427873777, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 11621565010787354140, 1949391780818670486, 7327781180606137861, 2419787217529136215, 13249250205018233525, 10029758640146777270, 5716716695107147273, 10829954014693503473, 7405851154679558693, 2030135877513774489, 10401768244118899621, 7992444660002654486, 1, 0, 0, 0, 1, 0, 0, 0, 0, 9190577937819620371, 12978309842325015235, 10477013461463931935, 4855391316239312738, 10519745218266697287, 18375374895419140100, 876067972673449756, 17915370314859305010, 17877705855294641231, 120652674332571204, 3378556434908723888, 17649391022523856338, 1, 0, 0, 0, 1, 0, 0, 0, 0, 15052947986857015373, 3007680259418135415, 3197694984858038551, 6563270153864719814, 6889631464391242687, 12614331779225506253, 8884325160266334095, 15067359903282619456, 6045216153329131722, 7293213550537411486, 18377064823051127268, 14733223614830533518, 1, 0, 0, 0, 1, 0, 1248924765333967865, 15568788993061722932, 4037714036443683170, 2584579945446987950, 3496704858534018972, 10965787981110521559, 9000006360952503550, 8377181923806419223, 18078834148678517323, 13751832434934340803, 15306332964801742551, 828627458527105190, 2519953652271814816, 5563221586835004955, 16428502736240336605, 1, 0, 0, 0, 1, 0, 161503374172189975, 7180975586994120588, 13070121377098205312, 9655464535561865455, 4169214041423852321, 5771090309048429384, 6993654059550252564, 14478380452460405826, 12150434000885474539, 18399347099839405992, 88779829066683150, 4428174353386180423, 7547120791432137516, 11951584238447172023, 8804182506418522715, 1, 0, 0, 0, 1, 0, 1859011259345361207, 13205265558511858864, 16229683663108620000, 17688418164436772208, 12658415008146819428, 6291208835901171779, 3297271436089179933, 12943628284217684119, 11639259038601904106, 10502234848011596680, 13946225273525543944, 11318468498957948083, 13851055481982014034, 5765565570506082255, 10777382518726251007, 1, 0, 0, 0, 1, 0, 1023422172081481959, 14540338366569412926, 10271517463444484758, 8863158288377959817, 9066561794313536160, 10161961919995709177, 2094278659773331823, 4371761587112760854, 10972685992181286814, 5641963675353630718, 15569415989710829261, 4258403342016907208, 4740804749082440837, 1594229550076307598, 5045104152796606559, 1, 0, 0, 0, 1, 0, 12053626300860885956, 13987509258486900924, 17286360383804666298, 8301538772707939488, 7700154594411825373, 14332053735409157564, 6894934729579673545, 5430665485920789830, 10553406992561403551, 11528229548578861261, 3294597468571627674, 2903493961726666462, 10560076388764518443, 3749651622493296975, 18114127684252877364, 1, 0, 0, 0, 1, 0, 12240592655856206466, 6264740020775290721, 859763567572081467, 8842953438422484122, 14329981889510246939, 3582542183068105786, 6023391989510151456, 2953193964713672141, 12396149302348639250, 13882467375549577428, 3586988377712407519, 7213506509798642482, 13435456572406932891, 9645941250097564536, 2781650568775738364, 1, 0, 0, 0, 1, 0, 15637532899188291351, 12683652363890573925, 2704597975013858668, 17832955104866332736, 6815586591600943723, 13755349213265671492, 8924117914024270326, 3329964149511691453, 11039495891702065838, 15670789219464690273, 11281671746346947225, 10492374165392519994, 11439270560757451470, 7337394676363778206, 2272256910055258613, 1, 0, 0, 0, 1, 0, 3130343892077994054, 0, 0, 1136320813223337744, 11438337112810950654, 16692992611178972868, 9482499518540692367, 5451078715157933845, 18403012202839423090, 13340398881404871439, 16853681425214524760, 5540259513623809808, 7754241405876268140, 15538673406175044580, 15705643278636475771, 1, 0, 0, 0, 1, 0, 0, 0, 0, 6593967995490198369, 546795078589070868, 8093299549277945163, 1445098694824947603, 16968796337604054074, 7105604958885889972, 12829574433066656016, 10962264142076089650, 6970346774265824779, 5668604568559492205, 15930738860655806958, 14403244990983785091, 1, 0, 0, 0, 1, 0, 0, 0, 0, 7770193319703938593, 6228225228483877842, 5315425894230577486, 8012448033829391087, 5395398520381640698, 8770911350053719042, 14827874098479004474, 11024999006644848903, 13791657658989935762, 17830220104295996918, 2090812709146185278, 8577173283657139529, 1, 0, 0, 0, 1, 0, 0, 0, 0, 17471481800618265475, 1930822204634793148, 12769804899579893379, 13068810900387198296, 10732524945348487200, 1519317270498249877, 12604995971822921101, 14107509487727911757, 8257552923782319555, 12034059115493819529, 4343039820825149431, 395799121324568963, 1, 0, 0, 0, 1, 0, 0, 0, 0, 7532528701100807439, 10480547126759850066, 6097728641437901141, 17248496754222975198, 12342802819241620905, 7554371666290801318, 8718773026382250605, 15984482998549000918, 15460443374009848343, 1087146607978023558, 7531163901062156801, 4426949494427873777, 1, 0, 0, 0, 1, 0, 0, 0, 0, 11656, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 8259689913693129242, 3400892600405308205, 17378179173256779268, 5060920854688287001, 9687195410980644248, 6313248141024338188, 2582093590609427596, 3953695074988874383, 11971751964106597008, 9907486161844974200, 17989903003960359463, 13336380866068769777, 1, 0, 0, 0, 1, 0, 0, 0, 0, 12279731404675001026, 6278812133505380138, 6233201299601221057, 2388727383803081265, 12084036741190483661, 2317300697897833956, 9759443477696867671, 10883057071610381859, 3944615791382572320, 4072273145811045884, 17852897021998211163, 9684438072608016253, 1, 0, 0, 0, 1, 0, 0, 0, 0, 3651584995004100725, 6423803920838032987, 14027200390009907647, 6592032860050067711, 2594447921553931384, 18306574626058358562, 4512185877168969647, 11342492757671323084, 15957751677575885720, 5761823199659062393, 6846407586191335849, 9817376758188911585, 1, 0, 0, 0, 1, 0, 18183126545069935350, 12563248011457733820, 8356966014032630063, 12041609793392315665, 5281186701877768352, 5541580267076219602, 11576047020972388374, 6661568194349527666, 15437143780340457719, 10754987180927492954, 4211835751645452119, 10566966891469040816, 690793516206281144, 3247962926818069970, 9036036859539968974, 1, 0, 0, 0, 1, 0, 15893445344909186288, 5778049594265975833, 1423581989082731508, 5458007776595562807, 2498425571573111469, 16059466580364398666, 8902716392494711213, 14882573357788460188, 3225597659422237250, 3128065202613218656, 16995684508107895104, 12196793732604029414, 17723663615896720413, 9829416315291197871, 580745865383399340, 1, 0, 0, 0, 1, 0, 13902067347991440733, 5984630683069450754, 12729386174124645267, 13785662250538369696, 272255205933159866, 735616656951483055, 12424664074133983590, 5026981889191825136, 5767485772665833989, 15651669603605283176, 7414308024158917695, 15811954123421478742, 13258769136679205830, 3664463833800174816, 15497592431183820173, 1, 0, 0, 0, 1, 0, 11156605567826983932, 3639316624646464570, 5042698793479444923, 8630374421727305636, 17027951314675117661, 2801906069577385610, 18065291493111457552, 18067767546753643362, 5248148594352695009, 7578134041089558055, 18445498855455618598, 7189106720666328053, 6562930842885656592, 6844922721754111014, 780716667496251522, 1, 0, 0, 0, 1, 0, 11860885490747304346, 12272615266561732125, 10423884872730116228, 13929733142214397431, 2117615618497875527, 5203222542820499724, 4538429948347629507, 6877693664463852318, 18109062185597913481, 10147653053574341319, 10079670109614966266, 12064951107563936135, 1152998120279634164, 12844815835032732057, 12896711460106342356, 1, 0, 0, 0, 1, 0, 3078919787028426439, 15265543379215102231, 570695753264939069, 459110976220447167, 2176716793919417092, 14863591412045443847, 14252826520731507004, 15860274927896899753, 10390267100193539166, 17043032359848981742, 818991875743271755, 16275785202399117535, 8465017515346473513, 2777064625189300576, 13072175816967000886, 1, 0, 0, 0, 1, 0, 3442153457185747577, 2606206929260007126, 2317686975478948049, 15948992202505097484, 5942181083636438599, 15457210791918859006, 887605399554676434, 12986387963278623196, 10075175986843357851, 4859683927561004597, 6555547085880890919, 8280537903442447606, 16640962983997717683, 2248822201261309400, 13163090516020988950, 1, 0, 0, 0, 1, 0, 7196986181046756683, 0, 0, 16549653703171386973, 11518702294444124172, 1109770523953150302, 11415315369035533823, 5890935665450471727, 2253657843173273901, 13858462521885404044, 9125187176834287629, 14925311787915179675, 9356310136195018005, 14965392043314054082, 18423301843359275387, 1, 0, 0, 0, 1, 0, 0, 0, 0, 7040940919216905671, 6187741949018394442, 10532732827118411505, 13505135286384426969, 917467356231706545, 9047752258933341547, 2335143583534705649, 18052717581435745313, 9355624911805935499, 7190586108559742607, 2304843099991312546, 16303126242918615541, 1, 0, 0, 0, 1, 0, 0, 0, 0, 15603840856162477962, 3504063088563989096, 6361775464868278813, 17698044987168049155, 8418309402148081318, 15988177746184666422, 4270534912200806378, 12370149697383197906, 8363034440938926080, 17941258791536373709, 11011611614519090457, 10702921331067290122, 1, 0, 0, 0, 1, 0, 0, 0, 0, 8416267285503610972, 15089551497492948945, 5363802036407642792, 10347532956075658842, 17181858623993805271, 15855824450153307212, 7743632312226714799, 1845073853648620670, 2000026205350826313, 18037231946791138113, 14309912549728703012, 13253445327127715869, 1, 0, 0, 0, 1, 0, 0, 0, 0, 8296916230783913551, 16462332824047406715, 6884552431231699198, 12264801256605292690, 18213254076385477335, 9294418641045383238, 8055320100535498720, 11030019888906999906, 1874843776400824061, 12942276814728926620, 15585255994602274508, 16203157087401046215, 1, 0, 0, 0, 1, 0, 0, 0, 0, 8296916230783913551, 16462332824047406715, 6884552431231699198, 12264801256605292690, 7532528701100807439, 10480547126759850066, 6097728641437901141, 17248496754222975198, 0, 87, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 10686862901019340628, 15711583786595019806, 9378042936835126164, 11939142602264935891, 13605517752371930016, 2544863311362262665, 6880055194706872138, 2404926559643725443, 11298729247352625131, 13639273524510051487, 3031605320954281704, 2952677760580202523, 1, 0, 0, 0, 1, 0, 0, 0, 0, 6949406075980976859, 9142069989509656801, 14676622013796942288, 5295633173573979080, 14862684288436559050, 7708888152496129562, 8667911075542880817, 14424367369474907891, 14303094264982903091, 9838552210955819611, 15088013178433258027, 5833102420062152227, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1932675776657481842, 14290498569500988181, 11741991701671402436, 3934903733189518965, 10047440752038846171, 14938209139342513571, 7659889883493126262, 2134579895120260539, 7819147353957995986, 17861588317805920712, 11020859927535923500, 15623868602690334525, 1, 0, 0, 0, 1, 0, 6264451320029412065, 5315770291001895612, 3923979823614336294, 15496957568148800678, 4856878698798286165, 18427152961697133322, 13172977369565732662, 8634756726478972696, 17549357918509499997, 7356106617646839123, 16192566970100663376, 4904526601366015673, 11478334329288517717, 607398074844683832, 9609971183005491570, 1, 0, 0, 0, 1, 0, 18264070764381924889, 7558994944201947568, 16698567473332535936, 4066201321205995431, 14552036519561423602, 5620710451624899086, 14969463994437329823, 11938508228196027882, 9200118839118887577, 6855444937813269923, 13901427726318773655, 3507966654472722962, 13139165600809348467, 3547085602937656739, 11244050388029555026, 1, 0, 0, 0, 1, 0, 8312328144036608043, 17972686765781519170, 10784039031850599726, 14134435301654782468, 13131877571979284929, 8266221982529104091, 159405248778538274, 5778967389144576888, 6057984302796584762, 11714059928473413141, 11763232719990709154, 7978933720497313146, 16635094485101159936, 18327609188632861057, 11071183167122824035, 1, 0, 0, 0, 1, 0, 10287810620841180003, 4548089904338037398, 6876519236022884332, 192351967064940869, 13616941784242570400, 7032108910940453446, 13625250436816808378, 17491100122417306359, 2292049730346364666, 2733535393252649149, 17750397792987890641, 6346476747248545150, 3575465615474366120, 18213303372206038112, 2518621101786158931, 1, 0, 0, 0, 1, 0, 842637389045220237, 14003171518185218367, 14997648696661468292, 13477259760240789253, 7438659305055821970, 7828458451594639328, 1805142843426507273, 3804729079035423760, 5684604326361654696, 17218885460122549497, 974371611540683935, 16762750120460661174, 739710162320190732, 3363948547922989023, 4267260670759647913, 1, 0, 0, 0, 1, 0, 10264158766070300923, 6050974414693797250, 847386589526447339, 3548106904874618124, 9289172558104066787, 8226909131216769737, 16380713199877477068, 4410762367217395758, 12555768451623030884, 10357980275595284555, 10303991993655092221, 4060030248038493229, 11216725884924445657, 10194932652661424405, 17494422570060569743, 1, 0, 0, 0, 1, 0, 522514578171525652, 3717501858890221638, 16025700499781393088, 15033579247524264929, 1744414008664189122, 6807378681147180078, 16955668219975052585, 18323017022834713256, 6662618285165080179, 12762215046608848013, 17134633855452090590, 6353725621416552612, 4449259194945598867, 8877290555352616803, 13666098560811114332, 1, 0, 0, 0, 1, 0, 3232143389630708424, 0, 0, 9014593992030055460, 10869121640834977224, 1905700011211118876, 955944440419378960, 265206078841667899, 13713964984862746492, 9702435518807270681, 12343078651970579400, 18227529633908655074, 9709048888339027683, 15154974039676851951, 16388400023664675593, 1, 0, 0, 0, 1, 0, 0, 0, 0, 12342730708987043912, 13274159397630057441, 12697978258400128397, 368152630932848211, 6555819701154221199, 97417680512067538, 2018507387878521400, 1529782995014995301, 13636792419679998309, 6197980968820055410, 737644335551408580, 9956102600220791675, 1, 0, 0, 0, 1, 0, 0, 0, 0, 14179025343931559433, 1175312715506728066, 11255361077722267605, 9822732455439796133, 13335036252549184126, 17127037879360292568, 16600677125340288437, 11659800847392950623, 12605660248276552114, 14805446144065764307, 14804045017754446897, 13192632014186378484, 1, 0, 0, 0, 1, 0, 0, 0, 0, 12383461936126681247, 745215043874424896, 4540981537676651137, 16486351305638014506, 10972364256824969372, 5647748125744546841, 5620391031839475969, 17973620544670757805, 1344519641939806437, 11395404185290209616, 4498705163534372313, 3336623779264323323, 1, 0, 0, 0, 1, 0, 0, 0, 0, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 8400310461204590462, 9108169057237353573, 17636133504178290964, 17406877359165992528, 1012686194999500095, 3119571665051516884, 6045109140346221273, 8023007352945590267, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], range_checker_cols: [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2187, 4374, 6561, 8748, 10935, 13122, 15309, 17496, 19683, 21870, 24057, 26244, 28431, 30618, 32805, 34992, 37179, 39366, 41553, 43740, 45927, 48114, 50301, 52488, 54675, 56862, 59049, 61236, 63423, 64152, 64881, 65124, 65367, 65448, 65529, 65532, 65535, 65535]], num_rows: 128 }, last_program_row: RowIndex(10) }, program_info: ProgramInfo { program_hash: Word([11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518]), kernel: Kernel([]) }, stack_outputs: StackOutputs { elements: [2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, precompile_requests: [], final_precompile_transcript: PrecompileTranscript { state: Word([0, 0, 0, 0]) }, trace_len_summary: TraceLenSummary { main_trace_len: 11, range_trace_len: 39, chiplets_trace_len: ChipletsLengths { hash_chiplet_len: 64, bitwise_chiplet_len: 0, memory_chiplet_len: 0, ace_chiplet_len: 0, kernel_rom_len: 0 } } } diff --git a/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_18.snap b/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_18.snap index a5f0d94b28..db50a4f102 100644 --- a/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_18.snap +++ b/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_18.snap @@ -2,4 +2,4 @@ source: processor/src/trace/parallel/tests.rs expression: DeterministicTrace(&trace_from_fragments) --- -ExecutionTrace { main_trace: MainTrace { columns: ColMatrix { columns: [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 33, 33, 33, 33, 1, 65, 65, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [11182969138190702361, 11656, 91, 0, 0, 11182969138190702361, 41, 0, 11006573531383828351, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010], [1109628455053940361, 42, 1, 1, 1, 1109628455053940361, 0, 1, 10983413158656624898, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331], [13928676565061410159, 0, 0, 0, 0, 13928676565061410159, 0, 0, 4869282124135316831, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319], [297470094449022674, 0, 0, 0, 0, 297470094449022674, 0, 0, 5899798166361732461, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694], [11006573531383828351, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [10983413158656624898, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [4869282124135316831, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [5899798166361732461, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 2, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 2, 42, 42, 42, 42, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2], [2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [3, 3, 3, 3, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3], [0, 0, 0, 0, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [16, 16, 16, 16, 17, 17, 17, 17, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16], [0, 0, 0, 0, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2187, 4374, 6561, 8748, 10935, 13122, 15309, 17496, 19683, 21870, 24057, 26244, 28431, 30618, 32805, 34992, 37179, 39366, 41553, 43740, 45927, 48114, 50301, 52488, 54675, 56862, 59049, 61236, 63423, 64152, 64881, 65124, 65367, 65448, 65529, 65532, 65535, 65535], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [11182969138190702361, 16344194729581826754, 15045917672181612303, 3672327111134984977, 11902001817992340801, 97480563262877602, 1831626543952762702, 12062163654685913941, 1451330498122947575, 1742063333427513989, 2331114102915733339, 8550984974115591347, 8960841496031156142, 13720918668577423004, 5779906183691085674, 3198599991840782485, 13728843979899181292, 7239115491427587826, 12128894594351473931, 15480692841914867508, 8817470180767843173, 10548371713427919789, 10315264763691724912, 1023167627240586914, 3818953450339058320, 14941570263133670432, 12615841091071546269, 15435370781163068976, 15373572920503822367, 11769995123877236600, 3762647969008011219, 8269653645296248010, 11656, 117148, 6714198787893475936, 5262284953624879131, 6828048997998717653, 14647846255598321281, 12213957512096072087, 15486993862206988880, 9916068016290756984, 12311676223031039230, 6798558233575208094, 6061515485015027193, 9178825932447902299, 16451694760407086053, 9245574117575493602, 6706571375738621744, 5707941763645196550, 13553995817865937844, 18312867062271325792, 11246612591729350508, 8806896510487478352, 16014621579841168337, 6332183310159529150, 2444726075814550534, 13415483499482541228, 16602291456530418215, 3069389264726801426, 4940323642218861897, 3979217445866956620, 6693606464693965975, 9525288177353527302, 11182969138190702361, 41, 410, 8488924048752676071, 5473488137200086909, 16124688533662466636, 4527044298581192722, 16887055178922689595, 5249711198271717177, 15470787238396171217, 5632634005697013617, 7337408598993184022, 11147561538212402733, 9710911023591971572, 8752830793140649116, 11546140485006286209, 10738951369466640003, 2139663271495255306, 6135983205453599776, 17538856881976830392, 2031516987289365197, 17199894398730562705, 4010699482290892787, 3922552954514582360, 7369439734883755459, 108303794773646012, 14521269346803535153, 14515762120928230173, 13893962684375637966, 13610167819530098127, 11215445033353754262, 8081237365032914784, 11006573531383828351, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1109628455053940361, 12119768350776285319, 8184561966951183876, 12431805880114311043, 2986356007899077631, 2836244341662188919, 146796491816379180, 8696360259937422388, 13878284404078727054, 7667548888861073206, 9741377056638459459, 11905155073870025459, 9736056580211703764, 17352787150580200349, 5883496260565631343, 9594088066979877926, 9297041447863221537, 6214639496702145664, 2461170076272033096, 17112913798212225634, 1035954869286151888, 2140568550425483844, 10584986198873793665, 12555736327846716176, 12072441430913369009, 13906015856663078107, 14389918991418187594, 2676571742010508284, 5150637797762075635, 11237118474907085960, 11752652705714102353, 997682303299740331, 42, 93752, 18084035356118526352, 8386870944408484201, 18056918720989013854, 11520229540186073721, 5668756658695595711, 14109792997657353922, 12303762929371991135, 14460911410586037148, 12418445481638740107, 16455507557982986163, 18172284878038222122, 6352198309363971688, 9198509167958908347, 1068046269761257463, 16102483860755268671, 1544674922431042375, 9868836391822552540, 7915117918356788325, 6533551228799195237, 3992189811639127908, 9511948951280762358, 13039263708530965818, 708611914251242147, 4206064101444952505, 17714998603219848343, 13074430791784659712, 14102459334756352921, 13661835471193379756, 3038016940647586670, 1109628455053940361, 0, 328, 7132218559010351790, 2687466917280430353, 14170238607512888511, 5453168895411602323, 8679138582261878552, 10871515559850126217, 7649138216344653830, 12086029516113687059, 14609582285822867389, 7271583017513514692, 3821121937809044409, 3833100151978191712, 5702916883024911354, 3579138882391492892, 14347405124134927123, 9277341930384005575, 2993137622300793545, 13370802209879109056, 13653108884642243926, 8702782587703766612, 12945832125614510830, 15167316901472929028, 4608694219239856197, 4443739924303229750, 8611475648437961511, 1575864515244779062, 10900065459953722709, 9162692523043045302, 17462008412377898139, 10983413158656624898, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [13928676565061410159, 5375705730949115787, 1314981229280595867, 1393532256400242982, 13433705342207763738, 12880831435259048250, 10699055768478348083, 2470044642731141974, 13732313223959877570, 2078090264025450769, 3845297826200108779, 15581584642080412492, 11359623335937034504, 14549946302435322871, 17424758021352066268, 15472130290487345321, 13048555428151627244, 13747770174448213841, 9164669383091055648, 3250455247796114093, 10799815877710934765, 9086202890994770785, 12116339825079888992, 1619117325320043308, 16898959203497269575, 15756045849228969140, 6190024525131486611, 6215657966742979785, 17671950935398765622, 15303512720733905693, 10727837149375754730, 12907160815575155319, 0, 23564, 4199576522683349447, 16513391592299529611, 11415640949254272304, 16138036929710694921, 9992494271122179933, 3020772293084222765, 15625472986208536177, 12149624601412828429, 10735117276139490774, 13332197512776217968, 13474689739491604605, 13815225937039366706, 706573335075180235, 4097091053989040149, 693823183101411164, 5341110475237803180, 4368449439175744649, 7740607367180462177, 13389502447794973829, 6721164191334334250, 6997451158266748059, 9767862146044075473, 4778055569341029558, 10088175016132507812, 3285997397792070136, 10914182999248450193, 14473951691792990803, 8827937223658185560, 9698676695870635420, 13928676565061410159, 0, 82, 18152833202936203138, 10305147718805144715, 13246631902503555591, 18142351346900318359, 11971140429919100117, 6903484634638418138, 3098698980745497723, 3068992673894668202, 9164459936648953977, 11194864417357882388, 12005359455571366116, 12356306486226268709, 10059737158050223658, 17119982236602677307, 4225663824996553892, 17852936504841763737, 5778553506856942969, 9045001363359345866, 18423338781077887809, 2711240319770097821, 8346149567490270428, 9594540064387516595, 1859863665658604717, 16919987197409252682, 7809934763889573038, 12492597695329698922, 18341122838405415754, 11967784234256998242, 10761804868734649587, 4869282124135316831, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [297470094449022674, 13535968261560526699, 10051713503687926694, 5258910437097366761, 14031537229609682064, 18190284629542346231, 4346004165604875907, 15375947702712472554, 4019409425675168575, 2064296209102051574, 17718639079388526425, 16642022229570326204, 1618478323171655450, 5998884876319667302, 6872649224968331273, 13753905356607269997, 7559241041198219519, 8363779881416372286, 2105649450986611656, 11644599807961994770, 12949568200151355456, 4366812189797744262, 9669235379242805159, 18184433440084438609, 13914998044815764482, 11325806379320193213, 1586181560816232196, 5920020313630770955, 8020025137186066841, 13419225700498867773, 13671651770198504476, 18024383338294781694, 0, 23396, 7560057297276955988, 7451013195867945919, 7468487593070852196, 5578183109591783882, 15747662796636990589, 2066701485189878406, 17025371161980089605, 4391959764977446152, 4985867595251695917, 6710066216774366729, 6241000701339836952, 4718440141936325382, 4986060230214018536, 5748634601882563491, 10896228304766504283, 6457499153671182820, 12270042173384394159, 11711065129605555908, 15065279868519608165, 17856220227797901726, 8953039722587792244, 16994104539161729445, 14670768895096516686, 14803898243742553487, 2327203233976270205, 17449705512918939747, 8253253226048886083, 11671578295265948239, 14297456315487806992, 297470094449022674, 0, 82, 302695496926486902, 16415403596737407938, 12969246825596557956, 15965643470182086386, 14881573336337548597, 2868629484750761697, 7317402970608805914, 2570537868338555591, 6697005353407257884, 5717939852331496040, 9408357527608003903, 8011884131194179594, 15942512744234440774, 9052662470595673790, 11913271961595885333, 15508051727969296111, 6269710669185644103, 12322255659000247132, 810875278274469351, 3499523055983644139, 9453749819048496107, 598273005722510655, 12338854942180141395, 2829445891916136836, 12653867244112536729, 4648827005364006908, 3153753366153954420, 12197142511433562971, 13557680898519201450, 5899798166361732461, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [11006573531383828351, 92579048505362891, 10772660272533654046, 3331697170176629084, 602109730184155310, 16230148280330706633, 6302091831624975391, 14001078336639287767, 14888577262766439787, 12258632680483319887, 7641862043593808385, 4740702640077452126, 8494032654039797119, 8314420015254970480, 18294822284401514132, 15552480182219334239, 908821363395967579, 18258193129875665644, 4226365574585037317, 3638253471537757569, 17581484848263912285, 6286301305761091621, 4777175749672661669, 10658559677463134471, 1417442037893012894, 7857622794514614671, 1052908464763109826, 4925127753504389599, 4274762298296320367, 7383511416371792464, 17305170235876004791, 2200823396264285425, 0, 58574, 18280076181055982575, 3965010120048981150, 1623299660155787797, 11930292174601709627, 17275008438838615802, 5756406115988630048, 17841510847136093686, 6729021181420822547, 1709787776185889305, 2022739540363098314, 5157634830695555269, 17099057016182449505, 4092740078069974091, 9582547144648304801, 4715310719341519129, 1597700055042697404, 480964694484615271, 56280064407246395, 10536769335197150641, 16099710145374622840, 3473101726323291593, 3295906456874767760, 716460020344690975, 10580825486552151036, 4976836170739997781, 16652319776094256449, 12319687016213027555, 13490282225851742651, 3371801902832234206, 3795543859124105201, 0, 205, 13622702382434675698, 8941567408770445183, 2168342371250989865, 17553704974699598306, 12818882650622055705, 16478401302589696546, 10652219805906948351, 13167156861512034068, 260666911081589986, 1428764500637505382, 2190433219200603887, 11999917547751101526, 2751093334206085539, 9318931023569054874, 16297727142514657495, 11875658036026604145, 5829323963705819601, 407792022339954638, 5684565403642367050, 13995368600016681288, 2845800306757116207, 5216498913603536417, 2411940295743487842, 2014066638340124975, 5258230180909223265, 17089893338044941808, 1124366766375746940, 9116801986360376826, 6650575029061305823, 4025036448660092914, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [10983413158656624898, 11859595567907759997, 10088766553729725414, 12574093635772317570, 5470069473511751658, 9645793732101008923, 1476556243604239385, 17933040757673393353, 7118521641278947238, 7588084371428510216, 12191494749556797391, 8228232126921631746, 15226641263820888277, 4239012011479875368, 14018593041447406970, 3541695062587160892, 11116896887234129281, 3929539690735302143, 11203930352796078636, 8751959587369085991, 12655249523595546680, 16379258612200834026, 9984807922535170831, 9638171237357393134, 12191893464144837018, 4677785078090407332, 8064604530099592479, 10076433135196495423, 544627542347870852, 11879905738846635842, 5683487714952213815, 8088984326603898052, 0, 46876, 15125170292333450443, 7072657932567702059, 10475291980250876467, 14632109792663117375, 18379882203306053694, 10250239327737538260, 11537033439839832588, 15180883293806522386, 18285674122603938406, 16116176887352657770, 15068074760365493774, 10507624248254584461, 7669544778380245671, 16424767991328560142, 16771797144770177609, 4105927596877687309, 7519344916607985067, 16277772212475505196, 1322695487397776109, 8302446182097155523, 14744324883381489574, 16338446684875281086, 5703860549203085948, 14077533030564871132, 12287193162084105824, 2535384450001991464, 13089916287630526229, 1568845385281768860, 982340402770608276, 12910581729787565904, 0, 164, 6093021124582015914, 375332441348258328, 16597900739273350797, 16788616498952461620, 10323894478242846558, 3730474644926313294, 17377183878976452334, 12746711269593150718, 13699107349734059694, 421533440407219618, 15109303318896079214, 17746438429032263850, 13224617406323308041, 5646455969610140563, 12626985742338481481, 14497665384991648640, 13894375308737560134, 3268393834564630675, 13312171511942754529, 611321250913478210, 12048873764879264902, 5334026694118161468, 14360341460112568406, 17654490467796517057, 1299716947845207044, 7609683397541157642, 14709808073905360012, 11742139955633481423, 13522070698443062110, 12847434483856017691, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [4869282124135316831, 10293244464294212936, 8691876854061179148, 2952350747126730564, 7968203687716298290, 6747517476428823928, 16731591574836256879, 12286682322909052293, 5699380547329532508, 8774011841981167612, 10988677337017809219, 6257583805205658612, 8595550098696265772, 17321901905145630028, 3295089823193122164, 6581488060195755410, 6329516418872359771, 7640632346113799527, 10454000694343684461, 15867346750604392587, 5805413556949044653, 9247297947852762648, 13748015074908171216, 13312272456227001370, 5054807356361880835, 1012271632864570722, 11252467974344770686, 492886975717156403, 2629112354487966090, 10128035487146424848, 18233951381382816412, 1751709948898726303, 0, 11782, 6055246182589913733, 15015595405278911690, 2209046468675768902, 16429197663637467330, 15810134098389081544, 9588791733994120847, 18370261572729563296, 7006788971063612777, 7962515674056117045, 15223121510830934757, 15872454912771340895, 1486059252283823706, 3912605942422700262, 4173681472723400357, 2922691200579275072, 7112424425452913463, 17213377378328786151, 6274713241106982122, 15112974401160243995, 17175975930045398893, 5467280291812001242, 5238070817263862176, 17584445990298638069, 171514605620090783, 4267926381848052110, 9011064139813451706, 17044511642202081265, 17370313250110904770, 13397257034080852565, 17596568325206204932, 0, 41, 9617260353707541367, 9187825164453421957, 17649953659489375797, 6396310504287885774, 17019569090864760371, 870218876784769460, 17213560015461715510, 16812494438448165271, 15885717661613279263, 2958950328581697287, 14311601477626423214, 12599125587081655507, 12078599565132475515, 3332808335850364509, 374688056722968094, 5591521890390007231, 9584980789501913045, 4066644474875437132, 17728945623551220217, 1158050506628066296, 3730734784735709807, 10671987699715228843, 3173999018565335463, 14949604462817069254, 11653871972148380806, 312408327658285690, 8531928004921347162, 98858158429688394, 6167334615107562354, 1234843923022284190, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [5899798166361732461, 2163003956713638315, 5989289390391757114, 15670015339098587014, 12708827926449341197, 10159927950043513901, 15395056832871965886, 17405960500607097380, 9229756563573051371, 1186079292937331145, 13463816706671585562, 10107168241231917326, 8534001612601599401, 12790948878158723266, 12619661555644649350, 11614101867080583800, 11255619179741810030, 10501448523390229441, 16971746085380600175, 7173352752193758542, 9960833320626690499, 3507659370538431093, 6846598866105961944, 2557094292829749679, 11416743759689580593, 12182449258645699464, 11951277814213817673, 10567677969346318078, 13884819925875295975, 1926379571595510347, 5918588896905128530, 3405979658670756574, 0, 11698, 8146055133796963630, 4724864404296433607, 10453305271538430204, 17141108237620938331, 16113292978122689735, 14630852758047225712, 16936235645680974811, 640959767495035790, 11162248672474783185, 10618808740372936561, 12973220127719589473, 13223353016814262874, 17652411276563186968, 10141330567980253051, 1770876161367154023, 12442058685904907795, 12986633647641209886, 5384244903407669612, 14778499304685795812, 8054814913234770610, 8358166993767322841, 11933451322373121057, 17795028935448509068, 11142588879850986282, 873880226830208445, 11017896854604878841, 6896812394605202475, 2024842447089060639, 16625734836325714912, 12512094004962322130, 0, 41, 12529483521877137515, 4671467226762388980, 13873740979092621907, 12847173262736205772, 2640423636460273022, 8374058502362870155, 7630996533587302384, 3556075572123538464, 8078558398785937163, 5856098383496092000, 7999607615804135893, 15509992149354799776, 13785560116650003734, 8358196300413379173, 10412508239405514928, 7840142081125036731, 18075062342410207477, 18173191150607640442, 2133036585496843963, 8931901040624025193, 9454731621283026961, 5837806564591410604, 5850596656185029719, 296117354535505751, 8985195681813998404, 1975947551471322175, 12041110943945791333, 11648250496545232642, 7830634726555216225, 5266777994490151623, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 11627839282500592134, 3407397722647202213, 13644814392425193274, 9689174787852538317, 15759480978611340324, 10073546228149283602, 8090878949578096073, 1502926046713635634, 7624167193861818791, 10274257988202953339, 4186763142475177793, 6025425965090069083, 8194342163688078130, 13163397875087894329, 5161390927343581791, 10103251159424454395, 575959985319833606, 13175926157437524595, 8928028362497258488, 8665485641724560922, 15570929820685955587, 6150675652390666890, 6384512333148749163, 35921027791486524, 3229184449291625000, 7414754653220847914, 11347301099028602515, 8368586536930615942, 10138228048917253579, 344980745193352015, 5644431973654019812, 0, 58574, 12761879591277148733, 3794756304714494565, 10919382803049057886, 13927811434585922718, 8315847055470475708, 10095847089706649983, 41153506376499461, 5529807447506440005, 72892344713547594, 18362204307013225363, 527610602670466995, 14772158556567070690, 9538491437159792328, 1580498045195806896, 8297535568256810268, 13797917351588149895, 1651894826575892086, 13380716913143325871, 2655893075036451977, 3750342908258071259, 18231595474498119868, 18163310674975357977, 2371603174180061555, 6433509503768865899, 5002589281792664271, 10946433388588585987, 9256382872640968643, 6570002101874463971, 3849537215181896567, 5735281858523620986, 0, 205, 7876112718273244024, 1276143811675585923, 9993912342918529935, 16999254614849428545, 8194747920293058753, 11171758628037424552, 8208119826419095432, 5568149314099479773, 17551537772960996556, 12651683228606533001, 13584145944854843210, 12212300608708011466, 18102951610480561318, 14720258372954226591, 15448472262117068008, 10575290756167155008, 11997391634424499349, 9879556170680135793, 12373753045781314057, 9529470285212177396, 10620662102176580756, 10199402949196411787, 9825825353570660203, 18337390924518345383, 15945306792731206141, 10537181099344133724, 5505106000120813030, 14774803975376978777, 14575654492591748955, 8207377881872409730, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [87, 1844206616423154361, 7941852203687681180, 2987825311454433607, 185071303888742221, 16140725249773135932, 13486449309893009073, 13471170357015645210, 11073859438158044651, 16507211018434913458, 4066228076398875428, 16536071023746429034, 10818247459046542341, 4392853051950044706, 12116759677655250999, 17293580330275603290, 2376540144284705519, 8057038266027202789, 15097730100005395027, 3583575859544955648, 11146351406925299070, 13473187462927502829, 8056538798141691018, 13509558775822115028, 6797301950091310335, 8773981691004278165, 4751058192101309365, 10661116978196100999, 15345629614104209519, 1689963602473071179, 12869561156624962469, 12554030503530361323, 0, 46876, 4789346784708035796, 9438751512570250357, 447952077691938652, 6351356675900770483, 4868676530510485341, 3192437812250556397, 11511034416225137032, 15380266628173325649, 10700144984876703355, 12230522212327928379, 15526804358639727019, 6410705682507666807, 15728916292645010880, 13992590038292222154, 1916422775943772979, 8280685582260709248, 12515254706968408232, 4845996266408136556, 15172713941042952680, 2233761585242005099, 13227100893355110663, 3914062371738178895, 7843298541359739176, 8386193964610423744, 8614894336467293783, 8834991867772635266, 14221135810103683560, 11406071542091908609, 571586377235018247, 3013510715159483905, 0, 164, 14482187202392982684, 17682350329754313417, 66214439016909251, 7504629639084879386, 11708178258767948919, 188011405648496761, 10242982970375452289, 16510140404231294235, 13381084464566932690, 9239012175869487665, 9339694231140180875, 9917181315244873380, 17448534469581521177, 4965043893766771965, 13305445405772227224, 6963375374275021656, 4554518835153561582, 1694446457415578298, 4604616361036784646, 11439774970058559661, 10784225701912607868, 17782855612978839775, 13368223431578003475, 18100595786373494652, 12753204151452870283, 17504098334052422651, 12896535568794110034, 7402084190222773115, 598469278842686486, 5912604878679295331, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 11371898088219304696, 4199208231896291776, 6349271639347163621, 5568595648257864309, 10224931331962954075, 8046167029187450402, 6585148777263545478, 3706462809677116963, 12578093594063946501, 11334181120248394313, 4953509182438845792, 4130560513564095433, 6665409895959715593, 12872180446847298231, 11452171012153290342, 5729159829892489539, 5675564903335979949, 14158677720471443076, 12300968791182495713, 13879671978791253311, 14820104759072107152, 17585955671327967478, 6737505022417937354, 17454985371239394211, 15749874646256262769, 10017226585432634212, 8893160827421013787, 11893931769684808775, 16471875099240353401, 9975926385796085953, 11231727832144176264, 0, 11782, 6351111885067026894, 14086295994708840477, 3142920623105062021, 4317195510637014184, 16341148873550430347, 8014762585425506108, 12977978004680762325, 15318810920503136316, 9472517513827583818, 211962335804367550, 14931353145911604525, 9340212215573419915, 5244269534978718672, 1584128384101705476, 4460891295949496863, 14654598206063183317, 13555452196222133132, 17680908597379218579, 13178742765486355260, 3964993209073179108, 4213917162333386044, 2639949635019592417, 3300803743280888923, 12914222891103397086, 13436383826829479040, 7004576641630317963, 12080155723705641895, 6767987840126452263, 14392317091133450653, 7390177608867021213, 0, 41, 3800418813655617572, 14503408479575576010, 10553169970007645345, 4946745422622378051, 7127828976000219721, 2687285609278369395, 16630221959750548176, 1114885198959805561, 3895092647933222339, 9831397389014117600, 12816842684293233323, 1779119880742935864, 17663607747965229138, 5382558247959552902, 11972955750871888364, 16616426694032134438, 9711126273890628516, 376576173107709408, 12451218545182255865, 14301764572821220192, 13209253693600827240, 5745169166190656073, 12916752429524642864, 14463770325561420619, 7870235520772452232, 13278341252249613603, 5432056100901092307, 8994645443800925562, 5908996313982662075, 1494658977663487041, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 17530820119034444668, 15233230393479930649, 15702789941308523576, 8819781861782654629, 7112644758334533508, 2549387492966523460, 15838339720324898846, 10242380937000070843, 1124701407395854549, 5706112669062280829, 17015988684670402201, 12671109438456697877, 15652595419009785355, 10753966634497852319, 3622124053041186910, 2063695485301676711, 17845322355197915738, 9894091605930112348, 10822348040176532279, 9689802115657313068, 6759722828145755337, 9479044480226984785, 7845909286502989649, 560081323074218824, 16017591174163981005, 1196237303718990885, 6783304352365897531, 5064625229425039166, 12661189034561966549, 11511655067934063768, 11479359825177848513, 0, 11698, 2084118884093035279, 16979859941949546961, 1454299506056429821, 9658643065222637557, 11605485146349749283, 13057696629474024230, 16650374201325163722, 7457309320444728046, 1243843599995756274, 17176177262691414244, 14152683925184093692, 198845790532099135, 442435874165139119, 1462611314767788334, 3462067515008653152, 4141759445261917472, 12323330957750482072, 14922731139272985797, 10387565380055278256, 9531386257124273696, 9539285450074189441, 3691450672437772660, 12463184698711878632, 4858502687517999226, 12256855995572753726, 9245347314341240247, 7569214225554358494, 1017686422583121037, 10327407591150878848, 15025446886891081073, 0, 41, 13092032916490151270, 2856458557507854671, 14059661153766146178, 1724041303048776424, 7119687853704366589, 3699246950542313036, 8338994289155538949, 7732171807197958061, 10653644351656999339, 15262849800927670044, 6132373490633371091, 16473831322001214578, 12928938600331453669, 6959935525856744214, 17173069020016176920, 6747622983845354522, 2484033613426731933, 9879916419081378373, 4275250202523893223, 5995505684018086986, 16115855409799741127, 2490003355474156145, 10034475279304353355, 7223217715426381376, 10334063888823214988, 2139000562522371457, 18314119367638727156, 15311716904301189063, 894706229073498557, 1570146104298050273, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] }, last_program_row: RowIndex(10) }, program_info: ProgramInfo { program_hash: Word([8269653645296248010, 997682303299740331, 12907160815575155319, 18024383338294781694]), kernel: Kernel([]) }, stack_outputs: StackOutputs { elements: [2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, merkle_store_nodes: {Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571]): (Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350]), Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350])), Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484]): (Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693]), Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693])), Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781]): (Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874]), Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874])), Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171]): (Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361]), Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361])), Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815]): (Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305]), Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305])), Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689]): (Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195]), Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195])), Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362]): (Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063]), Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063])), Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848]): (Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661]), Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661])), Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352]): (Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829]), Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829])), Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444]): (Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223]), Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223])), Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386]): (Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388]), Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388])), Word([13190842942618341421, 17548956981569849952, 15418963848144418856, 730733050713174879]): (Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144]), Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144])), Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874]): (Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675]), Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675])), Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594]): (Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115]), Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115])), Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809]): (Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257]), Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257])), Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777]): (Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555]), Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555])), Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509]): (Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882]), Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882])), Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725]): (Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979]), Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979])), Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134]): (Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987]), Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987])), Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828]): (Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910]), Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910])), Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830]): (Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054]), Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054])), Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228]): (Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742]), Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742])), Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443]): (Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928]), Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928])), Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643]): (Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979]), Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979])), Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758]): (Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106]), Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106])), Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580]): (Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594]), Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594])), Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765]): (Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045]), Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045])), Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766]): (Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281]), Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281])), Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385]): (Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828]), Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828])), Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579]): (Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171]), Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171])), Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212]): (Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992]), Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992])), Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463]): (Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004]), Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004])), Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502]): (Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023]), Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023])), Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539]): (Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537]), Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537])), Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865]): (Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225]), Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225])), Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690]): (Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947]), Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947])), Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202]): (Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552]), Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552])), Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079]): (Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444]), Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444])), Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850]): (Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548]), Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548])), Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448]): (Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987]), Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987])), Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041]): (Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035]), Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035])), Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301]): (Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414]), Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414])), Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414]): (Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212]), Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212])), Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703]): (Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439]), Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439])), Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271]): (Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955]), Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955])), Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882]): (Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802]), Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802])), Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152]): (Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887]), Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887])), Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028]): (Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948]), Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948])), Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331]): (Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093]), Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093])), Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394]): (Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134]), Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134])), Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546]): (Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228]), Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228])), Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620]): (Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414]), Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414])), Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800]): (Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703]), Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703])), Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671]): (Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205]), Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205])), Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537]): (Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011]), Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011])), Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516]): (Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301]), Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301])), Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831]): (Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986]), Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986])), Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415]): (Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057]), Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057])), Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722]): (Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689]), Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689])), Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144]): (Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682]), Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682])), Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295]): (Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268]), Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268])), Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818]): (Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513]), Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513])), Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241]): (Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565]), Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565])), Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439]): (Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012]), Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012])), Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512]): (Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850]), Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850])), Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986]): (Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865]), Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865])), Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982]): (Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777]), Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777])), Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808]): (Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394]), Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394])), Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979]): (Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690]), Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690])), Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093]): (Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620]), Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620])), Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902]): (Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789]), Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789])), Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542]): (Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094]), Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094])), Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057]): (Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362]), Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362])), Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205]): (Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961]), Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961])), Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401]): (Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580]), Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580])), Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553]): (Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960]), Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960])), Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169]): (Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031]), Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031])), Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682]): (Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053]), Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053])), Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118]): (Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562]), Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562])), Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725]): (Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666]), Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666])), Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661]): (Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897]), Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897])), Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981]): (Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447]), Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447])), Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072]): (Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646]), Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646])), Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140]): (Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404]), Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404])), Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515]): (Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152]), Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152])), Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709]): (Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664]), Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664])), Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800]): (Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103]), Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103])), Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741]): (Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169]), Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169])), Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005]): (Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758]), Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758])), Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802]): (Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070]), Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070])), Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159]): (Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005]), Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005])), Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350]): (Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443]), Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443])), Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697]): (Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573]), Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573])), Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928]): (Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331]), Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331])), Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320]): (Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166]), Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166])), Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814]): (Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079]), Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079])), Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447]): (Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820]), Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820])), Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284]): (Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057]), Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057])), Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697]): (Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131]), Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131])), Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955]): (Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290]), Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290])), Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910]): (Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202]), Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202])), Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910]): (Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822]), Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822])), Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106]): (Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847]), Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847])), Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404]): (Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441]), Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441])), Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796]): (Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186]), Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186])), Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053]): (Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516]), Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516])), Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992]): (Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818]), Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818])), Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957]): (Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315]), Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315])), Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709]): (Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794]), Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794])), Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091]): (Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539]), Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539])), Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664]): (Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558]), Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558])), Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294]): (Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579]), Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579])), Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947]): (Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502]), Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502])), Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829]): (Word([0, 0, 0, 0]), Word([0, 0, 0, 0])), Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045]): (Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137]), Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137])), Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914]): (Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041]), Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041])), Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573]): (Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378]), Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378])), Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699]): (Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873]), Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873])), Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225]): (Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262]), Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262])), Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057]): (Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692]), Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692])), Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131]): (Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997]), Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997])), Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555]): (Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385]), Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385])), Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195]): (Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709]), Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709])), Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166]): (Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542]), Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542])), Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027]): (Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373]), Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373])), Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378]): (Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509]), Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509])), Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097]): (Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553]), Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553])), Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217]): (Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815]), Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815])), Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873]): (Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864]), Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864])), Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997]): (Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722]), Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722])), Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887]): (Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766]), Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766])), Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589]): (Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757]), Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757])), Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539]): (Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665]), Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665])), Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129]): (Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229]), Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229])), Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137]): (Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312]), Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312])), Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019]): (Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378]), Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378])), Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331]): (Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713]), Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713])), Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]): (Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980]), Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980])), Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325]): (Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546]), Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546])), Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170]): (Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822]), Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822])), Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054]): (Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295]), Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295])), Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925]): (Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848]), Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848])), Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909]): (Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796]), Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796])), Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540]): (Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170]), Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170])), Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214]): (Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448]), Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448])), Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317]): (Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294]), Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294])), Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757]): (Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416]), Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416])), Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378]): (Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091]), Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091])), Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263]): (Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463]), Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463])), Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666]): (Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361]), Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361])), Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174]): (Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992]), Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992])), Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470]): (Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401]), Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401])), Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665]): (Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957]), Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957])), Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262]): (Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144]), Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144])), Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229]): (Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284]), Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284])), Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134]): (Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325]), Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325])), Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855]): (Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765]), Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765])), Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115]): (Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814]), Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814])), Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441]): (Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831]), Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831])), Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977]): (Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446]), Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446])), Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880]): (Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005]), Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005])), Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789]): (Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995]), Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995])), Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000]): (Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267]), Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267])), Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998]): (Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982]), Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982])), Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995]): (Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539]), Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539])), Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507]): (Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512]), Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512])), Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305]): (Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118]), Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118])), Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219]): (Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009]), Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009])), Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416]): (Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089]), Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089])), Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980]): (Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445]), Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445])), Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063]): (Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140]), Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140])), Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713]): (Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159]), Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159])), Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031]): (Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809]), Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809])), Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932]): (Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037]), Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037])), Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094]): (Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925]), Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925])), Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315]): (Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386]), Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386])), Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446]): (Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721]), Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721])), Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742]): (Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981]), Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981])), Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661]): (Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072]), Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072])), Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979]): (Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671]), Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671])), Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361]): (Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269]), Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269])), Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558]): (Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571]), Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571])), Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290]): (Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902]), Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902])), Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987]): (Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741]), Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741])), Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902]): (Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515]), Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515])), Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497]): (Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028]), Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028])), Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948]): (Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709]), Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709])), Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009]): (Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725]), Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725])), Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387]): (Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317]), Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317])), Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159]): (Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808]), Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808])), Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394]): (Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699]), Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699])), Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312]): (Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000]), Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000])), Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987]): (Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821]), Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821])), Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046]): (Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909]), Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909])), Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565]): (Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028]), Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028])), Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269]): (Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352]), Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352])), Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847]): (Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271]), Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271])), Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513]): (Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800]), Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800])), Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054]): (Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394]), Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394])), Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004]): (Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977]), Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977])), Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675]): (Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800]), Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800])), Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692]): (Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159]), Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159])), Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909]): (Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932]), Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932])), Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814]): (Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697]), Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697])), Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186]): (Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387]), Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387])), Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445]): (Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470]), Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470])), Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966]): (Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507]), Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507])), Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548]): (Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253]), Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253])), Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897]): (Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783]), Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783])), Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208]): (Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054]), Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054])), Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268]): (Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661]), Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661])), Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388]): (Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643]), Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643])), Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257]): (Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174]), Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174])), Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960]): (Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241]), Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241])), Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721]): (Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046]), Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046])), Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822]): (Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217]), Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217])), Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253]): (Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697]), Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697])), Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054]): (Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019]), Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019])), Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821]): (Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432]), Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432])), Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864]): (Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105]), Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105])), Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373]): (Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855]), Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855])), Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646]): (Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830]), Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830])), Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460]): (Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208]), Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208])), Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033]): (Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214]), Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214])), Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105]): (Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129]), Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129])), Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281]): (Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909]), Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909])), Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028]): (Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027]), Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027])), Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012]): (Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054]), Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054])), Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562]): (Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589]), Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589])), Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037]): (Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097]), Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097])), Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355]): (Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460]), Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460])), Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223]): (Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355]), Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355])), Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089]): (Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306]), Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306])), Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035]): (Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219]), Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219])), Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432]): (Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297]), Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297])), Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693]): (Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263]), Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263])), Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794]): (Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484]), Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484])), Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552]): (Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941]), Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941])), Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267]): (Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814]), Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814])), Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992]): (Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415]), Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415])), Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941]): (Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966]), Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966])), Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822]): (Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320]), Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320])), Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306]): (Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902]), Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902])), Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820]): (Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880]), Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880])), Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361]): (Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725]), Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725])), Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005]): (Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914]), Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914])), Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783]): (Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781]), Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781])), Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011]): (Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033]), Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033])), Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297]): (Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910]), Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910])), Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070]): (Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134]), Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134])), Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144]): (Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331]), Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331])), Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023]): (Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497]), Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497])), Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103]): (Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540]), Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540])), Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961]): (Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998]), Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998])), Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414]): (Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]), Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]))}, trace_len_summary: TraceLenSummary { main_trace_len: 11, range_trace_len: 39, chiplets_trace_len: ChipletsLengths { hash_chiplet_len: 96, bitwise_chiplet_len: 0, memory_chiplet_len: 0, kernel_rom_len: 0 } } } +ExecutionTrace { main_trace: MainTrace { storage: Parts { core_rm: [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 8296916230783913551, 16462332824047406715, 6884552431231699198, 12264801256605292690, 7532528701100807439, 10480547126759850066, 6097728641437901141, 17248496754222975198, 0, 0, 0, 0, 0, 0, 1, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 11656, 42, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 1, 1, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 2, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 91, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 3, 0, 0, 0, 0, 0, 3, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 4, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 0, 42, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 3, 1, 5, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 1, 1, 1, 8296916230783913551, 16462332824047406715, 6884552431231699198, 12264801256605292690, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 42, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 3, 1, 6, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 41, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 42, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 3, 1, 7, 0, 0, 0, 0, 0, 5, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 42, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 3, 1, 8, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 1, 1, 1, 7532528701100807439, 10480547126759850066, 6097728641437901141, 17248496754222975198, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 9, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 31, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 33, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 39, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 43, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 47, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 50, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 51, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 53, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 54, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 55, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 59, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 60, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 61, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 67, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 69, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 70, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 71, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 72, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 73, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 74, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 75, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 76, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 77, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 78, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 79, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 81, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 82, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 83, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 86, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 87, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 88, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 89, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 90, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 91, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 92, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 93, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 94, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 97, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 98, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 99, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 101, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 102, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 103, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 104, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 105, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 106, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 107, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 108, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 109, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 110, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 111, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 112, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 113, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 114, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 115, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 116, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 117, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 118, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 119, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 120, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 121, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 122, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 123, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 124, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 125, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 126, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 127, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0], chiplets_rm: [1, 1, 0, 0, 8296916230783913551, 16462332824047406715, 6884552431231699198, 12264801256605292690, 7532528701100807439, 10480547126759850066, 6097728641437901141, 17248496754222975198, 0, 87, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 8400310461204590462, 9108169057237353573, 17636133504178290964, 17406877359165992528, 1012686194999500095, 3119571665051516884, 6045109140346221273, 8023007352945590267, 0, 0, 1, 0, 0, 1, 1, 0, 0, 11656, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 8296916230783913551, 16462332824047406715, 6884552431231699198, 12264801256605292690, 18213254076385477335, 9294418641045383238, 8055320100535498720, 11030019888906999906, 1874843776400824061, 12942276814728926620, 15585255994602274508, 16203157087401046215, 0, 0, 1, 0, 0, 1, 1, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 7532528701100807439, 10480547126759850066, 6097728641437901141, 17248496754222975198, 12342802819241620905, 7554371666290801318, 8718773026382250605, 15984482998549000918, 15460443374009848343, 1087146607978023558, 7531163901062156801, 4426949494427873777, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 11621565010787354140, 1949391780818670486, 7327781180606137861, 2419787217529136215, 13249250205018233525, 10029758640146777270, 5716716695107147273, 10829954014693503473, 7405851154679558693, 2030135877513774489, 10401768244118899621, 7992444660002654486, 1, 0, 0, 0, 1, 0, 0, 0, 0, 9190577937819620371, 12978309842325015235, 10477013461463931935, 4855391316239312738, 10519745218266697287, 18375374895419140100, 876067972673449756, 17915370314859305010, 17877705855294641231, 120652674332571204, 3378556434908723888, 17649391022523856338, 1, 0, 0, 0, 1, 0, 0, 0, 0, 15052947986857015373, 3007680259418135415, 3197694984858038551, 6563270153864719814, 6889631464391242687, 12614331779225506253, 8884325160266334095, 15067359903282619456, 6045216153329131722, 7293213550537411486, 18377064823051127268, 14733223614830533518, 1, 0, 0, 0, 1, 0, 1248924765333967865, 15568788993061722932, 4037714036443683170, 2584579945446987950, 3496704858534018972, 10965787981110521559, 9000006360952503550, 8377181923806419223, 18078834148678517323, 13751832434934340803, 15306332964801742551, 828627458527105190, 2519953652271814816, 5563221586835004955, 16428502736240336605, 1, 0, 0, 0, 1, 0, 161503374172189975, 7180975586994120588, 13070121377098205312, 9655464535561865455, 4169214041423852321, 5771090309048429384, 6993654059550252564, 14478380452460405826, 12150434000885474539, 18399347099839405992, 88779829066683150, 4428174353386180423, 7547120791432137516, 11951584238447172023, 8804182506418522715, 1, 0, 0, 0, 1, 0, 1859011259345361207, 13205265558511858864, 16229683663108620000, 17688418164436772208, 12658415008146819428, 6291208835901171779, 3297271436089179933, 12943628284217684119, 11639259038601904106, 10502234848011596680, 13946225273525543944, 11318468498957948083, 13851055481982014034, 5765565570506082255, 10777382518726251007, 1, 0, 0, 0, 1, 0, 1023422172081481959, 14540338366569412926, 10271517463444484758, 8863158288377959817, 9066561794313536160, 10161961919995709177, 2094278659773331823, 4371761587112760854, 10972685992181286814, 5641963675353630718, 15569415989710829261, 4258403342016907208, 4740804749082440837, 1594229550076307598, 5045104152796606559, 1, 0, 0, 0, 1, 0, 12053626300860885956, 13987509258486900924, 17286360383804666298, 8301538772707939488, 7700154594411825373, 14332053735409157564, 6894934729579673545, 5430665485920789830, 10553406992561403551, 11528229548578861261, 3294597468571627674, 2903493961726666462, 10560076388764518443, 3749651622493296975, 18114127684252877364, 1, 0, 0, 0, 1, 0, 12240592655856206466, 6264740020775290721, 859763567572081467, 8842953438422484122, 14329981889510246939, 3582542183068105786, 6023391989510151456, 2953193964713672141, 12396149302348639250, 13882467375549577428, 3586988377712407519, 7213506509798642482, 13435456572406932891, 9645941250097564536, 2781650568775738364, 1, 0, 0, 0, 1, 0, 15637532899188291351, 12683652363890573925, 2704597975013858668, 17832955104866332736, 6815586591600943723, 13755349213265671492, 8924117914024270326, 3329964149511691453, 11039495891702065838, 15670789219464690273, 11281671746346947225, 10492374165392519994, 11439270560757451470, 7337394676363778206, 2272256910055258613, 1, 0, 0, 0, 1, 0, 3130343892077994054, 0, 0, 1136320813223337744, 11438337112810950654, 16692992611178972868, 9482499518540692367, 5451078715157933845, 18403012202839423090, 13340398881404871439, 16853681425214524760, 5540259513623809808, 7754241405876268140, 15538673406175044580, 15705643278636475771, 1, 0, 0, 0, 1, 0, 0, 0, 0, 6593967995490198369, 546795078589070868, 8093299549277945163, 1445098694824947603, 16968796337604054074, 7105604958885889972, 12829574433066656016, 10962264142076089650, 6970346774265824779, 5668604568559492205, 15930738860655806958, 14403244990983785091, 1, 0, 0, 0, 1, 0, 0, 0, 0, 7770193319703938593, 6228225228483877842, 5315425894230577486, 8012448033829391087, 5395398520381640698, 8770911350053719042, 14827874098479004474, 11024999006644848903, 13791657658989935762, 17830220104295996918, 2090812709146185278, 8577173283657139529, 1, 0, 0, 0, 1, 0, 0, 0, 0, 17471481800618265475, 1930822204634793148, 12769804899579893379, 13068810900387198296, 10732524945348487200, 1519317270498249877, 12604995971822921101, 14107509487727911757, 8257552923782319555, 12034059115493819529, 4343039820825149431, 395799121324568963, 1, 0, 0, 0, 1, 0, 0, 0, 0, 7532528701100807439, 10480547126759850066, 6097728641437901141, 17248496754222975198, 12342802819241620905, 7554371666290801318, 8718773026382250605, 15984482998549000918, 15460443374009848343, 1087146607978023558, 7531163901062156801, 4426949494427873777, 1, 0, 0, 0, 1, 0, 0, 0, 0, 11656, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 8259689913693129242, 3400892600405308205, 17378179173256779268, 5060920854688287001, 9687195410980644248, 6313248141024338188, 2582093590609427596, 3953695074988874383, 11971751964106597008, 9907486161844974200, 17989903003960359463, 13336380866068769777, 1, 0, 0, 0, 1, 0, 0, 0, 0, 12279731404675001026, 6278812133505380138, 6233201299601221057, 2388727383803081265, 12084036741190483661, 2317300697897833956, 9759443477696867671, 10883057071610381859, 3944615791382572320, 4072273145811045884, 17852897021998211163, 9684438072608016253, 1, 0, 0, 0, 1, 0, 0, 0, 0, 3651584995004100725, 6423803920838032987, 14027200390009907647, 6592032860050067711, 2594447921553931384, 18306574626058358562, 4512185877168969647, 11342492757671323084, 15957751677575885720, 5761823199659062393, 6846407586191335849, 9817376758188911585, 1, 0, 0, 0, 1, 0, 18183126545069935350, 12563248011457733820, 8356966014032630063, 12041609793392315665, 5281186701877768352, 5541580267076219602, 11576047020972388374, 6661568194349527666, 15437143780340457719, 10754987180927492954, 4211835751645452119, 10566966891469040816, 690793516206281144, 3247962926818069970, 9036036859539968974, 1, 0, 0, 0, 1, 0, 15893445344909186288, 5778049594265975833, 1423581989082731508, 5458007776595562807, 2498425571573111469, 16059466580364398666, 8902716392494711213, 14882573357788460188, 3225597659422237250, 3128065202613218656, 16995684508107895104, 12196793732604029414, 17723663615896720413, 9829416315291197871, 580745865383399340, 1, 0, 0, 0, 1, 0, 13902067347991440733, 5984630683069450754, 12729386174124645267, 13785662250538369696, 272255205933159866, 735616656951483055, 12424664074133983590, 5026981889191825136, 5767485772665833989, 15651669603605283176, 7414308024158917695, 15811954123421478742, 13258769136679205830, 3664463833800174816, 15497592431183820173, 1, 0, 0, 0, 1, 0, 11156605567826983932, 3639316624646464570, 5042698793479444923, 8630374421727305636, 17027951314675117661, 2801906069577385610, 18065291493111457552, 18067767546753643362, 5248148594352695009, 7578134041089558055, 18445498855455618598, 7189106720666328053, 6562930842885656592, 6844922721754111014, 780716667496251522, 1, 0, 0, 0, 1, 0, 11860885490747304346, 12272615266561732125, 10423884872730116228, 13929733142214397431, 2117615618497875527, 5203222542820499724, 4538429948347629507, 6877693664463852318, 18109062185597913481, 10147653053574341319, 10079670109614966266, 12064951107563936135, 1152998120279634164, 12844815835032732057, 12896711460106342356, 1, 0, 0, 0, 1, 0, 3078919787028426439, 15265543379215102231, 570695753264939069, 459110976220447167, 2176716793919417092, 14863591412045443847, 14252826520731507004, 15860274927896899753, 10390267100193539166, 17043032359848981742, 818991875743271755, 16275785202399117535, 8465017515346473513, 2777064625189300576, 13072175816967000886, 1, 0, 0, 0, 1, 0, 3442153457185747577, 2606206929260007126, 2317686975478948049, 15948992202505097484, 5942181083636438599, 15457210791918859006, 887605399554676434, 12986387963278623196, 10075175986843357851, 4859683927561004597, 6555547085880890919, 8280537903442447606, 16640962983997717683, 2248822201261309400, 13163090516020988950, 1, 0, 0, 0, 1, 0, 7196986181046756683, 0, 0, 16549653703171386973, 11518702294444124172, 1109770523953150302, 11415315369035533823, 5890935665450471727, 2253657843173273901, 13858462521885404044, 9125187176834287629, 14925311787915179675, 9356310136195018005, 14965392043314054082, 18423301843359275387, 1, 0, 0, 0, 1, 0, 0, 0, 0, 7040940919216905671, 6187741949018394442, 10532732827118411505, 13505135286384426969, 917467356231706545, 9047752258933341547, 2335143583534705649, 18052717581435745313, 9355624911805935499, 7190586108559742607, 2304843099991312546, 16303126242918615541, 1, 0, 0, 0, 1, 0, 0, 0, 0, 15603840856162477962, 3504063088563989096, 6361775464868278813, 17698044987168049155, 8418309402148081318, 15988177746184666422, 4270534912200806378, 12370149697383197906, 8363034440938926080, 17941258791536373709, 11011611614519090457, 10702921331067290122, 1, 0, 0, 0, 1, 0, 0, 0, 0, 8416267285503610972, 15089551497492948945, 5363802036407642792, 10347532956075658842, 17181858623993805271, 15855824450153307212, 7743632312226714799, 1845073853648620670, 2000026205350826313, 18037231946791138113, 14309912549728703012, 13253445327127715869, 1, 0, 0, 0, 1, 0, 0, 0, 0, 8296916230783913551, 16462332824047406715, 6884552431231699198, 12264801256605292690, 18213254076385477335, 9294418641045383238, 8055320100535498720, 11030019888906999906, 1874843776400824061, 12942276814728926620, 15585255994602274508, 16203157087401046215, 1, 0, 0, 0, 1, 0, 0, 0, 0, 8296916230783913551, 16462332824047406715, 6884552431231699198, 12264801256605292690, 7532528701100807439, 10480547126759850066, 6097728641437901141, 17248496754222975198, 0, 87, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 10686862901019340628, 15711583786595019806, 9378042936835126164, 11939142602264935891, 13605517752371930016, 2544863311362262665, 6880055194706872138, 2404926559643725443, 11298729247352625131, 13639273524510051487, 3031605320954281704, 2952677760580202523, 1, 0, 0, 0, 1, 0, 0, 0, 0, 6949406075980976859, 9142069989509656801, 14676622013796942288, 5295633173573979080, 14862684288436559050, 7708888152496129562, 8667911075542880817, 14424367369474907891, 14303094264982903091, 9838552210955819611, 15088013178433258027, 5833102420062152227, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1932675776657481842, 14290498569500988181, 11741991701671402436, 3934903733189518965, 10047440752038846171, 14938209139342513571, 7659889883493126262, 2134579895120260539, 7819147353957995986, 17861588317805920712, 11020859927535923500, 15623868602690334525, 1, 0, 0, 0, 1, 0, 6264451320029412065, 5315770291001895612, 3923979823614336294, 15496957568148800678, 4856878698798286165, 18427152961697133322, 13172977369565732662, 8634756726478972696, 17549357918509499997, 7356106617646839123, 16192566970100663376, 4904526601366015673, 11478334329288517717, 607398074844683832, 9609971183005491570, 1, 0, 0, 0, 1, 0, 18264070764381924889, 7558994944201947568, 16698567473332535936, 4066201321205995431, 14552036519561423602, 5620710451624899086, 14969463994437329823, 11938508228196027882, 9200118839118887577, 6855444937813269923, 13901427726318773655, 3507966654472722962, 13139165600809348467, 3547085602937656739, 11244050388029555026, 1, 0, 0, 0, 1, 0, 8312328144036608043, 17972686765781519170, 10784039031850599726, 14134435301654782468, 13131877571979284929, 8266221982529104091, 159405248778538274, 5778967389144576888, 6057984302796584762, 11714059928473413141, 11763232719990709154, 7978933720497313146, 16635094485101159936, 18327609188632861057, 11071183167122824035, 1, 0, 0, 0, 1, 0, 10287810620841180003, 4548089904338037398, 6876519236022884332, 192351967064940869, 13616941784242570400, 7032108910940453446, 13625250436816808378, 17491100122417306359, 2292049730346364666, 2733535393252649149, 17750397792987890641, 6346476747248545150, 3575465615474366120, 18213303372206038112, 2518621101786158931, 1, 0, 0, 0, 1, 0, 842637389045220237, 14003171518185218367, 14997648696661468292, 13477259760240789253, 7438659305055821970, 7828458451594639328, 1805142843426507273, 3804729079035423760, 5684604326361654696, 17218885460122549497, 974371611540683935, 16762750120460661174, 739710162320190732, 3363948547922989023, 4267260670759647913, 1, 0, 0, 0, 1, 0, 10264158766070300923, 6050974414693797250, 847386589526447339, 3548106904874618124, 9289172558104066787, 8226909131216769737, 16380713199877477068, 4410762367217395758, 12555768451623030884, 10357980275595284555, 10303991993655092221, 4060030248038493229, 11216725884924445657, 10194932652661424405, 17494422570060569743, 1, 0, 0, 0, 1, 0, 522514578171525652, 3717501858890221638, 16025700499781393088, 15033579247524264929, 1744414008664189122, 6807378681147180078, 16955668219975052585, 18323017022834713256, 6662618285165080179, 12762215046608848013, 17134633855452090590, 6353725621416552612, 4449259194945598867, 8877290555352616803, 13666098560811114332, 1, 0, 0, 0, 1, 0, 3232143389630708424, 0, 0, 9014593992030055460, 10869121640834977224, 1905700011211118876, 955944440419378960, 265206078841667899, 13713964984862746492, 9702435518807270681, 12343078651970579400, 18227529633908655074, 9709048888339027683, 15154974039676851951, 16388400023664675593, 1, 0, 0, 0, 1, 0, 0, 0, 0, 12342730708987043912, 13274159397630057441, 12697978258400128397, 368152630932848211, 6555819701154221199, 97417680512067538, 2018507387878521400, 1529782995014995301, 13636792419679998309, 6197980968820055410, 737644335551408580, 9956102600220791675, 1, 0, 0, 0, 1, 0, 0, 0, 0, 14179025343931559433, 1175312715506728066, 11255361077722267605, 9822732455439796133, 13335036252549184126, 17127037879360292568, 16600677125340288437, 11659800847392950623, 12605660248276552114, 14805446144065764307, 14804045017754446897, 13192632014186378484, 1, 0, 0, 0, 1, 0, 0, 0, 0, 12383461936126681247, 745215043874424896, 4540981537676651137, 16486351305638014506, 10972364256824969372, 5647748125744546841, 5620391031839475969, 17973620544670757805, 1344519641939806437, 11395404185290209616, 4498705163534372313, 3336623779264323323, 1, 0, 0, 0, 1, 0, 0, 0, 0, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 8400310461204590462, 9108169057237353573, 17636133504178290964, 17406877359165992528, 1012686194999500095, 3119571665051516884, 6045109140346221273, 8023007352945590267, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], range_checker_cols: [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2187, 4374, 6561, 8748, 10935, 13122, 15309, 17496, 19683, 21870, 24057, 26244, 28431, 30618, 32805, 34992, 37179, 39366, 41553, 43740, 45927, 48114, 50301, 52488, 54675, 56862, 59049, 61236, 63423, 64152, 64881, 65124, 65367, 65448, 65529, 65532, 65535, 65535]], num_rows: 128 }, last_program_row: RowIndex(10) }, program_info: ProgramInfo { program_hash: Word([11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518]), kernel: Kernel([]) }, stack_outputs: StackOutputs { elements: [2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, precompile_requests: [], final_precompile_transcript: PrecompileTranscript { state: Word([0, 0, 0, 0]) }, trace_len_summary: TraceLenSummary { main_trace_len: 11, range_trace_len: 39, chiplets_trace_len: ChipletsLengths { hash_chiplet_len: 64, bitwise_chiplet_len: 0, memory_chiplet_len: 0, ace_chiplet_len: 0, kernel_rom_len: 0 } } } diff --git a/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_19.snap b/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_19.snap index a5f0d94b28..db50a4f102 100644 --- a/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_19.snap +++ b/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_19.snap @@ -2,4 +2,4 @@ source: processor/src/trace/parallel/tests.rs expression: DeterministicTrace(&trace_from_fragments) --- -ExecutionTrace { main_trace: MainTrace { columns: ColMatrix { columns: [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 33, 33, 33, 33, 1, 65, 65, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [11182969138190702361, 11656, 91, 0, 0, 11182969138190702361, 41, 0, 11006573531383828351, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010, 8269653645296248010], [1109628455053940361, 42, 1, 1, 1, 1109628455053940361, 0, 1, 10983413158656624898, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331, 997682303299740331], [13928676565061410159, 0, 0, 0, 0, 13928676565061410159, 0, 0, 4869282124135316831, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319, 12907160815575155319], [297470094449022674, 0, 0, 0, 0, 297470094449022674, 0, 0, 5899798166361732461, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694, 18024383338294781694], [11006573531383828351, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [10983413158656624898, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [4869282124135316831, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [5899798166361732461, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 2, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 2, 42, 42, 42, 42, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2], [2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [3, 3, 3, 3, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3], [0, 0, 0, 0, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [16, 16, 16, 16, 17, 17, 17, 17, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16], [0, 0, 0, 0, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2187, 4374, 6561, 8748, 10935, 13122, 15309, 17496, 19683, 21870, 24057, 26244, 28431, 30618, 32805, 34992, 37179, 39366, 41553, 43740, 45927, 48114, 50301, 52488, 54675, 56862, 59049, 61236, 63423, 64152, 64881, 65124, 65367, 65448, 65529, 65532, 65535, 65535], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [11182969138190702361, 16344194729581826754, 15045917672181612303, 3672327111134984977, 11902001817992340801, 97480563262877602, 1831626543952762702, 12062163654685913941, 1451330498122947575, 1742063333427513989, 2331114102915733339, 8550984974115591347, 8960841496031156142, 13720918668577423004, 5779906183691085674, 3198599991840782485, 13728843979899181292, 7239115491427587826, 12128894594351473931, 15480692841914867508, 8817470180767843173, 10548371713427919789, 10315264763691724912, 1023167627240586914, 3818953450339058320, 14941570263133670432, 12615841091071546269, 15435370781163068976, 15373572920503822367, 11769995123877236600, 3762647969008011219, 8269653645296248010, 11656, 117148, 6714198787893475936, 5262284953624879131, 6828048997998717653, 14647846255598321281, 12213957512096072087, 15486993862206988880, 9916068016290756984, 12311676223031039230, 6798558233575208094, 6061515485015027193, 9178825932447902299, 16451694760407086053, 9245574117575493602, 6706571375738621744, 5707941763645196550, 13553995817865937844, 18312867062271325792, 11246612591729350508, 8806896510487478352, 16014621579841168337, 6332183310159529150, 2444726075814550534, 13415483499482541228, 16602291456530418215, 3069389264726801426, 4940323642218861897, 3979217445866956620, 6693606464693965975, 9525288177353527302, 11182969138190702361, 41, 410, 8488924048752676071, 5473488137200086909, 16124688533662466636, 4527044298581192722, 16887055178922689595, 5249711198271717177, 15470787238396171217, 5632634005697013617, 7337408598993184022, 11147561538212402733, 9710911023591971572, 8752830793140649116, 11546140485006286209, 10738951369466640003, 2139663271495255306, 6135983205453599776, 17538856881976830392, 2031516987289365197, 17199894398730562705, 4010699482290892787, 3922552954514582360, 7369439734883755459, 108303794773646012, 14521269346803535153, 14515762120928230173, 13893962684375637966, 13610167819530098127, 11215445033353754262, 8081237365032914784, 11006573531383828351, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1109628455053940361, 12119768350776285319, 8184561966951183876, 12431805880114311043, 2986356007899077631, 2836244341662188919, 146796491816379180, 8696360259937422388, 13878284404078727054, 7667548888861073206, 9741377056638459459, 11905155073870025459, 9736056580211703764, 17352787150580200349, 5883496260565631343, 9594088066979877926, 9297041447863221537, 6214639496702145664, 2461170076272033096, 17112913798212225634, 1035954869286151888, 2140568550425483844, 10584986198873793665, 12555736327846716176, 12072441430913369009, 13906015856663078107, 14389918991418187594, 2676571742010508284, 5150637797762075635, 11237118474907085960, 11752652705714102353, 997682303299740331, 42, 93752, 18084035356118526352, 8386870944408484201, 18056918720989013854, 11520229540186073721, 5668756658695595711, 14109792997657353922, 12303762929371991135, 14460911410586037148, 12418445481638740107, 16455507557982986163, 18172284878038222122, 6352198309363971688, 9198509167958908347, 1068046269761257463, 16102483860755268671, 1544674922431042375, 9868836391822552540, 7915117918356788325, 6533551228799195237, 3992189811639127908, 9511948951280762358, 13039263708530965818, 708611914251242147, 4206064101444952505, 17714998603219848343, 13074430791784659712, 14102459334756352921, 13661835471193379756, 3038016940647586670, 1109628455053940361, 0, 328, 7132218559010351790, 2687466917280430353, 14170238607512888511, 5453168895411602323, 8679138582261878552, 10871515559850126217, 7649138216344653830, 12086029516113687059, 14609582285822867389, 7271583017513514692, 3821121937809044409, 3833100151978191712, 5702916883024911354, 3579138882391492892, 14347405124134927123, 9277341930384005575, 2993137622300793545, 13370802209879109056, 13653108884642243926, 8702782587703766612, 12945832125614510830, 15167316901472929028, 4608694219239856197, 4443739924303229750, 8611475648437961511, 1575864515244779062, 10900065459953722709, 9162692523043045302, 17462008412377898139, 10983413158656624898, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [13928676565061410159, 5375705730949115787, 1314981229280595867, 1393532256400242982, 13433705342207763738, 12880831435259048250, 10699055768478348083, 2470044642731141974, 13732313223959877570, 2078090264025450769, 3845297826200108779, 15581584642080412492, 11359623335937034504, 14549946302435322871, 17424758021352066268, 15472130290487345321, 13048555428151627244, 13747770174448213841, 9164669383091055648, 3250455247796114093, 10799815877710934765, 9086202890994770785, 12116339825079888992, 1619117325320043308, 16898959203497269575, 15756045849228969140, 6190024525131486611, 6215657966742979785, 17671950935398765622, 15303512720733905693, 10727837149375754730, 12907160815575155319, 0, 23564, 4199576522683349447, 16513391592299529611, 11415640949254272304, 16138036929710694921, 9992494271122179933, 3020772293084222765, 15625472986208536177, 12149624601412828429, 10735117276139490774, 13332197512776217968, 13474689739491604605, 13815225937039366706, 706573335075180235, 4097091053989040149, 693823183101411164, 5341110475237803180, 4368449439175744649, 7740607367180462177, 13389502447794973829, 6721164191334334250, 6997451158266748059, 9767862146044075473, 4778055569341029558, 10088175016132507812, 3285997397792070136, 10914182999248450193, 14473951691792990803, 8827937223658185560, 9698676695870635420, 13928676565061410159, 0, 82, 18152833202936203138, 10305147718805144715, 13246631902503555591, 18142351346900318359, 11971140429919100117, 6903484634638418138, 3098698980745497723, 3068992673894668202, 9164459936648953977, 11194864417357882388, 12005359455571366116, 12356306486226268709, 10059737158050223658, 17119982236602677307, 4225663824996553892, 17852936504841763737, 5778553506856942969, 9045001363359345866, 18423338781077887809, 2711240319770097821, 8346149567490270428, 9594540064387516595, 1859863665658604717, 16919987197409252682, 7809934763889573038, 12492597695329698922, 18341122838405415754, 11967784234256998242, 10761804868734649587, 4869282124135316831, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [297470094449022674, 13535968261560526699, 10051713503687926694, 5258910437097366761, 14031537229609682064, 18190284629542346231, 4346004165604875907, 15375947702712472554, 4019409425675168575, 2064296209102051574, 17718639079388526425, 16642022229570326204, 1618478323171655450, 5998884876319667302, 6872649224968331273, 13753905356607269997, 7559241041198219519, 8363779881416372286, 2105649450986611656, 11644599807961994770, 12949568200151355456, 4366812189797744262, 9669235379242805159, 18184433440084438609, 13914998044815764482, 11325806379320193213, 1586181560816232196, 5920020313630770955, 8020025137186066841, 13419225700498867773, 13671651770198504476, 18024383338294781694, 0, 23396, 7560057297276955988, 7451013195867945919, 7468487593070852196, 5578183109591783882, 15747662796636990589, 2066701485189878406, 17025371161980089605, 4391959764977446152, 4985867595251695917, 6710066216774366729, 6241000701339836952, 4718440141936325382, 4986060230214018536, 5748634601882563491, 10896228304766504283, 6457499153671182820, 12270042173384394159, 11711065129605555908, 15065279868519608165, 17856220227797901726, 8953039722587792244, 16994104539161729445, 14670768895096516686, 14803898243742553487, 2327203233976270205, 17449705512918939747, 8253253226048886083, 11671578295265948239, 14297456315487806992, 297470094449022674, 0, 82, 302695496926486902, 16415403596737407938, 12969246825596557956, 15965643470182086386, 14881573336337548597, 2868629484750761697, 7317402970608805914, 2570537868338555591, 6697005353407257884, 5717939852331496040, 9408357527608003903, 8011884131194179594, 15942512744234440774, 9052662470595673790, 11913271961595885333, 15508051727969296111, 6269710669185644103, 12322255659000247132, 810875278274469351, 3499523055983644139, 9453749819048496107, 598273005722510655, 12338854942180141395, 2829445891916136836, 12653867244112536729, 4648827005364006908, 3153753366153954420, 12197142511433562971, 13557680898519201450, 5899798166361732461, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [11006573531383828351, 92579048505362891, 10772660272533654046, 3331697170176629084, 602109730184155310, 16230148280330706633, 6302091831624975391, 14001078336639287767, 14888577262766439787, 12258632680483319887, 7641862043593808385, 4740702640077452126, 8494032654039797119, 8314420015254970480, 18294822284401514132, 15552480182219334239, 908821363395967579, 18258193129875665644, 4226365574585037317, 3638253471537757569, 17581484848263912285, 6286301305761091621, 4777175749672661669, 10658559677463134471, 1417442037893012894, 7857622794514614671, 1052908464763109826, 4925127753504389599, 4274762298296320367, 7383511416371792464, 17305170235876004791, 2200823396264285425, 0, 58574, 18280076181055982575, 3965010120048981150, 1623299660155787797, 11930292174601709627, 17275008438838615802, 5756406115988630048, 17841510847136093686, 6729021181420822547, 1709787776185889305, 2022739540363098314, 5157634830695555269, 17099057016182449505, 4092740078069974091, 9582547144648304801, 4715310719341519129, 1597700055042697404, 480964694484615271, 56280064407246395, 10536769335197150641, 16099710145374622840, 3473101726323291593, 3295906456874767760, 716460020344690975, 10580825486552151036, 4976836170739997781, 16652319776094256449, 12319687016213027555, 13490282225851742651, 3371801902832234206, 3795543859124105201, 0, 205, 13622702382434675698, 8941567408770445183, 2168342371250989865, 17553704974699598306, 12818882650622055705, 16478401302589696546, 10652219805906948351, 13167156861512034068, 260666911081589986, 1428764500637505382, 2190433219200603887, 11999917547751101526, 2751093334206085539, 9318931023569054874, 16297727142514657495, 11875658036026604145, 5829323963705819601, 407792022339954638, 5684565403642367050, 13995368600016681288, 2845800306757116207, 5216498913603536417, 2411940295743487842, 2014066638340124975, 5258230180909223265, 17089893338044941808, 1124366766375746940, 9116801986360376826, 6650575029061305823, 4025036448660092914, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [10983413158656624898, 11859595567907759997, 10088766553729725414, 12574093635772317570, 5470069473511751658, 9645793732101008923, 1476556243604239385, 17933040757673393353, 7118521641278947238, 7588084371428510216, 12191494749556797391, 8228232126921631746, 15226641263820888277, 4239012011479875368, 14018593041447406970, 3541695062587160892, 11116896887234129281, 3929539690735302143, 11203930352796078636, 8751959587369085991, 12655249523595546680, 16379258612200834026, 9984807922535170831, 9638171237357393134, 12191893464144837018, 4677785078090407332, 8064604530099592479, 10076433135196495423, 544627542347870852, 11879905738846635842, 5683487714952213815, 8088984326603898052, 0, 46876, 15125170292333450443, 7072657932567702059, 10475291980250876467, 14632109792663117375, 18379882203306053694, 10250239327737538260, 11537033439839832588, 15180883293806522386, 18285674122603938406, 16116176887352657770, 15068074760365493774, 10507624248254584461, 7669544778380245671, 16424767991328560142, 16771797144770177609, 4105927596877687309, 7519344916607985067, 16277772212475505196, 1322695487397776109, 8302446182097155523, 14744324883381489574, 16338446684875281086, 5703860549203085948, 14077533030564871132, 12287193162084105824, 2535384450001991464, 13089916287630526229, 1568845385281768860, 982340402770608276, 12910581729787565904, 0, 164, 6093021124582015914, 375332441348258328, 16597900739273350797, 16788616498952461620, 10323894478242846558, 3730474644926313294, 17377183878976452334, 12746711269593150718, 13699107349734059694, 421533440407219618, 15109303318896079214, 17746438429032263850, 13224617406323308041, 5646455969610140563, 12626985742338481481, 14497665384991648640, 13894375308737560134, 3268393834564630675, 13312171511942754529, 611321250913478210, 12048873764879264902, 5334026694118161468, 14360341460112568406, 17654490467796517057, 1299716947845207044, 7609683397541157642, 14709808073905360012, 11742139955633481423, 13522070698443062110, 12847434483856017691, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [4869282124135316831, 10293244464294212936, 8691876854061179148, 2952350747126730564, 7968203687716298290, 6747517476428823928, 16731591574836256879, 12286682322909052293, 5699380547329532508, 8774011841981167612, 10988677337017809219, 6257583805205658612, 8595550098696265772, 17321901905145630028, 3295089823193122164, 6581488060195755410, 6329516418872359771, 7640632346113799527, 10454000694343684461, 15867346750604392587, 5805413556949044653, 9247297947852762648, 13748015074908171216, 13312272456227001370, 5054807356361880835, 1012271632864570722, 11252467974344770686, 492886975717156403, 2629112354487966090, 10128035487146424848, 18233951381382816412, 1751709948898726303, 0, 11782, 6055246182589913733, 15015595405278911690, 2209046468675768902, 16429197663637467330, 15810134098389081544, 9588791733994120847, 18370261572729563296, 7006788971063612777, 7962515674056117045, 15223121510830934757, 15872454912771340895, 1486059252283823706, 3912605942422700262, 4173681472723400357, 2922691200579275072, 7112424425452913463, 17213377378328786151, 6274713241106982122, 15112974401160243995, 17175975930045398893, 5467280291812001242, 5238070817263862176, 17584445990298638069, 171514605620090783, 4267926381848052110, 9011064139813451706, 17044511642202081265, 17370313250110904770, 13397257034080852565, 17596568325206204932, 0, 41, 9617260353707541367, 9187825164453421957, 17649953659489375797, 6396310504287885774, 17019569090864760371, 870218876784769460, 17213560015461715510, 16812494438448165271, 15885717661613279263, 2958950328581697287, 14311601477626423214, 12599125587081655507, 12078599565132475515, 3332808335850364509, 374688056722968094, 5591521890390007231, 9584980789501913045, 4066644474875437132, 17728945623551220217, 1158050506628066296, 3730734784735709807, 10671987699715228843, 3173999018565335463, 14949604462817069254, 11653871972148380806, 312408327658285690, 8531928004921347162, 98858158429688394, 6167334615107562354, 1234843923022284190, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [5899798166361732461, 2163003956713638315, 5989289390391757114, 15670015339098587014, 12708827926449341197, 10159927950043513901, 15395056832871965886, 17405960500607097380, 9229756563573051371, 1186079292937331145, 13463816706671585562, 10107168241231917326, 8534001612601599401, 12790948878158723266, 12619661555644649350, 11614101867080583800, 11255619179741810030, 10501448523390229441, 16971746085380600175, 7173352752193758542, 9960833320626690499, 3507659370538431093, 6846598866105961944, 2557094292829749679, 11416743759689580593, 12182449258645699464, 11951277814213817673, 10567677969346318078, 13884819925875295975, 1926379571595510347, 5918588896905128530, 3405979658670756574, 0, 11698, 8146055133796963630, 4724864404296433607, 10453305271538430204, 17141108237620938331, 16113292978122689735, 14630852758047225712, 16936235645680974811, 640959767495035790, 11162248672474783185, 10618808740372936561, 12973220127719589473, 13223353016814262874, 17652411276563186968, 10141330567980253051, 1770876161367154023, 12442058685904907795, 12986633647641209886, 5384244903407669612, 14778499304685795812, 8054814913234770610, 8358166993767322841, 11933451322373121057, 17795028935448509068, 11142588879850986282, 873880226830208445, 11017896854604878841, 6896812394605202475, 2024842447089060639, 16625734836325714912, 12512094004962322130, 0, 41, 12529483521877137515, 4671467226762388980, 13873740979092621907, 12847173262736205772, 2640423636460273022, 8374058502362870155, 7630996533587302384, 3556075572123538464, 8078558398785937163, 5856098383496092000, 7999607615804135893, 15509992149354799776, 13785560116650003734, 8358196300413379173, 10412508239405514928, 7840142081125036731, 18075062342410207477, 18173191150607640442, 2133036585496843963, 8931901040624025193, 9454731621283026961, 5837806564591410604, 5850596656185029719, 296117354535505751, 8985195681813998404, 1975947551471322175, 12041110943945791333, 11648250496545232642, 7830634726555216225, 5266777994490151623, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 11627839282500592134, 3407397722647202213, 13644814392425193274, 9689174787852538317, 15759480978611340324, 10073546228149283602, 8090878949578096073, 1502926046713635634, 7624167193861818791, 10274257988202953339, 4186763142475177793, 6025425965090069083, 8194342163688078130, 13163397875087894329, 5161390927343581791, 10103251159424454395, 575959985319833606, 13175926157437524595, 8928028362497258488, 8665485641724560922, 15570929820685955587, 6150675652390666890, 6384512333148749163, 35921027791486524, 3229184449291625000, 7414754653220847914, 11347301099028602515, 8368586536930615942, 10138228048917253579, 344980745193352015, 5644431973654019812, 0, 58574, 12761879591277148733, 3794756304714494565, 10919382803049057886, 13927811434585922718, 8315847055470475708, 10095847089706649983, 41153506376499461, 5529807447506440005, 72892344713547594, 18362204307013225363, 527610602670466995, 14772158556567070690, 9538491437159792328, 1580498045195806896, 8297535568256810268, 13797917351588149895, 1651894826575892086, 13380716913143325871, 2655893075036451977, 3750342908258071259, 18231595474498119868, 18163310674975357977, 2371603174180061555, 6433509503768865899, 5002589281792664271, 10946433388588585987, 9256382872640968643, 6570002101874463971, 3849537215181896567, 5735281858523620986, 0, 205, 7876112718273244024, 1276143811675585923, 9993912342918529935, 16999254614849428545, 8194747920293058753, 11171758628037424552, 8208119826419095432, 5568149314099479773, 17551537772960996556, 12651683228606533001, 13584145944854843210, 12212300608708011466, 18102951610480561318, 14720258372954226591, 15448472262117068008, 10575290756167155008, 11997391634424499349, 9879556170680135793, 12373753045781314057, 9529470285212177396, 10620662102176580756, 10199402949196411787, 9825825353570660203, 18337390924518345383, 15945306792731206141, 10537181099344133724, 5505106000120813030, 14774803975376978777, 14575654492591748955, 8207377881872409730, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [87, 1844206616423154361, 7941852203687681180, 2987825311454433607, 185071303888742221, 16140725249773135932, 13486449309893009073, 13471170357015645210, 11073859438158044651, 16507211018434913458, 4066228076398875428, 16536071023746429034, 10818247459046542341, 4392853051950044706, 12116759677655250999, 17293580330275603290, 2376540144284705519, 8057038266027202789, 15097730100005395027, 3583575859544955648, 11146351406925299070, 13473187462927502829, 8056538798141691018, 13509558775822115028, 6797301950091310335, 8773981691004278165, 4751058192101309365, 10661116978196100999, 15345629614104209519, 1689963602473071179, 12869561156624962469, 12554030503530361323, 0, 46876, 4789346784708035796, 9438751512570250357, 447952077691938652, 6351356675900770483, 4868676530510485341, 3192437812250556397, 11511034416225137032, 15380266628173325649, 10700144984876703355, 12230522212327928379, 15526804358639727019, 6410705682507666807, 15728916292645010880, 13992590038292222154, 1916422775943772979, 8280685582260709248, 12515254706968408232, 4845996266408136556, 15172713941042952680, 2233761585242005099, 13227100893355110663, 3914062371738178895, 7843298541359739176, 8386193964610423744, 8614894336467293783, 8834991867772635266, 14221135810103683560, 11406071542091908609, 571586377235018247, 3013510715159483905, 0, 164, 14482187202392982684, 17682350329754313417, 66214439016909251, 7504629639084879386, 11708178258767948919, 188011405648496761, 10242982970375452289, 16510140404231294235, 13381084464566932690, 9239012175869487665, 9339694231140180875, 9917181315244873380, 17448534469581521177, 4965043893766771965, 13305445405772227224, 6963375374275021656, 4554518835153561582, 1694446457415578298, 4604616361036784646, 11439774970058559661, 10784225701912607868, 17782855612978839775, 13368223431578003475, 18100595786373494652, 12753204151452870283, 17504098334052422651, 12896535568794110034, 7402084190222773115, 598469278842686486, 5912604878679295331, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 11371898088219304696, 4199208231896291776, 6349271639347163621, 5568595648257864309, 10224931331962954075, 8046167029187450402, 6585148777263545478, 3706462809677116963, 12578093594063946501, 11334181120248394313, 4953509182438845792, 4130560513564095433, 6665409895959715593, 12872180446847298231, 11452171012153290342, 5729159829892489539, 5675564903335979949, 14158677720471443076, 12300968791182495713, 13879671978791253311, 14820104759072107152, 17585955671327967478, 6737505022417937354, 17454985371239394211, 15749874646256262769, 10017226585432634212, 8893160827421013787, 11893931769684808775, 16471875099240353401, 9975926385796085953, 11231727832144176264, 0, 11782, 6351111885067026894, 14086295994708840477, 3142920623105062021, 4317195510637014184, 16341148873550430347, 8014762585425506108, 12977978004680762325, 15318810920503136316, 9472517513827583818, 211962335804367550, 14931353145911604525, 9340212215573419915, 5244269534978718672, 1584128384101705476, 4460891295949496863, 14654598206063183317, 13555452196222133132, 17680908597379218579, 13178742765486355260, 3964993209073179108, 4213917162333386044, 2639949635019592417, 3300803743280888923, 12914222891103397086, 13436383826829479040, 7004576641630317963, 12080155723705641895, 6767987840126452263, 14392317091133450653, 7390177608867021213, 0, 41, 3800418813655617572, 14503408479575576010, 10553169970007645345, 4946745422622378051, 7127828976000219721, 2687285609278369395, 16630221959750548176, 1114885198959805561, 3895092647933222339, 9831397389014117600, 12816842684293233323, 1779119880742935864, 17663607747965229138, 5382558247959552902, 11972955750871888364, 16616426694032134438, 9711126273890628516, 376576173107709408, 12451218545182255865, 14301764572821220192, 13209253693600827240, 5745169166190656073, 12916752429524642864, 14463770325561420619, 7870235520772452232, 13278341252249613603, 5432056100901092307, 8994645443800925562, 5908996313982662075, 1494658977663487041, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 17530820119034444668, 15233230393479930649, 15702789941308523576, 8819781861782654629, 7112644758334533508, 2549387492966523460, 15838339720324898846, 10242380937000070843, 1124701407395854549, 5706112669062280829, 17015988684670402201, 12671109438456697877, 15652595419009785355, 10753966634497852319, 3622124053041186910, 2063695485301676711, 17845322355197915738, 9894091605930112348, 10822348040176532279, 9689802115657313068, 6759722828145755337, 9479044480226984785, 7845909286502989649, 560081323074218824, 16017591174163981005, 1196237303718990885, 6783304352365897531, 5064625229425039166, 12661189034561966549, 11511655067934063768, 11479359825177848513, 0, 11698, 2084118884093035279, 16979859941949546961, 1454299506056429821, 9658643065222637557, 11605485146349749283, 13057696629474024230, 16650374201325163722, 7457309320444728046, 1243843599995756274, 17176177262691414244, 14152683925184093692, 198845790532099135, 442435874165139119, 1462611314767788334, 3462067515008653152, 4141759445261917472, 12323330957750482072, 14922731139272985797, 10387565380055278256, 9531386257124273696, 9539285450074189441, 3691450672437772660, 12463184698711878632, 4858502687517999226, 12256855995572753726, 9245347314341240247, 7569214225554358494, 1017686422583121037, 10327407591150878848, 15025446886891081073, 0, 41, 13092032916490151270, 2856458557507854671, 14059661153766146178, 1724041303048776424, 7119687853704366589, 3699246950542313036, 8338994289155538949, 7732171807197958061, 10653644351656999339, 15262849800927670044, 6132373490633371091, 16473831322001214578, 12928938600331453669, 6959935525856744214, 17173069020016176920, 6747622983845354522, 2484033613426731933, 9879916419081378373, 4275250202523893223, 5995505684018086986, 16115855409799741127, 2490003355474156145, 10034475279304353355, 7223217715426381376, 10334063888823214988, 2139000562522371457, 18314119367638727156, 15311716904301189063, 894706229073498557, 1570146104298050273, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] }, last_program_row: RowIndex(10) }, program_info: ProgramInfo { program_hash: Word([8269653645296248010, 997682303299740331, 12907160815575155319, 18024383338294781694]), kernel: Kernel([]) }, stack_outputs: StackOutputs { elements: [2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, merkle_store_nodes: {Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571]): (Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350]), Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350])), Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484]): (Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693]), Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693])), Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781]): (Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874]), Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874])), Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171]): (Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361]), Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361])), Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815]): (Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305]), Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305])), Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689]): (Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195]), Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195])), Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362]): (Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063]), Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063])), Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848]): (Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661]), Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661])), Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352]): (Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829]), Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829])), Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444]): (Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223]), Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223])), Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386]): (Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388]), Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388])), Word([13190842942618341421, 17548956981569849952, 15418963848144418856, 730733050713174879]): (Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144]), Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144])), Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874]): (Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675]), Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675])), Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594]): (Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115]), Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115])), Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809]): (Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257]), Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257])), Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777]): (Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555]), Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555])), Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509]): (Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882]), Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882])), Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725]): (Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979]), Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979])), Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134]): (Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987]), Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987])), Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828]): (Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910]), Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910])), Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830]): (Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054]), Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054])), Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228]): (Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742]), Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742])), Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443]): (Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928]), Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928])), Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643]): (Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979]), Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979])), Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758]): (Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106]), Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106])), Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580]): (Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594]), Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594])), Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765]): (Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045]), Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045])), Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766]): (Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281]), Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281])), Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385]): (Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828]), Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828])), Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579]): (Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171]), Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171])), Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212]): (Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992]), Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992])), Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463]): (Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004]), Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004])), Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502]): (Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023]), Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023])), Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539]): (Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537]), Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537])), Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865]): (Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225]), Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225])), Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690]): (Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947]), Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947])), Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202]): (Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552]), Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552])), Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079]): (Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444]), Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444])), Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850]): (Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548]), Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548])), Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448]): (Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987]), Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987])), Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041]): (Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035]), Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035])), Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301]): (Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414]), Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414])), Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414]): (Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212]), Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212])), Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703]): (Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439]), Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439])), Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271]): (Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955]), Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955])), Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882]): (Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802]), Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802])), Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152]): (Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887]), Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887])), Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028]): (Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948]), Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948])), Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331]): (Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093]), Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093])), Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394]): (Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134]), Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134])), Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546]): (Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228]), Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228])), Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620]): (Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414]), Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414])), Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800]): (Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703]), Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703])), Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671]): (Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205]), Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205])), Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537]): (Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011]), Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011])), Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516]): (Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301]), Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301])), Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831]): (Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986]), Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986])), Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415]): (Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057]), Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057])), Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722]): (Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689]), Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689])), Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144]): (Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682]), Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682])), Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295]): (Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268]), Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268])), Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818]): (Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513]), Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513])), Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241]): (Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565]), Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565])), Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439]): (Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012]), Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012])), Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512]): (Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850]), Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850])), Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986]): (Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865]), Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865])), Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982]): (Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777]), Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777])), Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808]): (Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394]), Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394])), Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979]): (Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690]), Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690])), Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093]): (Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620]), Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620])), Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902]): (Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789]), Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789])), Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542]): (Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094]), Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094])), Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057]): (Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362]), Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362])), Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205]): (Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961]), Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961])), Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401]): (Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580]), Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580])), Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553]): (Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960]), Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960])), Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169]): (Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031]), Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031])), Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682]): (Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053]), Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053])), Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118]): (Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562]), Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562])), Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725]): (Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666]), Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666])), Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661]): (Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897]), Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897])), Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981]): (Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447]), Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447])), Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072]): (Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646]), Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646])), Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140]): (Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404]), Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404])), Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515]): (Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152]), Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152])), Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709]): (Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664]), Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664])), Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800]): (Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103]), Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103])), Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741]): (Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169]), Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169])), Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005]): (Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758]), Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758])), Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802]): (Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070]), Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070])), Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159]): (Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005]), Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005])), Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350]): (Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443]), Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443])), Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697]): (Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573]), Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573])), Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928]): (Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331]), Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331])), Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320]): (Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166]), Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166])), Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814]): (Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079]), Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079])), Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447]): (Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820]), Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820])), Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284]): (Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057]), Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057])), Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697]): (Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131]), Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131])), Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955]): (Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290]), Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290])), Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910]): (Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202]), Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202])), Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910]): (Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822]), Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822])), Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106]): (Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847]), Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847])), Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404]): (Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441]), Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441])), Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796]): (Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186]), Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186])), Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053]): (Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516]), Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516])), Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992]): (Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818]), Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818])), Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957]): (Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315]), Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315])), Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709]): (Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794]), Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794])), Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091]): (Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539]), Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539])), Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664]): (Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558]), Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558])), Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294]): (Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579]), Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579])), Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947]): (Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502]), Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502])), Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829]): (Word([0, 0, 0, 0]), Word([0, 0, 0, 0])), Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045]): (Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137]), Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137])), Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914]): (Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041]), Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041])), Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573]): (Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378]), Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378])), Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699]): (Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873]), Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873])), Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225]): (Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262]), Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262])), Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057]): (Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692]), Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692])), Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131]): (Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997]), Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997])), Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555]): (Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385]), Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385])), Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195]): (Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709]), Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709])), Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166]): (Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542]), Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542])), Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027]): (Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373]), Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373])), Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378]): (Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509]), Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509])), Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097]): (Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553]), Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553])), Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217]): (Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815]), Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815])), Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873]): (Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864]), Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864])), Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997]): (Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722]), Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722])), Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887]): (Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766]), Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766])), Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589]): (Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757]), Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757])), Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539]): (Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665]), Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665])), Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129]): (Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229]), Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229])), Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137]): (Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312]), Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312])), Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019]): (Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378]), Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378])), Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331]): (Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713]), Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713])), Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]): (Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980]), Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980])), Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325]): (Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546]), Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546])), Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170]): (Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822]), Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822])), Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054]): (Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295]), Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295])), Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925]): (Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848]), Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848])), Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909]): (Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796]), Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796])), Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540]): (Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170]), Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170])), Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214]): (Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448]), Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448])), Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317]): (Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294]), Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294])), Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757]): (Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416]), Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416])), Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378]): (Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091]), Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091])), Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263]): (Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463]), Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463])), Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666]): (Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361]), Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361])), Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174]): (Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992]), Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992])), Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470]): (Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401]), Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401])), Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665]): (Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957]), Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957])), Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262]): (Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144]), Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144])), Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229]): (Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284]), Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284])), Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134]): (Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325]), Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325])), Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855]): (Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765]), Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765])), Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115]): (Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814]), Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814])), Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441]): (Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831]), Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831])), Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977]): (Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446]), Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446])), Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880]): (Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005]), Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005])), Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789]): (Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995]), Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995])), Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000]): (Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267]), Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267])), Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998]): (Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982]), Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982])), Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995]): (Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539]), Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539])), Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507]): (Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512]), Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512])), Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305]): (Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118]), Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118])), Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219]): (Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009]), Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009])), Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416]): (Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089]), Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089])), Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980]): (Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445]), Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445])), Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063]): (Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140]), Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140])), Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713]): (Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159]), Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159])), Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031]): (Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809]), Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809])), Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932]): (Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037]), Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037])), Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094]): (Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925]), Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925])), Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315]): (Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386]), Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386])), Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446]): (Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721]), Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721])), Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742]): (Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981]), Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981])), Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661]): (Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072]), Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072])), Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979]): (Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671]), Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671])), Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361]): (Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269]), Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269])), Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558]): (Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571]), Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571])), Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290]): (Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902]), Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902])), Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987]): (Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741]), Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741])), Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902]): (Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515]), Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515])), Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497]): (Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028]), Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028])), Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948]): (Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709]), Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709])), Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009]): (Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725]), Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725])), Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387]): (Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317]), Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317])), Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159]): (Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808]), Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808])), Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394]): (Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699]), Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699])), Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312]): (Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000]), Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000])), Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987]): (Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821]), Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821])), Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046]): (Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909]), Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909])), Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565]): (Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028]), Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028])), Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269]): (Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352]), Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352])), Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847]): (Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271]), Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271])), Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513]): (Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800]), Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800])), Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054]): (Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394]), Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394])), Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004]): (Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977]), Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977])), Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675]): (Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800]), Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800])), Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692]): (Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159]), Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159])), Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909]): (Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932]), Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932])), Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814]): (Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697]), Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697])), Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186]): (Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387]), Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387])), Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445]): (Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470]), Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470])), Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966]): (Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507]), Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507])), Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548]): (Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253]), Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253])), Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897]): (Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783]), Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783])), Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208]): (Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054]), Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054])), Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268]): (Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661]), Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661])), Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388]): (Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643]), Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643])), Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257]): (Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174]), Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174])), Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960]): (Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241]), Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241])), Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721]): (Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046]), Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046])), Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822]): (Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217]), Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217])), Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253]): (Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697]), Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697])), Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054]): (Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019]), Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019])), Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821]): (Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432]), Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432])), Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864]): (Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105]), Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105])), Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373]): (Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855]), Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855])), Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646]): (Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830]), Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830])), Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460]): (Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208]), Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208])), Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033]): (Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214]), Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214])), Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105]): (Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129]), Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129])), Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281]): (Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909]), Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909])), Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028]): (Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027]), Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027])), Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012]): (Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054]), Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054])), Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562]): (Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589]), Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589])), Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037]): (Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097]), Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097])), Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355]): (Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460]), Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460])), Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223]): (Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355]), Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355])), Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089]): (Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306]), Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306])), Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035]): (Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219]), Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219])), Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432]): (Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297]), Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297])), Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693]): (Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263]), Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263])), Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794]): (Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484]), Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484])), Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552]): (Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941]), Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941])), Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267]): (Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814]), Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814])), Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992]): (Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415]), Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415])), Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941]): (Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966]), Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966])), Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822]): (Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320]), Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320])), Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306]): (Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902]), Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902])), Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820]): (Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880]), Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880])), Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361]): (Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725]), Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725])), Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005]): (Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914]), Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914])), Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783]): (Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781]), Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781])), Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011]): (Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033]), Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033])), Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297]): (Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910]), Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910])), Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070]): (Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134]), Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134])), Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144]): (Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331]), Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331])), Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023]): (Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497]), Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497])), Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103]): (Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540]), Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540])), Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961]): (Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998]), Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998])), Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414]): (Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]), Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]))}, trace_len_summary: TraceLenSummary { main_trace_len: 11, range_trace_len: 39, chiplets_trace_len: ChipletsLengths { hash_chiplet_len: 96, bitwise_chiplet_len: 0, memory_chiplet_len: 0, kernel_rom_len: 0 } } } +ExecutionTrace { main_trace: MainTrace { storage: Parts { core_rm: [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 8296916230783913551, 16462332824047406715, 6884552431231699198, 12264801256605292690, 7532528701100807439, 10480547126759850066, 6097728641437901141, 17248496754222975198, 0, 0, 0, 0, 0, 0, 1, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 11656, 42, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 1, 1, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 2, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 91, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 3, 0, 0, 0, 0, 0, 3, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 4, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 0, 42, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 3, 1, 5, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 1, 1, 1, 8296916230783913551, 16462332824047406715, 6884552431231699198, 12264801256605292690, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 42, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 3, 1, 6, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 41, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 42, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 3, 1, 7, 0, 0, 0, 0, 0, 5, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 42, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 3, 1, 8, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 1, 1, 1, 7532528701100807439, 10480547126759850066, 6097728641437901141, 17248496754222975198, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 9, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 31, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 33, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 39, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 43, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 47, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 50, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 51, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 53, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 54, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 55, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 59, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 60, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 61, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 67, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 69, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 70, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 71, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 72, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 73, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 74, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 75, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 76, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 77, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 78, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 79, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 81, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 82, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 83, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 86, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 87, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 88, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 89, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 90, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 91, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 92, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 93, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 94, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 97, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 98, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 99, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 101, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 102, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 103, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 104, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 105, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 106, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 107, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 108, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 109, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 110, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 111, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 112, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 113, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 114, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 115, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 116, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 117, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 118, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 119, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 120, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 121, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 122, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 123, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 124, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 125, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 126, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 127, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0], chiplets_rm: [1, 1, 0, 0, 8296916230783913551, 16462332824047406715, 6884552431231699198, 12264801256605292690, 7532528701100807439, 10480547126759850066, 6097728641437901141, 17248496754222975198, 0, 87, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 8400310461204590462, 9108169057237353573, 17636133504178290964, 17406877359165992528, 1012686194999500095, 3119571665051516884, 6045109140346221273, 8023007352945590267, 0, 0, 1, 0, 0, 1, 1, 0, 0, 11656, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 8296916230783913551, 16462332824047406715, 6884552431231699198, 12264801256605292690, 18213254076385477335, 9294418641045383238, 8055320100535498720, 11030019888906999906, 1874843776400824061, 12942276814728926620, 15585255994602274508, 16203157087401046215, 0, 0, 1, 0, 0, 1, 1, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 7532528701100807439, 10480547126759850066, 6097728641437901141, 17248496754222975198, 12342802819241620905, 7554371666290801318, 8718773026382250605, 15984482998549000918, 15460443374009848343, 1087146607978023558, 7531163901062156801, 4426949494427873777, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 11621565010787354140, 1949391780818670486, 7327781180606137861, 2419787217529136215, 13249250205018233525, 10029758640146777270, 5716716695107147273, 10829954014693503473, 7405851154679558693, 2030135877513774489, 10401768244118899621, 7992444660002654486, 1, 0, 0, 0, 1, 0, 0, 0, 0, 9190577937819620371, 12978309842325015235, 10477013461463931935, 4855391316239312738, 10519745218266697287, 18375374895419140100, 876067972673449756, 17915370314859305010, 17877705855294641231, 120652674332571204, 3378556434908723888, 17649391022523856338, 1, 0, 0, 0, 1, 0, 0, 0, 0, 15052947986857015373, 3007680259418135415, 3197694984858038551, 6563270153864719814, 6889631464391242687, 12614331779225506253, 8884325160266334095, 15067359903282619456, 6045216153329131722, 7293213550537411486, 18377064823051127268, 14733223614830533518, 1, 0, 0, 0, 1, 0, 1248924765333967865, 15568788993061722932, 4037714036443683170, 2584579945446987950, 3496704858534018972, 10965787981110521559, 9000006360952503550, 8377181923806419223, 18078834148678517323, 13751832434934340803, 15306332964801742551, 828627458527105190, 2519953652271814816, 5563221586835004955, 16428502736240336605, 1, 0, 0, 0, 1, 0, 161503374172189975, 7180975586994120588, 13070121377098205312, 9655464535561865455, 4169214041423852321, 5771090309048429384, 6993654059550252564, 14478380452460405826, 12150434000885474539, 18399347099839405992, 88779829066683150, 4428174353386180423, 7547120791432137516, 11951584238447172023, 8804182506418522715, 1, 0, 0, 0, 1, 0, 1859011259345361207, 13205265558511858864, 16229683663108620000, 17688418164436772208, 12658415008146819428, 6291208835901171779, 3297271436089179933, 12943628284217684119, 11639259038601904106, 10502234848011596680, 13946225273525543944, 11318468498957948083, 13851055481982014034, 5765565570506082255, 10777382518726251007, 1, 0, 0, 0, 1, 0, 1023422172081481959, 14540338366569412926, 10271517463444484758, 8863158288377959817, 9066561794313536160, 10161961919995709177, 2094278659773331823, 4371761587112760854, 10972685992181286814, 5641963675353630718, 15569415989710829261, 4258403342016907208, 4740804749082440837, 1594229550076307598, 5045104152796606559, 1, 0, 0, 0, 1, 0, 12053626300860885956, 13987509258486900924, 17286360383804666298, 8301538772707939488, 7700154594411825373, 14332053735409157564, 6894934729579673545, 5430665485920789830, 10553406992561403551, 11528229548578861261, 3294597468571627674, 2903493961726666462, 10560076388764518443, 3749651622493296975, 18114127684252877364, 1, 0, 0, 0, 1, 0, 12240592655856206466, 6264740020775290721, 859763567572081467, 8842953438422484122, 14329981889510246939, 3582542183068105786, 6023391989510151456, 2953193964713672141, 12396149302348639250, 13882467375549577428, 3586988377712407519, 7213506509798642482, 13435456572406932891, 9645941250097564536, 2781650568775738364, 1, 0, 0, 0, 1, 0, 15637532899188291351, 12683652363890573925, 2704597975013858668, 17832955104866332736, 6815586591600943723, 13755349213265671492, 8924117914024270326, 3329964149511691453, 11039495891702065838, 15670789219464690273, 11281671746346947225, 10492374165392519994, 11439270560757451470, 7337394676363778206, 2272256910055258613, 1, 0, 0, 0, 1, 0, 3130343892077994054, 0, 0, 1136320813223337744, 11438337112810950654, 16692992611178972868, 9482499518540692367, 5451078715157933845, 18403012202839423090, 13340398881404871439, 16853681425214524760, 5540259513623809808, 7754241405876268140, 15538673406175044580, 15705643278636475771, 1, 0, 0, 0, 1, 0, 0, 0, 0, 6593967995490198369, 546795078589070868, 8093299549277945163, 1445098694824947603, 16968796337604054074, 7105604958885889972, 12829574433066656016, 10962264142076089650, 6970346774265824779, 5668604568559492205, 15930738860655806958, 14403244990983785091, 1, 0, 0, 0, 1, 0, 0, 0, 0, 7770193319703938593, 6228225228483877842, 5315425894230577486, 8012448033829391087, 5395398520381640698, 8770911350053719042, 14827874098479004474, 11024999006644848903, 13791657658989935762, 17830220104295996918, 2090812709146185278, 8577173283657139529, 1, 0, 0, 0, 1, 0, 0, 0, 0, 17471481800618265475, 1930822204634793148, 12769804899579893379, 13068810900387198296, 10732524945348487200, 1519317270498249877, 12604995971822921101, 14107509487727911757, 8257552923782319555, 12034059115493819529, 4343039820825149431, 395799121324568963, 1, 0, 0, 0, 1, 0, 0, 0, 0, 7532528701100807439, 10480547126759850066, 6097728641437901141, 17248496754222975198, 12342802819241620905, 7554371666290801318, 8718773026382250605, 15984482998549000918, 15460443374009848343, 1087146607978023558, 7531163901062156801, 4426949494427873777, 1, 0, 0, 0, 1, 0, 0, 0, 0, 11656, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 8259689913693129242, 3400892600405308205, 17378179173256779268, 5060920854688287001, 9687195410980644248, 6313248141024338188, 2582093590609427596, 3953695074988874383, 11971751964106597008, 9907486161844974200, 17989903003960359463, 13336380866068769777, 1, 0, 0, 0, 1, 0, 0, 0, 0, 12279731404675001026, 6278812133505380138, 6233201299601221057, 2388727383803081265, 12084036741190483661, 2317300697897833956, 9759443477696867671, 10883057071610381859, 3944615791382572320, 4072273145811045884, 17852897021998211163, 9684438072608016253, 1, 0, 0, 0, 1, 0, 0, 0, 0, 3651584995004100725, 6423803920838032987, 14027200390009907647, 6592032860050067711, 2594447921553931384, 18306574626058358562, 4512185877168969647, 11342492757671323084, 15957751677575885720, 5761823199659062393, 6846407586191335849, 9817376758188911585, 1, 0, 0, 0, 1, 0, 18183126545069935350, 12563248011457733820, 8356966014032630063, 12041609793392315665, 5281186701877768352, 5541580267076219602, 11576047020972388374, 6661568194349527666, 15437143780340457719, 10754987180927492954, 4211835751645452119, 10566966891469040816, 690793516206281144, 3247962926818069970, 9036036859539968974, 1, 0, 0, 0, 1, 0, 15893445344909186288, 5778049594265975833, 1423581989082731508, 5458007776595562807, 2498425571573111469, 16059466580364398666, 8902716392494711213, 14882573357788460188, 3225597659422237250, 3128065202613218656, 16995684508107895104, 12196793732604029414, 17723663615896720413, 9829416315291197871, 580745865383399340, 1, 0, 0, 0, 1, 0, 13902067347991440733, 5984630683069450754, 12729386174124645267, 13785662250538369696, 272255205933159866, 735616656951483055, 12424664074133983590, 5026981889191825136, 5767485772665833989, 15651669603605283176, 7414308024158917695, 15811954123421478742, 13258769136679205830, 3664463833800174816, 15497592431183820173, 1, 0, 0, 0, 1, 0, 11156605567826983932, 3639316624646464570, 5042698793479444923, 8630374421727305636, 17027951314675117661, 2801906069577385610, 18065291493111457552, 18067767546753643362, 5248148594352695009, 7578134041089558055, 18445498855455618598, 7189106720666328053, 6562930842885656592, 6844922721754111014, 780716667496251522, 1, 0, 0, 0, 1, 0, 11860885490747304346, 12272615266561732125, 10423884872730116228, 13929733142214397431, 2117615618497875527, 5203222542820499724, 4538429948347629507, 6877693664463852318, 18109062185597913481, 10147653053574341319, 10079670109614966266, 12064951107563936135, 1152998120279634164, 12844815835032732057, 12896711460106342356, 1, 0, 0, 0, 1, 0, 3078919787028426439, 15265543379215102231, 570695753264939069, 459110976220447167, 2176716793919417092, 14863591412045443847, 14252826520731507004, 15860274927896899753, 10390267100193539166, 17043032359848981742, 818991875743271755, 16275785202399117535, 8465017515346473513, 2777064625189300576, 13072175816967000886, 1, 0, 0, 0, 1, 0, 3442153457185747577, 2606206929260007126, 2317686975478948049, 15948992202505097484, 5942181083636438599, 15457210791918859006, 887605399554676434, 12986387963278623196, 10075175986843357851, 4859683927561004597, 6555547085880890919, 8280537903442447606, 16640962983997717683, 2248822201261309400, 13163090516020988950, 1, 0, 0, 0, 1, 0, 7196986181046756683, 0, 0, 16549653703171386973, 11518702294444124172, 1109770523953150302, 11415315369035533823, 5890935665450471727, 2253657843173273901, 13858462521885404044, 9125187176834287629, 14925311787915179675, 9356310136195018005, 14965392043314054082, 18423301843359275387, 1, 0, 0, 0, 1, 0, 0, 0, 0, 7040940919216905671, 6187741949018394442, 10532732827118411505, 13505135286384426969, 917467356231706545, 9047752258933341547, 2335143583534705649, 18052717581435745313, 9355624911805935499, 7190586108559742607, 2304843099991312546, 16303126242918615541, 1, 0, 0, 0, 1, 0, 0, 0, 0, 15603840856162477962, 3504063088563989096, 6361775464868278813, 17698044987168049155, 8418309402148081318, 15988177746184666422, 4270534912200806378, 12370149697383197906, 8363034440938926080, 17941258791536373709, 11011611614519090457, 10702921331067290122, 1, 0, 0, 0, 1, 0, 0, 0, 0, 8416267285503610972, 15089551497492948945, 5363802036407642792, 10347532956075658842, 17181858623993805271, 15855824450153307212, 7743632312226714799, 1845073853648620670, 2000026205350826313, 18037231946791138113, 14309912549728703012, 13253445327127715869, 1, 0, 0, 0, 1, 0, 0, 0, 0, 8296916230783913551, 16462332824047406715, 6884552431231699198, 12264801256605292690, 18213254076385477335, 9294418641045383238, 8055320100535498720, 11030019888906999906, 1874843776400824061, 12942276814728926620, 15585255994602274508, 16203157087401046215, 1, 0, 0, 0, 1, 0, 0, 0, 0, 8296916230783913551, 16462332824047406715, 6884552431231699198, 12264801256605292690, 7532528701100807439, 10480547126759850066, 6097728641437901141, 17248496754222975198, 0, 87, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 10686862901019340628, 15711583786595019806, 9378042936835126164, 11939142602264935891, 13605517752371930016, 2544863311362262665, 6880055194706872138, 2404926559643725443, 11298729247352625131, 13639273524510051487, 3031605320954281704, 2952677760580202523, 1, 0, 0, 0, 1, 0, 0, 0, 0, 6949406075980976859, 9142069989509656801, 14676622013796942288, 5295633173573979080, 14862684288436559050, 7708888152496129562, 8667911075542880817, 14424367369474907891, 14303094264982903091, 9838552210955819611, 15088013178433258027, 5833102420062152227, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1932675776657481842, 14290498569500988181, 11741991701671402436, 3934903733189518965, 10047440752038846171, 14938209139342513571, 7659889883493126262, 2134579895120260539, 7819147353957995986, 17861588317805920712, 11020859927535923500, 15623868602690334525, 1, 0, 0, 0, 1, 0, 6264451320029412065, 5315770291001895612, 3923979823614336294, 15496957568148800678, 4856878698798286165, 18427152961697133322, 13172977369565732662, 8634756726478972696, 17549357918509499997, 7356106617646839123, 16192566970100663376, 4904526601366015673, 11478334329288517717, 607398074844683832, 9609971183005491570, 1, 0, 0, 0, 1, 0, 18264070764381924889, 7558994944201947568, 16698567473332535936, 4066201321205995431, 14552036519561423602, 5620710451624899086, 14969463994437329823, 11938508228196027882, 9200118839118887577, 6855444937813269923, 13901427726318773655, 3507966654472722962, 13139165600809348467, 3547085602937656739, 11244050388029555026, 1, 0, 0, 0, 1, 0, 8312328144036608043, 17972686765781519170, 10784039031850599726, 14134435301654782468, 13131877571979284929, 8266221982529104091, 159405248778538274, 5778967389144576888, 6057984302796584762, 11714059928473413141, 11763232719990709154, 7978933720497313146, 16635094485101159936, 18327609188632861057, 11071183167122824035, 1, 0, 0, 0, 1, 0, 10287810620841180003, 4548089904338037398, 6876519236022884332, 192351967064940869, 13616941784242570400, 7032108910940453446, 13625250436816808378, 17491100122417306359, 2292049730346364666, 2733535393252649149, 17750397792987890641, 6346476747248545150, 3575465615474366120, 18213303372206038112, 2518621101786158931, 1, 0, 0, 0, 1, 0, 842637389045220237, 14003171518185218367, 14997648696661468292, 13477259760240789253, 7438659305055821970, 7828458451594639328, 1805142843426507273, 3804729079035423760, 5684604326361654696, 17218885460122549497, 974371611540683935, 16762750120460661174, 739710162320190732, 3363948547922989023, 4267260670759647913, 1, 0, 0, 0, 1, 0, 10264158766070300923, 6050974414693797250, 847386589526447339, 3548106904874618124, 9289172558104066787, 8226909131216769737, 16380713199877477068, 4410762367217395758, 12555768451623030884, 10357980275595284555, 10303991993655092221, 4060030248038493229, 11216725884924445657, 10194932652661424405, 17494422570060569743, 1, 0, 0, 0, 1, 0, 522514578171525652, 3717501858890221638, 16025700499781393088, 15033579247524264929, 1744414008664189122, 6807378681147180078, 16955668219975052585, 18323017022834713256, 6662618285165080179, 12762215046608848013, 17134633855452090590, 6353725621416552612, 4449259194945598867, 8877290555352616803, 13666098560811114332, 1, 0, 0, 0, 1, 0, 3232143389630708424, 0, 0, 9014593992030055460, 10869121640834977224, 1905700011211118876, 955944440419378960, 265206078841667899, 13713964984862746492, 9702435518807270681, 12343078651970579400, 18227529633908655074, 9709048888339027683, 15154974039676851951, 16388400023664675593, 1, 0, 0, 0, 1, 0, 0, 0, 0, 12342730708987043912, 13274159397630057441, 12697978258400128397, 368152630932848211, 6555819701154221199, 97417680512067538, 2018507387878521400, 1529782995014995301, 13636792419679998309, 6197980968820055410, 737644335551408580, 9956102600220791675, 1, 0, 0, 0, 1, 0, 0, 0, 0, 14179025343931559433, 1175312715506728066, 11255361077722267605, 9822732455439796133, 13335036252549184126, 17127037879360292568, 16600677125340288437, 11659800847392950623, 12605660248276552114, 14805446144065764307, 14804045017754446897, 13192632014186378484, 1, 0, 0, 0, 1, 0, 0, 0, 0, 12383461936126681247, 745215043874424896, 4540981537676651137, 16486351305638014506, 10972364256824969372, 5647748125744546841, 5620391031839475969, 17973620544670757805, 1344519641939806437, 11395404185290209616, 4498705163534372313, 3336623779264323323, 1, 0, 0, 0, 1, 0, 0, 0, 0, 11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518, 8400310461204590462, 9108169057237353573, 17636133504178290964, 17406877359165992528, 1012686194999500095, 3119571665051516884, 6045109140346221273, 8023007352945590267, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], range_checker_cols: [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2187, 4374, 6561, 8748, 10935, 13122, 15309, 17496, 19683, 21870, 24057, 26244, 28431, 30618, 32805, 34992, 37179, 39366, 41553, 43740, 45927, 48114, 50301, 52488, 54675, 56862, 59049, 61236, 63423, 64152, 64881, 65124, 65367, 65448, 65529, 65532, 65535, 65535]], num_rows: 128 }, last_program_row: RowIndex(10) }, program_info: ProgramInfo { program_hash: Word([11076886436648289475, 1436737619885125274, 13911724531697299597, 14872058964661698518]), kernel: Kernel([]) }, stack_outputs: StackOutputs { elements: [2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, precompile_requests: [], final_precompile_transcript: PrecompileTranscript { state: Word([0, 0, 0, 0]) }, trace_len_summary: TraceLenSummary { main_trace_len: 11, range_trace_len: 39, chiplets_trace_len: ChipletsLengths { hash_chiplet_len: 64, bitwise_chiplet_len: 0, memory_chiplet_len: 0, ace_chiplet_len: 0, kernel_rom_len: 0 } } } diff --git a/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_20.snap b/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_20.snap index 3aad1c0e3e..cf52fd4916 100644 --- a/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_20.snap +++ b/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_20.snap @@ -2,4 +2,4 @@ source: processor/src/trace/parallel/tests.rs expression: DeterministicTrace(&trace_from_fragments) --- -ExecutionTrace { main_trace: MainTrace { columns: ColMatrix { columns: [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 65, 65, 65, 65, 65, 65, 65, 65, 65, 1, 97, 97, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [16336503519826769294, 580999813345182728, 4539061041759240, 35461414388744, 277042299912, 2164392968, 16909320, 132104, 1032, 8, 0, 4539061041759240, 35461414388744, 277042299912, 2164392968, 16909320, 132104, 1032, 8, 0, 4539061041759240, 35461414388744, 277042299912, 2164392968, 16909320, 132104, 1032, 8, 0, 4539061041759240, 35461414388744, 277042299912, 2164392968, 16909320, 132104, 1032, 8, 0, 4539061041759240, 35461414388744, 277042299912, 2164392968, 16909320, 132104, 1032, 8, 0, 4539061041759240, 35461414388744, 277042299912, 2164392968, 16909320, 132104, 1032, 8, 0, 4539061041759240, 35461414388744, 277042299912, 2164392968, 16909320, 132104, 1032, 8, 0, 4539061041759240, 35461414388744, 277042299912, 2164392968, 16909320, 132104, 1032, 8, 0, 4539061041759240, 35461414388744, 277042299912, 2164392968, 16909320, 132104, 1032, 8, 0, 16336503519826769294, 41, 0, 11006573531383828351, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862], [9197671798777409481, 580999813345182728, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 9197671798777409481, 0, 1, 10983413158656624898, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770], [13035020452047724944, 580999813345182728, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13035020452047724944, 0, 0, 4869282124135316831, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811], [17733790707118953345, 580999813345182728, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17733790707118953345, 0, 0, 5899798166361732461, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096], [11006573531383828351, 580999813345182728, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [10983413158656624898, 580999813345182728, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [4869282124135316831, 580999813345182728, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [5899798166361732461, 580999813345182728, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 0, 1, 2, 3, 4, 5, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2], [2, 2, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 2, 1, 2, 1, 2, 1, 2, 1, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3], [3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2187, 4374, 6561, 8748, 10935, 13122, 15309, 17496, 19683, 21870, 24057, 26244, 28431, 30618, 32805, 34992, 37179, 39366, 41553, 43740, 45927, 48114, 50301, 52488, 54675, 56862, 59049, 61236, 63423, 64152, 64881, 65124, 65367, 65448, 65529, 65532, 65535, 65535], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [16336503519826769294, 7241595766844512545, 2990417547231451768, 8200055882763834902, 15107023413552199376, 8385687432658166895, 9658411005214642328, 4909632993745393767, 11139320331324068031, 7133947682362156748, 17192073988910191157, 1252671640222326947, 3013016866261693283, 8108123078799037039, 4014227156326565798, 12391143724758863082, 14176166539222112137, 17477853997594743235, 12238064792115483402, 14469369283093994356, 15706959181585180523, 9935807559722975979, 16381952245010805100, 15445358949429791952, 4394218334834403498, 7081942205803021819, 14286495051698513565, 1765182318039047708, 4315117985825319308, 13180871958580017059, 9324640818690322529, 6965138066206642862, 580999813345182728, 9441246971154186623, 14568136944800275082, 12559996978644727669, 16006034000059690936, 15808130082429351686, 11189427321576264326, 8056423375835200370, 894576452673648096, 1759663226535241487, 7111996287898491444, 9980680059887464609, 1246527623804764182, 15473044979114460820, 15843714178786416863, 11802722938645199711, 528524525625403517, 3395211782606276051, 4814987904082383725, 8549845730678305747, 3112263678112869121, 1192721472492662021, 5190583599302670309, 15237271270752782119, 4547129522910145518, 11550408183365383111, 6870828195219142669, 12383111777615982801, 12714099020863010695, 5224376302272959154, 14781572642473112572, 14537741408767373410, 4539061041759240, 166413184814318872, 3330424775026476592, 7732229819737520946, 12659763553976530720, 13820936547498519501, 15870553509947197608, 5797460196965489144, 5030538143349324000, 3122912243524936279, 7275337387902302889, 5695604368834329320, 14130306385452780113, 15363567770150994298, 8078757315035365696, 5442629662308931105, 16137685808790691775, 9729162786960114112, 6971938391156245940, 18003847752567480952, 3179630577014811908, 16175129257259814669, 7116272890564491051, 14999066466406693845, 11390566154350641025, 8405503273117460784, 17453232571701437290, 17122916750446457171, 7539745443808178835, 14554316550668318802, 15063345752223211733, 16336503519826769294, 41, 410, 8488924048752676071, 5473488137200086909, 16124688533662466636, 4527044298581192722, 16887055178922689595, 5249711198271717177, 15470787238396171217, 5632634005697013617, 7337408598993184022, 11147561538212402733, 9710911023591971572, 8752830793140649116, 11546140485006286209, 10738951369466640003, 2139663271495255306, 6135983205453599776, 17538856881976830392, 2031516987289365197, 17199894398730562705, 4010699482290892787, 3922552954514582360, 7369439734883755459, 108303794773646012, 14521269346803535153, 14515762120928230173, 13893962684375637966, 13610167819530098127, 11215445033353754262, 8081237365032914784, 11006573531383828351, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [9197671798777409481, 17469195903127682246, 11606517949721719272, 8595871163399933719, 7763683116636157069, 838997349906846708, 13728530742608929979, 6793201875126035063, 8111388737755370581, 14079832107643166597, 17737118927359740270, 3118134149246226434, 13627060471757962412, 587514782692598940, 2305040771202529034, 407676238176147180, 11304490035899669295, 4667652151526467516, 13681768858122081452, 17060146905316016781, 15750389702075093135, 7088767289424376680, 15640720737556518069, 2099687338970431013, 14448236636738050578, 5519067145334892916, 6791090761664616374, 420116652546322982, 17954920195441939375, 6438200026603866080, 1507262460208602102, 12596233587871940770, 580999813345182728, 2469249211011993887, 5693535723676280393, 9307941706856421244, 17583976365434994224, 11956256213068276591, 16650744379891120584, 11970932857482984253, 1340502547894095473, 17627623028259352738, 10800915493705299677, 12726130892030271688, 1966101965836764845, 8603197046817345275, 3287199712077657921, 4816347799520535722, 13726091214309035851, 14508720026418909433, 8845463819329319330, 319079387588421934, 9793349915183632648, 14664095371212951733, 7893897801913761594, 16244276080775719304, 5201962268638016263, 595824696721317186, 2520783628599955940, 849243249424286073, 12314456283572504356, 6535409800777915487, 11268362592956912536, 15771729313541940903, 0, 1073634951995504195, 13633250484821623215, 15098993065726469111, 1564281538360678972, 7168328730833322865, 9990637691333202156, 4315815088290272811, 13591172423217881213, 15655075338480513609, 996725104060870062, 1007570544942142144, 3729822968690386528, 10658087655041602841, 9498329046798837348, 14839704326644418801, 16811175179247371160, 5981274731275683258, 15610466289947195032, 14000599989678227804, 15292824893734897630, 627607295424670979, 2340223307289953865, 15059493462076997690, 16071082072689060288, 16820362574538767542, 5021883210577128063, 1555980395218755516, 9884045457320590091, 5367026278670357791, 8499294198486805672, 9197671798777409481, 0, 328, 7132218559010351790, 2687466917280430353, 14170238607512888511, 5453168895411602323, 8679138582261878552, 10871515559850126217, 7649138216344653830, 12086029516113687059, 14609582285822867389, 7271583017513514692, 3821121937809044409, 3833100151978191712, 5702916883024911354, 3579138882391492892, 14347405124134927123, 9277341930384005575, 2993137622300793545, 13370802209879109056, 13653108884642243926, 8702782587703766612, 12945832125614510830, 15167316901472929028, 4608694219239856197, 4443739924303229750, 8611475648437961511, 1575864515244779062, 10900065459953722709, 9162692523043045302, 17462008412377898139, 10983413158656624898, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [13035020452047724944, 4235056893170892481, 17598947928349150032, 4957589343064393818, 6242447045300438422, 4795761656943466364, 6264917032052353984, 15603723388972198024, 11627377236417283134, 6114228315229264629, 3286806106182827895, 15205984627333468001, 7321576485635388020, 17749542785007315566, 4569674865772026702, 7956650962315989946, 14478240861430583623, 14709859391037291514, 10913732310161131390, 2296203662546391134, 876174554396868075, 17404327975123101624, 2366722819671298513, 14303982336399641814, 12813527806534446210, 12774296173948151856, 12627603787832494922, 14277393185196427667, 2358074803509054857, 16405101789199201340, 1581131786309040293, 8197358252954291811, 580999813345182728, 9441246971154186623, 9230767544379437105, 18310630857442586767, 6798288544665969845, 12649659004750065655, 9127484939696035145, 3208400024176171154, 12601220862983867223, 3182150398630969932, 15946092271529760948, 312583470408719867, 1277989670489505373, 5390475388454384344, 1991947075903969606, 12041137591375643532, 17203613475518457508, 11172295513373146926, 1047366979417083402, 1230000128467178780, 166719433298183890, 9500917527157796789, 11443445413242899153, 18103925836791549846, 8328524023483162981, 16082128743854634628, 7353009946795117330, 18315678446936398634, 469635739213563567, 7901122908367659010, 5766087612434108876, 16254963956836991015, 0, 8506155510179977332, 16565837043221829196, 52948362219275850, 8677964002070154388, 7428484016288157022, 2806233373077400725, 13744878929079685610, 7596566350181367049, 8320838608801394259, 11416348334771026081, 5033691822950904881, 17904228615366476508, 1573747864700068677, 6115393411247877634, 299028171433900072, 17660677259671545725, 17197119244649549383, 11502210755699728407, 3657258890969942218, 3136236054167912163, 186206196971871344, 10885932290083514811, 11340220366618064719, 11020489504600957926, 15331358518756318712, 5496590912397587492, 14595950592094489892, 8382695108894398131, 9643181922175718153, 16042312733989464482, 13035020452047724944, 0, 82, 18152833202936203138, 10305147718805144715, 13246631902503555591, 18142351346900318359, 11971140429919100117, 6903484634638418138, 3098698980745497723, 3068992673894668202, 9164459936648953977, 11194864417357882388, 12005359455571366116, 12356306486226268709, 10059737158050223658, 17119982236602677307, 4225663824996553892, 17852936504841763737, 5778553506856942969, 9045001363359345866, 18423338781077887809, 2711240319770097821, 8346149567490270428, 9594540064387516595, 1859863665658604717, 16919987197409252682, 7809934763889573038, 12492597695329698922, 18341122838405415754, 11967784234256998242, 10761804868734649587, 4869282124135316831, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [17733790707118953345, 2298049257819688964, 14580412695609233024, 12971821499548943886, 12942151567717980516, 293990104348951469, 9511447919780245828, 12096675465574714978, 11966816476348176754, 6745364430325410240, 124350208982409384, 11534859557249128228, 13499302804947319126, 2073163037044338276, 980116766328138766, 6249894809652649629, 5225655700408130435, 15576478276301900443, 7892851227093729574, 15711810664626070442, 4889082965904642440, 18118185760308539378, 14951898769476191069, 12393266145043202429, 18370579783025919052, 13670428043882183738, 853764681371061454, 11311873924545773972, 12566827890799503780, 12734261918077566887, 13460201712649497096, 10673667133036073096, 580999813345182728, 2469249211011993887, 1921340627054025915, 11168366585808691894, 16344827155364741241, 13917605778022436041, 16775788395149485828, 3448656772275438142, 16222497246401579549, 7203217594655996602, 11409282451484046090, 758472841121971562, 7818365927012965985, 7903960434340948362, 3767440642589974121, 11209692269971430929, 3035346059787720244, 3431797671267201506, 6118779023340710484, 11335358665561171709, 5274326486456948617, 5525087067228805129, 5704922620886162396, 15867602839234938544, 9623255540514358603, 6605123704860531855, 17045986882743664444, 13118883604429226706, 4147903628926627533, 4079954944710007123, 10588667258124334541, 2046774012797929459, 0, 144771942538542601, 12610063329678779487, 9599099202048490781, 7298046952032101196, 16026473122383984320, 14666633261274526329, 10912616786956595600, 5410472981661512575, 8351163137101469720, 6900106104861748151, 5904063656561684665, 16445251460715434195, 10832015734039673623, 2891811661249932042, 8924808732795308287, 4687342342302612015, 16735389142514185239, 1470376739244986162, 1819268707172544638, 13251084164183215555, 16740657538571711568, 12986569577580758510, 6580507474643651363, 14039388877064634044, 17925541740654686755, 6693558341526111425, 11597938374506256020, 5283201688561864115, 5334752974852163097, 451731299183430202, 17733790707118953345, 0, 82, 302695496926486902, 16415403596737407938, 12969246825596557956, 15965643470182086386, 14881573336337548597, 2868629484750761697, 7317402970608805914, 2570537868338555591, 6697005353407257884, 5717939852331496040, 9408357527608003903, 8011884131194179594, 15942512744234440774, 9052662470595673790, 11913271961595885333, 15508051727969296111, 6269710669185644103, 12322255659000247132, 810875278274469351, 3499523055983644139, 9453749819048496107, 598273005722510655, 12338854942180141395, 2829445891916136836, 12653867244112536729, 4648827005364006908, 3153753366153954420, 12197142511433562971, 13557680898519201450, 5899798166361732461, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [11006573531383828351, 4764651601843997947, 13599348264422318050, 9048627971498202333, 4616644171576346372, 13446530094027973481, 515125260461286305, 13270828405354296543, 3589365582169471582, 7410433095216666761, 17324168673998498317, 264848703107953315, 2519145233399390872, 16944105578845184537, 891801733175697187, 1917456671376826149, 2178489717179959491, 5288871968538360514, 173128619939349444, 14938204230051641776, 14848674461360674975, 3298163296153338543, 12736435946586958561, 14151277613136798520, 6993584357807298191, 17243220101971525650, 6760124904423015973, 15448478475120864966, 11226925817970638094, 323561318445804460, 11770041052112546722, 8087083728976074902, 580999813345182728, 9441246971154186623, 4826001026438697181, 13927464871572189232, 8487031467837880959, 7953084218463226909, 14357560502528070253, 9198678924697643847, 16644535012971742472, 2610427154842113175, 1362602973689891222, 14563339716269964045, 10893524038980604908, 8604291529520412550, 3375764636979625919, 4598760434596487640, 14370201798336911320, 11592395684445633353, 18428909381025170046, 7556816872757379313, 15838446667082529291, 11840899228072824840, 5666563878473838907, 12094773271668234643, 18145098371590981833, 6227739674905468508, 14360904859585829753, 6349150325802118522, 13470963638813042195, 13830904396796715875, 9960013932953480218, 9448749568492005186, 0, 143717879605522672, 1406583001570465792, 12562663752152469569, 16633851142346839330, 17021480690231868718, 8387812497337000660, 15004187181055446563, 12021280163646879782, 15544096072222322408, 132132622953814287, 944699227762067814, 15889407327776555006, 8234710954956267885, 14704623317114553828, 5225072174929433338, 9992674649041617391, 17342022136955130751, 9806643750569796986, 10854572141100075982, 9877562264475108305, 3741205325444910799, 3008635823591126704, 8487705884637814572, 10764537169012636484, 3173467127968428287, 8847518126511086492, 295935891940673208, 11767201095350394052, 11260389542763349256, 4551861726624713720, 1413881954865567393, 0, 205, 13622702382434675698, 8941567408770445183, 2168342371250989865, 17553704974699598306, 12818882650622055705, 16478401302589696546, 10652219805906948351, 13167156861512034068, 260666911081589986, 1428764500637505382, 2190433219200603887, 11999917547751101526, 2751093334206085539, 9318931023569054874, 16297727142514657495, 11875658036026604145, 5829323963705819601, 407792022339954638, 5684565403642367050, 13995368600016681288, 2845800306757116207, 5216498913603536417, 2411940295743487842, 2014066638340124975, 5258230180909223265, 17089893338044941808, 1124366766375746940, 9116801986360376826, 6650575029061305823, 4025036448660092914, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [10983413158656624898, 5310937309376166300, 69556848653847272, 2279577280749402753, 6239043535079259963, 7823300322844699129, 16996148474654794437, 4230459886680751700, 12959563699934572877, 17777188402634189686, 11688615314691277560, 5613634717561556402, 99293997352733151, 4641048264628364064, 10453514483181846641, 1290992838422522292, 1652879052062614258, 12559634219275278239, 11344475397534544312, 4122197572510879508, 15407253393194772940, 2851848389283930949, 11702605024239517145, 1998109451585880901, 585739809492349094, 13332688213147014025, 1333400193073781990, 8814857714812706426, 1361027555808818653, 5346936254995238101, 8929045628408978585, 14294118012339765875, 580999813345182728, 2469249211011993887, 9026977856739391370, 4386750069800107475, 10598485069506239844, 13751116549494668150, 5108328399444950450, 17844111358351956213, 6869486424216496389, 12517021987770120609, 7851907349568758598, 18010894049048312095, 16693413552305953061, 4804538971513236292, 17649433461619154043, 11634860025288790992, 11313962652641817505, 855825648432312573, 13762197753828465221, 5743720479766949980, 3952939840611939921, 9604762177227689240, 8138871928234011911, 11384225568855102440, 9154844205260484435, 14664846725851493074, 2924959973998026295, 12642953022837695767, 429476535988054822, 17383573277674600677, 1883220378389933149, 8503069890613114305, 0, 1055478707828467235, 16768526919827857497, 17573593815267411876, 10818335527229137478, 11942460420815768259, 11201145811561632930, 5337320314888759058, 11378469682479349365, 8043644167131082885, 10448639655673781918, 12631760754265391769, 7376593749874885103, 16058512323740159729, 17873088011118479782, 17353196649080642803, 4721598436263747464, 11599468651034345541, 14009687636872815249, 7066071671554154790, 764975448091728428, 390750909719918391, 6065087221876806603, 15179557481995246257, 3787608625370371137, 2510512133707130589, 11690776235517962509, 1719109731839136237, 11166959267981414839, 12815587692045090980, 7859047597365690811, 8496939594631729748, 0, 164, 6093021124582015914, 375332441348258328, 16597900739273350797, 16788616498952461620, 10323894478242846558, 3730474644926313294, 17377183878976452334, 12746711269593150718, 13699107349734059694, 421533440407219618, 15109303318896079214, 17746438429032263850, 13224617406323308041, 5646455969610140563, 12626985742338481481, 14497665384991648640, 13894375308737560134, 3268393834564630675, 13312171511942754529, 611321250913478210, 12048873764879264902, 5334026694118161468, 14360341460112568406, 17654490467796517057, 1299716947845207044, 7609683397541157642, 14709808073905360012, 11742139955633481423, 13522070698443062110, 12847434483856017691, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [4869282124135316831, 9722920045405101283, 3813457227114323323, 6994299592571856765, 5702578803007136341, 15311994542782308321, 15962779709098309522, 3251959243165075337, 16837525512190061999, 5255873350627198987, 13662096656243952301, 1237772870699038471, 14338999341360692181, 14673770949791486715, 18097642912412713810, 10340874988740490351, 14305190726983389511, 16952069533520764759, 1485150603424506365, 14762405621252678105, 14445929105909601636, 16354500586064479473, 17536697575147489470, 9606769581569578625, 16440689431974469334, 6912749596454005081, 18063649775432527150, 14363667461722498847, 3204687512694590580, 523131765818647386, 13905210272577125578, 1524835811237900732, 580999813345182728, 9441246971154186623, 10597412231254617917, 11056066896847582412, 926831815845570768, 15146036891941496142, 17796585342020107437, 14725691510160207757, 13266683287137316598, 11211493525824266688, 10363424299958068143, 16931617059033676533, 10317747226871568657, 5507137035801773730, 15150382077316258576, 3011814040489752698, 15693519808819939877, 3749972803617457769, 17618989739824101716, 16792606508352577565, 17343623425168465586, 7527635805457035516, 5997951179959432212, 5020084506774034519, 14024972486716132755, 12302404123334003808, 2455930810486398184, 3241163780490493161, 10543436976244887593, 13682516968888804929, 11574410555278975115, 9471994857288690980, 0, 8501616449138218092, 4292185681439734302, 7698449017624504359, 4120049919115121735, 12642019494772420219, 14296370119911864390, 11592997338406165909, 840282323232377843, 12539549423037404132, 2113471727240446420, 14684696359318715547, 10727937735414582667, 8692606315144869678, 12960248188949622509, 5257625079275344763, 13015387036798755754, 856522523927216338, 7257469808648011210, 16558963709047870874, 12450766651322475975, 13636667172445831102, 13577724383754573439, 11193936901615452288, 7697944572311111481, 3932182442483072865, 5392781400556584604, 17762170874626363624, 15703610354425254697, 12391508132885235615, 8620148927055889210, 18000133586140028187, 0, 41, 9617260353707541367, 9187825164453421957, 17649953659489375797, 6396310504287885774, 17019569090864760371, 870218876784769460, 17213560015461715510, 16812494438448165271, 15885717661613279263, 2958950328581697287, 14311601477626423214, 12599125587081655507, 12078599565132475515, 3332808335850364509, 374688056722968094, 5591521890390007231, 9584980789501913045, 4066644474875437132, 17728945623551220217, 1158050506628066296, 3730734784735709807, 10671987699715228843, 3173999018565335463, 14949604462817069254, 11653871972148380806, 312408327658285690, 8531928004921347162, 98858158429688394, 6167334615107562354, 1234843923022284190, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [5899798166361732461, 5767416489550511608, 2886498774908945457, 15711135636713186135, 17215236981565434804, 908232164244690453, 5342947965117461497, 3199707432515651559, 12254673123217560222, 15216440457821236670, 481214964859672572, 18319684398448937806, 12603763899442623918, 10439805318219614253, 3602725314699933855, 8845316204090048147, 7271929134996712285, 13774466749383009485, 11005842405313098356, 14132576890947137734, 14321220139057541288, 6232608833314116824, 18436966792264288712, 1379169538700861503, 12062619363135681450, 16153824494526799043, 14882639257257424707, 6766308366816242208, 4464924001417791506, 4566463403740325912, 1351933157961486422, 6763063898149860947, 580999813345182728, 2469249211011993887, 8653818256660346722, 821691781470963977, 17943701130779573558, 3491480252041350267, 16358518409573919398, 16267496100921628089, 12162679553338055516, 1260655305474572880, 9540238327664971413, 15435832236802784694, 3812327996641515614, 10851655192011526024, 10610490743746459257, 13300292692349174603, 10113218173788314502, 10969265948996096203, 6220402056944103440, 3968382988012899732, 5018759638511748755, 2202263529713616511, 12948196389634753645, 3608565717871609608, 2453582700597880552, 2749677163981800836, 7973159619665332708, 16804313747076081769, 14670346996245963865, 6184594554218323809, 17786267665435354569, 16948092911786303144, 0, 140232881496783361, 10299881888812700030, 13506878991346097494, 14759589214631061464, 7301829639095749904, 15244303073312648502, 18132523245900274389, 2494235991830255255, 3432426521039531155, 7122756551450847884, 5549456538037663492, 10046538650654098331, 15912355352055409492, 17727271824480331481, 6704708084565647373, 4884177682333066524, 15210444525259934523, 3029374613861219290, 4615876382287073253, 7423511914796799812, 15469469226126445149, 8382746819546300959, 2890705529596562428, 9630719428827082769, 13318034444579216655, 4682383242810761218, 14195663397355254272, 12064640095342720771, 16112425486122001154, 9666454503914171857, 10680190414005925338, 0, 41, 12529483521877137515, 4671467226762388980, 13873740979092621907, 12847173262736205772, 2640423636460273022, 8374058502362870155, 7630996533587302384, 3556075572123538464, 8078558398785937163, 5856098383496092000, 7999607615804135893, 15509992149354799776, 13785560116650003734, 8358196300413379173, 10412508239405514928, 7840142081125036731, 18075062342410207477, 18173191150607640442, 2133036585496843963, 8931901040624025193, 9454731621283026961, 5837806564591410604, 5850596656185029719, 296117354535505751, 8985195681813998404, 1975947551471322175, 12041110943945791333, 11648250496545232642, 7830634726555216225, 5266777994490151623, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 16299911835839227190, 7439600795053578285, 17764699242312753117, 72379023848321437, 3840146011074602084, 10358472899138824122, 8678403567076310671, 771969030954554421, 17107733370651064258, 3926130618298284866, 777766613761440792, 18302679616424742231, 4399658422830000888, 14586568436552896239, 7848898512724128276, 16028822053598615935, 7613061892596625462, 13083593386467993284, 3013879140705624968, 17693711337466712468, 5033175548360176402, 5071731402891436170, 7353230019346707888, 17252905843818454714, 2640505909682592156, 14567186806364265088, 11858169615721049009, 8265106158072298997, 6616889263695345418, 11403119304603636779, 2145158521494695437, 0, 145249957631262975, 2401047653221911346, 4346621156346694740, 15690230013100567693, 12052213250462948496, 4313034443454791583, 2986358406776419767, 3160744395414731040, 14031039024085093183, 3877496541600093734, 10720145895975203640, 14936894451943192844, 4924903395035620384, 12381787083236736442, 12547862058645445192, 17342901573615257923, 16441368248785967826, 16642290968979905665, 8400425547892097127, 8935168685033341816, 11133810960521952919, 7535134649436940418, 5752598619104470273, 3942368633516548816, 15338087145388864340, 12628972628903398239, 13438747263841181181, 3139557918845001204, 1597138777695243925, 15852581941664405912, 12566536223313831832, 12566536223313831832, 264740454002249144, 5070319740822484234, 11549475095918428048, 9819109219817742568, 5677600078177657746, 250382926802577021, 3413687351079729358, 6870174020804907583, 2950358385880233426, 7094567085672854808, 14117325213115724257, 17249265058838620523, 6364580434745257188, 16537587825367420675, 6255602063998060074, 1816448877154048697, 1665145345483041546, 14003506401044241980, 10434287967974565457, 9500338696261382317, 13133067026913450803, 11258578054901736835, 14430869544081691912, 8503613085408412261, 3343513116649617296, 9343508596961576512, 12753874820303454617, 11936680880561889502, 3422498555177881379, 17255066275290727039, 2339032462720454103, 0, 205, 7876112718273244024, 1276143811675585923, 9993912342918529935, 16999254614849428545, 8194747920293058753, 11171758628037424552, 8208119826419095432, 5568149314099479773, 17551537772960996556, 12651683228606533001, 13584145944854843210, 12212300608708011466, 18102951610480561318, 14720258372954226591, 15448472262117068008, 10575290756167155008, 11997391634424499349, 9879556170680135793, 12373753045781314057, 9529470285212177396, 10620662102176580756, 10199402949196411787, 9825825353570660203, 18337390924518345383, 15945306792731206141, 10537181099344133724, 5505106000120813030, 14774803975376978777, 14575654492591748955, 8207377881872409730, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [87, 13742292427306144985, 17809381881860746878, 14185813834021479236, 2902380466328372776, 10999219428618119040, 9481695403573415070, 17673131597834433577, 12696786409220765700, 15592207435049660262, 13736774864431335246, 16717684302941853782, 14364466680417169443, 12260890044409800607, 17206474997006265051, 5035815000061711911, 9674580830266028521, 5580437753203777486, 15970593365487106653, 4096979907706804740, 15051763954056533599, 6913739807603556015, 9886633434535102281, 844824200045222171, 8033531154978796131, 17667639225113520026, 5672989858483365109, 2139538828134465604, 14154439558213594386, 15349070088087119300, 17443416980221933050, 10234632751699861532, 0, 13943995520284385472, 3038244952392737403, 2166498267314208258, 16766052460675760559, 17479836829311383480, 2421503110457951828, 4244078595888625427, 16470951341042419630, 10761733147329482159, 13363868789360680527, 8361105415211156204, 1063676068352620466, 15563346705142691804, 16788006368298087947, 1542676998191593053, 3303936282197422453, 6962236012055562966, 10808278092072460642, 5434427870325080160, 5951881526364525804, 10397118299016726484, 17744715934780154469, 6560905318933416747, 9119760857355898684, 12080225949269433371, 5462523753418276656, 4395579796774914984, 5461299377107545721, 10515379984412735135, 1357729935919477555, 4049192570105751375, 4049192570105751375, 2092801171489897510, 11830947885319956418, 7737209888784159602, 13533379427213586747, 12969897466948219293, 4397768078443292399, 11254764769292894033, 18099434164004083138, 2485855531816604722, 13525894453675963834, 8196759787025064775, 5345512927193726757, 10899057564736574513, 18177523421240333385, 5914611942628028009, 15108016113357317953, 1860837626615492164, 2201407520096262430, 15072295315432912557, 2703103454418315711, 923818922603460716, 18443738463070648510, 9827923975568229619, 11004068350566519627, 3092487934656948277, 16549791451828015234, 4910799883829461137, 15606093107492977367, 40421079456104423, 33594342817809819, 16993857945986913175, 0, 164, 14482187202392982684, 17682350329754313417, 66214439016909251, 7504629639084879386, 11708178258767948919, 188011405648496761, 10242982970375452289, 16510140404231294235, 13381084464566932690, 9239012175869487665, 9339694231140180875, 9917181315244873380, 17448534469581521177, 4965043893766771965, 13305445405772227224, 6963375374275021656, 4554518835153561582, 1694446457415578298, 4604616361036784646, 11439774970058559661, 10784225701912607868, 17782855612978839775, 13368223431578003475, 18100595786373494652, 12753204151452870283, 17504098334052422651, 12896535568794110034, 7402084190222773115, 598469278842686486, 5912604878679295331, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 10801573669330193043, 4014163844046372573, 1979187468149850032, 7068929233685234045, 6627279045165985143, 956116317527270230, 11757065279852506121, 1740402123045436483, 10251517583944092682, 5551917630030385122, 65503834883425781, 15453754233876106148, 10203814174951024159, 11998108441263059891, 922784102208491029, 17685677737193760186, 5204010590575197441, 3224334584493279137, 12733973074113146504, 12628586848138973198, 9618350092243669634, 1435727158819410801, 6720472488718189255, 8476570694128937109, 7307051990735150855, 15061013104031335890, 11522811345813436372, 4676228375886937826, 17477781110059685856, 9362502897182671987, 11254953448960768625, 0, 145249957631262975, 8386361303932939763, 13068211219747943554, 10741543262911175860, 16819603317278983686, 5783881320200053288, 18417524745718206114, 17717239843479976187, 4030689483576599003, 879151411992161296, 2779769903465702190, 14759893362240473482, 6691146416202555339, 11287199716539837261, 11126920347653441896, 12376075663235117060, 17793881754348373966, 2747583073029700026, 10825449445092551825, 5205786761888799519, 5879451121482504957, 8279206964799001491, 3768506969286097604, 10538414058473986667, 4512042016117019806, 9367766578866915876, 12466325711864282871, 4805225664863956509, 7450238737884914862, 7510284002737324288, 9029012768772075486, 9029012768772075486, 16998693837234676944, 15125640082304919550, 6110574402514906801, 4404297180800676786, 4728227612288081644, 5806909779738895718, 13841571116725704679, 10405162090868595527, 1295701329370151493, 15339349621927026708, 13512312828114051231, 10968291943912870575, 2665224526083019926, 11454603613487247488, 18085989619482158634, 8156733875584402577, 15725343254588574135, 17190667807892286789, 4147804706937142458, 13843504867107001118, 13430940141760251552, 2236397580466830219, 3736249992832820982, 11869484276361150688, 939908675643132953, 8795331189349109030, 1903118753742396596, 10434554919272483089, 15053297738150165437, 12279517140635782046, 8264942609101286638, 0, 41, 3800418813655617572, 14503408479575576010, 10553169970007645345, 4946745422622378051, 7127828976000219721, 2687285609278369395, 16630221959750548176, 1114885198959805561, 3895092647933222339, 9831397389014117600, 12816842684293233323, 1779119880742935864, 17663607747965229138, 5382558247959552902, 11972955750871888364, 16616426694032134438, 9711126273890628516, 376576173107709408, 12451218545182255865, 14301764572821220192, 13209253693600827240, 5745169166190656073, 12916752429524642864, 14463770325561420619, 7870235520772452232, 13278341252249613603, 5432056100901092307, 8994645443800925562, 5908996313982662075, 1494658977663487041, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 2688488582456733640, 3176173060019065635, 18309940476973301558, 6936565830330512698, 6894736762296179522, 90344116647093812, 7242437296897104684, 6840278566006653320, 12841299952034848927, 13801531974995903464, 3431188141752586880, 6945555547969535469, 16385619022525424479, 2302137229552580420, 3562300556391111858, 18050279212829828519, 11845451884839552921, 18010307414852664162, 1572578420442156655, 12278794746552983052, 7729016306498836651, 17389954356356902848, 14310782857892986700, 16540335065460741454, 9418678319655461294, 9662888408142346895, 9673811223372787800, 16236416741726566504, 1941798973941376537, 5283201687609097620, 677503724821015517, 0, 13943995520284385472, 13893715067188783613, 3737686312150097138, 6408571846489205195, 5309320507954343198, 7907473214578333250, 3220998093077600799, 6474302970739201787, 16744589822124330786, 15338963790186860624, 12429535237881910980, 4353091614275483153, 12430118441204168389, 15563175998310034114, 7172174870857485673, 2253621527545508840, 4507428390885076546, 2693291710499435080, 18303680792619501937, 12658208632913334575, 18044025142180450635, 14512997676069758708, 6038828855361889649, 16387791750090568457, 2816243451374973997, 15990457456638139626, 5938146028305439666, 8292027417405396428, 12456535987381445341, 4686309106959500238, 9680729728072440816, 9680729728072440816, 275926701951807482, 2368214261414429154, 15583218305860063073, 12342565443853005153, 7791191498940082574, 5368134609913732769, 18241043179323819051, 6247074573395806345, 7865016694973943467, 13276760677885131566, 12501576801121215107, 14003841288523724393, 7706369500077994851, 14277720092332100080, 16831403894744601879, 9685715221108858847, 12090932747658876990, 15574096712669166429, 16819229186816553924, 3675188622214856303, 6131072316753506600, 5455404512357596637, 3180536826353817667, 6733192297441041488, 3057140685660277923, 15037300764129498232, 12789460187938846931, 12722152077589496357, 5754948178406885282, 9383881360936187956, 10120172904062862410, 0, 41, 13092032916490151270, 2856458557507854671, 14059661153766146178, 1724041303048776424, 7119687853704366589, 3699246950542313036, 8338994289155538949, 7732171807197958061, 10653644351656999339, 15262849800927670044, 6132373490633371091, 16473831322001214578, 12928938600331453669, 6959935525856744214, 17173069020016176920, 6747622983845354522, 2484033613426731933, 9879916419081378373, 4275250202523893223, 5995505684018086986, 16115855409799741127, 2490003355474156145, 10034475279304353355, 7223217715426381376, 10334063888823214988, 2139000562522371457, 18314119367638727156, 15311716904301189063, 894706229073498557, 1570146104298050273, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] }, last_program_row: RowIndex(88) }, program_info: ProgramInfo { program_hash: Word([6965138066206642862, 12596233587871940770, 8197358252954291811, 10673667133036073096]), kernel: Kernel([]) }, stack_outputs: StackOutputs { elements: [2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, merkle_store_nodes: {Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571]): (Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350]), Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350])), Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484]): (Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693]), Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693])), Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781]): (Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874]), Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874])), Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171]): (Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361]), Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361])), Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815]): (Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305]), Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305])), Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689]): (Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195]), Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195])), Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362]): (Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063]), Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063])), Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848]): (Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661]), Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661])), Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352]): (Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829]), Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829])), Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444]): (Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223]), Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223])), Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386]): (Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388]), Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388])), Word([13190842942618341421, 17548956981569849952, 15418963848144418856, 730733050713174879]): (Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144]), Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144])), Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874]): (Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675]), Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675])), Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594]): (Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115]), Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115])), Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809]): (Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257]), Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257])), Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777]): (Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555]), Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555])), Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509]): (Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882]), Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882])), Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725]): (Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979]), Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979])), Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134]): (Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987]), Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987])), Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828]): (Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910]), Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910])), Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830]): (Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054]), Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054])), Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228]): (Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742]), Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742])), Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443]): (Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928]), Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928])), Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643]): (Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979]), Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979])), Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758]): (Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106]), Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106])), Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580]): (Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594]), Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594])), Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765]): (Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045]), Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045])), Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766]): (Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281]), Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281])), Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385]): (Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828]), Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828])), Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579]): (Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171]), Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171])), Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212]): (Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992]), Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992])), Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463]): (Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004]), Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004])), Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502]): (Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023]), Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023])), Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539]): (Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537]), Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537])), Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865]): (Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225]), Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225])), Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690]): (Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947]), Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947])), Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202]): (Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552]), Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552])), Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079]): (Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444]), Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444])), Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850]): (Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548]), Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548])), Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448]): (Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987]), Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987])), Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041]): (Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035]), Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035])), Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301]): (Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414]), Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414])), Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414]): (Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212]), Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212])), Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703]): (Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439]), Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439])), Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271]): (Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955]), Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955])), Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882]): (Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802]), Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802])), Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152]): (Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887]), Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887])), Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028]): (Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948]), Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948])), Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331]): (Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093]), Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093])), Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394]): (Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134]), Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134])), Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546]): (Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228]), Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228])), Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620]): (Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414]), Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414])), Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800]): (Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703]), Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703])), Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671]): (Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205]), Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205])), Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537]): (Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011]), Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011])), Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516]): (Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301]), Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301])), Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831]): (Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986]), Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986])), Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415]): (Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057]), Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057])), Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722]): (Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689]), Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689])), Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144]): (Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682]), Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682])), Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295]): (Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268]), Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268])), Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818]): (Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513]), Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513])), Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241]): (Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565]), Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565])), Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439]): (Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012]), Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012])), Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512]): (Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850]), Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850])), Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986]): (Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865]), Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865])), Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982]): (Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777]), Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777])), Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808]): (Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394]), Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394])), Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979]): (Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690]), Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690])), Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093]): (Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620]), Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620])), Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902]): (Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789]), Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789])), Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542]): (Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094]), Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094])), Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057]): (Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362]), Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362])), Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205]): (Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961]), Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961])), Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401]): (Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580]), Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580])), Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553]): (Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960]), Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960])), Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169]): (Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031]), Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031])), Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682]): (Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053]), Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053])), Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118]): (Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562]), Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562])), Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725]): (Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666]), Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666])), Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661]): (Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897]), Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897])), Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981]): (Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447]), Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447])), Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072]): (Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646]), Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646])), Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140]): (Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404]), Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404])), Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515]): (Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152]), Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152])), Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709]): (Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664]), Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664])), Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800]): (Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103]), Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103])), Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741]): (Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169]), Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169])), Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005]): (Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758]), Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758])), Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802]): (Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070]), Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070])), Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159]): (Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005]), Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005])), Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350]): (Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443]), Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443])), Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697]): (Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573]), Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573])), Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928]): (Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331]), Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331])), Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320]): (Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166]), Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166])), Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814]): (Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079]), Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079])), Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447]): (Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820]), Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820])), Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284]): (Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057]), Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057])), Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697]): (Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131]), Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131])), Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955]): (Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290]), Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290])), Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910]): (Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202]), Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202])), Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910]): (Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822]), Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822])), Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106]): (Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847]), Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847])), Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404]): (Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441]), Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441])), Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796]): (Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186]), Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186])), Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053]): (Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516]), Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516])), Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992]): (Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818]), Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818])), Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957]): (Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315]), Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315])), Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709]): (Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794]), Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794])), Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091]): (Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539]), Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539])), Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664]): (Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558]), Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558])), Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294]): (Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579]), Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579])), Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947]): (Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502]), Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502])), Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829]): (Word([0, 0, 0, 0]), Word([0, 0, 0, 0])), Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045]): (Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137]), Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137])), Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914]): (Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041]), Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041])), Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573]): (Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378]), Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378])), Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699]): (Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873]), Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873])), Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225]): (Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262]), Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262])), Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057]): (Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692]), Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692])), Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131]): (Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997]), Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997])), Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555]): (Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385]), Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385])), Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195]): (Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709]), Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709])), Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166]): (Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542]), Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542])), Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027]): (Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373]), Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373])), Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378]): (Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509]), Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509])), Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097]): (Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553]), Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553])), Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217]): (Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815]), Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815])), Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873]): (Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864]), Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864])), Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997]): (Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722]), Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722])), Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887]): (Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766]), Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766])), Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589]): (Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757]), Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757])), Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539]): (Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665]), Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665])), Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129]): (Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229]), Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229])), Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137]): (Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312]), Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312])), Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019]): (Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378]), Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378])), Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331]): (Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713]), Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713])), Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]): (Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980]), Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980])), Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325]): (Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546]), Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546])), Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170]): (Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822]), Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822])), Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054]): (Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295]), Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295])), Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925]): (Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848]), Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848])), Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909]): (Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796]), Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796])), Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540]): (Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170]), Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170])), Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214]): (Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448]), Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448])), Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317]): (Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294]), Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294])), Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757]): (Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416]), Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416])), Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378]): (Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091]), Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091])), Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263]): (Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463]), Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463])), Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666]): (Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361]), Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361])), Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174]): (Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992]), Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992])), Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470]): (Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401]), Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401])), Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665]): (Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957]), Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957])), Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262]): (Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144]), Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144])), Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229]): (Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284]), Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284])), Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134]): (Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325]), Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325])), Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855]): (Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765]), Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765])), Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115]): (Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814]), Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814])), Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441]): (Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831]), Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831])), Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977]): (Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446]), Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446])), Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880]): (Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005]), Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005])), Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789]): (Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995]), Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995])), Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000]): (Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267]), Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267])), Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998]): (Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982]), Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982])), Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995]): (Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539]), Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539])), Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507]): (Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512]), Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512])), Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305]): (Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118]), Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118])), Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219]): (Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009]), Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009])), Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416]): (Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089]), Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089])), Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980]): (Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445]), Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445])), Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063]): (Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140]), Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140])), Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713]): (Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159]), Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159])), Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031]): (Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809]), Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809])), Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932]): (Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037]), Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037])), Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094]): (Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925]), Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925])), Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315]): (Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386]), Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386])), Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446]): (Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721]), Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721])), Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742]): (Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981]), Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981])), Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661]): (Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072]), Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072])), Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979]): (Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671]), Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671])), Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361]): (Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269]), Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269])), Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558]): (Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571]), Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571])), Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290]): (Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902]), Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902])), Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987]): (Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741]), Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741])), Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902]): (Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515]), Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515])), Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497]): (Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028]), Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028])), Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948]): (Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709]), Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709])), Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009]): (Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725]), Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725])), Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387]): (Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317]), Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317])), Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159]): (Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808]), Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808])), Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394]): (Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699]), Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699])), Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312]): (Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000]), Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000])), Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987]): (Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821]), Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821])), Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046]): (Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909]), Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909])), Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565]): (Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028]), Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028])), Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269]): (Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352]), Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352])), Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847]): (Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271]), Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271])), Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513]): (Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800]), Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800])), Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054]): (Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394]), Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394])), Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004]): (Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977]), Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977])), Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675]): (Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800]), Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800])), Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692]): (Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159]), Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159])), Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909]): (Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932]), Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932])), Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814]): (Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697]), Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697])), Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186]): (Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387]), Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387])), Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445]): (Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470]), Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470])), Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966]): (Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507]), Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507])), Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548]): (Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253]), Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253])), Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897]): (Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783]), Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783])), Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208]): (Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054]), Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054])), Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268]): (Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661]), Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661])), Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388]): (Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643]), Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643])), Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257]): (Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174]), Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174])), Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960]): (Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241]), Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241])), Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721]): (Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046]), Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046])), Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822]): (Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217]), Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217])), Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253]): (Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697]), Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697])), Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054]): (Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019]), Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019])), Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821]): (Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432]), Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432])), Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864]): (Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105]), Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105])), Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373]): (Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855]), Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855])), Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646]): (Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830]), Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830])), Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460]): (Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208]), Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208])), Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033]): (Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214]), Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214])), Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105]): (Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129]), Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129])), Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281]): (Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909]), Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909])), Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028]): (Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027]), Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027])), Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012]): (Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054]), Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054])), Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562]): (Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589]), Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589])), Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037]): (Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097]), Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097])), Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355]): (Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460]), Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460])), Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223]): (Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355]), Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355])), Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089]): (Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306]), Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306])), Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035]): (Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219]), Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219])), Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432]): (Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297]), Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297])), Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693]): (Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263]), Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263])), Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794]): (Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484]), Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484])), Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552]): (Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941]), Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941])), Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267]): (Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814]), Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814])), Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992]): (Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415]), Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415])), Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941]): (Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966]), Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966])), Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822]): (Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320]), Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320])), Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306]): (Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902]), Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902])), Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820]): (Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880]), Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880])), Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361]): (Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725]), Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725])), Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005]): (Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914]), Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914])), Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783]): (Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781]), Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781])), Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011]): (Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033]), Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033])), Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297]): (Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910]), Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910])), Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070]): (Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134]), Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134])), Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144]): (Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331]), Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331])), Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023]): (Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497]), Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497])), Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103]): (Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540]), Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540])), Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961]): (Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998]), Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998])), Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414]): (Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]), Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]))}, trace_len_summary: TraceLenSummary { main_trace_len: 89, range_trace_len: 39, chiplets_trace_len: ChipletsLengths { hash_chiplet_len: 128, bitwise_chiplet_len: 0, memory_chiplet_len: 0, kernel_rom_len: 0 } } } +ExecutionTrace { main_trace: MainTrace { storage: Parts { core_rm: [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 3522571414841252998, 8184450079211665661, 6529578262649975717, 6261706375900221050, 7532528701100807439, 10480547126759850066, 6097728641437901141, 17248496754222975198, 0, 0, 0, 0, 0, 0, 1, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 580999813345182728, 580999813345182728, 580999813345182728, 580999813345182728, 580999813345182728, 580999813345182728, 580999813345182728, 580999813345182728, 0, 9, 0, 1, 0, 0, 1, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 2, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 4539061041759240, 1, 0, 0, 0, 0, 0, 0, 1, 8, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 3, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 35461414388744, 1, 0, 0, 0, 0, 0, 0, 1, 8, 1, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 4, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 277042299912, 1, 0, 0, 0, 0, 0, 0, 1, 8, 2, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 5, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 2164392968, 1, 0, 0, 0, 0, 0, 0, 1, 8, 3, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 6, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 16909320, 1, 0, 0, 0, 0, 0, 0, 1, 8, 4, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 7, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 132104, 1, 0, 0, 0, 0, 0, 0, 1, 8, 5, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 8, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 1032, 1, 0, 0, 0, 0, 0, 0, 1, 8, 6, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 9, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 8, 1, 0, 0, 0, 0, 0, 0, 1, 8, 7, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 10, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 8, 8, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 11, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 4539061041759240, 1, 0, 0, 0, 0, 0, 0, 1, 7, 0, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 12, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 35461414388744, 1, 0, 0, 0, 0, 0, 0, 1, 7, 1, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 13, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 277042299912, 1, 0, 0, 0, 0, 0, 0, 1, 7, 2, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 14, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 2164392968, 1, 0, 0, 0, 0, 0, 0, 1, 7, 3, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 15, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 16909320, 1, 0, 0, 0, 0, 0, 0, 1, 7, 4, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 16, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 132104, 1, 0, 0, 0, 0, 0, 0, 1, 7, 5, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 17, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 1032, 1, 0, 0, 0, 0, 0, 0, 1, 7, 6, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 18, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 8, 1, 0, 0, 0, 0, 0, 0, 1, 7, 7, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 19, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 7, 8, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 20, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 4539061041759240, 1, 0, 0, 0, 0, 0, 0, 1, 6, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 21, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 35461414388744, 1, 0, 0, 0, 0, 0, 0, 1, 6, 1, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 22, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 277042299912, 1, 0, 0, 0, 0, 0, 0, 1, 6, 2, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 23, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 2164392968, 1, 0, 0, 0, 0, 0, 0, 1, 6, 3, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 24, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 16909320, 1, 0, 0, 0, 0, 0, 0, 1, 6, 4, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 25, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 132104, 1, 0, 0, 0, 0, 0, 0, 1, 6, 5, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 26, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 1032, 1, 0, 0, 0, 0, 0, 0, 1, 6, 6, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 27, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 8, 1, 0, 0, 0, 0, 0, 0, 1, 6, 7, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 28, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 6, 8, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 29, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 4539061041759240, 1, 0, 0, 0, 0, 0, 0, 1, 5, 0, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 30, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 35461414388744, 1, 0, 0, 0, 0, 0, 0, 1, 5, 1, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 31, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 277042299912, 1, 0, 0, 0, 0, 0, 0, 1, 5, 2, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 32, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 2164392968, 1, 0, 0, 0, 0, 0, 0, 1, 5, 3, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 33, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 16909320, 1, 0, 0, 0, 0, 0, 0, 1, 5, 4, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 34, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 132104, 1, 0, 0, 0, 0, 0, 0, 1, 5, 5, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 35, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 1032, 1, 0, 0, 0, 0, 0, 0, 1, 5, 6, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 36, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 8, 1, 0, 0, 0, 0, 0, 0, 1, 5, 7, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 37, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 5, 8, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 38, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 4539061041759240, 1, 0, 0, 0, 0, 0, 0, 1, 4, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 39, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 35461414388744, 1, 0, 0, 0, 0, 0, 0, 1, 4, 1, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 40, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 277042299912, 1, 0, 0, 0, 0, 0, 0, 1, 4, 2, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 41, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 2164392968, 1, 0, 0, 0, 0, 0, 0, 1, 4, 3, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 42, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 16909320, 1, 0, 0, 0, 0, 0, 0, 1, 4, 4, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 43, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 132104, 1, 0, 0, 0, 0, 0, 0, 1, 4, 5, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 44, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 1032, 1, 0, 0, 0, 0, 0, 0, 1, 4, 6, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 45, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 8, 1, 0, 0, 0, 0, 0, 0, 1, 4, 7, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 46, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 4, 8, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 47, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 4539061041759240, 1, 0, 0, 0, 0, 0, 0, 1, 3, 0, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 48, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 35461414388744, 1, 0, 0, 0, 0, 0, 0, 1, 3, 1, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 49, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 277042299912, 1, 0, 0, 0, 0, 0, 0, 1, 3, 2, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 50, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 2164392968, 1, 0, 0, 0, 0, 0, 0, 1, 3, 3, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 51, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 16909320, 1, 0, 0, 0, 0, 0, 0, 1, 3, 4, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 52, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 132104, 1, 0, 0, 0, 0, 0, 0, 1, 3, 5, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 53, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 1032, 1, 0, 0, 0, 0, 0, 0, 1, 3, 6, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 54, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 8, 1, 0, 0, 0, 0, 0, 0, 1, 3, 7, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 55, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 3, 8, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 56, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 4539061041759240, 1, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 57, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 35461414388744, 1, 0, 0, 0, 0, 0, 0, 1, 2, 1, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 58, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 277042299912, 1, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 59, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 2164392968, 1, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 60, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 16909320, 1, 0, 0, 0, 0, 0, 0, 1, 2, 4, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 61, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 132104, 1, 0, 0, 0, 0, 0, 0, 1, 2, 5, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 62, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 1032, 1, 0, 0, 0, 0, 0, 0, 1, 2, 6, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 63, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 8, 1, 0, 0, 0, 0, 0, 0, 1, 2, 7, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 64, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 2, 8, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 65, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 4539061041759240, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 66, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 35461414388744, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 67, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 277042299912, 1, 0, 0, 0, 0, 0, 0, 1, 1, 2, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 68, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 2164392968, 1, 0, 0, 0, 0, 0, 0, 1, 1, 3, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 69, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 16909320, 1, 0, 0, 0, 0, 0, 0, 1, 1, 4, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 70, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 132104, 1, 0, 0, 0, 0, 0, 0, 1, 1, 5, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 71, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 1032, 1, 0, 0, 0, 0, 0, 0, 1, 1, 6, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 72, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 8, 1, 0, 0, 0, 0, 0, 0, 1, 1, 7, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 73, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 8, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 74, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 1, 1, 1, 4539061041759240, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 75, 0, 0, 0, 0, 0, 5, 0, 0, 0, 1, 0, 0, 0, 35461414388744, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 76, 0, 0, 0, 0, 0, 5, 0, 0, 0, 1, 0, 0, 0, 277042299912, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 77, 0, 0, 0, 0, 0, 5, 0, 0, 0, 1, 0, 0, 0, 2164392968, 1, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 78, 0, 0, 0, 0, 0, 5, 0, 0, 0, 1, 0, 0, 0, 16909320, 1, 0, 0, 0, 0, 0, 0, 1, 0, 3, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 79, 0, 0, 0, 0, 0, 5, 0, 0, 0, 1, 0, 0, 0, 132104, 1, 0, 0, 0, 0, 0, 0, 1, 0, 4, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 80, 0, 0, 0, 0, 0, 5, 0, 0, 0, 1, 0, 0, 0, 1032, 1, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 81, 0, 0, 0, 0, 0, 5, 0, 0, 0, 1, 0, 0, 0, 8, 1, 0, 0, 0, 0, 0, 0, 1, 0, 6, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 82, 0, 0, 0, 0, 0, 5, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 7, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 83, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 1, 1, 1, 3522571414841252998, 8184450079211665661, 6529578262649975717, 6261706375900221050, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 84, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 41, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 85, 0, 0, 0, 0, 0, 7, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 86, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 1, 1, 1, 7532528701100807439, 10480547126759850066, 6097728641437901141, 17248496754222975198, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 87, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 88, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 89, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 90, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 91, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 92, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 93, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 94, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 97, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 98, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 99, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 101, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 102, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 103, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 104, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 105, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 106, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 107, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 108, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 109, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 110, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 111, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 112, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 113, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 114, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 115, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 116, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 117, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 118, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 119, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 120, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 121, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 122, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 123, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 124, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 125, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 126, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 127, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0], chiplets_rm: [1, 1, 0, 0, 3522571414841252998, 8184450079211665661, 6529578262649975717, 6261706375900221050, 7532528701100807439, 10480547126759850066, 6097728641437901141, 17248496754222975198, 0, 87, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 17501946937763933948, 7675566390936895331, 4994195757323687992, 11767874304575963253, 1780538466631614833, 4063459066104458636, 4522236916001186996, 2303690644539739387, 0, 0, 1, 0, 0, 1, 1, 0, 0, 580999813345182728, 580999813345182728, 580999813345182728, 580999813345182728, 580999813345182728, 580999813345182728, 580999813345182728, 580999813345182728, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 17435140114479298129, 1435885832764997654, 215283041871207160, 7082661356804799086, 5416435572438850612, 2882953289127770017, 16218313204809782547, 8575194234315674944, 213625975700372028, 6103762562402135118, 8461833255366069567, 1720047680925886481, 0, 0, 0, 0, 0, 1, 1, 0, 0, 4539061041759240, 0, 0, 0, 0, 0, 0, 0, 213625975700372028, 6103762562402135118, 8461833255366069567, 1720047680925886481, 0, 0, 0, 0, 0, 1, 0, 0, 0, 3522571414841252998, 8184450079211665661, 6529578262649975717, 6261706375900221050, 7634873969298005933, 8950987357718038443, 13680774040296089728, 16762235143106196223, 16430047160501569010, 14861946194768960443, 10513948170299859642, 11975838346548297297, 0, 0, 1, 0, 0, 1, 1, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 7532528701100807439, 10480547126759850066, 6097728641437901141, 17248496754222975198, 12342802819241620905, 7554371666290801318, 8718773026382250605, 15984482998549000918, 15460443374009848343, 1087146607978023558, 7531163901062156801, 4426949494427873777, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 11621565010787354140, 1949391780818670486, 7327781180606137861, 2419787217529136215, 13249250205018233525, 10029758640146777270, 5716716695107147273, 10829954014693503473, 7405851154679558693, 2030135877513774489, 10401768244118899621, 7992444660002654486, 1, 0, 0, 0, 1, 0, 0, 0, 0, 9190577937819620371, 12978309842325015235, 10477013461463931935, 4855391316239312738, 10519745218266697287, 18375374895419140100, 876067972673449756, 17915370314859305010, 17877705855294641231, 120652674332571204, 3378556434908723888, 17649391022523856338, 1, 0, 0, 0, 1, 0, 0, 0, 0, 15052947986857015373, 3007680259418135415, 3197694984858038551, 6563270153864719814, 6889631464391242687, 12614331779225506253, 8884325160266334095, 15067359903282619456, 6045216153329131722, 7293213550537411486, 18377064823051127268, 14733223614830533518, 1, 0, 0, 0, 1, 0, 1248924765333967865, 15568788993061722932, 4037714036443683170, 2584579945446987950, 3496704858534018972, 10965787981110521559, 9000006360952503550, 8377181923806419223, 18078834148678517323, 13751832434934340803, 15306332964801742551, 828627458527105190, 2519953652271814816, 5563221586835004955, 16428502736240336605, 1, 0, 0, 0, 1, 0, 161503374172189975, 7180975586994120588, 13070121377098205312, 9655464535561865455, 4169214041423852321, 5771090309048429384, 6993654059550252564, 14478380452460405826, 12150434000885474539, 18399347099839405992, 88779829066683150, 4428174353386180423, 7547120791432137516, 11951584238447172023, 8804182506418522715, 1, 0, 0, 0, 1, 0, 1859011259345361207, 13205265558511858864, 16229683663108620000, 17688418164436772208, 12658415008146819428, 6291208835901171779, 3297271436089179933, 12943628284217684119, 11639259038601904106, 10502234848011596680, 13946225273525543944, 11318468498957948083, 13851055481982014034, 5765565570506082255, 10777382518726251007, 1, 0, 0, 0, 1, 0, 1023422172081481959, 14540338366569412926, 10271517463444484758, 8863158288377959817, 9066561794313536160, 10161961919995709177, 2094278659773331823, 4371761587112760854, 10972685992181286814, 5641963675353630718, 15569415989710829261, 4258403342016907208, 4740804749082440837, 1594229550076307598, 5045104152796606559, 1, 0, 0, 0, 1, 0, 12053626300860885956, 13987509258486900924, 17286360383804666298, 8301538772707939488, 7700154594411825373, 14332053735409157564, 6894934729579673545, 5430665485920789830, 10553406992561403551, 11528229548578861261, 3294597468571627674, 2903493961726666462, 10560076388764518443, 3749651622493296975, 18114127684252877364, 1, 0, 0, 0, 1, 0, 12240592655856206466, 6264740020775290721, 859763567572081467, 8842953438422484122, 14329981889510246939, 3582542183068105786, 6023391989510151456, 2953193964713672141, 12396149302348639250, 13882467375549577428, 3586988377712407519, 7213506509798642482, 13435456572406932891, 9645941250097564536, 2781650568775738364, 1, 0, 0, 0, 1, 0, 15637532899188291351, 12683652363890573925, 2704597975013858668, 17832955104866332736, 6815586591600943723, 13755349213265671492, 8924117914024270326, 3329964149511691453, 11039495891702065838, 15670789219464690273, 11281671746346947225, 10492374165392519994, 11439270560757451470, 7337394676363778206, 2272256910055258613, 1, 0, 0, 0, 1, 0, 3130343892077994054, 0, 0, 1136320813223337744, 11438337112810950654, 16692992611178972868, 9482499518540692367, 5451078715157933845, 18403012202839423090, 13340398881404871439, 16853681425214524760, 5540259513623809808, 7754241405876268140, 15538673406175044580, 15705643278636475771, 1, 0, 0, 0, 1, 0, 0, 0, 0, 6593967995490198369, 546795078589070868, 8093299549277945163, 1445098694824947603, 16968796337604054074, 7105604958885889972, 12829574433066656016, 10962264142076089650, 6970346774265824779, 5668604568559492205, 15930738860655806958, 14403244990983785091, 1, 0, 0, 0, 1, 0, 0, 0, 0, 7770193319703938593, 6228225228483877842, 5315425894230577486, 8012448033829391087, 5395398520381640698, 8770911350053719042, 14827874098479004474, 11024999006644848903, 13791657658989935762, 17830220104295996918, 2090812709146185278, 8577173283657139529, 1, 0, 0, 0, 1, 0, 0, 0, 0, 17471481800618265475, 1930822204634793148, 12769804899579893379, 13068810900387198296, 10732524945348487200, 1519317270498249877, 12604995971822921101, 14107509487727911757, 8257552923782319555, 12034059115493819529, 4343039820825149431, 395799121324568963, 1, 0, 0, 0, 1, 0, 0, 0, 0, 7532528701100807439, 10480547126759850066, 6097728641437901141, 17248496754222975198, 12342802819241620905, 7554371666290801318, 8718773026382250605, 15984482998549000918, 15460443374009848343, 1087146607978023558, 7531163901062156801, 4426949494427873777, 1, 0, 0, 0, 1, 0, 0, 0, 0, 4539061041759240, 0, 0, 0, 0, 0, 0, 0, 213625975700372028, 6103762562402135118, 8461833255366069567, 1720047680925886481, 1, 0, 0, 0, 1, 0, 0, 0, 0, 13071177483731847596, 9686292801190181773, 17651358204212384773, 623102158970833400, 18161683613551356205, 1905311249198158721, 11609382548502599221, 13817075853679351908, 9025310235253336765, 7882119478620692609, 18179794579967457372, 7964168423813383674, 1, 0, 0, 0, 1, 0, 0, 0, 0, 3167601002832997672, 14415171155867193311, 16137210400120039159, 66363658294528744, 18026300366666585427, 16119825485646609021, 1791495851310687818, 10854206662041334332, 13581647106013633474, 11888984354923028713, 1057821317113010102, 5796297350077934241, 1, 0, 0, 0, 1, 0, 0, 0, 0, 7784671065083678705, 3558884115261448151, 11418253632452412773, 1403627403973388394, 819084279764884206, 1407109872228328204, 5246174561222584074, 3872887851860878865, 6987805815025651594, 16813603419480913328, 2035491262798693541, 63867729655895697, 1, 0, 0, 0, 1, 0, 15907894811979069988, 4816131323033975155, 7888904563512413895, 5092349396408408417, 1042143422396538716, 3762822649239783949, 8196544070748041586, 10315355419527218517, 7339407603689058379, 10639948648547682671, 6123607466480072181, 14853363043128504640, 17058485441092820903, 17161076486544329100, 14143325759900421814, 1, 0, 0, 0, 1, 0, 7591190062109417050, 9132932650297078912, 18059219497059994491, 12482898336916528446, 13174698819228496505, 2493773128969151007, 12643635820180007001, 3083772711687177863, 15089756422354654327, 7693091574011130832, 9436166604667119301, 12830611190312913054, 7973972404932364743, 10464756062953622156, 109716314765170116, 1, 0, 0, 0, 1, 0, 4126769846122054656, 707829251663853104, 7629957164358255416, 9341908378498020691, 3690464399435141132, 13117698496574260979, 5451440718276137237, 7550245756112946615, 11753021061535422888, 15170963155944982481, 5947667375361174600, 1596111063080183500, 11749390155806323479, 12692175311028724710, 7916688742951942744, 1, 0, 0, 0, 1, 0, 4645035303164012400, 13915916204012920340, 12291486388396280500, 525851188163440848, 4707286392244844218, 16013577564573367551, 13868023936870720304, 5148135937681993147, 18040333195915377325, 11529652625051471948, 1852565776215464254, 14161537793254580129, 4048643506759177080, 14450982547699381817, 2934196537578419476, 1, 0, 0, 0, 1, 0, 11488303914325795411, 11765426007596825119, 1523836086483283753, 16127371626322030471, 13747186051093078910, 14683368485138504162, 12593690295898988948, 15228744413198821157, 7332814344843067213, 14138816066324498937, 2102762737278850021, 13313601398896337631, 13121420191740374129, 6257139546349661876, 9729033453413867848, 1, 0, 0, 0, 1, 0, 9708911278112697027, 15643607479776624214, 10807857923693087240, 8404702627227890823, 10047145562846981342, 15600116582547970218, 4297960339811615000, 17447637109133227112, 14290298932221000300, 13800955719543521787, 110863501940494442, 13161269314340397651, 2105063197779559491, 13124468932815073025, 714461081021505970, 1, 0, 0, 0, 1, 0, 9223191767830668365, 13626886630453446877, 10808778593074643576, 16763094170387080928, 10091458508962207795, 1734402459021112515, 4981576688453120205, 11005274036034670139, 14260715897147313611, 14806437275519594979, 10665791613726598397, 14265115120417368616, 747062796356804415, 4246870895382373678, 13220614616296969944, 1, 0, 0, 0, 1, 0, 13513127228332885632, 0, 0, 1736827337212275711, 17257174989540467501, 1988362627286450135, 99834712623465846, 5084645948111347049, 5551869680521103369, 12383048268571476338, 6568255087418472584, 13499605423494581814, 14111004362252364285, 15934954653433784852, 9984027318635910457, 1, 0, 0, 0, 1, 0, 0, 0, 0, 8495902383234192130, 13668678621722857045, 1558838040737371863, 15847552217836362268, 13055057243174343494, 8303291408352268536, 9870497363393333103, 18078068399423404657, 7583410213159199266, 1978193982764743020, 10535947734617692172, 10075032150190943363, 1, 0, 0, 0, 1, 0, 0, 0, 0, 12695633069775171902, 12809525764874681027, 9040743543114295790, 13518431885683893560, 13563025936958449940, 1763639376881521592, 970981096276376670, 9777469034389610638, 6320282846588280835, 14270738802862611769, 8722537202086045490, 8243744667044787741, 1, 0, 0, 0, 1, 0, 0, 0, 0, 13642526033304235324, 4183147132623728298, 15386162382022344959, 16003283145777258468, 8391278540569750664, 4213029299554789023, 3437746951445512084, 8911792534982071466, 16183870450597134620, 7787473152259124966, 7310128289290306511, 17060872974098059643, 1, 0, 0, 0, 1, 0, 0, 0, 0, 3522571414841252998, 8184450079211665661, 6529578262649975717, 6261706375900221050, 7634873969298005933, 8950987357718038443, 13680774040296089728, 16762235143106196223, 16430047160501569010, 14861946194768960443, 10513948170299859642, 11975838346548297297, 1, 0, 0, 0, 1, 0, 0, 0, 0, 580999813345182728, 580999813345182728, 580999813345182728, 580999813345182728, 580999813345182728, 580999813345182728, 580999813345182728, 580999813345182728, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 17247772468616032613, 7600025394925764221, 7955777840235657962, 14778507181110587334, 6625781598431722644, 11269587024342180880, 1095078499718437680, 17629529705726254471, 12173823341773609445, 12027777926473976977, 10548232447298848920, 11191668470571035623, 1, 0, 0, 0, 1, 0, 0, 0, 0, 7212854399021382347, 8260158641355935804, 2036343373575726272, 20645146758280648, 2412515286962891034, 12558060813250728464, 18115796003320518003, 9956385073995476810, 8355451719607804905, 11898465697935779867, 11481620581339396075, 5053988127852505047, 1, 0, 0, 0, 1, 0, 0, 0, 0, 4083599105365810292, 8723345258690657607, 11473264062281662940, 6256926579240276105, 5468644964009567782, 758108007400586868, 9520951491853586676, 17787553860746980342, 9963059105071042759, 5935249146141459086, 1727497401312731108, 7027114296019665026, 1, 0, 0, 0, 1, 0, 17225384659479695880, 7547107831863943900, 7586494724370585223, 18439830271691383815, 510380585799936904, 2097735149637624737, 5010192402325660771, 17721827191138606667, 14151172043623379279, 2621138995929369414, 4866521825536676258, 4936774475173485037, 6084983335248988076, 1316337623165354879, 9646582244215554347, 1, 0, 0, 0, 1, 0, 4516215479177926657, 9925616832160314316, 9773586622763691078, 948219269412661958, 14611700435569786419, 16773932546889685810, 1107809727464434614, 9560879713002703906, 11076903123274807987, 16881679433359356735, 2715948938378293043, 11628515061150373855, 4162557158410810904, 5205045181658915242, 11540698754684563718, 1, 0, 0, 0, 1, 0, 10202041226865208435, 141985322414560908, 3299848892110581995, 3159604077290060804, 8622054486534314214, 5474513080224483433, 4110000601336855383, 4902345883390777501, 15764127542136630764, 4294885769175896152, 6235735371157527541, 2485227587384103094, 8848665971323760288, 13954308106415618481, 10953923591850316072, 1, 0, 0, 0, 1, 0, 5257746147149307910, 17174783517453828871, 4597653677804532205, 18237887045237368733, 11918935917804454770, 14333756346908171038, 11371612979173978084, 3583002294292261341, 13270804703147200974, 14723227373679438701, 1357634590270471295, 5781266174666314114, 17760102468114475087, 16434384456628942893, 3900814811719656723, 1, 0, 0, 0, 1, 0, 13884820746927058788, 9270374989065318967, 5246121405124210671, 7663324268782961837, 2191709360144157218, 4148893382614159356, 2733948193995819857, 14132085828870775797, 1003614799924134348, 483130048856287960, 2093261773321017838, 7244482392958895511, 4476308567349096957, 11365067184664022772, 1496399840045018815, 1, 0, 0, 0, 1, 0, 14034150103549409361, 18096513872460075506, 11127518800743472703, 16169827357990058769, 768889104582256256, 5063672134989793000, 8177152994054270953, 14519774356616750515, 5282014258228939534, 11185753418772485201, 7339855872361189863, 2751765428506627026, 16410858644837695285, 3168955570935107271, 4235839041903922738, 1, 0, 0, 0, 1, 0, 18296364930804407816, 4876679931892485987, 8700931409395017179, 14306671231110976602, 2710499980265003166, 9240811163216966608, 8568348789446621778, 15370436904049879550, 4782083616386060395, 9191241905548455193, 6045653345021378740, 13028324881145000696, 5837184942005509449, 3594114040721413816, 5576112453622336198, 1, 0, 0, 0, 1, 0, 18227500723287175099, 0, 0, 16730341839826576408, 3692638321978467303, 6433242332622521009, 2291292895494898983, 3900172221093734467, 14080120921585297673, 13252907867885073269, 16652266278011828989, 12684155440930581084, 16853736578527067231, 10903248264916314668, 17159383822002743974, 1, 0, 0, 0, 1, 0, 0, 0, 0, 9663317297640029186, 3179815813611408161, 15382868405397841289, 17774841093291303690, 15561756925779456415, 11787075848521667463, 17026707310279468613, 12513410256584319322, 17661065248686859389, 10796110328971392976, 4822670343402163355, 11372642333714183005, 1, 0, 0, 0, 1, 0, 0, 0, 0, 12923780624719410118, 15228217436729383467, 16407456617835496488, 191254740555322213, 10417005955196427443, 15631224324097912792, 9481620082656198805, 14005095752388629920, 15242482978284769044, 14954808412257515074, 12996263148551024094, 15208300493676788879, 1, 0, 0, 0, 1, 0, 0, 0, 0, 8481699980895920040, 11355566957836326067, 10008478932238631638, 1125833604663061758, 16919269590511518832, 2391375154551093567, 14821552413345970431, 16787721412847018840, 7352920238514741096, 10037843785082573009, 10187073057528044009, 4767066643997340533, 1, 0, 0, 0, 1, 0, 0, 0, 0, 17435140114479298129, 1435885832764997654, 215283041871207160, 7082661356804799086, 5416435572438850612, 2882953289127770017, 16218313204809782547, 8575194234315674944, 213625975700372028, 6103762562402135118, 8461833255366069567, 1720047680925886481, 1, 0, 0, 0, 1, 0, 0, 0, 0, 3522571414841252998, 8184450079211665661, 6529578262649975717, 6261706375900221050, 7532528701100807439, 10480547126759850066, 6097728641437901141, 17248496754222975198, 0, 87, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 14335534823153189982, 2564274019290773358, 1240147410646593301, 4309759344612372747, 15680264455718574947, 7749928968172043074, 10379737442849991001, 12214799133441547975, 3010911421139668616, 1139563322249956440, 10665555756390945477, 11416383848154538939, 1, 0, 0, 0, 1, 0, 0, 0, 0, 2820210263285766173, 10720048331316524888, 16336081156703325682, 12593780523887353343, 14860169004739645851, 4935077138385472484, 3877939940902222438, 15459208758406011750, 3416780490017188932, 10124179113180116382, 6241701633229064883, 4550300662347412321, 1, 0, 0, 0, 1, 0, 0, 0, 0, 17236626943327285546, 6651694379495204788, 8336772613389807368, 4706110611062451689, 16613817815676391042, 14575939158311467485, 16532748839852396556, 15511587739895040434, 16203954224127058938, 7875674405969275087, 1782833494123441622, 5398391387950663852, 1, 0, 0, 0, 1, 0, 3216814705581329798, 8051488944047311617, 10360317537605597112, 10000406277741968662, 12388875369708291484, 5436159307074426676, 4141714552502191024, 5296179612907339628, 12465452801273636461, 11579821559146688098, 17723772565616660471, 269753408705321891, 5483693307349928485, 4148849849976411384, 14094161360764912752, 1, 0, 0, 0, 1, 0, 14178823458963512244, 3602272614600789469, 13905084130457283808, 3515474081943841043, 10660299906599270345, 5372326410876184636, 6156913135348580725, 2727608749578829361, 9988179754024184550, 1886131673715221226, 3768033638170488110, 6593749857609147597, 7566856789186803155, 3093019441584322610, 8761844938205749171, 1, 0, 0, 0, 1, 0, 14932870104720801196, 6785058050362917876, 15400461162492325976, 6053827097512010536, 18058988363310447424, 952127655583997344, 8130038137052345894, 14574147540888753393, 5211967294049811177, 1357444766332736487, 2891025200344158148, 4635414157698539724, 18277403464256252089, 8597937863411269927, 3185668978082087344, 1, 0, 0, 0, 1, 0, 1201637799925499218, 17612205884537743144, 12773097028646980525, 8960712552465026661, 9623705551395999386, 5020935239539129789, 701544453173650648, 8059351235840793745, 6694468041861665026, 12472822793413282781, 6236280916588703543, 15075342768292292116, 16879266252447328622, 7949966339384557545, 15511932232010057342, 1, 0, 0, 0, 1, 0, 6517296063227531697, 13317289165024626296, 11586609619777615563, 11979786878033472693, 843700314249069534, 11468557060291821177, 1938925551829656577, 10904264752260159799, 14795276649641559516, 15980631930421053887, 366057401724727850, 1413999795298148165, 10480838138111592719, 355079579910825811, 1574006689819641482, 1, 0, 0, 0, 1, 0, 7633630111197404945, 13444551449194423842, 3201988963668978031, 18123254724334785239, 5226109711488235461, 9579884402934033802, 10839677918877320285, 2271701567336889031, 7760841801390371710, 11471967310545114203, 10354312982073068000, 7915945758644279589, 6620992389563449781, 17687631000570413775, 16989897277811855421, 1, 0, 0, 0, 1, 0, 12268347784756099869, 10293513373138690724, 4130570496550447446, 134987944822694065, 10187646862534872963, 13580463007636418163, 8493022306153899371, 11388412644925859267, 6033082055004604682, 10953623189535037762, 15578008213258609099, 3945822118816847854, 2965464347717975564, 6363341880115016817, 9251952223235505862, 1, 0, 0, 0, 1, 0, 13712872653154503104, 0, 0, 7590275663852506792, 17142561411497204401, 15125840589396167585, 853397793542178445, 3473479938564490101, 1392444963431030092, 730262405744903776, 13260993287089333654, 8393438592264674483, 11306148085986296698, 5684934488312461188, 9028920192463013348, 1, 0, 0, 0, 1, 0, 0, 0, 0, 8641507014103477635, 3846511598062821009, 11894650477774570670, 14544980701902675312, 11986220662741086769, 12997958323187254385, 810115173760427441, 7273544940783271884, 10804780975337509125, 2086088846957217289, 10435649056729292941, 14937599399566357015, 1, 0, 0, 0, 1, 0, 0, 0, 0, 12810611099391073458, 10193722466575479921, 2671742567446566567, 5454248439622432085, 11254344690855207499, 5844726498509817937, 2972078815201344240, 16224554024045094426, 11285479015367787523, 1329278757683796924, 17595360511324176896, 12194499054171516103, 1, 0, 0, 0, 1, 0, 0, 0, 0, 18425592401989202654, 4468095142881580960, 4730631766664398723, 10135320711870011464, 10078686613521300141, 112670771943665928, 604160431047680026, 15076340203450547457, 5649049948736742168, 1372653659349995519, 10291410187286507610, 15319982794428564777, 1, 0, 0, 0, 1, 0, 0, 0, 0, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 17501946937763933948, 7675566390936895331, 4994195757323687992, 11767874304575963253, 1780538466631614833, 4063459066104458636, 4522236916001186996, 2303690644539739387, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], range_checker_cols: [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2187, 4374, 6561, 8748, 10935, 13122, 15309, 17496, 19683, 21870, 24057, 26244, 28431, 30618, 32805, 34992, 37179, 39366, 41553, 43740, 45927, 48114, 50301, 52488, 54675, 56862, 59049, 61236, 63423, 64152, 64881, 65124, 65367, 65448, 65529, 65532, 65535, 65535]], num_rows: 128 }, last_program_row: RowIndex(88) }, program_info: ProgramInfo { program_hash: Word([11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656]), kernel: Kernel([]) }, stack_outputs: StackOutputs { elements: [2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, precompile_requests: [], final_precompile_transcript: PrecompileTranscript { state: Word([0, 0, 0, 0]) }, trace_len_summary: TraceLenSummary { main_trace_len: 89, range_trace_len: 39, chiplets_trace_len: ChipletsLengths { hash_chiplet_len: 80, bitwise_chiplet_len: 0, memory_chiplet_len: 0, ace_chiplet_len: 0, kernel_rom_len: 0 } } } diff --git a/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_21.snap b/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_21.snap index 3aad1c0e3e..cf52fd4916 100644 --- a/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_21.snap +++ b/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_21.snap @@ -2,4 +2,4 @@ source: processor/src/trace/parallel/tests.rs expression: DeterministicTrace(&trace_from_fragments) --- -ExecutionTrace { main_trace: MainTrace { columns: ColMatrix { columns: [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 65, 65, 65, 65, 65, 65, 65, 65, 65, 1, 97, 97, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [16336503519826769294, 580999813345182728, 4539061041759240, 35461414388744, 277042299912, 2164392968, 16909320, 132104, 1032, 8, 0, 4539061041759240, 35461414388744, 277042299912, 2164392968, 16909320, 132104, 1032, 8, 0, 4539061041759240, 35461414388744, 277042299912, 2164392968, 16909320, 132104, 1032, 8, 0, 4539061041759240, 35461414388744, 277042299912, 2164392968, 16909320, 132104, 1032, 8, 0, 4539061041759240, 35461414388744, 277042299912, 2164392968, 16909320, 132104, 1032, 8, 0, 4539061041759240, 35461414388744, 277042299912, 2164392968, 16909320, 132104, 1032, 8, 0, 4539061041759240, 35461414388744, 277042299912, 2164392968, 16909320, 132104, 1032, 8, 0, 4539061041759240, 35461414388744, 277042299912, 2164392968, 16909320, 132104, 1032, 8, 0, 4539061041759240, 35461414388744, 277042299912, 2164392968, 16909320, 132104, 1032, 8, 0, 16336503519826769294, 41, 0, 11006573531383828351, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862, 6965138066206642862], [9197671798777409481, 580999813345182728, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 9197671798777409481, 0, 1, 10983413158656624898, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770, 12596233587871940770], [13035020452047724944, 580999813345182728, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13035020452047724944, 0, 0, 4869282124135316831, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811, 8197358252954291811], [17733790707118953345, 580999813345182728, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17733790707118953345, 0, 0, 5899798166361732461, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096, 10673667133036073096], [11006573531383828351, 580999813345182728, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [10983413158656624898, 580999813345182728, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [4869282124135316831, 580999813345182728, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [5899798166361732461, 580999813345182728, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 0, 1, 2, 3, 4, 5, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2], [2, 2, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 2, 1, 2, 1, 2, 1, 2, 1, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3], [3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2187, 4374, 6561, 8748, 10935, 13122, 15309, 17496, 19683, 21870, 24057, 26244, 28431, 30618, 32805, 34992, 37179, 39366, 41553, 43740, 45927, 48114, 50301, 52488, 54675, 56862, 59049, 61236, 63423, 64152, 64881, 65124, 65367, 65448, 65529, 65532, 65535, 65535], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [16336503519826769294, 7241595766844512545, 2990417547231451768, 8200055882763834902, 15107023413552199376, 8385687432658166895, 9658411005214642328, 4909632993745393767, 11139320331324068031, 7133947682362156748, 17192073988910191157, 1252671640222326947, 3013016866261693283, 8108123078799037039, 4014227156326565798, 12391143724758863082, 14176166539222112137, 17477853997594743235, 12238064792115483402, 14469369283093994356, 15706959181585180523, 9935807559722975979, 16381952245010805100, 15445358949429791952, 4394218334834403498, 7081942205803021819, 14286495051698513565, 1765182318039047708, 4315117985825319308, 13180871958580017059, 9324640818690322529, 6965138066206642862, 580999813345182728, 9441246971154186623, 14568136944800275082, 12559996978644727669, 16006034000059690936, 15808130082429351686, 11189427321576264326, 8056423375835200370, 894576452673648096, 1759663226535241487, 7111996287898491444, 9980680059887464609, 1246527623804764182, 15473044979114460820, 15843714178786416863, 11802722938645199711, 528524525625403517, 3395211782606276051, 4814987904082383725, 8549845730678305747, 3112263678112869121, 1192721472492662021, 5190583599302670309, 15237271270752782119, 4547129522910145518, 11550408183365383111, 6870828195219142669, 12383111777615982801, 12714099020863010695, 5224376302272959154, 14781572642473112572, 14537741408767373410, 4539061041759240, 166413184814318872, 3330424775026476592, 7732229819737520946, 12659763553976530720, 13820936547498519501, 15870553509947197608, 5797460196965489144, 5030538143349324000, 3122912243524936279, 7275337387902302889, 5695604368834329320, 14130306385452780113, 15363567770150994298, 8078757315035365696, 5442629662308931105, 16137685808790691775, 9729162786960114112, 6971938391156245940, 18003847752567480952, 3179630577014811908, 16175129257259814669, 7116272890564491051, 14999066466406693845, 11390566154350641025, 8405503273117460784, 17453232571701437290, 17122916750446457171, 7539745443808178835, 14554316550668318802, 15063345752223211733, 16336503519826769294, 41, 410, 8488924048752676071, 5473488137200086909, 16124688533662466636, 4527044298581192722, 16887055178922689595, 5249711198271717177, 15470787238396171217, 5632634005697013617, 7337408598993184022, 11147561538212402733, 9710911023591971572, 8752830793140649116, 11546140485006286209, 10738951369466640003, 2139663271495255306, 6135983205453599776, 17538856881976830392, 2031516987289365197, 17199894398730562705, 4010699482290892787, 3922552954514582360, 7369439734883755459, 108303794773646012, 14521269346803535153, 14515762120928230173, 13893962684375637966, 13610167819530098127, 11215445033353754262, 8081237365032914784, 11006573531383828351, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [9197671798777409481, 17469195903127682246, 11606517949721719272, 8595871163399933719, 7763683116636157069, 838997349906846708, 13728530742608929979, 6793201875126035063, 8111388737755370581, 14079832107643166597, 17737118927359740270, 3118134149246226434, 13627060471757962412, 587514782692598940, 2305040771202529034, 407676238176147180, 11304490035899669295, 4667652151526467516, 13681768858122081452, 17060146905316016781, 15750389702075093135, 7088767289424376680, 15640720737556518069, 2099687338970431013, 14448236636738050578, 5519067145334892916, 6791090761664616374, 420116652546322982, 17954920195441939375, 6438200026603866080, 1507262460208602102, 12596233587871940770, 580999813345182728, 2469249211011993887, 5693535723676280393, 9307941706856421244, 17583976365434994224, 11956256213068276591, 16650744379891120584, 11970932857482984253, 1340502547894095473, 17627623028259352738, 10800915493705299677, 12726130892030271688, 1966101965836764845, 8603197046817345275, 3287199712077657921, 4816347799520535722, 13726091214309035851, 14508720026418909433, 8845463819329319330, 319079387588421934, 9793349915183632648, 14664095371212951733, 7893897801913761594, 16244276080775719304, 5201962268638016263, 595824696721317186, 2520783628599955940, 849243249424286073, 12314456283572504356, 6535409800777915487, 11268362592956912536, 15771729313541940903, 0, 1073634951995504195, 13633250484821623215, 15098993065726469111, 1564281538360678972, 7168328730833322865, 9990637691333202156, 4315815088290272811, 13591172423217881213, 15655075338480513609, 996725104060870062, 1007570544942142144, 3729822968690386528, 10658087655041602841, 9498329046798837348, 14839704326644418801, 16811175179247371160, 5981274731275683258, 15610466289947195032, 14000599989678227804, 15292824893734897630, 627607295424670979, 2340223307289953865, 15059493462076997690, 16071082072689060288, 16820362574538767542, 5021883210577128063, 1555980395218755516, 9884045457320590091, 5367026278670357791, 8499294198486805672, 9197671798777409481, 0, 328, 7132218559010351790, 2687466917280430353, 14170238607512888511, 5453168895411602323, 8679138582261878552, 10871515559850126217, 7649138216344653830, 12086029516113687059, 14609582285822867389, 7271583017513514692, 3821121937809044409, 3833100151978191712, 5702916883024911354, 3579138882391492892, 14347405124134927123, 9277341930384005575, 2993137622300793545, 13370802209879109056, 13653108884642243926, 8702782587703766612, 12945832125614510830, 15167316901472929028, 4608694219239856197, 4443739924303229750, 8611475648437961511, 1575864515244779062, 10900065459953722709, 9162692523043045302, 17462008412377898139, 10983413158656624898, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [13035020452047724944, 4235056893170892481, 17598947928349150032, 4957589343064393818, 6242447045300438422, 4795761656943466364, 6264917032052353984, 15603723388972198024, 11627377236417283134, 6114228315229264629, 3286806106182827895, 15205984627333468001, 7321576485635388020, 17749542785007315566, 4569674865772026702, 7956650962315989946, 14478240861430583623, 14709859391037291514, 10913732310161131390, 2296203662546391134, 876174554396868075, 17404327975123101624, 2366722819671298513, 14303982336399641814, 12813527806534446210, 12774296173948151856, 12627603787832494922, 14277393185196427667, 2358074803509054857, 16405101789199201340, 1581131786309040293, 8197358252954291811, 580999813345182728, 9441246971154186623, 9230767544379437105, 18310630857442586767, 6798288544665969845, 12649659004750065655, 9127484939696035145, 3208400024176171154, 12601220862983867223, 3182150398630969932, 15946092271529760948, 312583470408719867, 1277989670489505373, 5390475388454384344, 1991947075903969606, 12041137591375643532, 17203613475518457508, 11172295513373146926, 1047366979417083402, 1230000128467178780, 166719433298183890, 9500917527157796789, 11443445413242899153, 18103925836791549846, 8328524023483162981, 16082128743854634628, 7353009946795117330, 18315678446936398634, 469635739213563567, 7901122908367659010, 5766087612434108876, 16254963956836991015, 0, 8506155510179977332, 16565837043221829196, 52948362219275850, 8677964002070154388, 7428484016288157022, 2806233373077400725, 13744878929079685610, 7596566350181367049, 8320838608801394259, 11416348334771026081, 5033691822950904881, 17904228615366476508, 1573747864700068677, 6115393411247877634, 299028171433900072, 17660677259671545725, 17197119244649549383, 11502210755699728407, 3657258890969942218, 3136236054167912163, 186206196971871344, 10885932290083514811, 11340220366618064719, 11020489504600957926, 15331358518756318712, 5496590912397587492, 14595950592094489892, 8382695108894398131, 9643181922175718153, 16042312733989464482, 13035020452047724944, 0, 82, 18152833202936203138, 10305147718805144715, 13246631902503555591, 18142351346900318359, 11971140429919100117, 6903484634638418138, 3098698980745497723, 3068992673894668202, 9164459936648953977, 11194864417357882388, 12005359455571366116, 12356306486226268709, 10059737158050223658, 17119982236602677307, 4225663824996553892, 17852936504841763737, 5778553506856942969, 9045001363359345866, 18423338781077887809, 2711240319770097821, 8346149567490270428, 9594540064387516595, 1859863665658604717, 16919987197409252682, 7809934763889573038, 12492597695329698922, 18341122838405415754, 11967784234256998242, 10761804868734649587, 4869282124135316831, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [17733790707118953345, 2298049257819688964, 14580412695609233024, 12971821499548943886, 12942151567717980516, 293990104348951469, 9511447919780245828, 12096675465574714978, 11966816476348176754, 6745364430325410240, 124350208982409384, 11534859557249128228, 13499302804947319126, 2073163037044338276, 980116766328138766, 6249894809652649629, 5225655700408130435, 15576478276301900443, 7892851227093729574, 15711810664626070442, 4889082965904642440, 18118185760308539378, 14951898769476191069, 12393266145043202429, 18370579783025919052, 13670428043882183738, 853764681371061454, 11311873924545773972, 12566827890799503780, 12734261918077566887, 13460201712649497096, 10673667133036073096, 580999813345182728, 2469249211011993887, 1921340627054025915, 11168366585808691894, 16344827155364741241, 13917605778022436041, 16775788395149485828, 3448656772275438142, 16222497246401579549, 7203217594655996602, 11409282451484046090, 758472841121971562, 7818365927012965985, 7903960434340948362, 3767440642589974121, 11209692269971430929, 3035346059787720244, 3431797671267201506, 6118779023340710484, 11335358665561171709, 5274326486456948617, 5525087067228805129, 5704922620886162396, 15867602839234938544, 9623255540514358603, 6605123704860531855, 17045986882743664444, 13118883604429226706, 4147903628926627533, 4079954944710007123, 10588667258124334541, 2046774012797929459, 0, 144771942538542601, 12610063329678779487, 9599099202048490781, 7298046952032101196, 16026473122383984320, 14666633261274526329, 10912616786956595600, 5410472981661512575, 8351163137101469720, 6900106104861748151, 5904063656561684665, 16445251460715434195, 10832015734039673623, 2891811661249932042, 8924808732795308287, 4687342342302612015, 16735389142514185239, 1470376739244986162, 1819268707172544638, 13251084164183215555, 16740657538571711568, 12986569577580758510, 6580507474643651363, 14039388877064634044, 17925541740654686755, 6693558341526111425, 11597938374506256020, 5283201688561864115, 5334752974852163097, 451731299183430202, 17733790707118953345, 0, 82, 302695496926486902, 16415403596737407938, 12969246825596557956, 15965643470182086386, 14881573336337548597, 2868629484750761697, 7317402970608805914, 2570537868338555591, 6697005353407257884, 5717939852331496040, 9408357527608003903, 8011884131194179594, 15942512744234440774, 9052662470595673790, 11913271961595885333, 15508051727969296111, 6269710669185644103, 12322255659000247132, 810875278274469351, 3499523055983644139, 9453749819048496107, 598273005722510655, 12338854942180141395, 2829445891916136836, 12653867244112536729, 4648827005364006908, 3153753366153954420, 12197142511433562971, 13557680898519201450, 5899798166361732461, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [11006573531383828351, 4764651601843997947, 13599348264422318050, 9048627971498202333, 4616644171576346372, 13446530094027973481, 515125260461286305, 13270828405354296543, 3589365582169471582, 7410433095216666761, 17324168673998498317, 264848703107953315, 2519145233399390872, 16944105578845184537, 891801733175697187, 1917456671376826149, 2178489717179959491, 5288871968538360514, 173128619939349444, 14938204230051641776, 14848674461360674975, 3298163296153338543, 12736435946586958561, 14151277613136798520, 6993584357807298191, 17243220101971525650, 6760124904423015973, 15448478475120864966, 11226925817970638094, 323561318445804460, 11770041052112546722, 8087083728976074902, 580999813345182728, 9441246971154186623, 4826001026438697181, 13927464871572189232, 8487031467837880959, 7953084218463226909, 14357560502528070253, 9198678924697643847, 16644535012971742472, 2610427154842113175, 1362602973689891222, 14563339716269964045, 10893524038980604908, 8604291529520412550, 3375764636979625919, 4598760434596487640, 14370201798336911320, 11592395684445633353, 18428909381025170046, 7556816872757379313, 15838446667082529291, 11840899228072824840, 5666563878473838907, 12094773271668234643, 18145098371590981833, 6227739674905468508, 14360904859585829753, 6349150325802118522, 13470963638813042195, 13830904396796715875, 9960013932953480218, 9448749568492005186, 0, 143717879605522672, 1406583001570465792, 12562663752152469569, 16633851142346839330, 17021480690231868718, 8387812497337000660, 15004187181055446563, 12021280163646879782, 15544096072222322408, 132132622953814287, 944699227762067814, 15889407327776555006, 8234710954956267885, 14704623317114553828, 5225072174929433338, 9992674649041617391, 17342022136955130751, 9806643750569796986, 10854572141100075982, 9877562264475108305, 3741205325444910799, 3008635823591126704, 8487705884637814572, 10764537169012636484, 3173467127968428287, 8847518126511086492, 295935891940673208, 11767201095350394052, 11260389542763349256, 4551861726624713720, 1413881954865567393, 0, 205, 13622702382434675698, 8941567408770445183, 2168342371250989865, 17553704974699598306, 12818882650622055705, 16478401302589696546, 10652219805906948351, 13167156861512034068, 260666911081589986, 1428764500637505382, 2190433219200603887, 11999917547751101526, 2751093334206085539, 9318931023569054874, 16297727142514657495, 11875658036026604145, 5829323963705819601, 407792022339954638, 5684565403642367050, 13995368600016681288, 2845800306757116207, 5216498913603536417, 2411940295743487842, 2014066638340124975, 5258230180909223265, 17089893338044941808, 1124366766375746940, 9116801986360376826, 6650575029061305823, 4025036448660092914, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [10983413158656624898, 5310937309376166300, 69556848653847272, 2279577280749402753, 6239043535079259963, 7823300322844699129, 16996148474654794437, 4230459886680751700, 12959563699934572877, 17777188402634189686, 11688615314691277560, 5613634717561556402, 99293997352733151, 4641048264628364064, 10453514483181846641, 1290992838422522292, 1652879052062614258, 12559634219275278239, 11344475397534544312, 4122197572510879508, 15407253393194772940, 2851848389283930949, 11702605024239517145, 1998109451585880901, 585739809492349094, 13332688213147014025, 1333400193073781990, 8814857714812706426, 1361027555808818653, 5346936254995238101, 8929045628408978585, 14294118012339765875, 580999813345182728, 2469249211011993887, 9026977856739391370, 4386750069800107475, 10598485069506239844, 13751116549494668150, 5108328399444950450, 17844111358351956213, 6869486424216496389, 12517021987770120609, 7851907349568758598, 18010894049048312095, 16693413552305953061, 4804538971513236292, 17649433461619154043, 11634860025288790992, 11313962652641817505, 855825648432312573, 13762197753828465221, 5743720479766949980, 3952939840611939921, 9604762177227689240, 8138871928234011911, 11384225568855102440, 9154844205260484435, 14664846725851493074, 2924959973998026295, 12642953022837695767, 429476535988054822, 17383573277674600677, 1883220378389933149, 8503069890613114305, 0, 1055478707828467235, 16768526919827857497, 17573593815267411876, 10818335527229137478, 11942460420815768259, 11201145811561632930, 5337320314888759058, 11378469682479349365, 8043644167131082885, 10448639655673781918, 12631760754265391769, 7376593749874885103, 16058512323740159729, 17873088011118479782, 17353196649080642803, 4721598436263747464, 11599468651034345541, 14009687636872815249, 7066071671554154790, 764975448091728428, 390750909719918391, 6065087221876806603, 15179557481995246257, 3787608625370371137, 2510512133707130589, 11690776235517962509, 1719109731839136237, 11166959267981414839, 12815587692045090980, 7859047597365690811, 8496939594631729748, 0, 164, 6093021124582015914, 375332441348258328, 16597900739273350797, 16788616498952461620, 10323894478242846558, 3730474644926313294, 17377183878976452334, 12746711269593150718, 13699107349734059694, 421533440407219618, 15109303318896079214, 17746438429032263850, 13224617406323308041, 5646455969610140563, 12626985742338481481, 14497665384991648640, 13894375308737560134, 3268393834564630675, 13312171511942754529, 611321250913478210, 12048873764879264902, 5334026694118161468, 14360341460112568406, 17654490467796517057, 1299716947845207044, 7609683397541157642, 14709808073905360012, 11742139955633481423, 13522070698443062110, 12847434483856017691, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [4869282124135316831, 9722920045405101283, 3813457227114323323, 6994299592571856765, 5702578803007136341, 15311994542782308321, 15962779709098309522, 3251959243165075337, 16837525512190061999, 5255873350627198987, 13662096656243952301, 1237772870699038471, 14338999341360692181, 14673770949791486715, 18097642912412713810, 10340874988740490351, 14305190726983389511, 16952069533520764759, 1485150603424506365, 14762405621252678105, 14445929105909601636, 16354500586064479473, 17536697575147489470, 9606769581569578625, 16440689431974469334, 6912749596454005081, 18063649775432527150, 14363667461722498847, 3204687512694590580, 523131765818647386, 13905210272577125578, 1524835811237900732, 580999813345182728, 9441246971154186623, 10597412231254617917, 11056066896847582412, 926831815845570768, 15146036891941496142, 17796585342020107437, 14725691510160207757, 13266683287137316598, 11211493525824266688, 10363424299958068143, 16931617059033676533, 10317747226871568657, 5507137035801773730, 15150382077316258576, 3011814040489752698, 15693519808819939877, 3749972803617457769, 17618989739824101716, 16792606508352577565, 17343623425168465586, 7527635805457035516, 5997951179959432212, 5020084506774034519, 14024972486716132755, 12302404123334003808, 2455930810486398184, 3241163780490493161, 10543436976244887593, 13682516968888804929, 11574410555278975115, 9471994857288690980, 0, 8501616449138218092, 4292185681439734302, 7698449017624504359, 4120049919115121735, 12642019494772420219, 14296370119911864390, 11592997338406165909, 840282323232377843, 12539549423037404132, 2113471727240446420, 14684696359318715547, 10727937735414582667, 8692606315144869678, 12960248188949622509, 5257625079275344763, 13015387036798755754, 856522523927216338, 7257469808648011210, 16558963709047870874, 12450766651322475975, 13636667172445831102, 13577724383754573439, 11193936901615452288, 7697944572311111481, 3932182442483072865, 5392781400556584604, 17762170874626363624, 15703610354425254697, 12391508132885235615, 8620148927055889210, 18000133586140028187, 0, 41, 9617260353707541367, 9187825164453421957, 17649953659489375797, 6396310504287885774, 17019569090864760371, 870218876784769460, 17213560015461715510, 16812494438448165271, 15885717661613279263, 2958950328581697287, 14311601477626423214, 12599125587081655507, 12078599565132475515, 3332808335850364509, 374688056722968094, 5591521890390007231, 9584980789501913045, 4066644474875437132, 17728945623551220217, 1158050506628066296, 3730734784735709807, 10671987699715228843, 3173999018565335463, 14949604462817069254, 11653871972148380806, 312408327658285690, 8531928004921347162, 98858158429688394, 6167334615107562354, 1234843923022284190, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [5899798166361732461, 5767416489550511608, 2886498774908945457, 15711135636713186135, 17215236981565434804, 908232164244690453, 5342947965117461497, 3199707432515651559, 12254673123217560222, 15216440457821236670, 481214964859672572, 18319684398448937806, 12603763899442623918, 10439805318219614253, 3602725314699933855, 8845316204090048147, 7271929134996712285, 13774466749383009485, 11005842405313098356, 14132576890947137734, 14321220139057541288, 6232608833314116824, 18436966792264288712, 1379169538700861503, 12062619363135681450, 16153824494526799043, 14882639257257424707, 6766308366816242208, 4464924001417791506, 4566463403740325912, 1351933157961486422, 6763063898149860947, 580999813345182728, 2469249211011993887, 8653818256660346722, 821691781470963977, 17943701130779573558, 3491480252041350267, 16358518409573919398, 16267496100921628089, 12162679553338055516, 1260655305474572880, 9540238327664971413, 15435832236802784694, 3812327996641515614, 10851655192011526024, 10610490743746459257, 13300292692349174603, 10113218173788314502, 10969265948996096203, 6220402056944103440, 3968382988012899732, 5018759638511748755, 2202263529713616511, 12948196389634753645, 3608565717871609608, 2453582700597880552, 2749677163981800836, 7973159619665332708, 16804313747076081769, 14670346996245963865, 6184594554218323809, 17786267665435354569, 16948092911786303144, 0, 140232881496783361, 10299881888812700030, 13506878991346097494, 14759589214631061464, 7301829639095749904, 15244303073312648502, 18132523245900274389, 2494235991830255255, 3432426521039531155, 7122756551450847884, 5549456538037663492, 10046538650654098331, 15912355352055409492, 17727271824480331481, 6704708084565647373, 4884177682333066524, 15210444525259934523, 3029374613861219290, 4615876382287073253, 7423511914796799812, 15469469226126445149, 8382746819546300959, 2890705529596562428, 9630719428827082769, 13318034444579216655, 4682383242810761218, 14195663397355254272, 12064640095342720771, 16112425486122001154, 9666454503914171857, 10680190414005925338, 0, 41, 12529483521877137515, 4671467226762388980, 13873740979092621907, 12847173262736205772, 2640423636460273022, 8374058502362870155, 7630996533587302384, 3556075572123538464, 8078558398785937163, 5856098383496092000, 7999607615804135893, 15509992149354799776, 13785560116650003734, 8358196300413379173, 10412508239405514928, 7840142081125036731, 18075062342410207477, 18173191150607640442, 2133036585496843963, 8931901040624025193, 9454731621283026961, 5837806564591410604, 5850596656185029719, 296117354535505751, 8985195681813998404, 1975947551471322175, 12041110943945791333, 11648250496545232642, 7830634726555216225, 5266777994490151623, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 16299911835839227190, 7439600795053578285, 17764699242312753117, 72379023848321437, 3840146011074602084, 10358472899138824122, 8678403567076310671, 771969030954554421, 17107733370651064258, 3926130618298284866, 777766613761440792, 18302679616424742231, 4399658422830000888, 14586568436552896239, 7848898512724128276, 16028822053598615935, 7613061892596625462, 13083593386467993284, 3013879140705624968, 17693711337466712468, 5033175548360176402, 5071731402891436170, 7353230019346707888, 17252905843818454714, 2640505909682592156, 14567186806364265088, 11858169615721049009, 8265106158072298997, 6616889263695345418, 11403119304603636779, 2145158521494695437, 0, 145249957631262975, 2401047653221911346, 4346621156346694740, 15690230013100567693, 12052213250462948496, 4313034443454791583, 2986358406776419767, 3160744395414731040, 14031039024085093183, 3877496541600093734, 10720145895975203640, 14936894451943192844, 4924903395035620384, 12381787083236736442, 12547862058645445192, 17342901573615257923, 16441368248785967826, 16642290968979905665, 8400425547892097127, 8935168685033341816, 11133810960521952919, 7535134649436940418, 5752598619104470273, 3942368633516548816, 15338087145388864340, 12628972628903398239, 13438747263841181181, 3139557918845001204, 1597138777695243925, 15852581941664405912, 12566536223313831832, 12566536223313831832, 264740454002249144, 5070319740822484234, 11549475095918428048, 9819109219817742568, 5677600078177657746, 250382926802577021, 3413687351079729358, 6870174020804907583, 2950358385880233426, 7094567085672854808, 14117325213115724257, 17249265058838620523, 6364580434745257188, 16537587825367420675, 6255602063998060074, 1816448877154048697, 1665145345483041546, 14003506401044241980, 10434287967974565457, 9500338696261382317, 13133067026913450803, 11258578054901736835, 14430869544081691912, 8503613085408412261, 3343513116649617296, 9343508596961576512, 12753874820303454617, 11936680880561889502, 3422498555177881379, 17255066275290727039, 2339032462720454103, 0, 205, 7876112718273244024, 1276143811675585923, 9993912342918529935, 16999254614849428545, 8194747920293058753, 11171758628037424552, 8208119826419095432, 5568149314099479773, 17551537772960996556, 12651683228606533001, 13584145944854843210, 12212300608708011466, 18102951610480561318, 14720258372954226591, 15448472262117068008, 10575290756167155008, 11997391634424499349, 9879556170680135793, 12373753045781314057, 9529470285212177396, 10620662102176580756, 10199402949196411787, 9825825353570660203, 18337390924518345383, 15945306792731206141, 10537181099344133724, 5505106000120813030, 14774803975376978777, 14575654492591748955, 8207377881872409730, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [87, 13742292427306144985, 17809381881860746878, 14185813834021479236, 2902380466328372776, 10999219428618119040, 9481695403573415070, 17673131597834433577, 12696786409220765700, 15592207435049660262, 13736774864431335246, 16717684302941853782, 14364466680417169443, 12260890044409800607, 17206474997006265051, 5035815000061711911, 9674580830266028521, 5580437753203777486, 15970593365487106653, 4096979907706804740, 15051763954056533599, 6913739807603556015, 9886633434535102281, 844824200045222171, 8033531154978796131, 17667639225113520026, 5672989858483365109, 2139538828134465604, 14154439558213594386, 15349070088087119300, 17443416980221933050, 10234632751699861532, 0, 13943995520284385472, 3038244952392737403, 2166498267314208258, 16766052460675760559, 17479836829311383480, 2421503110457951828, 4244078595888625427, 16470951341042419630, 10761733147329482159, 13363868789360680527, 8361105415211156204, 1063676068352620466, 15563346705142691804, 16788006368298087947, 1542676998191593053, 3303936282197422453, 6962236012055562966, 10808278092072460642, 5434427870325080160, 5951881526364525804, 10397118299016726484, 17744715934780154469, 6560905318933416747, 9119760857355898684, 12080225949269433371, 5462523753418276656, 4395579796774914984, 5461299377107545721, 10515379984412735135, 1357729935919477555, 4049192570105751375, 4049192570105751375, 2092801171489897510, 11830947885319956418, 7737209888784159602, 13533379427213586747, 12969897466948219293, 4397768078443292399, 11254764769292894033, 18099434164004083138, 2485855531816604722, 13525894453675963834, 8196759787025064775, 5345512927193726757, 10899057564736574513, 18177523421240333385, 5914611942628028009, 15108016113357317953, 1860837626615492164, 2201407520096262430, 15072295315432912557, 2703103454418315711, 923818922603460716, 18443738463070648510, 9827923975568229619, 11004068350566519627, 3092487934656948277, 16549791451828015234, 4910799883829461137, 15606093107492977367, 40421079456104423, 33594342817809819, 16993857945986913175, 0, 164, 14482187202392982684, 17682350329754313417, 66214439016909251, 7504629639084879386, 11708178258767948919, 188011405648496761, 10242982970375452289, 16510140404231294235, 13381084464566932690, 9239012175869487665, 9339694231140180875, 9917181315244873380, 17448534469581521177, 4965043893766771965, 13305445405772227224, 6963375374275021656, 4554518835153561582, 1694446457415578298, 4604616361036784646, 11439774970058559661, 10784225701912607868, 17782855612978839775, 13368223431578003475, 18100595786373494652, 12753204151452870283, 17504098334052422651, 12896535568794110034, 7402084190222773115, 598469278842686486, 5912604878679295331, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 10801573669330193043, 4014163844046372573, 1979187468149850032, 7068929233685234045, 6627279045165985143, 956116317527270230, 11757065279852506121, 1740402123045436483, 10251517583944092682, 5551917630030385122, 65503834883425781, 15453754233876106148, 10203814174951024159, 11998108441263059891, 922784102208491029, 17685677737193760186, 5204010590575197441, 3224334584493279137, 12733973074113146504, 12628586848138973198, 9618350092243669634, 1435727158819410801, 6720472488718189255, 8476570694128937109, 7307051990735150855, 15061013104031335890, 11522811345813436372, 4676228375886937826, 17477781110059685856, 9362502897182671987, 11254953448960768625, 0, 145249957631262975, 8386361303932939763, 13068211219747943554, 10741543262911175860, 16819603317278983686, 5783881320200053288, 18417524745718206114, 17717239843479976187, 4030689483576599003, 879151411992161296, 2779769903465702190, 14759893362240473482, 6691146416202555339, 11287199716539837261, 11126920347653441896, 12376075663235117060, 17793881754348373966, 2747583073029700026, 10825449445092551825, 5205786761888799519, 5879451121482504957, 8279206964799001491, 3768506969286097604, 10538414058473986667, 4512042016117019806, 9367766578866915876, 12466325711864282871, 4805225664863956509, 7450238737884914862, 7510284002737324288, 9029012768772075486, 9029012768772075486, 16998693837234676944, 15125640082304919550, 6110574402514906801, 4404297180800676786, 4728227612288081644, 5806909779738895718, 13841571116725704679, 10405162090868595527, 1295701329370151493, 15339349621927026708, 13512312828114051231, 10968291943912870575, 2665224526083019926, 11454603613487247488, 18085989619482158634, 8156733875584402577, 15725343254588574135, 17190667807892286789, 4147804706937142458, 13843504867107001118, 13430940141760251552, 2236397580466830219, 3736249992832820982, 11869484276361150688, 939908675643132953, 8795331189349109030, 1903118753742396596, 10434554919272483089, 15053297738150165437, 12279517140635782046, 8264942609101286638, 0, 41, 3800418813655617572, 14503408479575576010, 10553169970007645345, 4946745422622378051, 7127828976000219721, 2687285609278369395, 16630221959750548176, 1114885198959805561, 3895092647933222339, 9831397389014117600, 12816842684293233323, 1779119880742935864, 17663607747965229138, 5382558247959552902, 11972955750871888364, 16616426694032134438, 9711126273890628516, 376576173107709408, 12451218545182255865, 14301764572821220192, 13209253693600827240, 5745169166190656073, 12916752429524642864, 14463770325561420619, 7870235520772452232, 13278341252249613603, 5432056100901092307, 8994645443800925562, 5908996313982662075, 1494658977663487041, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 2688488582456733640, 3176173060019065635, 18309940476973301558, 6936565830330512698, 6894736762296179522, 90344116647093812, 7242437296897104684, 6840278566006653320, 12841299952034848927, 13801531974995903464, 3431188141752586880, 6945555547969535469, 16385619022525424479, 2302137229552580420, 3562300556391111858, 18050279212829828519, 11845451884839552921, 18010307414852664162, 1572578420442156655, 12278794746552983052, 7729016306498836651, 17389954356356902848, 14310782857892986700, 16540335065460741454, 9418678319655461294, 9662888408142346895, 9673811223372787800, 16236416741726566504, 1941798973941376537, 5283201687609097620, 677503724821015517, 0, 13943995520284385472, 13893715067188783613, 3737686312150097138, 6408571846489205195, 5309320507954343198, 7907473214578333250, 3220998093077600799, 6474302970739201787, 16744589822124330786, 15338963790186860624, 12429535237881910980, 4353091614275483153, 12430118441204168389, 15563175998310034114, 7172174870857485673, 2253621527545508840, 4507428390885076546, 2693291710499435080, 18303680792619501937, 12658208632913334575, 18044025142180450635, 14512997676069758708, 6038828855361889649, 16387791750090568457, 2816243451374973997, 15990457456638139626, 5938146028305439666, 8292027417405396428, 12456535987381445341, 4686309106959500238, 9680729728072440816, 9680729728072440816, 275926701951807482, 2368214261414429154, 15583218305860063073, 12342565443853005153, 7791191498940082574, 5368134609913732769, 18241043179323819051, 6247074573395806345, 7865016694973943467, 13276760677885131566, 12501576801121215107, 14003841288523724393, 7706369500077994851, 14277720092332100080, 16831403894744601879, 9685715221108858847, 12090932747658876990, 15574096712669166429, 16819229186816553924, 3675188622214856303, 6131072316753506600, 5455404512357596637, 3180536826353817667, 6733192297441041488, 3057140685660277923, 15037300764129498232, 12789460187938846931, 12722152077589496357, 5754948178406885282, 9383881360936187956, 10120172904062862410, 0, 41, 13092032916490151270, 2856458557507854671, 14059661153766146178, 1724041303048776424, 7119687853704366589, 3699246950542313036, 8338994289155538949, 7732171807197958061, 10653644351656999339, 15262849800927670044, 6132373490633371091, 16473831322001214578, 12928938600331453669, 6959935525856744214, 17173069020016176920, 6747622983845354522, 2484033613426731933, 9879916419081378373, 4275250202523893223, 5995505684018086986, 16115855409799741127, 2490003355474156145, 10034475279304353355, 7223217715426381376, 10334063888823214988, 2139000562522371457, 18314119367638727156, 15311716904301189063, 894706229073498557, 1570146104298050273, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] }, last_program_row: RowIndex(88) }, program_info: ProgramInfo { program_hash: Word([6965138066206642862, 12596233587871940770, 8197358252954291811, 10673667133036073096]), kernel: Kernel([]) }, stack_outputs: StackOutputs { elements: [2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, merkle_store_nodes: {Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571]): (Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350]), Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350])), Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484]): (Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693]), Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693])), Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781]): (Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874]), Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874])), Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171]): (Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361]), Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361])), Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815]): (Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305]), Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305])), Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689]): (Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195]), Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195])), Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362]): (Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063]), Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063])), Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848]): (Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661]), Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661])), Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352]): (Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829]), Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829])), Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444]): (Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223]), Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223])), Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386]): (Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388]), Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388])), Word([13190842942618341421, 17548956981569849952, 15418963848144418856, 730733050713174879]): (Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144]), Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144])), Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874]): (Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675]), Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675])), Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594]): (Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115]), Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115])), Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809]): (Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257]), Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257])), Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777]): (Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555]), Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555])), Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509]): (Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882]), Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882])), Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725]): (Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979]), Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979])), Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134]): (Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987]), Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987])), Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828]): (Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910]), Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910])), Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830]): (Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054]), Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054])), Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228]): (Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742]), Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742])), Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443]): (Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928]), Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928])), Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643]): (Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979]), Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979])), Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758]): (Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106]), Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106])), Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580]): (Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594]), Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594])), Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765]): (Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045]), Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045])), Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766]): (Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281]), Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281])), Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385]): (Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828]), Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828])), Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579]): (Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171]), Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171])), Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212]): (Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992]), Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992])), Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463]): (Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004]), Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004])), Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502]): (Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023]), Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023])), Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539]): (Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537]), Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537])), Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865]): (Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225]), Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225])), Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690]): (Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947]), Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947])), Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202]): (Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552]), Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552])), Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079]): (Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444]), Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444])), Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850]): (Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548]), Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548])), Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448]): (Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987]), Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987])), Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041]): (Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035]), Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035])), Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301]): (Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414]), Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414])), Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414]): (Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212]), Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212])), Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703]): (Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439]), Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439])), Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271]): (Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955]), Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955])), Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882]): (Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802]), Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802])), Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152]): (Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887]), Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887])), Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028]): (Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948]), Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948])), Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331]): (Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093]), Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093])), Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394]): (Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134]), Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134])), Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546]): (Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228]), Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228])), Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620]): (Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414]), Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414])), Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800]): (Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703]), Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703])), Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671]): (Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205]), Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205])), Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537]): (Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011]), Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011])), Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516]): (Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301]), Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301])), Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831]): (Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986]), Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986])), Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415]): (Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057]), Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057])), Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722]): (Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689]), Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689])), Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144]): (Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682]), Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682])), Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295]): (Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268]), Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268])), Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818]): (Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513]), Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513])), Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241]): (Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565]), Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565])), Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439]): (Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012]), Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012])), Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512]): (Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850]), Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850])), Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986]): (Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865]), Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865])), Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982]): (Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777]), Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777])), Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808]): (Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394]), Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394])), Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979]): (Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690]), Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690])), Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093]): (Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620]), Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620])), Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902]): (Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789]), Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789])), Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542]): (Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094]), Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094])), Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057]): (Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362]), Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362])), Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205]): (Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961]), Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961])), Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401]): (Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580]), Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580])), Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553]): (Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960]), Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960])), Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169]): (Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031]), Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031])), Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682]): (Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053]), Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053])), Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118]): (Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562]), Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562])), Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725]): (Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666]), Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666])), Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661]): (Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897]), Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897])), Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981]): (Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447]), Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447])), Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072]): (Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646]), Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646])), Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140]): (Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404]), Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404])), Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515]): (Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152]), Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152])), Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709]): (Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664]), Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664])), Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800]): (Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103]), Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103])), Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741]): (Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169]), Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169])), Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005]): (Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758]), Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758])), Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802]): (Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070]), Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070])), Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159]): (Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005]), Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005])), Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350]): (Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443]), Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443])), Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697]): (Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573]), Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573])), Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928]): (Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331]), Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331])), Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320]): (Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166]), Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166])), Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814]): (Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079]), Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079])), Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447]): (Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820]), Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820])), Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284]): (Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057]), Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057])), Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697]): (Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131]), Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131])), Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955]): (Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290]), Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290])), Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910]): (Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202]), Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202])), Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910]): (Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822]), Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822])), Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106]): (Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847]), Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847])), Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404]): (Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441]), Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441])), Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796]): (Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186]), Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186])), Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053]): (Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516]), Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516])), Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992]): (Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818]), Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818])), Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957]): (Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315]), Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315])), Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709]): (Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794]), Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794])), Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091]): (Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539]), Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539])), Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664]): (Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558]), Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558])), Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294]): (Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579]), Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579])), Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947]): (Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502]), Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502])), Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829]): (Word([0, 0, 0, 0]), Word([0, 0, 0, 0])), Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045]): (Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137]), Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137])), Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914]): (Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041]), Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041])), Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573]): (Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378]), Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378])), Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699]): (Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873]), Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873])), Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225]): (Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262]), Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262])), Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057]): (Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692]), Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692])), Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131]): (Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997]), Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997])), Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555]): (Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385]), Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385])), Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195]): (Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709]), Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709])), Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166]): (Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542]), Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542])), Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027]): (Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373]), Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373])), Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378]): (Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509]), Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509])), Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097]): (Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553]), Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553])), Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217]): (Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815]), Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815])), Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873]): (Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864]), Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864])), Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997]): (Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722]), Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722])), Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887]): (Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766]), Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766])), Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589]): (Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757]), Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757])), Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539]): (Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665]), Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665])), Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129]): (Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229]), Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229])), Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137]): (Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312]), Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312])), Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019]): (Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378]), Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378])), Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331]): (Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713]), Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713])), Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]): (Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980]), Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980])), Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325]): (Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546]), Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546])), Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170]): (Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822]), Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822])), Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054]): (Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295]), Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295])), Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925]): (Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848]), Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848])), Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909]): (Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796]), Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796])), Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540]): (Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170]), Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170])), Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214]): (Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448]), Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448])), Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317]): (Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294]), Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294])), Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757]): (Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416]), Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416])), Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378]): (Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091]), Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091])), Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263]): (Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463]), Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463])), Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666]): (Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361]), Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361])), Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174]): (Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992]), Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992])), Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470]): (Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401]), Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401])), Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665]): (Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957]), Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957])), Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262]): (Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144]), Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144])), Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229]): (Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284]), Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284])), Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134]): (Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325]), Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325])), Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855]): (Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765]), Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765])), Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115]): (Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814]), Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814])), Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441]): (Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831]), Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831])), Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977]): (Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446]), Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446])), Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880]): (Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005]), Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005])), Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789]): (Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995]), Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995])), Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000]): (Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267]), Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267])), Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998]): (Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982]), Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982])), Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995]): (Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539]), Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539])), Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507]): (Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512]), Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512])), Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305]): (Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118]), Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118])), Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219]): (Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009]), Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009])), Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416]): (Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089]), Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089])), Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980]): (Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445]), Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445])), Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063]): (Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140]), Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140])), Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713]): (Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159]), Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159])), Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031]): (Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809]), Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809])), Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932]): (Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037]), Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037])), Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094]): (Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925]), Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925])), Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315]): (Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386]), Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386])), Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446]): (Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721]), Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721])), Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742]): (Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981]), Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981])), Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661]): (Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072]), Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072])), Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979]): (Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671]), Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671])), Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361]): (Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269]), Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269])), Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558]): (Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571]), Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571])), Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290]): (Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902]), Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902])), Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987]): (Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741]), Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741])), Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902]): (Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515]), Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515])), Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497]): (Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028]), Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028])), Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948]): (Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709]), Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709])), Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009]): (Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725]), Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725])), Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387]): (Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317]), Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317])), Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159]): (Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808]), Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808])), Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394]): (Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699]), Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699])), Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312]): (Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000]), Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000])), Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987]): (Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821]), Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821])), Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046]): (Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909]), Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909])), Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565]): (Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028]), Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028])), Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269]): (Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352]), Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352])), Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847]): (Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271]), Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271])), Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513]): (Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800]), Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800])), Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054]): (Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394]), Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394])), Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004]): (Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977]), Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977])), Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675]): (Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800]), Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800])), Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692]): (Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159]), Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159])), Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909]): (Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932]), Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932])), Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814]): (Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697]), Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697])), Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186]): (Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387]), Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387])), Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445]): (Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470]), Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470])), Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966]): (Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507]), Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507])), Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548]): (Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253]), Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253])), Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897]): (Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783]), Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783])), Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208]): (Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054]), Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054])), Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268]): (Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661]), Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661])), Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388]): (Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643]), Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643])), Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257]): (Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174]), Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174])), Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960]): (Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241]), Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241])), Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721]): (Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046]), Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046])), Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822]): (Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217]), Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217])), Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253]): (Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697]), Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697])), Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054]): (Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019]), Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019])), Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821]): (Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432]), Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432])), Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864]): (Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105]), Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105])), Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373]): (Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855]), Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855])), Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646]): (Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830]), Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830])), Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460]): (Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208]), Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208])), Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033]): (Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214]), Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214])), Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105]): (Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129]), Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129])), Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281]): (Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909]), Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909])), Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028]): (Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027]), Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027])), Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012]): (Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054]), Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054])), Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562]): (Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589]), Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589])), Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037]): (Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097]), Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097])), Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355]): (Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460]), Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460])), Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223]): (Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355]), Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355])), Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089]): (Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306]), Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306])), Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035]): (Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219]), Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219])), Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432]): (Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297]), Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297])), Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693]): (Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263]), Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263])), Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794]): (Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484]), Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484])), Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552]): (Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941]), Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941])), Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267]): (Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814]), Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814])), Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992]): (Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415]), Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415])), Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941]): (Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966]), Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966])), Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822]): (Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320]), Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320])), Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306]): (Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902]), Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902])), Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820]): (Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880]), Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880])), Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361]): (Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725]), Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725])), Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005]): (Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914]), Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914])), Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783]): (Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781]), Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781])), Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011]): (Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033]), Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033])), Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297]): (Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910]), Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910])), Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070]): (Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134]), Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134])), Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144]): (Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331]), Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331])), Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023]): (Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497]), Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497])), Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103]): (Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540]), Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540])), Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961]): (Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998]), Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998])), Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414]): (Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]), Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]))}, trace_len_summary: TraceLenSummary { main_trace_len: 89, range_trace_len: 39, chiplets_trace_len: ChipletsLengths { hash_chiplet_len: 128, bitwise_chiplet_len: 0, memory_chiplet_len: 0, kernel_rom_len: 0 } } } +ExecutionTrace { main_trace: MainTrace { storage: Parts { core_rm: [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 3522571414841252998, 8184450079211665661, 6529578262649975717, 6261706375900221050, 7532528701100807439, 10480547126759850066, 6097728641437901141, 17248496754222975198, 0, 0, 0, 0, 0, 0, 1, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 580999813345182728, 580999813345182728, 580999813345182728, 580999813345182728, 580999813345182728, 580999813345182728, 580999813345182728, 580999813345182728, 0, 9, 0, 1, 0, 0, 1, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 2, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 4539061041759240, 1, 0, 0, 0, 0, 0, 0, 1, 8, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 3, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 35461414388744, 1, 0, 0, 0, 0, 0, 0, 1, 8, 1, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 4, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 277042299912, 1, 0, 0, 0, 0, 0, 0, 1, 8, 2, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 5, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 2164392968, 1, 0, 0, 0, 0, 0, 0, 1, 8, 3, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 6, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 16909320, 1, 0, 0, 0, 0, 0, 0, 1, 8, 4, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 7, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 132104, 1, 0, 0, 0, 0, 0, 0, 1, 8, 5, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 8, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 1032, 1, 0, 0, 0, 0, 0, 0, 1, 8, 6, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 9, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 8, 1, 0, 0, 0, 0, 0, 0, 1, 8, 7, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 10, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 8, 8, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 11, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 4539061041759240, 1, 0, 0, 0, 0, 0, 0, 1, 7, 0, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 12, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 35461414388744, 1, 0, 0, 0, 0, 0, 0, 1, 7, 1, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 13, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 277042299912, 1, 0, 0, 0, 0, 0, 0, 1, 7, 2, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 14, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 2164392968, 1, 0, 0, 0, 0, 0, 0, 1, 7, 3, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 15, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 16909320, 1, 0, 0, 0, 0, 0, 0, 1, 7, 4, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 16, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 132104, 1, 0, 0, 0, 0, 0, 0, 1, 7, 5, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 17, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 1032, 1, 0, 0, 0, 0, 0, 0, 1, 7, 6, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 18, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 8, 1, 0, 0, 0, 0, 0, 0, 1, 7, 7, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 19, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 7, 8, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 20, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 4539061041759240, 1, 0, 0, 0, 0, 0, 0, 1, 6, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 21, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 35461414388744, 1, 0, 0, 0, 0, 0, 0, 1, 6, 1, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 22, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 277042299912, 1, 0, 0, 0, 0, 0, 0, 1, 6, 2, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 23, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 2164392968, 1, 0, 0, 0, 0, 0, 0, 1, 6, 3, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 24, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 16909320, 1, 0, 0, 0, 0, 0, 0, 1, 6, 4, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 25, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 132104, 1, 0, 0, 0, 0, 0, 0, 1, 6, 5, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 26, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 1032, 1, 0, 0, 0, 0, 0, 0, 1, 6, 6, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 27, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 8, 1, 0, 0, 0, 0, 0, 0, 1, 6, 7, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 28, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 6, 8, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 29, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 4539061041759240, 1, 0, 0, 0, 0, 0, 0, 1, 5, 0, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 30, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 35461414388744, 1, 0, 0, 0, 0, 0, 0, 1, 5, 1, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 31, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 277042299912, 1, 0, 0, 0, 0, 0, 0, 1, 5, 2, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 32, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 2164392968, 1, 0, 0, 0, 0, 0, 0, 1, 5, 3, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 33, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 16909320, 1, 0, 0, 0, 0, 0, 0, 1, 5, 4, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 34, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 132104, 1, 0, 0, 0, 0, 0, 0, 1, 5, 5, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 35, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 1032, 1, 0, 0, 0, 0, 0, 0, 1, 5, 6, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 36, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 8, 1, 0, 0, 0, 0, 0, 0, 1, 5, 7, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 37, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 5, 8, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 38, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 4539061041759240, 1, 0, 0, 0, 0, 0, 0, 1, 4, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 39, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 35461414388744, 1, 0, 0, 0, 0, 0, 0, 1, 4, 1, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 40, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 277042299912, 1, 0, 0, 0, 0, 0, 0, 1, 4, 2, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 41, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 2164392968, 1, 0, 0, 0, 0, 0, 0, 1, 4, 3, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 42, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 16909320, 1, 0, 0, 0, 0, 0, 0, 1, 4, 4, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 43, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 132104, 1, 0, 0, 0, 0, 0, 0, 1, 4, 5, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 44, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 1032, 1, 0, 0, 0, 0, 0, 0, 1, 4, 6, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 45, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 8, 1, 0, 0, 0, 0, 0, 0, 1, 4, 7, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 46, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 4, 8, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 47, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 4539061041759240, 1, 0, 0, 0, 0, 0, 0, 1, 3, 0, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 48, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 35461414388744, 1, 0, 0, 0, 0, 0, 0, 1, 3, 1, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 49, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 277042299912, 1, 0, 0, 0, 0, 0, 0, 1, 3, 2, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 50, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 2164392968, 1, 0, 0, 0, 0, 0, 0, 1, 3, 3, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 51, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 16909320, 1, 0, 0, 0, 0, 0, 0, 1, 3, 4, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 52, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 132104, 1, 0, 0, 0, 0, 0, 0, 1, 3, 5, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 53, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 1032, 1, 0, 0, 0, 0, 0, 0, 1, 3, 6, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 54, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 8, 1, 0, 0, 0, 0, 0, 0, 1, 3, 7, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 55, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 3, 8, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 56, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 4539061041759240, 1, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 57, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 35461414388744, 1, 0, 0, 0, 0, 0, 0, 1, 2, 1, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 58, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 277042299912, 1, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 59, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 2164392968, 1, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 60, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 16909320, 1, 0, 0, 0, 0, 0, 0, 1, 2, 4, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 61, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 132104, 1, 0, 0, 0, 0, 0, 0, 1, 2, 5, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 62, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 1032, 1, 0, 0, 0, 0, 0, 0, 1, 2, 6, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 63, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 8, 1, 0, 0, 0, 0, 0, 0, 1, 2, 7, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 64, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 2, 8, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 65, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 4539061041759240, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 66, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 35461414388744, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 67, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 277042299912, 1, 0, 0, 0, 0, 0, 0, 1, 1, 2, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 68, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 2164392968, 1, 0, 0, 0, 0, 0, 0, 1, 1, 3, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 69, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 16909320, 1, 0, 0, 0, 0, 0, 0, 1, 1, 4, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 70, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 132104, 1, 0, 0, 0, 0, 0, 0, 1, 1, 5, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 71, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 1032, 1, 0, 0, 0, 0, 0, 0, 1, 1, 6, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 72, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 8, 1, 0, 0, 0, 0, 0, 0, 1, 1, 7, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 73, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 8, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 74, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 1, 1, 1, 4539061041759240, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 75, 0, 0, 0, 0, 0, 5, 0, 0, 0, 1, 0, 0, 0, 35461414388744, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 76, 0, 0, 0, 0, 0, 5, 0, 0, 0, 1, 0, 0, 0, 277042299912, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 77, 0, 0, 0, 0, 0, 5, 0, 0, 0, 1, 0, 0, 0, 2164392968, 1, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 78, 0, 0, 0, 0, 0, 5, 0, 0, 0, 1, 0, 0, 0, 16909320, 1, 0, 0, 0, 0, 0, 0, 1, 0, 3, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 79, 0, 0, 0, 0, 0, 5, 0, 0, 0, 1, 0, 0, 0, 132104, 1, 0, 0, 0, 0, 0, 0, 1, 0, 4, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 80, 0, 0, 0, 0, 0, 5, 0, 0, 0, 1, 0, 0, 0, 1032, 1, 0, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 81, 0, 0, 0, 0, 0, 5, 0, 0, 0, 1, 0, 0, 0, 8, 1, 0, 0, 0, 0, 0, 0, 1, 0, 6, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 82, 0, 0, 0, 0, 0, 5, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 7, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 83, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 1, 1, 1, 3522571414841252998, 8184450079211665661, 6529578262649975717, 6261706375900221050, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 84, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 41, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 85, 0, 0, 0, 0, 0, 7, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 86, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 1, 1, 1, 7532528701100807439, 10480547126759850066, 6097728641437901141, 17248496754222975198, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 87, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 88, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 89, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 90, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 91, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 92, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 93, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 94, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 97, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 98, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 99, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 101, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 102, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 103, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 104, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 105, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 106, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 107, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 108, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 109, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 110, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 111, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 112, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 113, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 114, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 115, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 116, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 117, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 118, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 119, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 120, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 121, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 122, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 123, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 124, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 125, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 126, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 127, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0], chiplets_rm: [1, 1, 0, 0, 3522571414841252998, 8184450079211665661, 6529578262649975717, 6261706375900221050, 7532528701100807439, 10480547126759850066, 6097728641437901141, 17248496754222975198, 0, 87, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 17501946937763933948, 7675566390936895331, 4994195757323687992, 11767874304575963253, 1780538466631614833, 4063459066104458636, 4522236916001186996, 2303690644539739387, 0, 0, 1, 0, 0, 1, 1, 0, 0, 580999813345182728, 580999813345182728, 580999813345182728, 580999813345182728, 580999813345182728, 580999813345182728, 580999813345182728, 580999813345182728, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 17435140114479298129, 1435885832764997654, 215283041871207160, 7082661356804799086, 5416435572438850612, 2882953289127770017, 16218313204809782547, 8575194234315674944, 213625975700372028, 6103762562402135118, 8461833255366069567, 1720047680925886481, 0, 0, 0, 0, 0, 1, 1, 0, 0, 4539061041759240, 0, 0, 0, 0, 0, 0, 0, 213625975700372028, 6103762562402135118, 8461833255366069567, 1720047680925886481, 0, 0, 0, 0, 0, 1, 0, 0, 0, 3522571414841252998, 8184450079211665661, 6529578262649975717, 6261706375900221050, 7634873969298005933, 8950987357718038443, 13680774040296089728, 16762235143106196223, 16430047160501569010, 14861946194768960443, 10513948170299859642, 11975838346548297297, 0, 0, 1, 0, 0, 1, 1, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 7532528701100807439, 10480547126759850066, 6097728641437901141, 17248496754222975198, 12342802819241620905, 7554371666290801318, 8718773026382250605, 15984482998549000918, 15460443374009848343, 1087146607978023558, 7531163901062156801, 4426949494427873777, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 11621565010787354140, 1949391780818670486, 7327781180606137861, 2419787217529136215, 13249250205018233525, 10029758640146777270, 5716716695107147273, 10829954014693503473, 7405851154679558693, 2030135877513774489, 10401768244118899621, 7992444660002654486, 1, 0, 0, 0, 1, 0, 0, 0, 0, 9190577937819620371, 12978309842325015235, 10477013461463931935, 4855391316239312738, 10519745218266697287, 18375374895419140100, 876067972673449756, 17915370314859305010, 17877705855294641231, 120652674332571204, 3378556434908723888, 17649391022523856338, 1, 0, 0, 0, 1, 0, 0, 0, 0, 15052947986857015373, 3007680259418135415, 3197694984858038551, 6563270153864719814, 6889631464391242687, 12614331779225506253, 8884325160266334095, 15067359903282619456, 6045216153329131722, 7293213550537411486, 18377064823051127268, 14733223614830533518, 1, 0, 0, 0, 1, 0, 1248924765333967865, 15568788993061722932, 4037714036443683170, 2584579945446987950, 3496704858534018972, 10965787981110521559, 9000006360952503550, 8377181923806419223, 18078834148678517323, 13751832434934340803, 15306332964801742551, 828627458527105190, 2519953652271814816, 5563221586835004955, 16428502736240336605, 1, 0, 0, 0, 1, 0, 161503374172189975, 7180975586994120588, 13070121377098205312, 9655464535561865455, 4169214041423852321, 5771090309048429384, 6993654059550252564, 14478380452460405826, 12150434000885474539, 18399347099839405992, 88779829066683150, 4428174353386180423, 7547120791432137516, 11951584238447172023, 8804182506418522715, 1, 0, 0, 0, 1, 0, 1859011259345361207, 13205265558511858864, 16229683663108620000, 17688418164436772208, 12658415008146819428, 6291208835901171779, 3297271436089179933, 12943628284217684119, 11639259038601904106, 10502234848011596680, 13946225273525543944, 11318468498957948083, 13851055481982014034, 5765565570506082255, 10777382518726251007, 1, 0, 0, 0, 1, 0, 1023422172081481959, 14540338366569412926, 10271517463444484758, 8863158288377959817, 9066561794313536160, 10161961919995709177, 2094278659773331823, 4371761587112760854, 10972685992181286814, 5641963675353630718, 15569415989710829261, 4258403342016907208, 4740804749082440837, 1594229550076307598, 5045104152796606559, 1, 0, 0, 0, 1, 0, 12053626300860885956, 13987509258486900924, 17286360383804666298, 8301538772707939488, 7700154594411825373, 14332053735409157564, 6894934729579673545, 5430665485920789830, 10553406992561403551, 11528229548578861261, 3294597468571627674, 2903493961726666462, 10560076388764518443, 3749651622493296975, 18114127684252877364, 1, 0, 0, 0, 1, 0, 12240592655856206466, 6264740020775290721, 859763567572081467, 8842953438422484122, 14329981889510246939, 3582542183068105786, 6023391989510151456, 2953193964713672141, 12396149302348639250, 13882467375549577428, 3586988377712407519, 7213506509798642482, 13435456572406932891, 9645941250097564536, 2781650568775738364, 1, 0, 0, 0, 1, 0, 15637532899188291351, 12683652363890573925, 2704597975013858668, 17832955104866332736, 6815586591600943723, 13755349213265671492, 8924117914024270326, 3329964149511691453, 11039495891702065838, 15670789219464690273, 11281671746346947225, 10492374165392519994, 11439270560757451470, 7337394676363778206, 2272256910055258613, 1, 0, 0, 0, 1, 0, 3130343892077994054, 0, 0, 1136320813223337744, 11438337112810950654, 16692992611178972868, 9482499518540692367, 5451078715157933845, 18403012202839423090, 13340398881404871439, 16853681425214524760, 5540259513623809808, 7754241405876268140, 15538673406175044580, 15705643278636475771, 1, 0, 0, 0, 1, 0, 0, 0, 0, 6593967995490198369, 546795078589070868, 8093299549277945163, 1445098694824947603, 16968796337604054074, 7105604958885889972, 12829574433066656016, 10962264142076089650, 6970346774265824779, 5668604568559492205, 15930738860655806958, 14403244990983785091, 1, 0, 0, 0, 1, 0, 0, 0, 0, 7770193319703938593, 6228225228483877842, 5315425894230577486, 8012448033829391087, 5395398520381640698, 8770911350053719042, 14827874098479004474, 11024999006644848903, 13791657658989935762, 17830220104295996918, 2090812709146185278, 8577173283657139529, 1, 0, 0, 0, 1, 0, 0, 0, 0, 17471481800618265475, 1930822204634793148, 12769804899579893379, 13068810900387198296, 10732524945348487200, 1519317270498249877, 12604995971822921101, 14107509487727911757, 8257552923782319555, 12034059115493819529, 4343039820825149431, 395799121324568963, 1, 0, 0, 0, 1, 0, 0, 0, 0, 7532528701100807439, 10480547126759850066, 6097728641437901141, 17248496754222975198, 12342802819241620905, 7554371666290801318, 8718773026382250605, 15984482998549000918, 15460443374009848343, 1087146607978023558, 7531163901062156801, 4426949494427873777, 1, 0, 0, 0, 1, 0, 0, 0, 0, 4539061041759240, 0, 0, 0, 0, 0, 0, 0, 213625975700372028, 6103762562402135118, 8461833255366069567, 1720047680925886481, 1, 0, 0, 0, 1, 0, 0, 0, 0, 13071177483731847596, 9686292801190181773, 17651358204212384773, 623102158970833400, 18161683613551356205, 1905311249198158721, 11609382548502599221, 13817075853679351908, 9025310235253336765, 7882119478620692609, 18179794579967457372, 7964168423813383674, 1, 0, 0, 0, 1, 0, 0, 0, 0, 3167601002832997672, 14415171155867193311, 16137210400120039159, 66363658294528744, 18026300366666585427, 16119825485646609021, 1791495851310687818, 10854206662041334332, 13581647106013633474, 11888984354923028713, 1057821317113010102, 5796297350077934241, 1, 0, 0, 0, 1, 0, 0, 0, 0, 7784671065083678705, 3558884115261448151, 11418253632452412773, 1403627403973388394, 819084279764884206, 1407109872228328204, 5246174561222584074, 3872887851860878865, 6987805815025651594, 16813603419480913328, 2035491262798693541, 63867729655895697, 1, 0, 0, 0, 1, 0, 15907894811979069988, 4816131323033975155, 7888904563512413895, 5092349396408408417, 1042143422396538716, 3762822649239783949, 8196544070748041586, 10315355419527218517, 7339407603689058379, 10639948648547682671, 6123607466480072181, 14853363043128504640, 17058485441092820903, 17161076486544329100, 14143325759900421814, 1, 0, 0, 0, 1, 0, 7591190062109417050, 9132932650297078912, 18059219497059994491, 12482898336916528446, 13174698819228496505, 2493773128969151007, 12643635820180007001, 3083772711687177863, 15089756422354654327, 7693091574011130832, 9436166604667119301, 12830611190312913054, 7973972404932364743, 10464756062953622156, 109716314765170116, 1, 0, 0, 0, 1, 0, 4126769846122054656, 707829251663853104, 7629957164358255416, 9341908378498020691, 3690464399435141132, 13117698496574260979, 5451440718276137237, 7550245756112946615, 11753021061535422888, 15170963155944982481, 5947667375361174600, 1596111063080183500, 11749390155806323479, 12692175311028724710, 7916688742951942744, 1, 0, 0, 0, 1, 0, 4645035303164012400, 13915916204012920340, 12291486388396280500, 525851188163440848, 4707286392244844218, 16013577564573367551, 13868023936870720304, 5148135937681993147, 18040333195915377325, 11529652625051471948, 1852565776215464254, 14161537793254580129, 4048643506759177080, 14450982547699381817, 2934196537578419476, 1, 0, 0, 0, 1, 0, 11488303914325795411, 11765426007596825119, 1523836086483283753, 16127371626322030471, 13747186051093078910, 14683368485138504162, 12593690295898988948, 15228744413198821157, 7332814344843067213, 14138816066324498937, 2102762737278850021, 13313601398896337631, 13121420191740374129, 6257139546349661876, 9729033453413867848, 1, 0, 0, 0, 1, 0, 9708911278112697027, 15643607479776624214, 10807857923693087240, 8404702627227890823, 10047145562846981342, 15600116582547970218, 4297960339811615000, 17447637109133227112, 14290298932221000300, 13800955719543521787, 110863501940494442, 13161269314340397651, 2105063197779559491, 13124468932815073025, 714461081021505970, 1, 0, 0, 0, 1, 0, 9223191767830668365, 13626886630453446877, 10808778593074643576, 16763094170387080928, 10091458508962207795, 1734402459021112515, 4981576688453120205, 11005274036034670139, 14260715897147313611, 14806437275519594979, 10665791613726598397, 14265115120417368616, 747062796356804415, 4246870895382373678, 13220614616296969944, 1, 0, 0, 0, 1, 0, 13513127228332885632, 0, 0, 1736827337212275711, 17257174989540467501, 1988362627286450135, 99834712623465846, 5084645948111347049, 5551869680521103369, 12383048268571476338, 6568255087418472584, 13499605423494581814, 14111004362252364285, 15934954653433784852, 9984027318635910457, 1, 0, 0, 0, 1, 0, 0, 0, 0, 8495902383234192130, 13668678621722857045, 1558838040737371863, 15847552217836362268, 13055057243174343494, 8303291408352268536, 9870497363393333103, 18078068399423404657, 7583410213159199266, 1978193982764743020, 10535947734617692172, 10075032150190943363, 1, 0, 0, 0, 1, 0, 0, 0, 0, 12695633069775171902, 12809525764874681027, 9040743543114295790, 13518431885683893560, 13563025936958449940, 1763639376881521592, 970981096276376670, 9777469034389610638, 6320282846588280835, 14270738802862611769, 8722537202086045490, 8243744667044787741, 1, 0, 0, 0, 1, 0, 0, 0, 0, 13642526033304235324, 4183147132623728298, 15386162382022344959, 16003283145777258468, 8391278540569750664, 4213029299554789023, 3437746951445512084, 8911792534982071466, 16183870450597134620, 7787473152259124966, 7310128289290306511, 17060872974098059643, 1, 0, 0, 0, 1, 0, 0, 0, 0, 3522571414841252998, 8184450079211665661, 6529578262649975717, 6261706375900221050, 7634873969298005933, 8950987357718038443, 13680774040296089728, 16762235143106196223, 16430047160501569010, 14861946194768960443, 10513948170299859642, 11975838346548297297, 1, 0, 0, 0, 1, 0, 0, 0, 0, 580999813345182728, 580999813345182728, 580999813345182728, 580999813345182728, 580999813345182728, 580999813345182728, 580999813345182728, 580999813345182728, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 17247772468616032613, 7600025394925764221, 7955777840235657962, 14778507181110587334, 6625781598431722644, 11269587024342180880, 1095078499718437680, 17629529705726254471, 12173823341773609445, 12027777926473976977, 10548232447298848920, 11191668470571035623, 1, 0, 0, 0, 1, 0, 0, 0, 0, 7212854399021382347, 8260158641355935804, 2036343373575726272, 20645146758280648, 2412515286962891034, 12558060813250728464, 18115796003320518003, 9956385073995476810, 8355451719607804905, 11898465697935779867, 11481620581339396075, 5053988127852505047, 1, 0, 0, 0, 1, 0, 0, 0, 0, 4083599105365810292, 8723345258690657607, 11473264062281662940, 6256926579240276105, 5468644964009567782, 758108007400586868, 9520951491853586676, 17787553860746980342, 9963059105071042759, 5935249146141459086, 1727497401312731108, 7027114296019665026, 1, 0, 0, 0, 1, 0, 17225384659479695880, 7547107831863943900, 7586494724370585223, 18439830271691383815, 510380585799936904, 2097735149637624737, 5010192402325660771, 17721827191138606667, 14151172043623379279, 2621138995929369414, 4866521825536676258, 4936774475173485037, 6084983335248988076, 1316337623165354879, 9646582244215554347, 1, 0, 0, 0, 1, 0, 4516215479177926657, 9925616832160314316, 9773586622763691078, 948219269412661958, 14611700435569786419, 16773932546889685810, 1107809727464434614, 9560879713002703906, 11076903123274807987, 16881679433359356735, 2715948938378293043, 11628515061150373855, 4162557158410810904, 5205045181658915242, 11540698754684563718, 1, 0, 0, 0, 1, 0, 10202041226865208435, 141985322414560908, 3299848892110581995, 3159604077290060804, 8622054486534314214, 5474513080224483433, 4110000601336855383, 4902345883390777501, 15764127542136630764, 4294885769175896152, 6235735371157527541, 2485227587384103094, 8848665971323760288, 13954308106415618481, 10953923591850316072, 1, 0, 0, 0, 1, 0, 5257746147149307910, 17174783517453828871, 4597653677804532205, 18237887045237368733, 11918935917804454770, 14333756346908171038, 11371612979173978084, 3583002294292261341, 13270804703147200974, 14723227373679438701, 1357634590270471295, 5781266174666314114, 17760102468114475087, 16434384456628942893, 3900814811719656723, 1, 0, 0, 0, 1, 0, 13884820746927058788, 9270374989065318967, 5246121405124210671, 7663324268782961837, 2191709360144157218, 4148893382614159356, 2733948193995819857, 14132085828870775797, 1003614799924134348, 483130048856287960, 2093261773321017838, 7244482392958895511, 4476308567349096957, 11365067184664022772, 1496399840045018815, 1, 0, 0, 0, 1, 0, 14034150103549409361, 18096513872460075506, 11127518800743472703, 16169827357990058769, 768889104582256256, 5063672134989793000, 8177152994054270953, 14519774356616750515, 5282014258228939534, 11185753418772485201, 7339855872361189863, 2751765428506627026, 16410858644837695285, 3168955570935107271, 4235839041903922738, 1, 0, 0, 0, 1, 0, 18296364930804407816, 4876679931892485987, 8700931409395017179, 14306671231110976602, 2710499980265003166, 9240811163216966608, 8568348789446621778, 15370436904049879550, 4782083616386060395, 9191241905548455193, 6045653345021378740, 13028324881145000696, 5837184942005509449, 3594114040721413816, 5576112453622336198, 1, 0, 0, 0, 1, 0, 18227500723287175099, 0, 0, 16730341839826576408, 3692638321978467303, 6433242332622521009, 2291292895494898983, 3900172221093734467, 14080120921585297673, 13252907867885073269, 16652266278011828989, 12684155440930581084, 16853736578527067231, 10903248264916314668, 17159383822002743974, 1, 0, 0, 0, 1, 0, 0, 0, 0, 9663317297640029186, 3179815813611408161, 15382868405397841289, 17774841093291303690, 15561756925779456415, 11787075848521667463, 17026707310279468613, 12513410256584319322, 17661065248686859389, 10796110328971392976, 4822670343402163355, 11372642333714183005, 1, 0, 0, 0, 1, 0, 0, 0, 0, 12923780624719410118, 15228217436729383467, 16407456617835496488, 191254740555322213, 10417005955196427443, 15631224324097912792, 9481620082656198805, 14005095752388629920, 15242482978284769044, 14954808412257515074, 12996263148551024094, 15208300493676788879, 1, 0, 0, 0, 1, 0, 0, 0, 0, 8481699980895920040, 11355566957836326067, 10008478932238631638, 1125833604663061758, 16919269590511518832, 2391375154551093567, 14821552413345970431, 16787721412847018840, 7352920238514741096, 10037843785082573009, 10187073057528044009, 4767066643997340533, 1, 0, 0, 0, 1, 0, 0, 0, 0, 17435140114479298129, 1435885832764997654, 215283041871207160, 7082661356804799086, 5416435572438850612, 2882953289127770017, 16218313204809782547, 8575194234315674944, 213625975700372028, 6103762562402135118, 8461833255366069567, 1720047680925886481, 1, 0, 0, 0, 1, 0, 0, 0, 0, 3522571414841252998, 8184450079211665661, 6529578262649975717, 6261706375900221050, 7532528701100807439, 10480547126759850066, 6097728641437901141, 17248496754222975198, 0, 87, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 14335534823153189982, 2564274019290773358, 1240147410646593301, 4309759344612372747, 15680264455718574947, 7749928968172043074, 10379737442849991001, 12214799133441547975, 3010911421139668616, 1139563322249956440, 10665555756390945477, 11416383848154538939, 1, 0, 0, 0, 1, 0, 0, 0, 0, 2820210263285766173, 10720048331316524888, 16336081156703325682, 12593780523887353343, 14860169004739645851, 4935077138385472484, 3877939940902222438, 15459208758406011750, 3416780490017188932, 10124179113180116382, 6241701633229064883, 4550300662347412321, 1, 0, 0, 0, 1, 0, 0, 0, 0, 17236626943327285546, 6651694379495204788, 8336772613389807368, 4706110611062451689, 16613817815676391042, 14575939158311467485, 16532748839852396556, 15511587739895040434, 16203954224127058938, 7875674405969275087, 1782833494123441622, 5398391387950663852, 1, 0, 0, 0, 1, 0, 3216814705581329798, 8051488944047311617, 10360317537605597112, 10000406277741968662, 12388875369708291484, 5436159307074426676, 4141714552502191024, 5296179612907339628, 12465452801273636461, 11579821559146688098, 17723772565616660471, 269753408705321891, 5483693307349928485, 4148849849976411384, 14094161360764912752, 1, 0, 0, 0, 1, 0, 14178823458963512244, 3602272614600789469, 13905084130457283808, 3515474081943841043, 10660299906599270345, 5372326410876184636, 6156913135348580725, 2727608749578829361, 9988179754024184550, 1886131673715221226, 3768033638170488110, 6593749857609147597, 7566856789186803155, 3093019441584322610, 8761844938205749171, 1, 0, 0, 0, 1, 0, 14932870104720801196, 6785058050362917876, 15400461162492325976, 6053827097512010536, 18058988363310447424, 952127655583997344, 8130038137052345894, 14574147540888753393, 5211967294049811177, 1357444766332736487, 2891025200344158148, 4635414157698539724, 18277403464256252089, 8597937863411269927, 3185668978082087344, 1, 0, 0, 0, 1, 0, 1201637799925499218, 17612205884537743144, 12773097028646980525, 8960712552465026661, 9623705551395999386, 5020935239539129789, 701544453173650648, 8059351235840793745, 6694468041861665026, 12472822793413282781, 6236280916588703543, 15075342768292292116, 16879266252447328622, 7949966339384557545, 15511932232010057342, 1, 0, 0, 0, 1, 0, 6517296063227531697, 13317289165024626296, 11586609619777615563, 11979786878033472693, 843700314249069534, 11468557060291821177, 1938925551829656577, 10904264752260159799, 14795276649641559516, 15980631930421053887, 366057401724727850, 1413999795298148165, 10480838138111592719, 355079579910825811, 1574006689819641482, 1, 0, 0, 0, 1, 0, 7633630111197404945, 13444551449194423842, 3201988963668978031, 18123254724334785239, 5226109711488235461, 9579884402934033802, 10839677918877320285, 2271701567336889031, 7760841801390371710, 11471967310545114203, 10354312982073068000, 7915945758644279589, 6620992389563449781, 17687631000570413775, 16989897277811855421, 1, 0, 0, 0, 1, 0, 12268347784756099869, 10293513373138690724, 4130570496550447446, 134987944822694065, 10187646862534872963, 13580463007636418163, 8493022306153899371, 11388412644925859267, 6033082055004604682, 10953623189535037762, 15578008213258609099, 3945822118816847854, 2965464347717975564, 6363341880115016817, 9251952223235505862, 1, 0, 0, 0, 1, 0, 13712872653154503104, 0, 0, 7590275663852506792, 17142561411497204401, 15125840589396167585, 853397793542178445, 3473479938564490101, 1392444963431030092, 730262405744903776, 13260993287089333654, 8393438592264674483, 11306148085986296698, 5684934488312461188, 9028920192463013348, 1, 0, 0, 0, 1, 0, 0, 0, 0, 8641507014103477635, 3846511598062821009, 11894650477774570670, 14544980701902675312, 11986220662741086769, 12997958323187254385, 810115173760427441, 7273544940783271884, 10804780975337509125, 2086088846957217289, 10435649056729292941, 14937599399566357015, 1, 0, 0, 0, 1, 0, 0, 0, 0, 12810611099391073458, 10193722466575479921, 2671742567446566567, 5454248439622432085, 11254344690855207499, 5844726498509817937, 2972078815201344240, 16224554024045094426, 11285479015367787523, 1329278757683796924, 17595360511324176896, 12194499054171516103, 1, 0, 0, 0, 1, 0, 0, 0, 0, 18425592401989202654, 4468095142881580960, 4730631766664398723, 10135320711870011464, 10078686613521300141, 112670771943665928, 604160431047680026, 15076340203450547457, 5649049948736742168, 1372653659349995519, 10291410187286507610, 15319982794428564777, 1, 0, 0, 0, 1, 0, 0, 0, 0, 11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656, 17501946937763933948, 7675566390936895331, 4994195757323687992, 11767874304575963253, 1780538466631614833, 4063459066104458636, 4522236916001186996, 2303690644539739387, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], range_checker_cols: [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2187, 4374, 6561, 8748, 10935, 13122, 15309, 17496, 19683, 21870, 24057, 26244, 28431, 30618, 32805, 34992, 37179, 39366, 41553, 43740, 45927, 48114, 50301, 52488, 54675, 56862, 59049, 61236, 63423, 64152, 64881, 65124, 65367, 65448, 65529, 65532, 65535, 65535]], num_rows: 128 }, last_program_row: RowIndex(88) }, program_info: ProgramInfo { program_hash: Word([11335578881191217942, 8731100815641553480, 3932297499273598802, 11617552580386582656]), kernel: Kernel([]) }, stack_outputs: StackOutputs { elements: [2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, precompile_requests: [], final_precompile_transcript: PrecompileTranscript { state: Word([0, 0, 0, 0]) }, trace_len_summary: TraceLenSummary { main_trace_len: 89, range_trace_len: 39, chiplets_trace_len: ChipletsLengths { hash_chiplet_len: 80, bitwise_chiplet_len: 0, memory_chiplet_len: 0, ace_chiplet_len: 0, kernel_rom_len: 0 } } } diff --git a/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_22.snap b/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_22.snap index f743d6b60a..6ebd0c19ac 100644 --- a/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_22.snap +++ b/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_22.snap @@ -2,4 +2,4 @@ source: processor/src/trace/parallel/tests.rs expression: DeterministicTrace(&trace_from_fragments) --- -ExecutionTrace { main_trace: MainTrace { columns: ColMatrix { columns: [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 1, 65, 97, 97, 65, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [5482243896119908732, 401642074298203, 3137828705454, 24514286761, 191517865, 1496233, 11689, 91, 0, 0, 0, 5482243896119908732, 3358534066525179769, 8, 0, 3358534066525179769, 13210061556570014836, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525], [17271741639510569126, 40, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17271741639510569126, 9365253138981608257, 0, 65, 9365253138981608257, 16003296542960478536, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728], [10627125303494028926, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10627125303494028926, 4243893038989355703, 0, 0, 4243893038989355703, 6732564319544917702, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410], [12334791106787903660, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12334791106787903660, 2372900269115514267, 0, 0, 2372900269115514267, 16687523027086140644, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683], [13210061556570014836, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [16003296542960478536, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [6732564319544917702, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [16687523027086140644, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 4, 3, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [3358534066525179769, 3358534066525179769, 3358534066525179769, 40, 3358534066525179769, 9365253138981608257, 4243893038989355703, 2372900269115514267, 0, 40, 40, 40, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [9365253138981608257, 9365253138981608257, 9365253138981608257, 3358534066525179769, 9365253138981608257, 4243893038989355703, 2372900269115514267, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [4243893038989355703, 4243893038989355703, 4243893038989355703, 9365253138981608257, 4243893038989355703, 2372900269115514267, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [2372900269115514267, 2372900269115514267, 2372900269115514267, 4243893038989355703, 2372900269115514267, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 2372900269115514267, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [16, 16, 16, 17, 16, 16, 16, 16, 16, 17, 17, 17, 17, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16], [0, 0, 0, 2, 0, 0, 0, 0, 0, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 7, 8, 9, 2196, 4383, 6570, 8757, 10944, 13131, 15318, 17505, 19692, 21879, 24066, 26253, 28440, 30627, 32814, 35001, 37188, 39375, 41562, 43749, 45936, 48123, 50310, 52497, 54684, 56871, 59058, 61245, 63432, 64161, 64890, 65133, 65376, 65457, 65484, 65511, 65520, 65529, 65532, 65535, 65535], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [5482243896119908732, 18015781855758016478, 4383606322674378669, 11282929110176162954, 17215248529293365853, 13193227772306657556, 11735240166769603875, 3717289286029653294, 5492874275384737590, 12486768927296380145, 7992161010257837902, 5965860733558915216, 13973209423992708161, 5139670008027876415, 6906630570311142812, 808538110186084468, 2187643142553675840, 11028121748345672612, 18181286167455191614, 15014367804365107227, 10866688391213961683, 16520440189869744108, 5493823407617825232, 501346961392724628, 18105097706170191265, 13534558354914049543, 3820689183586493894, 16784019981734849061, 2862138511955678409, 7758258992155315690, 17115115516972321026, 9874694795284567525, 401642074298203, 4016420742982670, 14280802901810915241, 7925919485060883878, 9094034340168608638, 6650811367268781560, 13344927435882217244, 15870694671012449597, 13091389828882674218, 168434371192049215, 13973668876111195937, 680445747454648704, 15441309962929722976, 15749770188837954531, 5233297770622824375, 3367253731665130938, 5066484463076591248, 9867160564810673994, 16707816004584596036, 6832899290197418961, 10263347723858682786, 6209209797490182000, 8678413656546712232, 9643915442530902318, 17208626611000903707, 11389822518212260982, 887493237489321299, 48736118273260452, 13483864438078018308, 8159241411748295729, 10385528691577928985, 5482243896119908732, 0, 616, 13342492399873323769, 1439796670523758837, 2591609871503882494, 5919456033500076693, 5232333079875635931, 12079101376381790329, 5687909194194711965, 13514584364960626778, 10501272396704173758, 7941686916236651549, 11501430483965911830, 10227424397178507773, 10471520652203868473, 14226149352545573719, 5877312072455938554, 4586059525590481046, 1601223390241498740, 2723805050156540964, 14314758709191331837, 15918659712373688555, 3030433806959200828, 16403500445172050158, 4533755278593082652, 10807446599885826609, 6981555831806437627, 13412972662619459764, 13711912288503888270, 7425430573821419685, 16752277069679715408, 13210061556570014836, 8, 80, 16253482711025978099, 16690839578921925157, 11755424915479552417, 17934377671577204140, 15509754874715907467, 6426721221030580337, 11049594146888643723, 14912334368661229147, 17657273147290084056, 9105126057127804171, 13430225876739607206, 3614830725909060912, 14569284676797348998, 4705513459362295944, 424917224365117418, 2835737623710330612, 1964100172858915134, 14896843043547784767, 15482419984058848245, 18437547705335910066, 3162257106529980441, 5297995970636059087, 9661978795293871188, 10128143329575104151, 770728251595531533, 9782965673735423214, 1347942901513492691, 12086966446141742548, 10239457018222882008, 3358534066525179769, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [17271741639510569126, 8154194758959345943, 13264028927506398677, 5896249534368220847, 11382862066285680273, 5436084715181539253, 3806787319072410229, 6511238228694043548, 9049442861863566881, 3576764171564075210, 450124369605914003, 3732227441816681926, 14029816209330408163, 8200782329890006994, 10416842793286403595, 6907512650407721813, 5351083897603196824, 9182929970775715030, 16141859999570517823, 9888871621811661249, 4078956937078417294, 5937931242192299623, 3211370055999743360, 12301747922262729865, 11292399879083020280, 5346237718208015471, 8535816953133153286, 9097410120098142273, 2554244438665697829, 6695383891040002341, 9265251570417433175, 11914585017133270728, 40, 3213136594386184, 1835177830541154044, 826263100281998566, 9612296353153372169, 2509054224639990472, 11363599377854067153, 5593295816013818122, 4611398810491526224, 17064807786960234347, 18427889571151062396, 10159688738464070440, 14427917509182297997, 6874689601963577621, 745298233749984501, 4960831845018172313, 1451394763904737446, 17942681985602265676, 17508193444101172646, 1672370857206926433, 10152063658776528390, 14576660961872281746, 13602838247655372264, 5274902253855511588, 3163862752932557920, 7292072545764012550, 6033538369482377655, 10941848106600998110, 3570589185097006252, 4587292818271677447, 16771298688176486904, 17271741639510569126, 0, 528, 4511615971967153504, 11189511375577512439, 14523290705070057408, 11602649596278030541, 15937333004537029302, 7414360896531864023, 7973996941547777109, 691576170553327010, 16392526795103433215, 3672880019205947738, 3018308815206440911, 15753827566219281917, 12969815742735761919, 16814873348334179176, 9850453545266944859, 10757916804785969985, 15838808218411872755, 4464803664915013475, 1326425913004665964, 12560438841096766551, 448453576971543277, 8998725782446855275, 14421875759181138198, 3100710952877190431, 3320646806195653797, 11565789183953445370, 502156843765695809, 13147348360138928114, 11903841834984596874, 16003296542960478536, 0, 64, 5751576643258238090, 7830268710878889486, 4868320831660690795, 7042762868047858013, 1028615964620729689, 12270587957620579653, 7267371538363991280, 16125626865182516658, 16950134439933558852, 13427183447069512151, 16117382505273595827, 2222792985740553749, 6517696895688418945, 15516128650333221731, 6357034143715229949, 12960707821770488929, 12451444460344609421, 8786747128188560390, 7634329044629047826, 7741107824034642016, 10975559322169081956, 6007758954686348362, 13971256108093330407, 16868860295450858142, 434120282701603474, 11571634562637977474, 5581285869985960561, 6581368197537384623, 17661012293298952642, 9365253138981608257, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [10627125303494028926, 14952889910786498171, 4766776471757604196, 12230245468863423579, 18104224094677170296, 15873409126341319274, 10073785188538358192, 9346697284679931865, 9007898958502691821, 18310381669862731969, 6720634958674998611, 4972858056675247397, 3284008361973965746, 14482858214234206831, 15154449156086880838, 5792220624700559072, 12843525862417693577, 642245012387336876, 14582627702688057517, 2964899186980974939, 8169860993617536308, 10855885493426519851, 1871971423867885122, 7909458165142256993, 3879457158905131550, 11439385698067115077, 12781603895645888322, 12658641528827989062, 9129723360543316479, 2424787611628537668, 16343713044075599831, 14619522228640933410, 40, 803284148597046, 10010111294767420802, 16943179644353820008, 8996122336997085030, 17350347680949584060, 13520911097528541892, 14769691589967587136, 81685142906752346, 7559897225353479520, 128512095027132822, 9792116363139842106, 4634576985104787587, 8679380235287294885, 1134592111928495305, 4684288247441474792, 15613043314698948257, 4841731940180862534, 5786518576333159075, 12666070374819933283, 2487841274273895537, 5690982477694717281, 5924572671969496500, 8629130978595053833, 18206699227813987098, 14234831161984809711, 16798226782780142546, 9330568307929665420, 9731250716956559616, 12286920896461242142, 1919835269886444210, 10627125303494028926, 0, 264, 9085863547783897978, 4029278259426396811, 16053154709446024998, 15730095788089532534, 1184856151594203190, 7658158244024203478, 7908104163460391198, 11768448888839053133, 15952542848401697239, 2236539493336923746, 12654027314481387133, 183479441840898968, 12829755263022627333, 14927722658095997307, 8579481663516436508, 2326984138263422166, 12584151503586926798, 5547037854005909933, 18320766430359725566, 16436941964924985549, 2398490839703252269, 15603212774947060210, 2697950444757558845, 7336230381913860230, 2577750295211676178, 16469775866150825791, 360850050916534143, 7183698983616787617, 9070535322622906244, 6732564319544917702, 0, 16, 7110029021941723513, 10115409991715085575, 11428668827299215140, 4015039023438705588, 3732466887400149035, 5870841944205588609, 8421627027326523148, 8231214549142439222, 10318470559229280016, 15171283498151438808, 12477430934852872037, 3853779543897991795, 14662750186533371679, 7423988381383082226, 13549468426633458145, 11079168775731474830, 12471207782095033761, 17595325414333663547, 7042468264080735391, 17650115337646869205, 14946074228061446423, 4655654314239637986, 11187552516160183253, 18115881480442018545, 899748567092010447, 14020868337400209874, 15417366235984526759, 3331301994171189600, 15814677761660135474, 4243893038989355703, 40, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [12334791106787903660, 10536106724359599792, 14660905060901389201, 17357985657180629743, 10490790376815116141, 8856174280738574418, 17564486157138470037, 2383050989032417578, 9423711593310475409, 4142017075081989212, 6217567350304044823, 15435624740876731287, 3215908606625999288, 11222238183310766613, 17187582840477322187, 11654551786904653634, 6201498867875513095, 9940061963065628902, 1432819846316931691, 5068010018173215582, 13903556343063122489, 8872060411343823556, 17720392065240548352, 17643816943101201258, 1449530809054027683, 17965277233811019017, 4895491920411997249, 10751559368097521724, 16513197729164811328, 4815287357290896051, 3003012580421078075, 6636010883309744683, 0, 803284148596806, 2549897079792572603, 5670682422759337153, 4249626004536644548, 9138873913574622404, 1343119293110958009, 15707367360995172765, 2149720931386886989, 12579497520806083785, 14990373923527496282, 7330871518527332444, 5790961380321049961, 5495469617420264118, 10789212522972025785, 4356961356341052500, 8032044444015716361, 5554647570062987979, 1022644107902166331, 6764324513849573852, 14002884382934858252, 14316154512513580139, 8331374540726760892, 13067519389098510351, 8671032013540344722, 13457978878695920483, 16399505509770566014, 10578307416004071064, 11950037765875050974, 12195903600484928258, 17694444981837938563, 12334791106787903660, 0, 88, 13728083094831419091, 5555139373262852832, 2905384006316447019, 12155959663009124293, 13187847930197094867, 15053688477158705110, 5239197399579256268, 18372875045424962848, 6782570937531856778, 5670979983981263850, 10968120781620208764, 2099848306821515114, 7984319522957739004, 14143871504578433969, 14093328990578646811, 5769086287272836702, 13010501651213663576, 16984828703781093727, 13803823311240773956, 17471084929704555662, 5508754216278517899, 14994098977964244257, 8220163139135834751, 17625713553185819225, 15041604777168753281, 17976701769209321205, 10958079103202840999, 17793074612839242130, 3601655880141993647, 16687523027086140644, 0, 16, 3208043314804619251, 6920597847411412414, 17985619796195836408, 11907191178709112742, 16377455862733420451, 15572876043608056600, 9466912758182965715, 17480763791598773801, 15029113851915312964, 1953587265841775225, 7175742902791404624, 6820764940134875350, 16069841829669607101, 15548451706938320654, 11760680638795846495, 1560700914733041660, 762367990279432470, 2603436428456411224, 6200990949184863170, 11673627333152839295, 7804486006334068097, 1006207264024395366, 11193609705356653459, 5704515878100803393, 14918729158665343812, 10658508130485449873, 380737719356524599, 12870561906904032245, 6984680585936259437, 2372900269115514267, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [13210061556570014836, 1599157050859759633, 12446750015896088802, 10353774239160274935, 11424271721157330669, 15057005486179715954, 8861044108273791962, 12243038632327996294, 6387235594535598756, 10620968503766467282, 10090957857949391364, 610949617653761740, 2641692952954235941, 16682338453560518377, 1667764180674112574, 3944406972826047531, 7937338373741897463, 677543792580138430, 16064632909904135712, 18144484844415291494, 7226453148331774623, 1179808805540104806, 2700524299164928450, 739842910379542056, 18551850792840682, 16856435263285305760, 6893839572721182305, 14666214556500183752, 10619536471246139015, 4063396021928247911, 1116280449848444285, 11377866377890790275, 0, 2008210371491335, 16850544756775285522, 652387120995254672, 4188956971131276775, 18389965100329173053, 852421464532798418, 17258729097516267384, 11347427093515448316, 13908538323250058716, 6558337355650114042, 4089976927111145333, 17816809041231283545, 12843997071522346840, 1655996231185402724, 11256141768734986569, 3019459069615110433, 16778373777892540383, 10175251160015024193, 11396702708789693017, 16481019216530994753, 5122353003150766192, 17913616556333538828, 6485826671956173957, 15738756542654855641, 12199621872357116369, 12077164016468113545, 8907315944885273345, 4878983963291132913, 1618531819557712390, 565132887411573955, 7288090792972058500, 0, 616, 4968648927826019469, 17195207199910519646, 6734621562241387182, 9715952180361858627, 2034771934048449998, 13730246563790151743, 15224252119305799711, 16575323315490024998, 9453153207794904511, 8194394828646838882, 1235308382947710635, 134218781076142871, 12444330148186854115, 16838588367568106248, 3274404606032631663, 8680261223649739505, 13512134067010568333, 15074317169196019601, 3919235389861209780, 14979187502739607198, 1116932806094012842, 12657319342943489784, 998626228777839492, 2347840117369842691, 15743276195226846510, 9881270424621082635, 2778123425092199841, 2613774562373586415, 1448060333031158668, 6190635258012880107, 0, 40, 18130890293586930078, 18252951749527557342, 4460903658820341507, 859505755654562117, 5961685480015386121, 12134776249586726543, 11174658189737631113, 18385152961050631924, 9881471501704199804, 9636744945302995714, 12323181865658998064, 14903454669611502952, 1490539036394497080, 11688514875590095153, 16093513520259190726, 7731471377060742735, 5247500963110975116, 5269361527156951110, 13733877647296302634, 11865469401112846356, 7643242142337524006, 15572658687280648106, 9345628789826937825, 3291248301730279223, 16808111015808513609, 16274730253017522022, 12243901590027926887, 6559275936659510680, 17224785255700525855, 1390310476158884261, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [16003296542960478536, 13466221688393768258, 12927954860087459534, 3759003303159369746, 1148549753827007441, 7129001791528740265, 5281592040827142238, 16203079979032760691, 7039074043166063940, 9054598259215599503, 2018397558465392243, 16413792935045431209, 12604373665766922919, 1493466405559625913, 11868526707386259660, 3043746450373199613, 8246328563832581273, 5887036391937389613, 2796053561793572028, 7645118395649289364, 12303475117195379639, 207358776078213315, 9218579057118601952, 14479451218433079532, 2031744097966400086, 2566041186493151514, 17259376159632543425, 10376116775360567681, 11289943669462175698, 10804772324353478999, 17288383771256214060, 9885671831159451104, 0, 1606568297193092, 1076973899277284702, 14086579741019377519, 3818478693739735842, 5593621083784091164, 11728670858811596587, 12625736484548160126, 968047239546776409, 15493380284459454506, 15542100289574010625, 15053368214221814937, 17388070103506970075, 4738318434573394804, 15389814481683087606, 14763812299525073807, 384493414835098150, 7660052382355122994, 7691788916209089905, 14721544157906502013, 737940994724202658, 3221762534387838371, 7517398897305596666, 13211005290810103003, 12141388589516060378, 13672030567886044471, 12296311093518063031, 6143526203440544581, 5554567664494429423, 12302163852964786956, 14310991091785572129, 7008881577152522467, 0, 528, 12828040835569540857, 15946070950510533025, 6868712626693654693, 16719465941571322506, 15929304398043808838, 7333330621525318559, 8574904634803746916, 11585949634519199591, 14215120915846294561, 15431555872184246136, 556415272972402332, 13729762303106745810, 1895854814022398925, 16120810718921859928, 14563556215553868244, 9584551737159741567, 1050656582218051719, 2849157683178260515, 4987801895818641338, 3252006976820452311, 4232022539410523688, 12145542090324719848, 13475056960068950678, 4212050629407893798, 18068871666013902057, 4214295938146797537, 13664544216029702565, 1391392205806749871, 3418909895274525076, 4840757955412667387, 0, 32, 10452764368937945515, 6969997263492352670, 15570786589164252178, 16136993048454358354, 16378352067056606124, 11747573379431147483, 12296464969648251345, 8155132212936940581, 2470200969414032680, 18126939303114916528, 16736276280592238734, 15549342782445497049, 9033882039108268313, 5121596298161079296, 14336897502470956191, 6301009824137139871, 16614860627935231068, 10383378433371415142, 10330363517752279308, 10937466001850040595, 16305844076412050396, 7189713532379018536, 7568236447715590536, 10805187342082326609, 7424874700566577356, 13861219118264849665, 7052270251739242825, 17586339544079318164, 14071176523136369481, 12282546735285148319, 3, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [6732564319544917702, 11424946734513850952, 14751589151467562513, 3091073535594807983, 17274728363719186424, 6785780051417756764, 15374515033027594653, 12476673273305390844, 11491856728648046938, 889587581187765015, 1832729573374625479, 11964718430105317483, 10284914521902415429, 4989117988224154817, 7310308994414837120, 4896165117485439507, 781193619199190152, 4972018469228063343, 11237024791849123316, 8136517227202567877, 12980119595156137175, 5277784125198234251, 8730957263237386090, 6627357084936364627, 9579937749716133270, 13182791294901350976, 7788172704304532836, 1814160375547940386, 7818804555865981505, 11573391963135759227, 18390005084876364234, 49905639292627904, 0, 401642074298523, 16072847024087248681, 1047399340937520223, 13840617071834531990, 13835424809772757395, 12438858367585478828, 14080077230806112448, 11208516754282785707, 7691155727086178136, 17898846423848868766, 13990233438164144322, 14765296463244153634, 10144768301469359068, 16658833476738371029, 4674204014270448977, 12722211832796318871, 492549161703070590, 13986658207276323375, 14512155514173182920, 13983563295828088546, 2440687363152463730, 15931932209781173412, 11078906302351818677, 3584926465549602493, 6813538466449503008, 2334817027508375898, 12619526317209583817, 6515674137823977144, 393947096345211186, 1951192747307666741, 7526556702499462773, 0, 264, 14858685484860085108, 16638144790071955925, 14803289513390493682, 7947368985060100292, 8540021318758160201, 1005829865088874654, 2182109332887118586, 2709878912677862734, 8639678844062658411, 1087022739668739893, 10504771173378443613, 10062807734250201377, 7979854057356878352, 5264886220300798691, 17178601938487182393, 14209807647112141969, 364963036030481104, 6977342036970944167, 9475211165936098151, 2067156367555811068, 13444810812224497486, 17338503932931685384, 18075892757378330321, 5992364927925930356, 280994234174845985, 4192504288997153355, 10293012497513243194, 12632074680840502609, 12384471116364520725, 14304772746964984975, 0, 8, 9114363797835460134, 5446076396314160376, 12863008906537145423, 10008421878335836436, 9952321233871043669, 12872379155893703237, 7266552182027361169, 1266036355585216796, 2621902104176569009, 8791105532651972211, 6351975813451610601, 11821139808280113179, 11281913023757770338, 3277134497757048289, 13219080767636598429, 10181825490691565485, 2766637533497216499, 5527857141123489970, 8463471033597650592, 16863468430858262436, 4521466714741486225, 2112404415880305855, 6776665887355979100, 4283028800297139078, 17448147405455891940, 2672696094870261596, 654959311657763753, 15404879372302137522, 458610335793450516, 11708893791522292939, 3358534066525179769, 3358534066525179769, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [16687523027086140644, 9086882804838007993, 18208410790236506017, 3398985649909830369, 11870335859895317550, 1782594595734670280, 7950908231675299553, 11699755763721080867, 5559192297727634984, 15856483324254330201, 3827177513892222045, 8697421447132597636, 6525137006607571383, 9739016092723027913, 37096681180297292, 5998909423699657245, 1737478325904747641, 9603988472267868801, 14612309354257526062, 963817021754931361, 2954837086209820968, 11485058781500311480, 10011022503247302490, 6596157637386353039, 2185026052398200396, 8667196121129603577, 17444739644589522901, 17384087895468261804, 4673396992430997118, 5652365973964779246, 14148401294484512817, 594790136239256278, 0, 401642074298403, 6959791354043610236, 1843180796447728437, 9556362158826632350, 3220022195391792741, 6012411438022691140, 4309223969498591447, 7596903557041777533, 18393682838284953355, 3973832102121938954, 12190997158276486897, 15972235844585587264, 14899488070931524727, 17337514399056563302, 10500237188498665928, 18440452962210035879, 7481614450647261413, 65300580117832193, 14713590013611289205, 13086268929321267306, 17247769089209001713, 11421561962034654967, 4561010052951998759, 9562817622798343284, 3062054327467638127, 6016566887476098647, 5513989129644936969, 13097123292793361360, 17631302057213141907, 8382824402074565601, 16136160484984138575, 0, 88, 11332670461359993442, 14431967032738938661, 10393518078208184991, 2462224494429193628, 2381519205788696693, 5156397633515475273, 13071332837477200404, 6583788956280193302, 8309261923972302555, 7204946769828595498, 10143223184962015615, 2291749916011172217, 12651590612371699683, 1757329184049619756, 8575055855333374088, 10782010546727900871, 11693001677843026089, 13372591108841832182, 6745878472543166577, 17326074735792689056, 17178266551378060244, 9012900451066906030, 9513119903156534723, 14316793092410720577, 15850020848376370982, 5093266838540794296, 2953143545478827927, 9172592184988170325, 3259030218090439002, 13670896049781213124, 0, 8, 6104172690014223231, 3119855977255645286, 2700229040680838768, 4228220371303630837, 12976691418076017877, 15391527008624099592, 15522155400452634037, 17655908650961725957, 5157987610310047621, 13664486701019622043, 12908699189677656287, 14840926611057477527, 6092037682822283700, 15181448373122947619, 2083722204849270202, 1893419523737526751, 11329911669537538562, 12331432886354737271, 9636585409664050258, 5131588463040403759, 10248116973079783912, 2136665268102207704, 17448444978654544666, 11945433761064128885, 4462464721020457233, 17579935132869425842, 7098417589530391109, 15343623253038912080, 7762335122892638892, 10310226363807226654, 9365253138981608257, 9365253138981608257, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 6538312968872592849, 8060897427763484267, 15694315280551902473, 15462035367190511759, 16783127636073026773, 10756964923802715923, 4768450986425500783, 586150029444692874, 14745636460228146879, 5204776334183399126, 7685703760533694936, 16111592919872596132, 6944599323919802145, 1254987403839644538, 9402574875622777470, 16210856058698621820, 6207690803740787708, 5909774410804808527, 11610503998702777421, 686805010274260483, 8419527378140004636, 6342702858222909287, 8706567413279745902, 8451985615096117101, 8796637399824800240, 15979424445015031332, 13704751155696621736, 18261872069356847559, 7568935938034555881, 3939988349760901151, 3558778201956820739, 0, 2008210371491335, 13098960849839742034, 9449621519891201049, 2814310786559014444, 5305842545683321494, 4969236906288915907, 1243780951433164967, 6167749875842285147, 9490220981060631819, 3665259354621890034, 7437125179920904126, 12655958476488865400, 17935537000594940941, 91614862745339577, 1869550524566103495, 17384150297165671545, 1154605885284628266, 8665046436862728398, 6741156569294553317, 9490927005547387767, 8947900188307771735, 13752550215202657538, 7714188412126691626, 12225947487197390724, 13509943592829854189, 7120740401378484294, 6789669275155346195, 2929601484581949152, 1077164174037184778, 7253613682453412944, 12957959164911169922, 0, 1232, 6031863247325663438, 674016650738724202, 9655491867310024790, 4753798685424869288, 10749041705000945043, 14520855376130294244, 1540176383869885892, 10236894625417199268, 9196614711423540610, 7978597004657283049, 6086008265617713639, 14043785705271347590, 10693788391520380705, 12309293813476849789, 12287432898048046644, 12476380710530844150, 2814554338965902349, 12370730861881949935, 13055692992345669402, 801564953257569940, 10614676804436196472, 7985393687855976209, 16788264280259941604, 4042445936043537075, 17844212763579117389, 14723420347046552696, 2456530167870834703, 7343890316269580191, 6483315548845037473, 9440211366785524370, 0, 40, 1560947813056021755, 6935064976442414148, 9999441144135002932, 10354700837586583171, 6040781227937012106, 4698117391978117444, 4735711626023545756, 11217844833019453026, 3130590714605394722, 2809204122464618686, 10935232469327759448, 18335893537613898174, 10868401885487323501, 15799177281014635734, 17187052562019754838, 4027411046406207040, 11879721967266924677, 3613659344771632047, 1846469577394958972, 14668357323201408029, 14939045883642543835, 2885718226990976376, 4969257074069595075, 10824274197210729467, 13212275138420405274, 10563919532671437398, 12234598862193668129, 14653607410806008848, 2498958194485300229, 3512215170452429648, 4243893038989355703, 4243893038989355703, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [87, 7206805482451038763, 10391043349415287037, 17044036436784806527, 13171139175044072684, 2094744771380247596, 13239410091625892436, 168039991714389118, 9272483157421678641, 9491323991579079848, 16844742792488708348, 9520544349855559315, 792788122696624862, 16163267682416611248, 7281147841738764349, 9382208451579624348, 15681622260194273891, 1390751769269680465, 8196141638178857464, 15172831853577650839, 12922697597526240324, 7829823799088278618, 1783927422614660621, 4975249353684987436, 13048186608776014077, 3034445649013398243, 6966167031354634355, 7794510095811729812, 8010670397007670803, 871847630272290682, 18441078654886601219, 1106728433230065324, 0, 1606568297193092, 17457628753812655267, 5096693283465186518, 12947605480618213072, 13490514080936595140, 16186587491946121120, 10245245868334896235, 6026705707665599719, 9827345407768028181, 2812471843237874845, 12940670116574659651, 2714930976118111710, 11931084046533097040, 5957825878304116293, 4815270995456833861, 3281433232253188744, 1527514044633931889, 3155608937877823823, 496495357063373704, 12643114535206930756, 2926290280590787897, 4481685646324082958, 2913086696180341350, 4929647997916999987, 9053067786296036128, 12860916533743270733, 13426707234447106813, 15934882759672330788, 2173747106952139997, 5260381980138555939, 9238536158694879401, 88, 1056, 10194964851803169917, 2476887483552371976, 9610004573075108621, 4964236593939309395, 10117579878001530331, 8588168632019162203, 7961669463441676499, 8688363314921128388, 7669238601546834041, 15117861700401653408, 7267798175629900560, 18420331634788000621, 2168204218347522931, 13774182815867438503, 11793649490935032382, 264326996749206681, 422815844549413164, 11144132125283193307, 16600930886850462534, 14741236577529096830, 7550071867985447349, 10163945784944658272, 8810849992229527370, 979169410947035438, 18181508983255172512, 10501853123801116024, 10292737970295456228, 632012914013142222, 9098012027422757538, 7698805642109006453, 0, 32, 9302012295643728416, 424328237663665361, 17748121622218558811, 6681769685034042719, 10907932526941371789, 14996603190997478665, 13982878080104642188, 3336783822228111865, 7403528606603453519, 7309352233404946366, 11509327586943808925, 6803943428138467537, 12870260590513220077, 3798257798625653324, 15652192157997003684, 8260391000410661595, 9099897743400681933, 16067207775248165408, 7640841583197908852, 16739199083410292994, 1998275509994500625, 10688417071827877337, 16160081185811655577, 2725954513011781037, 3040692668058239811, 15097072321276989567, 7813293313258815644, 15261763399945716285, 2258772319189190202, 6756061023037720295, 2372900269115514267, 2372900269115514267, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 2643697525295255282, 7848268271641614303, 1670964981039714496, 12506995107569119516, 16020980424362300069, 3910461774754452973, 14887150284650111993, 11430895388638705560, 15925982986489674986, 559122298435457095, 16369319727902045750, 5911900249842037740, 9993545485068101534, 16804807948024450931, 6109216944498588777, 6962786378900996817, 14779846517676698965, 14597810963258762343, 16333362039819991192, 2239891938742671995, 8902636803530046125, 12348911713752556021, 9576130314342554279, 9464686824958661262, 14724291818312841818, 5956660324772534609, 5179789141411429720, 14891365206755013222, 833106187556617464, 14690990432528119604, 7399742180187746173, 0, 401642074298523, 10076989882539553734, 13617634258944637452, 11664888937794835322, 6832371865971954132, 7435465380685145582, 8856983143236954540, 15647394574465449881, 5004639611979401749, 16333513927375132208, 11586223746088007538, 17258599442845821467, 10089347514894229223, 8927362828162004403, 1274761678102044944, 13987176689734561031, 968318691601385838, 17920302096119022338, 18172419653743826470, 5238866342343116613, 4715585282245523496, 6782917713521523376, 845034972551066538, 8264516316211712068, 4395820162956710988, 17367170950581948054, 11715439359473390301, 4924405821869545305, 1674381281184830519, 4077397353846458666, 16570851802495678006, 0, 528, 3020492374890726247, 15867024276402164724, 2691485309401819348, 10383311521670833729, 16323720466012865692, 12111425008963394821, 6863497050423701439, 4068736078963485223, 6871052579055075230, 11135759119963236724, 8026699645344521142, 4857505768584918289, 10792639723427933554, 15144263097518946995, 2672819086738268108, 9175748808845810742, 8523928999979138359, 5837654600063955860, 4020408003683484830, 6777545915715419993, 16222025381660955186, 14681340973312169871, 11211579677305883898, 8623233971250462580, 418056849863168392, 2919384330136358405, 2666974936005298869, 14966813495153624489, 13584072213050301608, 17057575786157171701, 0, 8, 7519454690376123692, 7627104070861575574, 17604686071836489236, 14277148259130460564, 8312218486680706135, 8395439642754559152, 17307771294890409643, 9298206908486537717, 3027629924013931359, 2933551330348935458, 1450485994192951386, 8585052201707081835, 10624425952582111111, 16773523322999621677, 13337622149287916761, 17874287708894504070, 14164897610403484003, 11216401648549709020, 911970190394256131, 3202853507803349037, 14616902435260689479, 14924823153427050614, 4881022900440414264, 9723366934152472594, 16335725686098559697, 8087897843744270993, 11437013713086863200, 7627258546495067733, 18044191572661655945, 16490279521751489469, 1, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 392081819927674604, 13621084556403650323, 17078772340992927473, 862170971660204027, 5676881743340217488, 5517012370953012053, 3863387227510711423, 6521284656283570782, 17282496836457066698, 8668839984066399279, 10481218501610762636, 13268880552322298648, 9575112247205521418, 14191613402325013881, 17855143966403217682, 8464300128340058390, 4400313738036540825, 14739186344673284697, 1501891124109012983, 9798699259742823392, 8843421723884165135, 7746605484191389759, 8323169935435436763, 15323881858459172368, 8509325593168557185, 14233099751914870044, 12164983556041574509, 17356025534910089368, 2031310896521954322, 16067965450256037769, 8147499972447601337, 0, 401642074298403, 9851586117636382793, 7414079509745519565, 10414894202973226643, 11403399710197601656, 10230759118395809329, 4887466173119518776, 12376579030877442488, 15222686873173021915, 11343634646223977946, 15054143113295762432, 8578483304162845495, 8187399805941604842, 17460975957431844228, 12368453570037757143, 4715095521846408852, 10685847052710927197, 5160934306801665605, 12877482432527277885, 1026289052488784895, 12183816968946827507, 954239020314042893, 1899038343674936222, 3582199871763692750, 10141562795735590523, 5883730844910027408, 10313342961711791200, 10308552102917724507, 1101239144209002141, 16732112788727027442, 6132059608254040410, 0, 176, 14015299246960655077, 18240053740881435667, 9264051620447261114, 3770835013589498382, 14269426645353023865, 1064418857115644823, 9055361938666247589, 1923541152082479674, 7329032621716426413, 14147095007921770778, 12290092320014837503, 14167154425694482177, 2008826339817234435, 12727493810822145141, 13765995246049388004, 5723824967382588797, 11506863252089006870, 13547802874613831044, 2099106023167119258, 6345494554579617353, 13921991112058773762, 5885105447661412229, 8709961227558437878, 9751610933111772233, 13912537796384226859, 5691895930177454540, 2936046437280927758, 7163672760378086559, 12965649133168865250, 17131584050600476194, 0, 8, 17781582622500481192, 12847902632736061277, 12021499907877242591, 16751519355106661703, 9062087890172095618, 3834953580385337540, 2969703856153678454, 11604562295556139307, 10447912046373566534, 12987934619706800857, 12352596220492768030, 14816150974992525275, 2172600571554701126, 18086375044546604023, 16313093185369681775, 14997664071320688070, 347950016295486690, 9206182676441692601, 3566552483989599402, 4925983231752336365, 1728701557101400581, 7087476601458867917, 9759961360999781392, 12569092891286895547, 14206292953735333262, 16422952955631166803, 6294107725304445883, 9537940691512987143, 15535806100011306333, 7080716573279759555, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4099276459869907627, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] }, last_program_row: RowIndex(18) }, program_info: ProgramInfo { program_hash: Word([9874694795284567525, 11914585017133270728, 14619522228640933410, 6636010883309744683]), kernel: Kernel([]) }, stack_outputs: StackOutputs { elements: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, merkle_store_nodes: {Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571]): (Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350]), Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350])), Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484]): (Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693]), Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693])), Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781]): (Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874]), Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874])), Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171]): (Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361]), Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361])), Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815]): (Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305]), Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305])), Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689]): (Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195]), Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195])), Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362]): (Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063]), Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063])), Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848]): (Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661]), Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661])), Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352]): (Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829]), Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829])), Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444]): (Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223]), Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223])), Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386]): (Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388]), Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388])), Word([13190842942618341421, 17548956981569849952, 15418963848144418856, 730733050713174879]): (Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144]), Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144])), Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874]): (Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675]), Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675])), Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594]): (Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115]), Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115])), Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809]): (Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257]), Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257])), Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777]): (Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555]), Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555])), Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509]): (Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882]), Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882])), Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725]): (Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979]), Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979])), Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134]): (Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987]), Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987])), Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828]): (Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910]), Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910])), Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830]): (Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054]), Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054])), Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228]): (Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742]), Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742])), Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443]): (Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928]), Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928])), Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643]): (Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979]), Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979])), Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758]): (Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106]), Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106])), Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580]): (Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594]), Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594])), Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765]): (Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045]), Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045])), Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766]): (Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281]), Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281])), Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385]): (Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828]), Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828])), Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579]): (Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171]), Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171])), Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212]): (Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992]), Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992])), Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463]): (Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004]), Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004])), Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502]): (Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023]), Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023])), Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539]): (Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537]), Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537])), Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865]): (Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225]), Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225])), Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690]): (Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947]), Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947])), Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202]): (Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552]), Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552])), Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079]): (Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444]), Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444])), Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850]): (Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548]), Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548])), Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448]): (Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987]), Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987])), Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041]): (Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035]), Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035])), Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301]): (Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414]), Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414])), Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414]): (Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212]), Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212])), Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703]): (Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439]), Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439])), Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271]): (Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955]), Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955])), Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882]): (Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802]), Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802])), Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152]): (Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887]), Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887])), Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028]): (Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948]), Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948])), Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331]): (Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093]), Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093])), Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394]): (Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134]), Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134])), Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546]): (Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228]), Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228])), Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620]): (Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414]), Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414])), Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800]): (Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703]), Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703])), Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671]): (Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205]), Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205])), Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537]): (Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011]), Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011])), Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516]): (Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301]), Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301])), Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831]): (Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986]), Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986])), Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415]): (Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057]), Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057])), Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722]): (Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689]), Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689])), Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144]): (Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682]), Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682])), Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295]): (Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268]), Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268])), Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818]): (Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513]), Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513])), Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241]): (Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565]), Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565])), Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439]): (Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012]), Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012])), Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512]): (Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850]), Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850])), Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986]): (Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865]), Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865])), Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982]): (Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777]), Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777])), Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808]): (Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394]), Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394])), Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979]): (Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690]), Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690])), Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093]): (Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620]), Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620])), Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902]): (Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789]), Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789])), Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542]): (Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094]), Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094])), Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057]): (Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362]), Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362])), Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205]): (Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961]), Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961])), Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401]): (Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580]), Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580])), Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553]): (Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960]), Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960])), Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169]): (Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031]), Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031])), Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682]): (Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053]), Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053])), Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118]): (Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562]), Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562])), Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725]): (Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666]), Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666])), Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661]): (Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897]), Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897])), Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981]): (Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447]), Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447])), Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072]): (Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646]), Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646])), Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140]): (Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404]), Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404])), Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515]): (Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152]), Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152])), Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709]): (Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664]), Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664])), Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800]): (Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103]), Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103])), Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741]): (Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169]), Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169])), Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005]): (Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758]), Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758])), Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802]): (Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070]), Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070])), Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159]): (Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005]), Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005])), Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350]): (Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443]), Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443])), Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697]): (Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573]), Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573])), Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928]): (Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331]), Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331])), Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320]): (Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166]), Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166])), Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814]): (Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079]), Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079])), Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447]): (Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820]), Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820])), Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284]): (Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057]), Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057])), Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697]): (Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131]), Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131])), Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955]): (Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290]), Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290])), Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910]): (Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202]), Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202])), Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910]): (Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822]), Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822])), Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106]): (Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847]), Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847])), Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404]): (Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441]), Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441])), Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796]): (Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186]), Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186])), Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053]): (Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516]), Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516])), Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992]): (Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818]), Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818])), Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957]): (Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315]), Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315])), Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709]): (Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794]), Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794])), Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091]): (Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539]), Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539])), Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664]): (Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558]), Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558])), Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294]): (Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579]), Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579])), Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947]): (Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502]), Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502])), Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829]): (Word([0, 0, 0, 0]), Word([0, 0, 0, 0])), Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045]): (Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137]), Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137])), Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914]): (Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041]), Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041])), Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573]): (Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378]), Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378])), Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699]): (Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873]), Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873])), Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225]): (Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262]), Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262])), Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057]): (Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692]), Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692])), Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131]): (Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997]), Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997])), Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555]): (Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385]), Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385])), Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195]): (Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709]), Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709])), Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166]): (Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542]), Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542])), Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027]): (Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373]), Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373])), Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378]): (Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509]), Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509])), Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097]): (Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553]), Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553])), Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217]): (Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815]), Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815])), Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873]): (Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864]), Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864])), Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997]): (Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722]), Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722])), Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887]): (Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766]), Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766])), Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589]): (Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757]), Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757])), Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539]): (Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665]), Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665])), Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129]): (Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229]), Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229])), Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137]): (Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312]), Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312])), Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019]): (Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378]), Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378])), Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331]): (Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713]), Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713])), Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]): (Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980]), Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980])), Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325]): (Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546]), Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546])), Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170]): (Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822]), Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822])), Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054]): (Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295]), Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295])), Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925]): (Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848]), Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848])), Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909]): (Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796]), Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796])), Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540]): (Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170]), Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170])), Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214]): (Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448]), Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448])), Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317]): (Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294]), Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294])), Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757]): (Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416]), Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416])), Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378]): (Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091]), Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091])), Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263]): (Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463]), Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463])), Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666]): (Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361]), Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361])), Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174]): (Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992]), Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992])), Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470]): (Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401]), Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401])), Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665]): (Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957]), Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957])), Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262]): (Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144]), Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144])), Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229]): (Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284]), Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284])), Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134]): (Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325]), Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325])), Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855]): (Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765]), Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765])), Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115]): (Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814]), Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814])), Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441]): (Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831]), Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831])), Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977]): (Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446]), Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446])), Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880]): (Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005]), Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005])), Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789]): (Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995]), Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995])), Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000]): (Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267]), Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267])), Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998]): (Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982]), Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982])), Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995]): (Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539]), Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539])), Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507]): (Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512]), Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512])), Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305]): (Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118]), Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118])), Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219]): (Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009]), Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009])), Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416]): (Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089]), Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089])), Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980]): (Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445]), Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445])), Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063]): (Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140]), Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140])), Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713]): (Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159]), Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159])), Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031]): (Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809]), Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809])), Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932]): (Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037]), Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037])), Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094]): (Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925]), Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925])), Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315]): (Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386]), Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386])), Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446]): (Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721]), Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721])), Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742]): (Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981]), Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981])), Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661]): (Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072]), Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072])), Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979]): (Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671]), Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671])), Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361]): (Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269]), Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269])), Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558]): (Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571]), Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571])), Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290]): (Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902]), Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902])), Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987]): (Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741]), Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741])), Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902]): (Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515]), Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515])), Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497]): (Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028]), Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028])), Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948]): (Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709]), Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709])), Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009]): (Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725]), Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725])), Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387]): (Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317]), Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317])), Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159]): (Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808]), Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808])), Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394]): (Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699]), Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699])), Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312]): (Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000]), Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000])), Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987]): (Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821]), Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821])), Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046]): (Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909]), Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909])), Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565]): (Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028]), Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028])), Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269]): (Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352]), Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352])), Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847]): (Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271]), Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271])), Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513]): (Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800]), Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800])), Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054]): (Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394]), Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394])), Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004]): (Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977]), Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977])), Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675]): (Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800]), Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800])), Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692]): (Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159]), Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159])), Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909]): (Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932]), Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932])), Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814]): (Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697]), Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697])), Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186]): (Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387]), Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387])), Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445]): (Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470]), Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470])), Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966]): (Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507]), Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507])), Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548]): (Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253]), Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253])), Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897]): (Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783]), Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783])), Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208]): (Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054]), Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054])), Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268]): (Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661]), Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661])), Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388]): (Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643]), Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643])), Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257]): (Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174]), Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174])), Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960]): (Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241]), Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241])), Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721]): (Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046]), Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046])), Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822]): (Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217]), Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217])), Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253]): (Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697]), Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697])), Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054]): (Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019]), Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019])), Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821]): (Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432]), Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432])), Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864]): (Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105]), Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105])), Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373]): (Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855]), Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855])), Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646]): (Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830]), Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830])), Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460]): (Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208]), Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208])), Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033]): (Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214]), Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214])), Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105]): (Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129]), Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129])), Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281]): (Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909]), Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909])), Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028]): (Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027]), Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027])), Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012]): (Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054]), Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054])), Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562]): (Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589]), Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589])), Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037]): (Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097]), Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097])), Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355]): (Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460]), Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460])), Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223]): (Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355]), Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355])), Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089]): (Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306]), Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306])), Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035]): (Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219]), Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219])), Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432]): (Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297]), Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297])), Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693]): (Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263]), Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263])), Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794]): (Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484]), Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484])), Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552]): (Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941]), Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941])), Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267]): (Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814]), Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814])), Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992]): (Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415]), Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415])), Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941]): (Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966]), Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966])), Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822]): (Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320]), Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320])), Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306]): (Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902]), Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902])), Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820]): (Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880]), Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880])), Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361]): (Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725]), Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725])), Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005]): (Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914]), Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914])), Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783]): (Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781]), Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781])), Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011]): (Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033]), Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033])), Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297]): (Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910]), Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910])), Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070]): (Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134]), Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134])), Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144]): (Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331]), Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331])), Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023]): (Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497]), Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497])), Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103]): (Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540]), Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540])), Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961]): (Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998]), Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998])), Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414]): (Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]), Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]))}, trace_len_summary: TraceLenSummary { main_trace_len: 19, range_trace_len: 47, chiplets_trace_len: ChipletsLengths { hash_chiplet_len: 128, bitwise_chiplet_len: 0, memory_chiplet_len: 2, kernel_rom_len: 0 } } } +ExecutionTrace { main_trace: MainTrace { storage: Parts { core_rm: [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 3987768130567869605, 17866922374020149524, 8514580104850791069, 13475546435959911551, 16952228088962355159, 5793482471479538911, 14446299416172848527, 13522295374716441620, 0, 0, 0, 0, 0, 0, 1, 0, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 401642074298203, 40, 40, 0, 0, 0, 0, 0, 0, 4, 0, 0, 1, 0, 1, 0, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 2, 0, 0, 0, 0, 0, 3, 1, 1, 0, 1, 1, 0, 1, 3137828705454, 1, 0, 0, 0, 0, 0, 0, 1, 3, 0, 0, 0, 0, 1, 0, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 3, 0, 0, 0, 0, 0, 3, 0, 1, 1, 1, 0, 1, 0, 24514286761, 1, 0, 0, 0, 0, 0, 0, 1, 2, 1, 0, 0, 0, 0, 0, 40, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 2, 1, 4, 0, 0, 0, 0, 0, 3, 1, 0, 0, 1, 0, 1, 0, 191517865, 1, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 5, 0, 0, 0, 0, 0, 3, 1, 0, 0, 1, 0, 1, 0, 1496233, 1, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 8451315773087502901, 3716949716844628593, 10394526050930609580, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 6, 0, 0, 0, 0, 0, 3, 1, 0, 0, 1, 0, 1, 0, 11689, 1, 0, 0, 0, 0, 0, 0, 1, 2, 4, 0, 0, 0, 0, 0, 3716949716844628593, 10394526050930609580, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 7, 0, 0, 0, 0, 0, 3, 1, 0, 0, 1, 0, 1, 0, 91, 1, 0, 0, 0, 0, 0, 0, 1, 2, 5, 0, 0, 0, 0, 0, 10394526050930609580, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 8, 0, 0, 0, 0, 0, 3, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 2, 6, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 9, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 7, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 8, 1, 10, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 8, 1, 11, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 1, 1, 1, 3987768130567869605, 17866922374020149524, 8514580104850791069, 13475546435959911551, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 8, 1, 12, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 8, 1, 13, 0, 0, 0, 0, 0, 5, 0, 1, 1, 0, 1, 0, 1, 8, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 14, 0, 0, 0, 0, 0, 7, 0, 0, 0, 1, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 15, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 1, 1, 1, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 16, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 1, 1, 1, 16952228088962355159, 5793482471479538911, 14446299416172848527, 13522295374716441620, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 17, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 31, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 33, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 39, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 43, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 47, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 50, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 51, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 53, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 54, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 55, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 59, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 60, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 61, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 67, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 69, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 70, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 71, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 72, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 73, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 74, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 75, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 76, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 77, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 78, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 79, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 81, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 82, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 83, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 86, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 87, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 88, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 89, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 90, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 91, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 92, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 93, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 94, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 97, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 98, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 99, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 101, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 102, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 103, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 104, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 105, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 106, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 107, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 108, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 109, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 110, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 111, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 112, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 113, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 114, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 115, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 116, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 117, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 118, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 119, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 120, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 121, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 122, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 123, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 124, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 125, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 126, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 127, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0], chiplets_rm: [1, 1, 0, 0, 3987768130567869605, 17866922374020149524, 8514580104850791069, 13475546435959911551, 16952228088962355159, 5793482471479538911, 14446299416172848527, 13522295374716441620, 0, 87, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 8242146665224381578, 15911532375448333238, 1386357366995233596, 8611444126933110985, 4676083100930238397, 6139688846062542757, 9002714910392091903, 5823797362462191159, 0, 0, 1, 0, 0, 1, 1, 0, 0, 401642074298203, 40, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 3987768130567869605, 17866922374020149524, 8514580104850791069, 13475546435959911551, 7789855707707231369, 4610326148461237922, 1784941811671601269, 9924745492516640019, 7791549396364371277, 2968443994649453078, 1308562153347600605, 4332337354844628651, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 88, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 16952228088962355159, 5793482471479538911, 14446299416172848527, 13522295374716441620, 5915784406748100112, 6722847756588924736, 14012694245464324059, 2066991057620171669, 7739875740167294943, 7018932903636824263, 3536373181423802149, 16715512295218120604, 0, 0, 1, 0, 0, 1, 1, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 1244837894821529086, 14023738310468542470, 9319458442815716445, 5220020845190256514, 18381067342435073896, 15418184987737128626, 17753079332212842976, 12382717352847060954, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 88, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1744857570235497404, 7224541920618385714, 6671488038711247732, 9418477143622752895, 9703867417214980336, 12489503772578086800, 7630918900393673526, 922936908940985560, 13119444482451573268, 8102518886279384149, 1794056580842530013, 6019859370758513415, 1, 0, 0, 0, 1, 0, 0, 0, 0, 11225476840467288604, 1258325688295597329, 127125292503096007, 14464605090260677523, 1356149198325814678, 16210500530871871700, 7703315482792482057, 9670557752572652209, 14715521009568351134, 5622479790818646070, 1994313401293831292, 12198921534065454764, 1, 0, 0, 0, 1, 0, 0, 0, 0, 6475944301769848126, 2915217068128247285, 10539364050497833639, 1329434144584264601, 4724829826743698824, 11656831663640211358, 18159325948688903721, 2263120035450455133, 3044551438691886778, 1378219755367734085, 27066760951347720, 7594002804590750508, 1, 0, 0, 0, 1, 0, 7094992666845579929, 10682949197627750021, 15511495322322885910, 15870512746805692064, 4742278351791462207, 7505045441162082383, 9115585980456141894, 11819132067426344142, 5933534952755427427, 5289666558408553872, 13337066958757631081, 6199794689781794653, 5527421833010022906, 4651988931660818160, 2987054724042595780, 1, 0, 0, 0, 1, 0, 3458358424286082329, 7093523218540709637, 10672998680593063500, 9582569954668317010, 13201115384751580570, 1845418544539288297, 9232442292023153805, 12186827811356238706, 10935576324406113028, 8489922013276339729, 12624430369688872770, 17630820426326624548, 2455558777867773614, 8013720398498280010, 12827655532307024322, 1, 0, 0, 0, 1, 0, 5785580083697586953, 5496776863607614961, 13562358148399326759, 9619728790481291702, 7348374190345066861, 13428391720342760502, 1625987251039265071, 4628549345299080849, 1482769832760029881, 15392110855022396191, 11685531496513883979, 16631929378585709364, 1206841992098443123, 9033969076040507441, 132716663048694064, 1, 0, 0, 0, 1, 0, 4935270318350649204, 11208979634658466526, 15063992759093620930, 69377025486693860, 2005546075822572073, 6505215078608999447, 5174094099800739640, 13001606491845435526, 1072287532585676149, 8674354724303146421, 2891558581869634704, 12003109342828923560, 2795184266895760838, 8907697550851381515, 7407535969740942827, 1, 0, 0, 0, 1, 0, 12928689569348120744, 18117769253874083942, 6430757471563325625, 11001198331791943845, 5782583463951144663, 3192834997426419970, 13479879407860298287, 12933861238108488467, 16278293297035470863, 6876436357683812502, 1917626248124261877, 7470768955678552355, 11361229958543541222, 7877487828305683469, 12846364871258595728, 1, 0, 0, 0, 1, 0, 3208246304442396143, 602388884213530987, 15428433977489879680, 13971985988839335428, 2737452825195583328, 15596845393022603175, 10706929119701705862, 4857505199118487438, 17086155371834155818, 14942339901122070806, 18093611989159833406, 8678554698795861566, 2399201986323959674, 14423713805583819215, 13940821782800746629, 1, 0, 0, 0, 1, 0, 5752176924989565290, 4446226812085120357, 4892387022627626332, 12766647202711608745, 16601117776639897488, 11733197324703429636, 12249169652316186841, 15421392054100411011, 10950661145505749420, 8676915018037525034, 2287206221212892475, 840670749677123625, 14199538947967054445, 11736020252788430378, 8602113489330523197, 1, 0, 0, 0, 1, 0, 16339610044914982284, 0, 0, 17640015747325898849, 16347444792678324740, 8885896841027368623, 10718432816977168969, 5156908241230918449, 17013559050399408119, 14174891037708262638, 1568239283519947871, 11922342832652198664, 17716568425187950727, 14294596817162139623, 8762912941700788919, 1, 0, 0, 0, 1, 0, 0, 0, 0, 10691440065277113539, 11571864114015088873, 14769641188290399688, 15214258832131517513, 16096616261062028405, 17526009277172454447, 7932842201848681903, 7306503137329194055, 13369935276997096320, 15066831218638174923, 9520626635373991696, 13296433431293103463, 1, 0, 0, 0, 1, 0, 0, 0, 0, 15457748872647003252, 12161715639235802937, 14007251173141324536, 1685517899923633866, 5112172969895687532, 5291999820044553537, 8437113893887445899, 3726439603382583733, 8404976155487828619, 7450257481186581855, 18356039864791793168, 15198056038162548435, 1, 0, 0, 0, 1, 0, 0, 0, 0, 12039411220003022329, 844322165626728828, 6152440980082407113, 11008191087326916441, 15301657567101812620, 7647514108863503629, 11736853678981601451, 13408456878721317654, 137431712022909617, 9004259806363632349, 994790402583656889, 3215329497276289397, 1, 0, 0, 0, 1, 0, 0, 0, 0, 16952228088962355159, 5793482471479538911, 14446299416172848527, 13522295374716441620, 5915784406748100112, 6722847756588924736, 14012694245464324059, 2066991057620171669, 7739875740167294943, 7018932903636824263, 3536373181423802149, 16715512295218120604, 1, 0, 0, 0, 1, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1532070872953744281, 11675978725956395507, 8258108365434236190, 8977540451988253054, 8832291907404336605, 16801197610032323372, 8498902414702613411, 2217861947967210820, 14648106445605106304, 5194857384255130698, 4543357020291533691, 1677011855369223059, 1, 0, 0, 0, 1, 0, 0, 0, 0, 18164368745351378969, 665130184182531292, 14548211377038648988, 9026463808500414994, 12372059324693434695, 8512906579977137276, 10951940384741553765, 2990681100436043903, 15463650459774420968, 6115025020360005524, 13619612156045325099, 9915559200666512746, 1, 0, 0, 0, 1, 0, 0, 0, 0, 73542357038484620, 16275608702285065538, 15615370514429573107, 11554047591217380375, 9626234372118459069, 14043139718664795091, 7172345985251039651, 13714446996516992992, 14079807935308074442, 17175342044195045043, 16936021968982853164, 3883665509408281322, 1, 0, 0, 0, 1, 0, 8133824218287649370, 1205363866316521559, 7923953289074004648, 1611370566290075655, 12516876786630134052, 16156412840636435500, 16066365782016562356, 12209717470970729826, 648151295134950813, 8424608506935970051, 941071657155810425, 12476535243066524999, 13046835168670418046, 13563090428318398174, 10213204276953300366, 1, 0, 0, 0, 1, 0, 11656233811569695541, 16780366708706866018, 10469348806910132738, 12317597613336433996, 16800450568443907772, 7958196127911254005, 5580405360121542127, 17991322909541306091, 9587008055009063413, 917862094456531518, 17636182943787095305, 5347924966817937746, 15791860137463552476, 5352122275530338033, 8207615265206228485, 1, 0, 0, 0, 1, 0, 13280747180546192023, 13818056542207317059, 12768869371961439487, 2029833730308772760, 3067168931363951888, 630426464913806566, 13807710542081112496, 10340529818978391824, 8301137772228612306, 18032943025979156234, 5571856761516233924, 15102755171792177729, 1386022355796901548, 10780164990569095481, 14005839963275167003, 1, 0, 0, 0, 1, 0, 8161514060541966002, 5430054846479849757, 855673369941768792, 8583346124368767357, 7152703336258374657, 4793816855328822248, 1475819744300266017, 5162097063446717296, 9158417383194264473, 17323069022182310843, 17309666448184518221, 16540233824244985004, 13271685073550397851, 3683818685539825395, 12883632168742702763, 1, 0, 0, 0, 1, 0, 14889661894667616899, 13319328534492736282, 511216470843933116, 5414088302741599345, 16030190225904238830, 6111859869108706126, 4321093113239299552, 4706826096768711507, 11021679444547674749, 15678561454143187205, 15168765916033556420, 7046395423559884948, 3431032212531228618, 9443306432483343000, 6291224588853575811, 1, 0, 0, 0, 1, 0, 11384512740043719026, 17996531901144166752, 4183594834611630116, 17695445402585642319, 15258305803668890228, 17106752205417894410, 13259786553689259064, 15859967842550332610, 5138368225191856866, 8345451659183769670, 4299979085769618674, 10058172520180004407, 16132576493934338934, 312707111584502977, 8025187035739711204, 1, 0, 0, 0, 1, 0, 17152042124522816142, 9826569971726481595, 8959076337043698126, 1987260706895490300, 17423289859865292784, 12258188545233319580, 4291864820252135891, 2950910453815263271, 852440029525711434, 1223549137263517018, 605327998629874385, 3009980753663636725, 8722464778364467857, 17216818427461180092, 13380853612843880678, 1, 0, 0, 0, 1, 0, 7979264206910945674, 0, 0, 7448791324579059841, 1050285053399784347, 16767087000176263535, 14849165193424062452, 2498996933077132011, 13658177069616805094, 495936213960522537, 13576872019913404781, 7640966386182958606, 4271515987309482058, 13463445006653778819, 12292225704634605892, 1, 0, 0, 0, 1, 0, 0, 0, 0, 6053040396430810733, 2172892474788961636, 18161859984545851402, 13488248907260320483, 8430623432188198915, 3055646124754645267, 4245215712607391946, 2243958878529225177, 14990440908620774864, 3080921390696878855, 595284666932255390, 6192940699035995377, 1, 0, 0, 0, 1, 0, 0, 0, 0, 14921496778760644502, 16662036864627516510, 6434377642684009725, 1840544361770929313, 15074823591915634941, 5258982948465254673, 2683768063818053258, 238295676214993337, 17552036469726894364, 15877921873938893194, 14734786106453693759, 1371624439541100057, 1, 0, 0, 0, 1, 0, 0, 0, 0, 516742705862090749, 5947805230277704319, 5952541516123965670, 9026915957393505056, 5986317686192419732, 75717367401824328, 8923961895635206791, 17106810061565988432, 7157463081631406163, 150940732863733992, 15657864298531798718, 12227344478922314236, 1, 0, 0, 0, 1, 0, 0, 0, 0, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 1244837894821529086, 14023738310468542470, 9319458442815716445, 5220020845190256514, 18381067342435073896, 15418184987737128626, 17753079332212842976, 12382717352847060954, 1, 0, 0, 0, 1, 0, 0, 0, 0, 401642074298203, 40, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 5792301967904643716, 14513996957604530562, 6300577652167374432, 1030532363437082530, 9868636994953646365, 13312054463817713847, 1163060834237983926, 17159751124589539180, 15748271025379903662, 15673345155938926996, 15542740004802895548, 4070736982096634948, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1453121677659348577, 17403066345171442603, 9526966027631081464, 4562917345183859100, 16736668858502190206, 12710250320191836356, 9043028743666878997, 9570842800862454404, 10889819954451461225, 1374882310944969176, 11041329929342678296, 6376909268692149801, 1, 0, 0, 0, 1, 0, 0, 0, 0, 6798464049283172704, 10094602609597426273, 5441108908322692152, 13319823174770042865, 3687504758717747002, 11828007000931365406, 15642196062511550808, 4387538442135057894, 12016453509822632603, 16688879161845796765, 15353663875595798268, 9433687029957117661, 1, 0, 0, 0, 1, 0, 11436455846193695609, 17419948132223780613, 10707930966158261719, 7805136509413905123, 10748223278202845625, 5102455166015213038, 16060345288112427467, 9937020917196030767, 13713675713530315700, 11873887283723171030, 6245447289360608210, 2758175399376775060, 6794131889413756751, 6954584401067417189, 5092580402017360453, 1, 0, 0, 0, 1, 0, 138168370802146349, 561179642041056504, 13282391328952434407, 3586306435690112870, 17278658194357811156, 2504635638454636683, 7235500145280211409, 11191458759516692993, 6465450803792948194, 2111071922636782066, 11802465958807233213, 9116942394473193925, 11145482942031811955, 14726020691764699927, 16903672043479974450, 1, 0, 0, 0, 1, 0, 263960295682680947, 15697220842527476860, 17868088579823291326, 2175933588395873247, 8749749468735109989, 11010166446741390499, 17943104442301856895, 15821423767384514021, 16018668147064525478, 5560768172433028490, 5619212355349254932, 17391285462458271036, 2603291588626814071, 5238953246197227863, 5602891381109897586, 1, 0, 0, 0, 1, 0, 12301036190174877474, 12651281118484863330, 11983275442902746825, 9125195986387370903, 2181062690427536463, 13921861517061570826, 350891571660248295, 11013048057925712708, 11055047889476803308, 15398332646604634982, 5808711407549689243, 8949777591082911961, 14824627964979845981, 8130365156760288485, 3947069696768920416, 1, 0, 0, 0, 1, 0, 753507401801380169, 11557202300537182401, 12635550211207024884, 13277984171307670821, 2631795936834054713, 14094327291919754106, 12673624581190519723, 4509450209340246689, 10606486226190872261, 889124163739951988, 12547380261461657128, 16829937485708676196, 15832095999334895743, 5377353767201125639, 11053610747785598805, 1, 0, 0, 0, 1, 0, 17726880391953768878, 13956049620380258223, 11273932727072475337, 6855896085734577371, 1129400045567810133, 16519057148475618054, 10699416941054230316, 17256608828803451668, 6887723245936746466, 552364255868028623, 17909079490987407142, 9570595819850351164, 8654686163127378448, 16203109760043627710, 8480295614280342552, 1, 0, 0, 0, 1, 0, 5047048529377126902, 2720906371958061367, 10084181298533567509, 10367672116357405411, 11036446985399396097, 13294567520571596163, 17521531050433436007, 1868701710513242496, 5411603901210245247, 11609599138736895146, 16874855234706410918, 4393409689646403917, 9543195090298605247, 7478523150127634789, 2693101708644875762, 1, 0, 0, 0, 1, 0, 3528724572660247995, 0, 0, 12432722351030045, 1367308201666984940, 3681473655802754494, 15340518851882934883, 12978887161137913348, 15761699408266065961, 3053535844413236872, 13043307337058007179, 1605626291192886407, 3512088686484392896, 17370072541480613908, 15945489250832697271, 1, 0, 0, 0, 1, 0, 0, 0, 0, 18236855931369748683, 5145738009993425605, 9599849581440088949, 7181962801200058100, 7842895042061868932, 12656177266019986902, 8530248384503061153, 7088178758240165913, 8843525768370306419, 9760798177389960884, 15297557810674980998, 17513790474795511142, 1, 0, 0, 0, 1, 0, 0, 0, 0, 11582029127760482436, 12210748157899031357, 9473509448225646970, 17514007687115301207, 15252116786733410669, 10068681917011840638, 5010610666981558682, 14100290159714849481, 10038370148733513877, 4164887708143705047, 12759194225663538416, 5155504400103783318, 1, 0, 0, 0, 1, 0, 0, 0, 0, 2256431941220947766, 13487119117857302457, 10370113277604876234, 1506538453550143326, 9611088164777633619, 9944172425891749050, 2585766031776029836, 7469792865149057403, 3748706915022560085, 480217827283441208, 7902514309755880799, 16608422580379539141, 1, 0, 0, 0, 1, 0, 0, 0, 0, 3987768130567869605, 17866922374020149524, 8514580104850791069, 13475546435959911551, 7789855707707231369, 4610326148461237922, 1784941811671601269, 9924745492516640019, 7791549396364371277, 2968443994649453078, 1308562153347600605, 4332337354844628651, 1, 0, 0, 0, 1, 0, 0, 0, 0, 3987768130567869605, 17866922374020149524, 8514580104850791069, 13475546435959911551, 16952228088962355159, 5793482471479538911, 14446299416172848527, 13522295374716441620, 0, 87, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 15982823105988775806, 8055676711367425373, 17941169771108522281, 17144527358953736194, 14947610898944891577, 971614072768782170, 6527463406041159829, 3832659229659994697, 4267689650839244805, 7476341399175005462, 13956706726156239325, 1362637335972540923, 1, 0, 0, 0, 1, 0, 0, 0, 0, 5870626296958083933, 15831852620745746684, 3185498590211330291, 4142206734944835575, 1703654304778633946, 16779850255772273060, 17529309452142070777, 3820424470916782417, 13044986967311981583, 16932680220731892573, 15512851049245904995, 4407692356467248372, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1222210540818995679, 9596558254971998891, 17836151103719299929, 972583351096828487, 16036135922289885914, 9046461447407029762, 13420377050848926972, 8268741668021650938, 15162095256779392528, 6250951389520005938, 4880080490180073887, 5079644903468213758, 1, 0, 0, 0, 1, 0, 4277112440869277830, 16975894093684028062, 17916235475615809558, 14524910789332636826, 11691364468631390887, 7787341040263241822, 9379002423052238093, 9978142397546997785, 13711991341735230802, 2995007776024477424, 4712167935694753945, 1064069264700679460, 16784239691558161828, 13171136420515290288, 7377465172358292401, 1, 0, 0, 0, 1, 0, 7863758113629837220, 34545184916281199, 3993169000277716254, 7364322756301525079, 10650631026443210837, 1517619643121483559, 17270732420407911054, 4258304245011181242, 5161000027742486976, 8399067086847534736, 11003984578732833046, 15464732564240072836, 6182941569324809186, 11275803822943060218, 158655113981893701, 1, 0, 0, 0, 1, 0, 2476402089664475908, 9916425135419809036, 3028465534706354547, 15472564680003668093, 6373098182685681762, 12520752577019080054, 5394462987259780313, 4831149567958541538, 12904631563004530976, 13837253351754641870, 3923208428450719385, 3554976680697606440, 17043251418254499417, 5302393607875037297, 8096532195498204177, 1, 0, 0, 0, 1, 0, 5401472078486138644, 17911378919292638386, 1604440114467418180, 4779855905656105676, 6025526479746347251, 4449154494231990099, 11830346459740212406, 2743894608322163398, 10184996808268436049, 3882545820330029085, 5202687146936953923, 777280530525071979, 9570037184747372126, 10484193697881848161, 11860662735451501625, 1, 0, 0, 0, 1, 0, 15748781809771449617, 12223876502815956005, 8462728310504683652, 13057156105981161589, 11957472249295015469, 11549246553227545561, 15033014935301073849, 423385249083279348, 10856312299574527186, 2052856619870651334, 10305616267836960765, 14352183358244000568, 1261949652056609866, 916956049912161855, 3353438403242689585, 1, 0, 0, 0, 1, 0, 11740120563940364368, 1391869256781506493, 11057309605482706459, 17704317629486807708, 6564342187673520486, 2792692044523533343, 12797232677587390356, 14797653849693720774, 9082763018815888798, 17062564998145646419, 17163741437026102402, 14920816938307553514, 18409839409942969565, 16099949995219613642, 9387728217249208068, 1, 0, 0, 0, 1, 0, 3254516890705807916, 7365800426850749937, 15974018227958845798, 8444961928162939943, 8050679843713964343, 1245616094758475931, 2976182234519674621, 11861324009571007650, 18000519861091284933, 10809856712858383834, 6898855362441294480, 13146633521971264482, 11152948692891359460, 10343969929561703022, 10591999464601502689, 1, 0, 0, 0, 1, 0, 13540695320312597078, 0, 0, 933984176226341473, 4938354828005165424, 3057022637731780053, 18149554045659845084, 9709632327217036413, 16645387828565996715, 10873951879782645518, 214597493824524577, 7950640568527571392, 15274457345887794634, 9280090582838465603, 1242243096703449887, 1, 0, 0, 0, 1, 0, 0, 0, 0, 5626861946644684679, 9519120652743404725, 3153363644848796249, 16387713581663902851, 10655954775576173219, 16168525333832765040, 7013656376478213608, 7333415223195735541, 9069684467099779645, 10706178255503280152, 17753787514920247819, 16088561184006536263, 1, 0, 0, 0, 1, 0, 0, 0, 0, 10636061157542345097, 15008846988127407811, 16614085001509596773, 12600455057253767871, 13458552295186750925, 10343839881402182751, 1108696518251840495, 9621971582260379329, 11613485699478956673, 16861381831518076617, 17933004011918959112, 18255208815154765383, 1, 0, 0, 0, 1, 0, 0, 0, 0, 10509741793670097910, 12960656197959013774, 9112727654277900213, 14176014235755683408, 9647930301481695061, 10818726819316593067, 11744599510375600263, 2780827620762362248, 60352997716668050, 2064777537623220055, 12394773470270210064, 15490398721638241462, 1, 0, 0, 0, 1, 0, 0, 0, 0, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 8242146665224381578, 15911532375448333238, 1386357366995233596, 8611444126933110985, 4676083100930238397, 6139688846062542757, 9002714910392091903, 5823797362462191159, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 40, 0, 0, 3, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 1, 0, 1, 1, 10, 0, 0, 0, 1, 0, 1, 1, 0, 40, 0, 0, 12, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 9, 0, 4099276459869907627, 1, 10, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], range_checker_cols: [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 1, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 7, 8, 9, 10, 2197, 4384, 6571, 8758, 10945, 13132, 15319, 17506, 19693, 21880, 24067, 26254, 28441, 30628, 32815, 35002, 37189, 39376, 41563, 43750, 45937, 48124, 50311, 52498, 54685, 56872, 59059, 61246, 63433, 64162, 64891, 65134, 65377, 65458, 65485, 65512, 65521, 65530, 65533, 65534, 65535, 65535]], num_rows: 128 }, last_program_row: RowIndex(18) }, program_info: ProgramInfo { program_hash: Word([14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674]), kernel: Kernel([]) }, stack_outputs: StackOutputs { elements: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, precompile_requests: [], final_precompile_transcript: PrecompileTranscript { state: Word([0, 0, 0, 0]) }, trace_len_summary: TraceLenSummary { main_trace_len: 19, range_trace_len: 49, chiplets_trace_len: ChipletsLengths { hash_chiplet_len: 80, bitwise_chiplet_len: 0, memory_chiplet_len: 2, ace_chiplet_len: 0, kernel_rom_len: 0 } } } diff --git a/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_23.snap b/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_23.snap index f743d6b60a..6ebd0c19ac 100644 --- a/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_23.snap +++ b/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_23.snap @@ -2,4 +2,4 @@ source: processor/src/trace/parallel/tests.rs expression: DeterministicTrace(&trace_from_fragments) --- -ExecutionTrace { main_trace: MainTrace { columns: ColMatrix { columns: [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 1, 65, 97, 97, 65, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [5482243896119908732, 401642074298203, 3137828705454, 24514286761, 191517865, 1496233, 11689, 91, 0, 0, 0, 5482243896119908732, 3358534066525179769, 8, 0, 3358534066525179769, 13210061556570014836, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525], [17271741639510569126, 40, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17271741639510569126, 9365253138981608257, 0, 65, 9365253138981608257, 16003296542960478536, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728], [10627125303494028926, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10627125303494028926, 4243893038989355703, 0, 0, 4243893038989355703, 6732564319544917702, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410], [12334791106787903660, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12334791106787903660, 2372900269115514267, 0, 0, 2372900269115514267, 16687523027086140644, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683], [13210061556570014836, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [16003296542960478536, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [6732564319544917702, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [16687523027086140644, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 4, 3, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [3358534066525179769, 3358534066525179769, 3358534066525179769, 40, 3358534066525179769, 9365253138981608257, 4243893038989355703, 2372900269115514267, 0, 40, 40, 40, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [9365253138981608257, 9365253138981608257, 9365253138981608257, 3358534066525179769, 9365253138981608257, 4243893038989355703, 2372900269115514267, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [4243893038989355703, 4243893038989355703, 4243893038989355703, 9365253138981608257, 4243893038989355703, 2372900269115514267, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [2372900269115514267, 2372900269115514267, 2372900269115514267, 4243893038989355703, 2372900269115514267, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 2372900269115514267, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [16, 16, 16, 17, 16, 16, 16, 16, 16, 17, 17, 17, 17, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16], [0, 0, 0, 2, 0, 0, 0, 0, 0, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 7, 8, 9, 2196, 4383, 6570, 8757, 10944, 13131, 15318, 17505, 19692, 21879, 24066, 26253, 28440, 30627, 32814, 35001, 37188, 39375, 41562, 43749, 45936, 48123, 50310, 52497, 54684, 56871, 59058, 61245, 63432, 64161, 64890, 65133, 65376, 65457, 65484, 65511, 65520, 65529, 65532, 65535, 65535], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [5482243896119908732, 18015781855758016478, 4383606322674378669, 11282929110176162954, 17215248529293365853, 13193227772306657556, 11735240166769603875, 3717289286029653294, 5492874275384737590, 12486768927296380145, 7992161010257837902, 5965860733558915216, 13973209423992708161, 5139670008027876415, 6906630570311142812, 808538110186084468, 2187643142553675840, 11028121748345672612, 18181286167455191614, 15014367804365107227, 10866688391213961683, 16520440189869744108, 5493823407617825232, 501346961392724628, 18105097706170191265, 13534558354914049543, 3820689183586493894, 16784019981734849061, 2862138511955678409, 7758258992155315690, 17115115516972321026, 9874694795284567525, 401642074298203, 4016420742982670, 14280802901810915241, 7925919485060883878, 9094034340168608638, 6650811367268781560, 13344927435882217244, 15870694671012449597, 13091389828882674218, 168434371192049215, 13973668876111195937, 680445747454648704, 15441309962929722976, 15749770188837954531, 5233297770622824375, 3367253731665130938, 5066484463076591248, 9867160564810673994, 16707816004584596036, 6832899290197418961, 10263347723858682786, 6209209797490182000, 8678413656546712232, 9643915442530902318, 17208626611000903707, 11389822518212260982, 887493237489321299, 48736118273260452, 13483864438078018308, 8159241411748295729, 10385528691577928985, 5482243896119908732, 0, 616, 13342492399873323769, 1439796670523758837, 2591609871503882494, 5919456033500076693, 5232333079875635931, 12079101376381790329, 5687909194194711965, 13514584364960626778, 10501272396704173758, 7941686916236651549, 11501430483965911830, 10227424397178507773, 10471520652203868473, 14226149352545573719, 5877312072455938554, 4586059525590481046, 1601223390241498740, 2723805050156540964, 14314758709191331837, 15918659712373688555, 3030433806959200828, 16403500445172050158, 4533755278593082652, 10807446599885826609, 6981555831806437627, 13412972662619459764, 13711912288503888270, 7425430573821419685, 16752277069679715408, 13210061556570014836, 8, 80, 16253482711025978099, 16690839578921925157, 11755424915479552417, 17934377671577204140, 15509754874715907467, 6426721221030580337, 11049594146888643723, 14912334368661229147, 17657273147290084056, 9105126057127804171, 13430225876739607206, 3614830725909060912, 14569284676797348998, 4705513459362295944, 424917224365117418, 2835737623710330612, 1964100172858915134, 14896843043547784767, 15482419984058848245, 18437547705335910066, 3162257106529980441, 5297995970636059087, 9661978795293871188, 10128143329575104151, 770728251595531533, 9782965673735423214, 1347942901513492691, 12086966446141742548, 10239457018222882008, 3358534066525179769, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [17271741639510569126, 8154194758959345943, 13264028927506398677, 5896249534368220847, 11382862066285680273, 5436084715181539253, 3806787319072410229, 6511238228694043548, 9049442861863566881, 3576764171564075210, 450124369605914003, 3732227441816681926, 14029816209330408163, 8200782329890006994, 10416842793286403595, 6907512650407721813, 5351083897603196824, 9182929970775715030, 16141859999570517823, 9888871621811661249, 4078956937078417294, 5937931242192299623, 3211370055999743360, 12301747922262729865, 11292399879083020280, 5346237718208015471, 8535816953133153286, 9097410120098142273, 2554244438665697829, 6695383891040002341, 9265251570417433175, 11914585017133270728, 40, 3213136594386184, 1835177830541154044, 826263100281998566, 9612296353153372169, 2509054224639990472, 11363599377854067153, 5593295816013818122, 4611398810491526224, 17064807786960234347, 18427889571151062396, 10159688738464070440, 14427917509182297997, 6874689601963577621, 745298233749984501, 4960831845018172313, 1451394763904737446, 17942681985602265676, 17508193444101172646, 1672370857206926433, 10152063658776528390, 14576660961872281746, 13602838247655372264, 5274902253855511588, 3163862752932557920, 7292072545764012550, 6033538369482377655, 10941848106600998110, 3570589185097006252, 4587292818271677447, 16771298688176486904, 17271741639510569126, 0, 528, 4511615971967153504, 11189511375577512439, 14523290705070057408, 11602649596278030541, 15937333004537029302, 7414360896531864023, 7973996941547777109, 691576170553327010, 16392526795103433215, 3672880019205947738, 3018308815206440911, 15753827566219281917, 12969815742735761919, 16814873348334179176, 9850453545266944859, 10757916804785969985, 15838808218411872755, 4464803664915013475, 1326425913004665964, 12560438841096766551, 448453576971543277, 8998725782446855275, 14421875759181138198, 3100710952877190431, 3320646806195653797, 11565789183953445370, 502156843765695809, 13147348360138928114, 11903841834984596874, 16003296542960478536, 0, 64, 5751576643258238090, 7830268710878889486, 4868320831660690795, 7042762868047858013, 1028615964620729689, 12270587957620579653, 7267371538363991280, 16125626865182516658, 16950134439933558852, 13427183447069512151, 16117382505273595827, 2222792985740553749, 6517696895688418945, 15516128650333221731, 6357034143715229949, 12960707821770488929, 12451444460344609421, 8786747128188560390, 7634329044629047826, 7741107824034642016, 10975559322169081956, 6007758954686348362, 13971256108093330407, 16868860295450858142, 434120282701603474, 11571634562637977474, 5581285869985960561, 6581368197537384623, 17661012293298952642, 9365253138981608257, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [10627125303494028926, 14952889910786498171, 4766776471757604196, 12230245468863423579, 18104224094677170296, 15873409126341319274, 10073785188538358192, 9346697284679931865, 9007898958502691821, 18310381669862731969, 6720634958674998611, 4972858056675247397, 3284008361973965746, 14482858214234206831, 15154449156086880838, 5792220624700559072, 12843525862417693577, 642245012387336876, 14582627702688057517, 2964899186980974939, 8169860993617536308, 10855885493426519851, 1871971423867885122, 7909458165142256993, 3879457158905131550, 11439385698067115077, 12781603895645888322, 12658641528827989062, 9129723360543316479, 2424787611628537668, 16343713044075599831, 14619522228640933410, 40, 803284148597046, 10010111294767420802, 16943179644353820008, 8996122336997085030, 17350347680949584060, 13520911097528541892, 14769691589967587136, 81685142906752346, 7559897225353479520, 128512095027132822, 9792116363139842106, 4634576985104787587, 8679380235287294885, 1134592111928495305, 4684288247441474792, 15613043314698948257, 4841731940180862534, 5786518576333159075, 12666070374819933283, 2487841274273895537, 5690982477694717281, 5924572671969496500, 8629130978595053833, 18206699227813987098, 14234831161984809711, 16798226782780142546, 9330568307929665420, 9731250716956559616, 12286920896461242142, 1919835269886444210, 10627125303494028926, 0, 264, 9085863547783897978, 4029278259426396811, 16053154709446024998, 15730095788089532534, 1184856151594203190, 7658158244024203478, 7908104163460391198, 11768448888839053133, 15952542848401697239, 2236539493336923746, 12654027314481387133, 183479441840898968, 12829755263022627333, 14927722658095997307, 8579481663516436508, 2326984138263422166, 12584151503586926798, 5547037854005909933, 18320766430359725566, 16436941964924985549, 2398490839703252269, 15603212774947060210, 2697950444757558845, 7336230381913860230, 2577750295211676178, 16469775866150825791, 360850050916534143, 7183698983616787617, 9070535322622906244, 6732564319544917702, 0, 16, 7110029021941723513, 10115409991715085575, 11428668827299215140, 4015039023438705588, 3732466887400149035, 5870841944205588609, 8421627027326523148, 8231214549142439222, 10318470559229280016, 15171283498151438808, 12477430934852872037, 3853779543897991795, 14662750186533371679, 7423988381383082226, 13549468426633458145, 11079168775731474830, 12471207782095033761, 17595325414333663547, 7042468264080735391, 17650115337646869205, 14946074228061446423, 4655654314239637986, 11187552516160183253, 18115881480442018545, 899748567092010447, 14020868337400209874, 15417366235984526759, 3331301994171189600, 15814677761660135474, 4243893038989355703, 40, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [12334791106787903660, 10536106724359599792, 14660905060901389201, 17357985657180629743, 10490790376815116141, 8856174280738574418, 17564486157138470037, 2383050989032417578, 9423711593310475409, 4142017075081989212, 6217567350304044823, 15435624740876731287, 3215908606625999288, 11222238183310766613, 17187582840477322187, 11654551786904653634, 6201498867875513095, 9940061963065628902, 1432819846316931691, 5068010018173215582, 13903556343063122489, 8872060411343823556, 17720392065240548352, 17643816943101201258, 1449530809054027683, 17965277233811019017, 4895491920411997249, 10751559368097521724, 16513197729164811328, 4815287357290896051, 3003012580421078075, 6636010883309744683, 0, 803284148596806, 2549897079792572603, 5670682422759337153, 4249626004536644548, 9138873913574622404, 1343119293110958009, 15707367360995172765, 2149720931386886989, 12579497520806083785, 14990373923527496282, 7330871518527332444, 5790961380321049961, 5495469617420264118, 10789212522972025785, 4356961356341052500, 8032044444015716361, 5554647570062987979, 1022644107902166331, 6764324513849573852, 14002884382934858252, 14316154512513580139, 8331374540726760892, 13067519389098510351, 8671032013540344722, 13457978878695920483, 16399505509770566014, 10578307416004071064, 11950037765875050974, 12195903600484928258, 17694444981837938563, 12334791106787903660, 0, 88, 13728083094831419091, 5555139373262852832, 2905384006316447019, 12155959663009124293, 13187847930197094867, 15053688477158705110, 5239197399579256268, 18372875045424962848, 6782570937531856778, 5670979983981263850, 10968120781620208764, 2099848306821515114, 7984319522957739004, 14143871504578433969, 14093328990578646811, 5769086287272836702, 13010501651213663576, 16984828703781093727, 13803823311240773956, 17471084929704555662, 5508754216278517899, 14994098977964244257, 8220163139135834751, 17625713553185819225, 15041604777168753281, 17976701769209321205, 10958079103202840999, 17793074612839242130, 3601655880141993647, 16687523027086140644, 0, 16, 3208043314804619251, 6920597847411412414, 17985619796195836408, 11907191178709112742, 16377455862733420451, 15572876043608056600, 9466912758182965715, 17480763791598773801, 15029113851915312964, 1953587265841775225, 7175742902791404624, 6820764940134875350, 16069841829669607101, 15548451706938320654, 11760680638795846495, 1560700914733041660, 762367990279432470, 2603436428456411224, 6200990949184863170, 11673627333152839295, 7804486006334068097, 1006207264024395366, 11193609705356653459, 5704515878100803393, 14918729158665343812, 10658508130485449873, 380737719356524599, 12870561906904032245, 6984680585936259437, 2372900269115514267, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [13210061556570014836, 1599157050859759633, 12446750015896088802, 10353774239160274935, 11424271721157330669, 15057005486179715954, 8861044108273791962, 12243038632327996294, 6387235594535598756, 10620968503766467282, 10090957857949391364, 610949617653761740, 2641692952954235941, 16682338453560518377, 1667764180674112574, 3944406972826047531, 7937338373741897463, 677543792580138430, 16064632909904135712, 18144484844415291494, 7226453148331774623, 1179808805540104806, 2700524299164928450, 739842910379542056, 18551850792840682, 16856435263285305760, 6893839572721182305, 14666214556500183752, 10619536471246139015, 4063396021928247911, 1116280449848444285, 11377866377890790275, 0, 2008210371491335, 16850544756775285522, 652387120995254672, 4188956971131276775, 18389965100329173053, 852421464532798418, 17258729097516267384, 11347427093515448316, 13908538323250058716, 6558337355650114042, 4089976927111145333, 17816809041231283545, 12843997071522346840, 1655996231185402724, 11256141768734986569, 3019459069615110433, 16778373777892540383, 10175251160015024193, 11396702708789693017, 16481019216530994753, 5122353003150766192, 17913616556333538828, 6485826671956173957, 15738756542654855641, 12199621872357116369, 12077164016468113545, 8907315944885273345, 4878983963291132913, 1618531819557712390, 565132887411573955, 7288090792972058500, 0, 616, 4968648927826019469, 17195207199910519646, 6734621562241387182, 9715952180361858627, 2034771934048449998, 13730246563790151743, 15224252119305799711, 16575323315490024998, 9453153207794904511, 8194394828646838882, 1235308382947710635, 134218781076142871, 12444330148186854115, 16838588367568106248, 3274404606032631663, 8680261223649739505, 13512134067010568333, 15074317169196019601, 3919235389861209780, 14979187502739607198, 1116932806094012842, 12657319342943489784, 998626228777839492, 2347840117369842691, 15743276195226846510, 9881270424621082635, 2778123425092199841, 2613774562373586415, 1448060333031158668, 6190635258012880107, 0, 40, 18130890293586930078, 18252951749527557342, 4460903658820341507, 859505755654562117, 5961685480015386121, 12134776249586726543, 11174658189737631113, 18385152961050631924, 9881471501704199804, 9636744945302995714, 12323181865658998064, 14903454669611502952, 1490539036394497080, 11688514875590095153, 16093513520259190726, 7731471377060742735, 5247500963110975116, 5269361527156951110, 13733877647296302634, 11865469401112846356, 7643242142337524006, 15572658687280648106, 9345628789826937825, 3291248301730279223, 16808111015808513609, 16274730253017522022, 12243901590027926887, 6559275936659510680, 17224785255700525855, 1390310476158884261, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [16003296542960478536, 13466221688393768258, 12927954860087459534, 3759003303159369746, 1148549753827007441, 7129001791528740265, 5281592040827142238, 16203079979032760691, 7039074043166063940, 9054598259215599503, 2018397558465392243, 16413792935045431209, 12604373665766922919, 1493466405559625913, 11868526707386259660, 3043746450373199613, 8246328563832581273, 5887036391937389613, 2796053561793572028, 7645118395649289364, 12303475117195379639, 207358776078213315, 9218579057118601952, 14479451218433079532, 2031744097966400086, 2566041186493151514, 17259376159632543425, 10376116775360567681, 11289943669462175698, 10804772324353478999, 17288383771256214060, 9885671831159451104, 0, 1606568297193092, 1076973899277284702, 14086579741019377519, 3818478693739735842, 5593621083784091164, 11728670858811596587, 12625736484548160126, 968047239546776409, 15493380284459454506, 15542100289574010625, 15053368214221814937, 17388070103506970075, 4738318434573394804, 15389814481683087606, 14763812299525073807, 384493414835098150, 7660052382355122994, 7691788916209089905, 14721544157906502013, 737940994724202658, 3221762534387838371, 7517398897305596666, 13211005290810103003, 12141388589516060378, 13672030567886044471, 12296311093518063031, 6143526203440544581, 5554567664494429423, 12302163852964786956, 14310991091785572129, 7008881577152522467, 0, 528, 12828040835569540857, 15946070950510533025, 6868712626693654693, 16719465941571322506, 15929304398043808838, 7333330621525318559, 8574904634803746916, 11585949634519199591, 14215120915846294561, 15431555872184246136, 556415272972402332, 13729762303106745810, 1895854814022398925, 16120810718921859928, 14563556215553868244, 9584551737159741567, 1050656582218051719, 2849157683178260515, 4987801895818641338, 3252006976820452311, 4232022539410523688, 12145542090324719848, 13475056960068950678, 4212050629407893798, 18068871666013902057, 4214295938146797537, 13664544216029702565, 1391392205806749871, 3418909895274525076, 4840757955412667387, 0, 32, 10452764368937945515, 6969997263492352670, 15570786589164252178, 16136993048454358354, 16378352067056606124, 11747573379431147483, 12296464969648251345, 8155132212936940581, 2470200969414032680, 18126939303114916528, 16736276280592238734, 15549342782445497049, 9033882039108268313, 5121596298161079296, 14336897502470956191, 6301009824137139871, 16614860627935231068, 10383378433371415142, 10330363517752279308, 10937466001850040595, 16305844076412050396, 7189713532379018536, 7568236447715590536, 10805187342082326609, 7424874700566577356, 13861219118264849665, 7052270251739242825, 17586339544079318164, 14071176523136369481, 12282546735285148319, 3, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [6732564319544917702, 11424946734513850952, 14751589151467562513, 3091073535594807983, 17274728363719186424, 6785780051417756764, 15374515033027594653, 12476673273305390844, 11491856728648046938, 889587581187765015, 1832729573374625479, 11964718430105317483, 10284914521902415429, 4989117988224154817, 7310308994414837120, 4896165117485439507, 781193619199190152, 4972018469228063343, 11237024791849123316, 8136517227202567877, 12980119595156137175, 5277784125198234251, 8730957263237386090, 6627357084936364627, 9579937749716133270, 13182791294901350976, 7788172704304532836, 1814160375547940386, 7818804555865981505, 11573391963135759227, 18390005084876364234, 49905639292627904, 0, 401642074298523, 16072847024087248681, 1047399340937520223, 13840617071834531990, 13835424809772757395, 12438858367585478828, 14080077230806112448, 11208516754282785707, 7691155727086178136, 17898846423848868766, 13990233438164144322, 14765296463244153634, 10144768301469359068, 16658833476738371029, 4674204014270448977, 12722211832796318871, 492549161703070590, 13986658207276323375, 14512155514173182920, 13983563295828088546, 2440687363152463730, 15931932209781173412, 11078906302351818677, 3584926465549602493, 6813538466449503008, 2334817027508375898, 12619526317209583817, 6515674137823977144, 393947096345211186, 1951192747307666741, 7526556702499462773, 0, 264, 14858685484860085108, 16638144790071955925, 14803289513390493682, 7947368985060100292, 8540021318758160201, 1005829865088874654, 2182109332887118586, 2709878912677862734, 8639678844062658411, 1087022739668739893, 10504771173378443613, 10062807734250201377, 7979854057356878352, 5264886220300798691, 17178601938487182393, 14209807647112141969, 364963036030481104, 6977342036970944167, 9475211165936098151, 2067156367555811068, 13444810812224497486, 17338503932931685384, 18075892757378330321, 5992364927925930356, 280994234174845985, 4192504288997153355, 10293012497513243194, 12632074680840502609, 12384471116364520725, 14304772746964984975, 0, 8, 9114363797835460134, 5446076396314160376, 12863008906537145423, 10008421878335836436, 9952321233871043669, 12872379155893703237, 7266552182027361169, 1266036355585216796, 2621902104176569009, 8791105532651972211, 6351975813451610601, 11821139808280113179, 11281913023757770338, 3277134497757048289, 13219080767636598429, 10181825490691565485, 2766637533497216499, 5527857141123489970, 8463471033597650592, 16863468430858262436, 4521466714741486225, 2112404415880305855, 6776665887355979100, 4283028800297139078, 17448147405455891940, 2672696094870261596, 654959311657763753, 15404879372302137522, 458610335793450516, 11708893791522292939, 3358534066525179769, 3358534066525179769, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [16687523027086140644, 9086882804838007993, 18208410790236506017, 3398985649909830369, 11870335859895317550, 1782594595734670280, 7950908231675299553, 11699755763721080867, 5559192297727634984, 15856483324254330201, 3827177513892222045, 8697421447132597636, 6525137006607571383, 9739016092723027913, 37096681180297292, 5998909423699657245, 1737478325904747641, 9603988472267868801, 14612309354257526062, 963817021754931361, 2954837086209820968, 11485058781500311480, 10011022503247302490, 6596157637386353039, 2185026052398200396, 8667196121129603577, 17444739644589522901, 17384087895468261804, 4673396992430997118, 5652365973964779246, 14148401294484512817, 594790136239256278, 0, 401642074298403, 6959791354043610236, 1843180796447728437, 9556362158826632350, 3220022195391792741, 6012411438022691140, 4309223969498591447, 7596903557041777533, 18393682838284953355, 3973832102121938954, 12190997158276486897, 15972235844585587264, 14899488070931524727, 17337514399056563302, 10500237188498665928, 18440452962210035879, 7481614450647261413, 65300580117832193, 14713590013611289205, 13086268929321267306, 17247769089209001713, 11421561962034654967, 4561010052951998759, 9562817622798343284, 3062054327467638127, 6016566887476098647, 5513989129644936969, 13097123292793361360, 17631302057213141907, 8382824402074565601, 16136160484984138575, 0, 88, 11332670461359993442, 14431967032738938661, 10393518078208184991, 2462224494429193628, 2381519205788696693, 5156397633515475273, 13071332837477200404, 6583788956280193302, 8309261923972302555, 7204946769828595498, 10143223184962015615, 2291749916011172217, 12651590612371699683, 1757329184049619756, 8575055855333374088, 10782010546727900871, 11693001677843026089, 13372591108841832182, 6745878472543166577, 17326074735792689056, 17178266551378060244, 9012900451066906030, 9513119903156534723, 14316793092410720577, 15850020848376370982, 5093266838540794296, 2953143545478827927, 9172592184988170325, 3259030218090439002, 13670896049781213124, 0, 8, 6104172690014223231, 3119855977255645286, 2700229040680838768, 4228220371303630837, 12976691418076017877, 15391527008624099592, 15522155400452634037, 17655908650961725957, 5157987610310047621, 13664486701019622043, 12908699189677656287, 14840926611057477527, 6092037682822283700, 15181448373122947619, 2083722204849270202, 1893419523737526751, 11329911669537538562, 12331432886354737271, 9636585409664050258, 5131588463040403759, 10248116973079783912, 2136665268102207704, 17448444978654544666, 11945433761064128885, 4462464721020457233, 17579935132869425842, 7098417589530391109, 15343623253038912080, 7762335122892638892, 10310226363807226654, 9365253138981608257, 9365253138981608257, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 6538312968872592849, 8060897427763484267, 15694315280551902473, 15462035367190511759, 16783127636073026773, 10756964923802715923, 4768450986425500783, 586150029444692874, 14745636460228146879, 5204776334183399126, 7685703760533694936, 16111592919872596132, 6944599323919802145, 1254987403839644538, 9402574875622777470, 16210856058698621820, 6207690803740787708, 5909774410804808527, 11610503998702777421, 686805010274260483, 8419527378140004636, 6342702858222909287, 8706567413279745902, 8451985615096117101, 8796637399824800240, 15979424445015031332, 13704751155696621736, 18261872069356847559, 7568935938034555881, 3939988349760901151, 3558778201956820739, 0, 2008210371491335, 13098960849839742034, 9449621519891201049, 2814310786559014444, 5305842545683321494, 4969236906288915907, 1243780951433164967, 6167749875842285147, 9490220981060631819, 3665259354621890034, 7437125179920904126, 12655958476488865400, 17935537000594940941, 91614862745339577, 1869550524566103495, 17384150297165671545, 1154605885284628266, 8665046436862728398, 6741156569294553317, 9490927005547387767, 8947900188307771735, 13752550215202657538, 7714188412126691626, 12225947487197390724, 13509943592829854189, 7120740401378484294, 6789669275155346195, 2929601484581949152, 1077164174037184778, 7253613682453412944, 12957959164911169922, 0, 1232, 6031863247325663438, 674016650738724202, 9655491867310024790, 4753798685424869288, 10749041705000945043, 14520855376130294244, 1540176383869885892, 10236894625417199268, 9196614711423540610, 7978597004657283049, 6086008265617713639, 14043785705271347590, 10693788391520380705, 12309293813476849789, 12287432898048046644, 12476380710530844150, 2814554338965902349, 12370730861881949935, 13055692992345669402, 801564953257569940, 10614676804436196472, 7985393687855976209, 16788264280259941604, 4042445936043537075, 17844212763579117389, 14723420347046552696, 2456530167870834703, 7343890316269580191, 6483315548845037473, 9440211366785524370, 0, 40, 1560947813056021755, 6935064976442414148, 9999441144135002932, 10354700837586583171, 6040781227937012106, 4698117391978117444, 4735711626023545756, 11217844833019453026, 3130590714605394722, 2809204122464618686, 10935232469327759448, 18335893537613898174, 10868401885487323501, 15799177281014635734, 17187052562019754838, 4027411046406207040, 11879721967266924677, 3613659344771632047, 1846469577394958972, 14668357323201408029, 14939045883642543835, 2885718226990976376, 4969257074069595075, 10824274197210729467, 13212275138420405274, 10563919532671437398, 12234598862193668129, 14653607410806008848, 2498958194485300229, 3512215170452429648, 4243893038989355703, 4243893038989355703, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [87, 7206805482451038763, 10391043349415287037, 17044036436784806527, 13171139175044072684, 2094744771380247596, 13239410091625892436, 168039991714389118, 9272483157421678641, 9491323991579079848, 16844742792488708348, 9520544349855559315, 792788122696624862, 16163267682416611248, 7281147841738764349, 9382208451579624348, 15681622260194273891, 1390751769269680465, 8196141638178857464, 15172831853577650839, 12922697597526240324, 7829823799088278618, 1783927422614660621, 4975249353684987436, 13048186608776014077, 3034445649013398243, 6966167031354634355, 7794510095811729812, 8010670397007670803, 871847630272290682, 18441078654886601219, 1106728433230065324, 0, 1606568297193092, 17457628753812655267, 5096693283465186518, 12947605480618213072, 13490514080936595140, 16186587491946121120, 10245245868334896235, 6026705707665599719, 9827345407768028181, 2812471843237874845, 12940670116574659651, 2714930976118111710, 11931084046533097040, 5957825878304116293, 4815270995456833861, 3281433232253188744, 1527514044633931889, 3155608937877823823, 496495357063373704, 12643114535206930756, 2926290280590787897, 4481685646324082958, 2913086696180341350, 4929647997916999987, 9053067786296036128, 12860916533743270733, 13426707234447106813, 15934882759672330788, 2173747106952139997, 5260381980138555939, 9238536158694879401, 88, 1056, 10194964851803169917, 2476887483552371976, 9610004573075108621, 4964236593939309395, 10117579878001530331, 8588168632019162203, 7961669463441676499, 8688363314921128388, 7669238601546834041, 15117861700401653408, 7267798175629900560, 18420331634788000621, 2168204218347522931, 13774182815867438503, 11793649490935032382, 264326996749206681, 422815844549413164, 11144132125283193307, 16600930886850462534, 14741236577529096830, 7550071867985447349, 10163945784944658272, 8810849992229527370, 979169410947035438, 18181508983255172512, 10501853123801116024, 10292737970295456228, 632012914013142222, 9098012027422757538, 7698805642109006453, 0, 32, 9302012295643728416, 424328237663665361, 17748121622218558811, 6681769685034042719, 10907932526941371789, 14996603190997478665, 13982878080104642188, 3336783822228111865, 7403528606603453519, 7309352233404946366, 11509327586943808925, 6803943428138467537, 12870260590513220077, 3798257798625653324, 15652192157997003684, 8260391000410661595, 9099897743400681933, 16067207775248165408, 7640841583197908852, 16739199083410292994, 1998275509994500625, 10688417071827877337, 16160081185811655577, 2725954513011781037, 3040692668058239811, 15097072321276989567, 7813293313258815644, 15261763399945716285, 2258772319189190202, 6756061023037720295, 2372900269115514267, 2372900269115514267, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 2643697525295255282, 7848268271641614303, 1670964981039714496, 12506995107569119516, 16020980424362300069, 3910461774754452973, 14887150284650111993, 11430895388638705560, 15925982986489674986, 559122298435457095, 16369319727902045750, 5911900249842037740, 9993545485068101534, 16804807948024450931, 6109216944498588777, 6962786378900996817, 14779846517676698965, 14597810963258762343, 16333362039819991192, 2239891938742671995, 8902636803530046125, 12348911713752556021, 9576130314342554279, 9464686824958661262, 14724291818312841818, 5956660324772534609, 5179789141411429720, 14891365206755013222, 833106187556617464, 14690990432528119604, 7399742180187746173, 0, 401642074298523, 10076989882539553734, 13617634258944637452, 11664888937794835322, 6832371865971954132, 7435465380685145582, 8856983143236954540, 15647394574465449881, 5004639611979401749, 16333513927375132208, 11586223746088007538, 17258599442845821467, 10089347514894229223, 8927362828162004403, 1274761678102044944, 13987176689734561031, 968318691601385838, 17920302096119022338, 18172419653743826470, 5238866342343116613, 4715585282245523496, 6782917713521523376, 845034972551066538, 8264516316211712068, 4395820162956710988, 17367170950581948054, 11715439359473390301, 4924405821869545305, 1674381281184830519, 4077397353846458666, 16570851802495678006, 0, 528, 3020492374890726247, 15867024276402164724, 2691485309401819348, 10383311521670833729, 16323720466012865692, 12111425008963394821, 6863497050423701439, 4068736078963485223, 6871052579055075230, 11135759119963236724, 8026699645344521142, 4857505768584918289, 10792639723427933554, 15144263097518946995, 2672819086738268108, 9175748808845810742, 8523928999979138359, 5837654600063955860, 4020408003683484830, 6777545915715419993, 16222025381660955186, 14681340973312169871, 11211579677305883898, 8623233971250462580, 418056849863168392, 2919384330136358405, 2666974936005298869, 14966813495153624489, 13584072213050301608, 17057575786157171701, 0, 8, 7519454690376123692, 7627104070861575574, 17604686071836489236, 14277148259130460564, 8312218486680706135, 8395439642754559152, 17307771294890409643, 9298206908486537717, 3027629924013931359, 2933551330348935458, 1450485994192951386, 8585052201707081835, 10624425952582111111, 16773523322999621677, 13337622149287916761, 17874287708894504070, 14164897610403484003, 11216401648549709020, 911970190394256131, 3202853507803349037, 14616902435260689479, 14924823153427050614, 4881022900440414264, 9723366934152472594, 16335725686098559697, 8087897843744270993, 11437013713086863200, 7627258546495067733, 18044191572661655945, 16490279521751489469, 1, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 392081819927674604, 13621084556403650323, 17078772340992927473, 862170971660204027, 5676881743340217488, 5517012370953012053, 3863387227510711423, 6521284656283570782, 17282496836457066698, 8668839984066399279, 10481218501610762636, 13268880552322298648, 9575112247205521418, 14191613402325013881, 17855143966403217682, 8464300128340058390, 4400313738036540825, 14739186344673284697, 1501891124109012983, 9798699259742823392, 8843421723884165135, 7746605484191389759, 8323169935435436763, 15323881858459172368, 8509325593168557185, 14233099751914870044, 12164983556041574509, 17356025534910089368, 2031310896521954322, 16067965450256037769, 8147499972447601337, 0, 401642074298403, 9851586117636382793, 7414079509745519565, 10414894202973226643, 11403399710197601656, 10230759118395809329, 4887466173119518776, 12376579030877442488, 15222686873173021915, 11343634646223977946, 15054143113295762432, 8578483304162845495, 8187399805941604842, 17460975957431844228, 12368453570037757143, 4715095521846408852, 10685847052710927197, 5160934306801665605, 12877482432527277885, 1026289052488784895, 12183816968946827507, 954239020314042893, 1899038343674936222, 3582199871763692750, 10141562795735590523, 5883730844910027408, 10313342961711791200, 10308552102917724507, 1101239144209002141, 16732112788727027442, 6132059608254040410, 0, 176, 14015299246960655077, 18240053740881435667, 9264051620447261114, 3770835013589498382, 14269426645353023865, 1064418857115644823, 9055361938666247589, 1923541152082479674, 7329032621716426413, 14147095007921770778, 12290092320014837503, 14167154425694482177, 2008826339817234435, 12727493810822145141, 13765995246049388004, 5723824967382588797, 11506863252089006870, 13547802874613831044, 2099106023167119258, 6345494554579617353, 13921991112058773762, 5885105447661412229, 8709961227558437878, 9751610933111772233, 13912537796384226859, 5691895930177454540, 2936046437280927758, 7163672760378086559, 12965649133168865250, 17131584050600476194, 0, 8, 17781582622500481192, 12847902632736061277, 12021499907877242591, 16751519355106661703, 9062087890172095618, 3834953580385337540, 2969703856153678454, 11604562295556139307, 10447912046373566534, 12987934619706800857, 12352596220492768030, 14816150974992525275, 2172600571554701126, 18086375044546604023, 16313093185369681775, 14997664071320688070, 347950016295486690, 9206182676441692601, 3566552483989599402, 4925983231752336365, 1728701557101400581, 7087476601458867917, 9759961360999781392, 12569092891286895547, 14206292953735333262, 16422952955631166803, 6294107725304445883, 9537940691512987143, 15535806100011306333, 7080716573279759555, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4099276459869907627, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] }, last_program_row: RowIndex(18) }, program_info: ProgramInfo { program_hash: Word([9874694795284567525, 11914585017133270728, 14619522228640933410, 6636010883309744683]), kernel: Kernel([]) }, stack_outputs: StackOutputs { elements: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, merkle_store_nodes: {Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571]): (Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350]), Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350])), Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484]): (Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693]), Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693])), Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781]): (Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874]), Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874])), Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171]): (Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361]), Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361])), Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815]): (Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305]), Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305])), Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689]): (Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195]), Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195])), Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362]): (Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063]), Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063])), Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848]): (Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661]), Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661])), Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352]): (Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829]), Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829])), Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444]): (Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223]), Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223])), Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386]): (Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388]), Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388])), Word([13190842942618341421, 17548956981569849952, 15418963848144418856, 730733050713174879]): (Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144]), Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144])), Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874]): (Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675]), Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675])), Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594]): (Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115]), Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115])), Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809]): (Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257]), Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257])), Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777]): (Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555]), Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555])), Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509]): (Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882]), Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882])), Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725]): (Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979]), Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979])), Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134]): (Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987]), Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987])), Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828]): (Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910]), Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910])), Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830]): (Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054]), Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054])), Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228]): (Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742]), Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742])), Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443]): (Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928]), Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928])), Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643]): (Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979]), Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979])), Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758]): (Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106]), Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106])), Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580]): (Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594]), Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594])), Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765]): (Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045]), Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045])), Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766]): (Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281]), Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281])), Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385]): (Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828]), Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828])), Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579]): (Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171]), Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171])), Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212]): (Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992]), Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992])), Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463]): (Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004]), Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004])), Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502]): (Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023]), Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023])), Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539]): (Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537]), Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537])), Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865]): (Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225]), Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225])), Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690]): (Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947]), Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947])), Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202]): (Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552]), Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552])), Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079]): (Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444]), Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444])), Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850]): (Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548]), Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548])), Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448]): (Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987]), Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987])), Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041]): (Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035]), Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035])), Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301]): (Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414]), Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414])), Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414]): (Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212]), Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212])), Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703]): (Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439]), Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439])), Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271]): (Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955]), Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955])), Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882]): (Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802]), Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802])), Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152]): (Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887]), Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887])), Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028]): (Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948]), Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948])), Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331]): (Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093]), Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093])), Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394]): (Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134]), Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134])), Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546]): (Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228]), Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228])), Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620]): (Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414]), Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414])), Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800]): (Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703]), Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703])), Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671]): (Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205]), Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205])), Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537]): (Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011]), Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011])), Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516]): (Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301]), Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301])), Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831]): (Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986]), Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986])), Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415]): (Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057]), Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057])), Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722]): (Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689]), Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689])), Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144]): (Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682]), Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682])), Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295]): (Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268]), Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268])), Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818]): (Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513]), Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513])), Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241]): (Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565]), Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565])), Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439]): (Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012]), Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012])), Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512]): (Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850]), Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850])), Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986]): (Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865]), Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865])), Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982]): (Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777]), Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777])), Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808]): (Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394]), Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394])), Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979]): (Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690]), Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690])), Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093]): (Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620]), Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620])), Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902]): (Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789]), Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789])), Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542]): (Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094]), Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094])), Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057]): (Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362]), Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362])), Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205]): (Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961]), Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961])), Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401]): (Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580]), Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580])), Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553]): (Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960]), Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960])), Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169]): (Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031]), Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031])), Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682]): (Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053]), Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053])), Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118]): (Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562]), Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562])), Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725]): (Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666]), Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666])), Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661]): (Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897]), Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897])), Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981]): (Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447]), Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447])), Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072]): (Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646]), Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646])), Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140]): (Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404]), Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404])), Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515]): (Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152]), Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152])), Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709]): (Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664]), Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664])), Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800]): (Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103]), Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103])), Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741]): (Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169]), Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169])), Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005]): (Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758]), Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758])), Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802]): (Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070]), Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070])), Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159]): (Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005]), Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005])), Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350]): (Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443]), Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443])), Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697]): (Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573]), Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573])), Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928]): (Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331]), Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331])), Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320]): (Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166]), Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166])), Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814]): (Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079]), Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079])), Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447]): (Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820]), Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820])), Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284]): (Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057]), Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057])), Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697]): (Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131]), Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131])), Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955]): (Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290]), Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290])), Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910]): (Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202]), Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202])), Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910]): (Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822]), Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822])), Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106]): (Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847]), Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847])), Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404]): (Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441]), Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441])), Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796]): (Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186]), Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186])), Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053]): (Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516]), Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516])), Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992]): (Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818]), Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818])), Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957]): (Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315]), Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315])), Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709]): (Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794]), Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794])), Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091]): (Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539]), Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539])), Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664]): (Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558]), Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558])), Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294]): (Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579]), Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579])), Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947]): (Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502]), Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502])), Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829]): (Word([0, 0, 0, 0]), Word([0, 0, 0, 0])), Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045]): (Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137]), Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137])), Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914]): (Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041]), Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041])), Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573]): (Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378]), Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378])), Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699]): (Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873]), Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873])), Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225]): (Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262]), Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262])), Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057]): (Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692]), Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692])), Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131]): (Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997]), Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997])), Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555]): (Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385]), Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385])), Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195]): (Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709]), Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709])), Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166]): (Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542]), Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542])), Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027]): (Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373]), Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373])), Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378]): (Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509]), Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509])), Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097]): (Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553]), Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553])), Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217]): (Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815]), Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815])), Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873]): (Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864]), Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864])), Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997]): (Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722]), Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722])), Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887]): (Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766]), Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766])), Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589]): (Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757]), Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757])), Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539]): (Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665]), Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665])), Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129]): (Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229]), Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229])), Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137]): (Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312]), Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312])), Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019]): (Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378]), Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378])), Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331]): (Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713]), Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713])), Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]): (Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980]), Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980])), Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325]): (Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546]), Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546])), Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170]): (Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822]), Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822])), Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054]): (Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295]), Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295])), Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925]): (Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848]), Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848])), Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909]): (Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796]), Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796])), Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540]): (Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170]), Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170])), Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214]): (Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448]), Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448])), Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317]): (Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294]), Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294])), Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757]): (Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416]), Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416])), Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378]): (Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091]), Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091])), Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263]): (Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463]), Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463])), Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666]): (Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361]), Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361])), Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174]): (Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992]), Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992])), Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470]): (Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401]), Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401])), Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665]): (Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957]), Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957])), Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262]): (Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144]), Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144])), Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229]): (Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284]), Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284])), Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134]): (Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325]), Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325])), Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855]): (Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765]), Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765])), Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115]): (Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814]), Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814])), Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441]): (Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831]), Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831])), Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977]): (Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446]), Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446])), Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880]): (Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005]), Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005])), Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789]): (Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995]), Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995])), Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000]): (Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267]), Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267])), Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998]): (Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982]), Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982])), Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995]): (Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539]), Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539])), Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507]): (Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512]), Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512])), Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305]): (Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118]), Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118])), Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219]): (Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009]), Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009])), Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416]): (Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089]), Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089])), Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980]): (Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445]), Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445])), Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063]): (Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140]), Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140])), Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713]): (Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159]), Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159])), Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031]): (Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809]), Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809])), Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932]): (Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037]), Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037])), Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094]): (Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925]), Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925])), Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315]): (Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386]), Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386])), Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446]): (Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721]), Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721])), Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742]): (Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981]), Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981])), Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661]): (Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072]), Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072])), Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979]): (Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671]), Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671])), Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361]): (Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269]), Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269])), Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558]): (Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571]), Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571])), Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290]): (Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902]), Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902])), Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987]): (Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741]), Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741])), Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902]): (Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515]), Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515])), Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497]): (Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028]), Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028])), Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948]): (Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709]), Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709])), Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009]): (Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725]), Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725])), Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387]): (Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317]), Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317])), Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159]): (Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808]), Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808])), Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394]): (Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699]), Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699])), Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312]): (Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000]), Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000])), Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987]): (Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821]), Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821])), Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046]): (Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909]), Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909])), Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565]): (Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028]), Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028])), Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269]): (Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352]), Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352])), Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847]): (Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271]), Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271])), Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513]): (Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800]), Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800])), Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054]): (Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394]), Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394])), Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004]): (Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977]), Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977])), Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675]): (Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800]), Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800])), Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692]): (Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159]), Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159])), Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909]): (Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932]), Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932])), Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814]): (Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697]), Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697])), Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186]): (Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387]), Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387])), Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445]): (Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470]), Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470])), Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966]): (Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507]), Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507])), Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548]): (Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253]), Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253])), Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897]): (Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783]), Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783])), Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208]): (Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054]), Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054])), Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268]): (Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661]), Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661])), Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388]): (Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643]), Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643])), Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257]): (Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174]), Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174])), Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960]): (Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241]), Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241])), Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721]): (Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046]), Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046])), Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822]): (Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217]), Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217])), Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253]): (Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697]), Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697])), Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054]): (Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019]), Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019])), Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821]): (Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432]), Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432])), Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864]): (Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105]), Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105])), Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373]): (Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855]), Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855])), Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646]): (Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830]), Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830])), Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460]): (Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208]), Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208])), Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033]): (Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214]), Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214])), Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105]): (Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129]), Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129])), Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281]): (Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909]), Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909])), Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028]): (Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027]), Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027])), Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012]): (Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054]), Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054])), Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562]): (Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589]), Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589])), Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037]): (Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097]), Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097])), Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355]): (Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460]), Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460])), Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223]): (Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355]), Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355])), Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089]): (Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306]), Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306])), Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035]): (Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219]), Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219])), Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432]): (Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297]), Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297])), Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693]): (Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263]), Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263])), Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794]): (Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484]), Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484])), Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552]): (Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941]), Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941])), Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267]): (Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814]), Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814])), Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992]): (Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415]), Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415])), Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941]): (Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966]), Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966])), Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822]): (Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320]), Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320])), Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306]): (Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902]), Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902])), Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820]): (Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880]), Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880])), Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361]): (Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725]), Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725])), Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005]): (Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914]), Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914])), Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783]): (Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781]), Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781])), Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011]): (Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033]), Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033])), Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297]): (Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910]), Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910])), Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070]): (Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134]), Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134])), Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144]): (Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331]), Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331])), Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023]): (Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497]), Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497])), Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103]): (Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540]), Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540])), Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961]): (Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998]), Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998])), Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414]): (Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]), Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]))}, trace_len_summary: TraceLenSummary { main_trace_len: 19, range_trace_len: 47, chiplets_trace_len: ChipletsLengths { hash_chiplet_len: 128, bitwise_chiplet_len: 0, memory_chiplet_len: 2, kernel_rom_len: 0 } } } +ExecutionTrace { main_trace: MainTrace { storage: Parts { core_rm: [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 3987768130567869605, 17866922374020149524, 8514580104850791069, 13475546435959911551, 16952228088962355159, 5793482471479538911, 14446299416172848527, 13522295374716441620, 0, 0, 0, 0, 0, 0, 1, 0, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 401642074298203, 40, 40, 0, 0, 0, 0, 0, 0, 4, 0, 0, 1, 0, 1, 0, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 2, 0, 0, 0, 0, 0, 3, 1, 1, 0, 1, 1, 0, 1, 3137828705454, 1, 0, 0, 0, 0, 0, 0, 1, 3, 0, 0, 0, 0, 1, 0, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 3, 0, 0, 0, 0, 0, 3, 0, 1, 1, 1, 0, 1, 0, 24514286761, 1, 0, 0, 0, 0, 0, 0, 1, 2, 1, 0, 0, 0, 0, 0, 40, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 2, 1, 4, 0, 0, 0, 0, 0, 3, 1, 0, 0, 1, 0, 1, 0, 191517865, 1, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 5, 0, 0, 0, 0, 0, 3, 1, 0, 0, 1, 0, 1, 0, 1496233, 1, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 8451315773087502901, 3716949716844628593, 10394526050930609580, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 6, 0, 0, 0, 0, 0, 3, 1, 0, 0, 1, 0, 1, 0, 11689, 1, 0, 0, 0, 0, 0, 0, 1, 2, 4, 0, 0, 0, 0, 0, 3716949716844628593, 10394526050930609580, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 7, 0, 0, 0, 0, 0, 3, 1, 0, 0, 1, 0, 1, 0, 91, 1, 0, 0, 0, 0, 0, 0, 1, 2, 5, 0, 0, 0, 0, 0, 10394526050930609580, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 8, 0, 0, 0, 0, 0, 3, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 2, 6, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 9, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 7, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 8, 1, 10, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 8, 1, 11, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 1, 1, 1, 3987768130567869605, 17866922374020149524, 8514580104850791069, 13475546435959911551, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 8, 1, 12, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 8, 1, 13, 0, 0, 0, 0, 0, 5, 0, 1, 1, 0, 1, 0, 1, 8, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 14, 0, 0, 0, 0, 0, 7, 0, 0, 0, 1, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 15, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 1, 1, 1, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 16, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 1, 1, 1, 16952228088962355159, 5793482471479538911, 14446299416172848527, 13522295374716441620, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 17, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 31, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 33, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 39, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 43, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 47, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 50, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 51, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 53, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 54, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 55, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 59, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 60, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 61, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 67, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 69, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 70, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 71, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 72, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 73, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 74, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 75, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 76, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 77, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 78, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 79, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 81, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 82, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 83, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 86, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 87, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 88, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 89, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 90, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 91, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 92, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 93, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 94, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 97, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 98, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 99, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 101, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 102, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 103, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 104, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 105, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 106, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 107, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 108, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 109, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 110, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 111, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 112, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 113, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 114, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 115, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 116, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 117, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 118, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 119, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 120, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 121, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 122, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 123, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 124, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 125, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 126, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 127, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0], chiplets_rm: [1, 1, 0, 0, 3987768130567869605, 17866922374020149524, 8514580104850791069, 13475546435959911551, 16952228088962355159, 5793482471479538911, 14446299416172848527, 13522295374716441620, 0, 87, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 8242146665224381578, 15911532375448333238, 1386357366995233596, 8611444126933110985, 4676083100930238397, 6139688846062542757, 9002714910392091903, 5823797362462191159, 0, 0, 1, 0, 0, 1, 1, 0, 0, 401642074298203, 40, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 3987768130567869605, 17866922374020149524, 8514580104850791069, 13475546435959911551, 7789855707707231369, 4610326148461237922, 1784941811671601269, 9924745492516640019, 7791549396364371277, 2968443994649453078, 1308562153347600605, 4332337354844628651, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 88, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 16952228088962355159, 5793482471479538911, 14446299416172848527, 13522295374716441620, 5915784406748100112, 6722847756588924736, 14012694245464324059, 2066991057620171669, 7739875740167294943, 7018932903636824263, 3536373181423802149, 16715512295218120604, 0, 0, 1, 0, 0, 1, 1, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 1244837894821529086, 14023738310468542470, 9319458442815716445, 5220020845190256514, 18381067342435073896, 15418184987737128626, 17753079332212842976, 12382717352847060954, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 88, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1744857570235497404, 7224541920618385714, 6671488038711247732, 9418477143622752895, 9703867417214980336, 12489503772578086800, 7630918900393673526, 922936908940985560, 13119444482451573268, 8102518886279384149, 1794056580842530013, 6019859370758513415, 1, 0, 0, 0, 1, 0, 0, 0, 0, 11225476840467288604, 1258325688295597329, 127125292503096007, 14464605090260677523, 1356149198325814678, 16210500530871871700, 7703315482792482057, 9670557752572652209, 14715521009568351134, 5622479790818646070, 1994313401293831292, 12198921534065454764, 1, 0, 0, 0, 1, 0, 0, 0, 0, 6475944301769848126, 2915217068128247285, 10539364050497833639, 1329434144584264601, 4724829826743698824, 11656831663640211358, 18159325948688903721, 2263120035450455133, 3044551438691886778, 1378219755367734085, 27066760951347720, 7594002804590750508, 1, 0, 0, 0, 1, 0, 7094992666845579929, 10682949197627750021, 15511495322322885910, 15870512746805692064, 4742278351791462207, 7505045441162082383, 9115585980456141894, 11819132067426344142, 5933534952755427427, 5289666558408553872, 13337066958757631081, 6199794689781794653, 5527421833010022906, 4651988931660818160, 2987054724042595780, 1, 0, 0, 0, 1, 0, 3458358424286082329, 7093523218540709637, 10672998680593063500, 9582569954668317010, 13201115384751580570, 1845418544539288297, 9232442292023153805, 12186827811356238706, 10935576324406113028, 8489922013276339729, 12624430369688872770, 17630820426326624548, 2455558777867773614, 8013720398498280010, 12827655532307024322, 1, 0, 0, 0, 1, 0, 5785580083697586953, 5496776863607614961, 13562358148399326759, 9619728790481291702, 7348374190345066861, 13428391720342760502, 1625987251039265071, 4628549345299080849, 1482769832760029881, 15392110855022396191, 11685531496513883979, 16631929378585709364, 1206841992098443123, 9033969076040507441, 132716663048694064, 1, 0, 0, 0, 1, 0, 4935270318350649204, 11208979634658466526, 15063992759093620930, 69377025486693860, 2005546075822572073, 6505215078608999447, 5174094099800739640, 13001606491845435526, 1072287532585676149, 8674354724303146421, 2891558581869634704, 12003109342828923560, 2795184266895760838, 8907697550851381515, 7407535969740942827, 1, 0, 0, 0, 1, 0, 12928689569348120744, 18117769253874083942, 6430757471563325625, 11001198331791943845, 5782583463951144663, 3192834997426419970, 13479879407860298287, 12933861238108488467, 16278293297035470863, 6876436357683812502, 1917626248124261877, 7470768955678552355, 11361229958543541222, 7877487828305683469, 12846364871258595728, 1, 0, 0, 0, 1, 0, 3208246304442396143, 602388884213530987, 15428433977489879680, 13971985988839335428, 2737452825195583328, 15596845393022603175, 10706929119701705862, 4857505199118487438, 17086155371834155818, 14942339901122070806, 18093611989159833406, 8678554698795861566, 2399201986323959674, 14423713805583819215, 13940821782800746629, 1, 0, 0, 0, 1, 0, 5752176924989565290, 4446226812085120357, 4892387022627626332, 12766647202711608745, 16601117776639897488, 11733197324703429636, 12249169652316186841, 15421392054100411011, 10950661145505749420, 8676915018037525034, 2287206221212892475, 840670749677123625, 14199538947967054445, 11736020252788430378, 8602113489330523197, 1, 0, 0, 0, 1, 0, 16339610044914982284, 0, 0, 17640015747325898849, 16347444792678324740, 8885896841027368623, 10718432816977168969, 5156908241230918449, 17013559050399408119, 14174891037708262638, 1568239283519947871, 11922342832652198664, 17716568425187950727, 14294596817162139623, 8762912941700788919, 1, 0, 0, 0, 1, 0, 0, 0, 0, 10691440065277113539, 11571864114015088873, 14769641188290399688, 15214258832131517513, 16096616261062028405, 17526009277172454447, 7932842201848681903, 7306503137329194055, 13369935276997096320, 15066831218638174923, 9520626635373991696, 13296433431293103463, 1, 0, 0, 0, 1, 0, 0, 0, 0, 15457748872647003252, 12161715639235802937, 14007251173141324536, 1685517899923633866, 5112172969895687532, 5291999820044553537, 8437113893887445899, 3726439603382583733, 8404976155487828619, 7450257481186581855, 18356039864791793168, 15198056038162548435, 1, 0, 0, 0, 1, 0, 0, 0, 0, 12039411220003022329, 844322165626728828, 6152440980082407113, 11008191087326916441, 15301657567101812620, 7647514108863503629, 11736853678981601451, 13408456878721317654, 137431712022909617, 9004259806363632349, 994790402583656889, 3215329497276289397, 1, 0, 0, 0, 1, 0, 0, 0, 0, 16952228088962355159, 5793482471479538911, 14446299416172848527, 13522295374716441620, 5915784406748100112, 6722847756588924736, 14012694245464324059, 2066991057620171669, 7739875740167294943, 7018932903636824263, 3536373181423802149, 16715512295218120604, 1, 0, 0, 0, 1, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1532070872953744281, 11675978725956395507, 8258108365434236190, 8977540451988253054, 8832291907404336605, 16801197610032323372, 8498902414702613411, 2217861947967210820, 14648106445605106304, 5194857384255130698, 4543357020291533691, 1677011855369223059, 1, 0, 0, 0, 1, 0, 0, 0, 0, 18164368745351378969, 665130184182531292, 14548211377038648988, 9026463808500414994, 12372059324693434695, 8512906579977137276, 10951940384741553765, 2990681100436043903, 15463650459774420968, 6115025020360005524, 13619612156045325099, 9915559200666512746, 1, 0, 0, 0, 1, 0, 0, 0, 0, 73542357038484620, 16275608702285065538, 15615370514429573107, 11554047591217380375, 9626234372118459069, 14043139718664795091, 7172345985251039651, 13714446996516992992, 14079807935308074442, 17175342044195045043, 16936021968982853164, 3883665509408281322, 1, 0, 0, 0, 1, 0, 8133824218287649370, 1205363866316521559, 7923953289074004648, 1611370566290075655, 12516876786630134052, 16156412840636435500, 16066365782016562356, 12209717470970729826, 648151295134950813, 8424608506935970051, 941071657155810425, 12476535243066524999, 13046835168670418046, 13563090428318398174, 10213204276953300366, 1, 0, 0, 0, 1, 0, 11656233811569695541, 16780366708706866018, 10469348806910132738, 12317597613336433996, 16800450568443907772, 7958196127911254005, 5580405360121542127, 17991322909541306091, 9587008055009063413, 917862094456531518, 17636182943787095305, 5347924966817937746, 15791860137463552476, 5352122275530338033, 8207615265206228485, 1, 0, 0, 0, 1, 0, 13280747180546192023, 13818056542207317059, 12768869371961439487, 2029833730308772760, 3067168931363951888, 630426464913806566, 13807710542081112496, 10340529818978391824, 8301137772228612306, 18032943025979156234, 5571856761516233924, 15102755171792177729, 1386022355796901548, 10780164990569095481, 14005839963275167003, 1, 0, 0, 0, 1, 0, 8161514060541966002, 5430054846479849757, 855673369941768792, 8583346124368767357, 7152703336258374657, 4793816855328822248, 1475819744300266017, 5162097063446717296, 9158417383194264473, 17323069022182310843, 17309666448184518221, 16540233824244985004, 13271685073550397851, 3683818685539825395, 12883632168742702763, 1, 0, 0, 0, 1, 0, 14889661894667616899, 13319328534492736282, 511216470843933116, 5414088302741599345, 16030190225904238830, 6111859869108706126, 4321093113239299552, 4706826096768711507, 11021679444547674749, 15678561454143187205, 15168765916033556420, 7046395423559884948, 3431032212531228618, 9443306432483343000, 6291224588853575811, 1, 0, 0, 0, 1, 0, 11384512740043719026, 17996531901144166752, 4183594834611630116, 17695445402585642319, 15258305803668890228, 17106752205417894410, 13259786553689259064, 15859967842550332610, 5138368225191856866, 8345451659183769670, 4299979085769618674, 10058172520180004407, 16132576493934338934, 312707111584502977, 8025187035739711204, 1, 0, 0, 0, 1, 0, 17152042124522816142, 9826569971726481595, 8959076337043698126, 1987260706895490300, 17423289859865292784, 12258188545233319580, 4291864820252135891, 2950910453815263271, 852440029525711434, 1223549137263517018, 605327998629874385, 3009980753663636725, 8722464778364467857, 17216818427461180092, 13380853612843880678, 1, 0, 0, 0, 1, 0, 7979264206910945674, 0, 0, 7448791324579059841, 1050285053399784347, 16767087000176263535, 14849165193424062452, 2498996933077132011, 13658177069616805094, 495936213960522537, 13576872019913404781, 7640966386182958606, 4271515987309482058, 13463445006653778819, 12292225704634605892, 1, 0, 0, 0, 1, 0, 0, 0, 0, 6053040396430810733, 2172892474788961636, 18161859984545851402, 13488248907260320483, 8430623432188198915, 3055646124754645267, 4245215712607391946, 2243958878529225177, 14990440908620774864, 3080921390696878855, 595284666932255390, 6192940699035995377, 1, 0, 0, 0, 1, 0, 0, 0, 0, 14921496778760644502, 16662036864627516510, 6434377642684009725, 1840544361770929313, 15074823591915634941, 5258982948465254673, 2683768063818053258, 238295676214993337, 17552036469726894364, 15877921873938893194, 14734786106453693759, 1371624439541100057, 1, 0, 0, 0, 1, 0, 0, 0, 0, 516742705862090749, 5947805230277704319, 5952541516123965670, 9026915957393505056, 5986317686192419732, 75717367401824328, 8923961895635206791, 17106810061565988432, 7157463081631406163, 150940732863733992, 15657864298531798718, 12227344478922314236, 1, 0, 0, 0, 1, 0, 0, 0, 0, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 1244837894821529086, 14023738310468542470, 9319458442815716445, 5220020845190256514, 18381067342435073896, 15418184987737128626, 17753079332212842976, 12382717352847060954, 1, 0, 0, 0, 1, 0, 0, 0, 0, 401642074298203, 40, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 5792301967904643716, 14513996957604530562, 6300577652167374432, 1030532363437082530, 9868636994953646365, 13312054463817713847, 1163060834237983926, 17159751124589539180, 15748271025379903662, 15673345155938926996, 15542740004802895548, 4070736982096634948, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1453121677659348577, 17403066345171442603, 9526966027631081464, 4562917345183859100, 16736668858502190206, 12710250320191836356, 9043028743666878997, 9570842800862454404, 10889819954451461225, 1374882310944969176, 11041329929342678296, 6376909268692149801, 1, 0, 0, 0, 1, 0, 0, 0, 0, 6798464049283172704, 10094602609597426273, 5441108908322692152, 13319823174770042865, 3687504758717747002, 11828007000931365406, 15642196062511550808, 4387538442135057894, 12016453509822632603, 16688879161845796765, 15353663875595798268, 9433687029957117661, 1, 0, 0, 0, 1, 0, 11436455846193695609, 17419948132223780613, 10707930966158261719, 7805136509413905123, 10748223278202845625, 5102455166015213038, 16060345288112427467, 9937020917196030767, 13713675713530315700, 11873887283723171030, 6245447289360608210, 2758175399376775060, 6794131889413756751, 6954584401067417189, 5092580402017360453, 1, 0, 0, 0, 1, 0, 138168370802146349, 561179642041056504, 13282391328952434407, 3586306435690112870, 17278658194357811156, 2504635638454636683, 7235500145280211409, 11191458759516692993, 6465450803792948194, 2111071922636782066, 11802465958807233213, 9116942394473193925, 11145482942031811955, 14726020691764699927, 16903672043479974450, 1, 0, 0, 0, 1, 0, 263960295682680947, 15697220842527476860, 17868088579823291326, 2175933588395873247, 8749749468735109989, 11010166446741390499, 17943104442301856895, 15821423767384514021, 16018668147064525478, 5560768172433028490, 5619212355349254932, 17391285462458271036, 2603291588626814071, 5238953246197227863, 5602891381109897586, 1, 0, 0, 0, 1, 0, 12301036190174877474, 12651281118484863330, 11983275442902746825, 9125195986387370903, 2181062690427536463, 13921861517061570826, 350891571660248295, 11013048057925712708, 11055047889476803308, 15398332646604634982, 5808711407549689243, 8949777591082911961, 14824627964979845981, 8130365156760288485, 3947069696768920416, 1, 0, 0, 0, 1, 0, 753507401801380169, 11557202300537182401, 12635550211207024884, 13277984171307670821, 2631795936834054713, 14094327291919754106, 12673624581190519723, 4509450209340246689, 10606486226190872261, 889124163739951988, 12547380261461657128, 16829937485708676196, 15832095999334895743, 5377353767201125639, 11053610747785598805, 1, 0, 0, 0, 1, 0, 17726880391953768878, 13956049620380258223, 11273932727072475337, 6855896085734577371, 1129400045567810133, 16519057148475618054, 10699416941054230316, 17256608828803451668, 6887723245936746466, 552364255868028623, 17909079490987407142, 9570595819850351164, 8654686163127378448, 16203109760043627710, 8480295614280342552, 1, 0, 0, 0, 1, 0, 5047048529377126902, 2720906371958061367, 10084181298533567509, 10367672116357405411, 11036446985399396097, 13294567520571596163, 17521531050433436007, 1868701710513242496, 5411603901210245247, 11609599138736895146, 16874855234706410918, 4393409689646403917, 9543195090298605247, 7478523150127634789, 2693101708644875762, 1, 0, 0, 0, 1, 0, 3528724572660247995, 0, 0, 12432722351030045, 1367308201666984940, 3681473655802754494, 15340518851882934883, 12978887161137913348, 15761699408266065961, 3053535844413236872, 13043307337058007179, 1605626291192886407, 3512088686484392896, 17370072541480613908, 15945489250832697271, 1, 0, 0, 0, 1, 0, 0, 0, 0, 18236855931369748683, 5145738009993425605, 9599849581440088949, 7181962801200058100, 7842895042061868932, 12656177266019986902, 8530248384503061153, 7088178758240165913, 8843525768370306419, 9760798177389960884, 15297557810674980998, 17513790474795511142, 1, 0, 0, 0, 1, 0, 0, 0, 0, 11582029127760482436, 12210748157899031357, 9473509448225646970, 17514007687115301207, 15252116786733410669, 10068681917011840638, 5010610666981558682, 14100290159714849481, 10038370148733513877, 4164887708143705047, 12759194225663538416, 5155504400103783318, 1, 0, 0, 0, 1, 0, 0, 0, 0, 2256431941220947766, 13487119117857302457, 10370113277604876234, 1506538453550143326, 9611088164777633619, 9944172425891749050, 2585766031776029836, 7469792865149057403, 3748706915022560085, 480217827283441208, 7902514309755880799, 16608422580379539141, 1, 0, 0, 0, 1, 0, 0, 0, 0, 3987768130567869605, 17866922374020149524, 8514580104850791069, 13475546435959911551, 7789855707707231369, 4610326148461237922, 1784941811671601269, 9924745492516640019, 7791549396364371277, 2968443994649453078, 1308562153347600605, 4332337354844628651, 1, 0, 0, 0, 1, 0, 0, 0, 0, 3987768130567869605, 17866922374020149524, 8514580104850791069, 13475546435959911551, 16952228088962355159, 5793482471479538911, 14446299416172848527, 13522295374716441620, 0, 87, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 15982823105988775806, 8055676711367425373, 17941169771108522281, 17144527358953736194, 14947610898944891577, 971614072768782170, 6527463406041159829, 3832659229659994697, 4267689650839244805, 7476341399175005462, 13956706726156239325, 1362637335972540923, 1, 0, 0, 0, 1, 0, 0, 0, 0, 5870626296958083933, 15831852620745746684, 3185498590211330291, 4142206734944835575, 1703654304778633946, 16779850255772273060, 17529309452142070777, 3820424470916782417, 13044986967311981583, 16932680220731892573, 15512851049245904995, 4407692356467248372, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1222210540818995679, 9596558254971998891, 17836151103719299929, 972583351096828487, 16036135922289885914, 9046461447407029762, 13420377050848926972, 8268741668021650938, 15162095256779392528, 6250951389520005938, 4880080490180073887, 5079644903468213758, 1, 0, 0, 0, 1, 0, 4277112440869277830, 16975894093684028062, 17916235475615809558, 14524910789332636826, 11691364468631390887, 7787341040263241822, 9379002423052238093, 9978142397546997785, 13711991341735230802, 2995007776024477424, 4712167935694753945, 1064069264700679460, 16784239691558161828, 13171136420515290288, 7377465172358292401, 1, 0, 0, 0, 1, 0, 7863758113629837220, 34545184916281199, 3993169000277716254, 7364322756301525079, 10650631026443210837, 1517619643121483559, 17270732420407911054, 4258304245011181242, 5161000027742486976, 8399067086847534736, 11003984578732833046, 15464732564240072836, 6182941569324809186, 11275803822943060218, 158655113981893701, 1, 0, 0, 0, 1, 0, 2476402089664475908, 9916425135419809036, 3028465534706354547, 15472564680003668093, 6373098182685681762, 12520752577019080054, 5394462987259780313, 4831149567958541538, 12904631563004530976, 13837253351754641870, 3923208428450719385, 3554976680697606440, 17043251418254499417, 5302393607875037297, 8096532195498204177, 1, 0, 0, 0, 1, 0, 5401472078486138644, 17911378919292638386, 1604440114467418180, 4779855905656105676, 6025526479746347251, 4449154494231990099, 11830346459740212406, 2743894608322163398, 10184996808268436049, 3882545820330029085, 5202687146936953923, 777280530525071979, 9570037184747372126, 10484193697881848161, 11860662735451501625, 1, 0, 0, 0, 1, 0, 15748781809771449617, 12223876502815956005, 8462728310504683652, 13057156105981161589, 11957472249295015469, 11549246553227545561, 15033014935301073849, 423385249083279348, 10856312299574527186, 2052856619870651334, 10305616267836960765, 14352183358244000568, 1261949652056609866, 916956049912161855, 3353438403242689585, 1, 0, 0, 0, 1, 0, 11740120563940364368, 1391869256781506493, 11057309605482706459, 17704317629486807708, 6564342187673520486, 2792692044523533343, 12797232677587390356, 14797653849693720774, 9082763018815888798, 17062564998145646419, 17163741437026102402, 14920816938307553514, 18409839409942969565, 16099949995219613642, 9387728217249208068, 1, 0, 0, 0, 1, 0, 3254516890705807916, 7365800426850749937, 15974018227958845798, 8444961928162939943, 8050679843713964343, 1245616094758475931, 2976182234519674621, 11861324009571007650, 18000519861091284933, 10809856712858383834, 6898855362441294480, 13146633521971264482, 11152948692891359460, 10343969929561703022, 10591999464601502689, 1, 0, 0, 0, 1, 0, 13540695320312597078, 0, 0, 933984176226341473, 4938354828005165424, 3057022637731780053, 18149554045659845084, 9709632327217036413, 16645387828565996715, 10873951879782645518, 214597493824524577, 7950640568527571392, 15274457345887794634, 9280090582838465603, 1242243096703449887, 1, 0, 0, 0, 1, 0, 0, 0, 0, 5626861946644684679, 9519120652743404725, 3153363644848796249, 16387713581663902851, 10655954775576173219, 16168525333832765040, 7013656376478213608, 7333415223195735541, 9069684467099779645, 10706178255503280152, 17753787514920247819, 16088561184006536263, 1, 0, 0, 0, 1, 0, 0, 0, 0, 10636061157542345097, 15008846988127407811, 16614085001509596773, 12600455057253767871, 13458552295186750925, 10343839881402182751, 1108696518251840495, 9621971582260379329, 11613485699478956673, 16861381831518076617, 17933004011918959112, 18255208815154765383, 1, 0, 0, 0, 1, 0, 0, 0, 0, 10509741793670097910, 12960656197959013774, 9112727654277900213, 14176014235755683408, 9647930301481695061, 10818726819316593067, 11744599510375600263, 2780827620762362248, 60352997716668050, 2064777537623220055, 12394773470270210064, 15490398721638241462, 1, 0, 0, 0, 1, 0, 0, 0, 0, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 8242146665224381578, 15911532375448333238, 1386357366995233596, 8611444126933110985, 4676083100930238397, 6139688846062542757, 9002714910392091903, 5823797362462191159, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 40, 0, 0, 3, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 1, 0, 1, 1, 10, 0, 0, 0, 1, 0, 1, 1, 0, 40, 0, 0, 12, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 9, 0, 4099276459869907627, 1, 10, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], range_checker_cols: [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 1, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 7, 8, 9, 10, 2197, 4384, 6571, 8758, 10945, 13132, 15319, 17506, 19693, 21880, 24067, 26254, 28441, 30628, 32815, 35002, 37189, 39376, 41563, 43750, 45937, 48124, 50311, 52498, 54685, 56872, 59059, 61246, 63433, 64162, 64891, 65134, 65377, 65458, 65485, 65512, 65521, 65530, 65533, 65534, 65535, 65535]], num_rows: 128 }, last_program_row: RowIndex(18) }, program_info: ProgramInfo { program_hash: Word([14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674]), kernel: Kernel([]) }, stack_outputs: StackOutputs { elements: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, precompile_requests: [], final_precompile_transcript: PrecompileTranscript { state: Word([0, 0, 0, 0]) }, trace_len_summary: TraceLenSummary { main_trace_len: 19, range_trace_len: 49, chiplets_trace_len: ChipletsLengths { hash_chiplet_len: 80, bitwise_chiplet_len: 0, memory_chiplet_len: 2, ace_chiplet_len: 0, kernel_rom_len: 0 } } } diff --git a/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_24.snap b/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_24.snap index 2d5bc4bfe7..d7925f3428 100644 --- a/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_24.snap +++ b/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_24.snap @@ -2,4 +2,4 @@ source: processor/src/trace/parallel/tests.rs expression: DeterministicTrace(&trace_from_fragments) --- -ExecutionTrace { main_trace: MainTrace { columns: ColMatrix { columns: [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3358534066525179769, 3358534066525179769, 3358534066525179769, 3358534066525179769, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9365253138981608257, 9365253138981608257, 9365253138981608257, 9365253138981608257, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4243893038989355703, 4243893038989355703, 4243893038989355703, 4243893038989355703, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2372900269115514267, 2372900269115514267, 2372900269115514267, 2372900269115514267, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 1, 65, 97, 97, 65, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [5482243896119908732, 401642074298203, 3137828705454, 24514286761, 191517865, 1496233, 11689, 91, 0, 0, 0, 5482243896119908732, 3358534066525179769, 8, 0, 3358534066525179769, 14319792288905293245, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220], [17271741639510569126, 40, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17271741639510569126, 9365253138981608257, 0, 65, 9365253138981608257, 11465345153771181037, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864], [10627125303494028926, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10627125303494028926, 4243893038989355703, 0, 0, 4243893038989355703, 16104169334207009019, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481], [12334791106787903660, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12334791106787903660, 2372900269115514267, 0, 0, 2372900269115514267, 2750797734633655770, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240], [14319792288905293245, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [11465345153771181037, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [16104169334207009019, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [2750797734633655770, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 4, 3, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [3358534066525179769, 3358534066525179769, 3358534066525179769, 40, 3358534066525179769, 9365253138981608257, 4243893038989355703, 2372900269115514267, 0, 40, 40, 40, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [9365253138981608257, 9365253138981608257, 9365253138981608257, 3358534066525179769, 9365253138981608257, 4243893038989355703, 2372900269115514267, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [4243893038989355703, 4243893038989355703, 4243893038989355703, 9365253138981608257, 4243893038989355703, 2372900269115514267, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [2372900269115514267, 2372900269115514267, 2372900269115514267, 4243893038989355703, 2372900269115514267, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 2372900269115514267, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [16, 16, 16, 17, 16, 16, 16, 16, 16, 17, 17, 17, 17, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16], [0, 0, 0, 2, 0, 0, 0, 0, 0, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 7, 8, 9, 12, 13, 2200, 4387, 6574, 8761, 10948, 13135, 15322, 17509, 19696, 21883, 24070, 26257, 28444, 30631, 32818, 35005, 37192, 39379, 41566, 43753, 45940, 48127, 50314, 52501, 54688, 56875, 59062, 61249, 63436, 64165, 64894, 65137, 65380, 65461, 65488, 65515, 65524, 65533, 65534, 65535, 65535], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [5482243896119908732, 14700437138657715688, 4194228403373198226, 4321424756204952178, 17106991433953495229, 480007043786623808, 9077933169163287651, 10301794879477559358, 7837641036032671415, 9957661348832415284, 3403527796290311921, 8465759122953264103, 9491055353357939181, 14342984469850983837, 9771451080159159411, 8537706246195014625, 11423410855123831518, 17765926817646991510, 8321792161956545451, 13783267673851502179, 4529776878769021619, 8116795789739369570, 3611313486028920718, 14057252888063062893, 13188102157225090063, 40859616366247747, 9776318485951152693, 14134961488520769281, 14580812564900766592, 6012095218278392893, 12583880807825187559, 4192437018821097220, 401642074298203, 4016420742982670, 14280802901810915241, 7925919485060883878, 9094034340168608638, 6650811367268781560, 13344927435882217244, 15870694671012449597, 13091389828882674218, 168434371192049215, 13973668876111195937, 680445747454648704, 15441309962929722976, 15749770188837954531, 5233297770622824375, 3367253731665130938, 5066484463076591248, 9867160564810673994, 16707816004584596036, 6832899290197418961, 10263347723858682786, 6209209797490182000, 8678413656546712232, 9643915442530902318, 17208626611000903707, 11389822518212260982, 887493237489321299, 48736118273260452, 13483864438078018308, 8159241411748295729, 10385528691577928985, 5482243896119908732, 0, 644, 13398731741387911383, 1702596310854469483, 5960531672215414966, 14152498107176274636, 12742762049153184106, 747050504586908561, 5800650255543088287, 16122619596578164144, 6772875084421984040, 288495594474105189, 8600976689152153054, 3411751581427101134, 10304697226126818963, 3398791421797336513, 4476944395780698788, 7796778119718125747, 5617773719451830708, 18153429098783777295, 11043847812690714922, 1719133760987188643, 10906522308373106683, 16409243384953073963, 916060433516903836, 6973907531599316043, 9109780042108713794, 17099296735351468833, 15306362721670767113, 2730832614768234730, 479016032615721743, 14319792288905293245, 8, 80, 16253482711025978099, 16690839578921925157, 11755424915479552417, 17934377671577204140, 15509754874715907467, 6426721221030580337, 11049594146888643723, 14912334368661229147, 17657273147290084056, 9105126057127804171, 13430225876739607206, 3614830725909060912, 14569284676797348998, 4705513459362295944, 424917224365117418, 2835737623710330612, 1964100172858915134, 14896843043547784767, 15482419984058848245, 18437547705335910066, 3162257106529980441, 5297995970636059087, 9661978795293871188, 10128143329575104151, 770728251595531533, 9782965673735423214, 1347942901513492691, 12086966446141742548, 10239457018222882008, 3358534066525179769, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [17271741639510569126, 17693777214203449670, 17446294671039685780, 12180657588796280274, 3901851127268644692, 15132938321031306327, 4529077938382910243, 1349343284414021678, 12010127700996563076, 3802141577517901644, 10153500743657060380, 1665683881724788425, 2536206416673670232, 6321132288631485459, 1484367395490874035, 9791226137836052251, 10111774824823842282, 16052656468702535281, 10276660848524574906, 11241218962943578830, 169695422976636841, 7241344066748902545, 3569311910587147072, 8215766650263520356, 2619309237284639419, 1962296512232188159, 12890305973496102809, 11438817727011493827, 15861640058126249653, 14517213901488835116, 6582109139928846076, 9480578168622006864, 40, 3213136594386184, 1835177830541154044, 826263100281998566, 9612296353153372169, 2509054224639990472, 11363599377854067153, 5593295816013818122, 4611398810491526224, 17064807786960234347, 18427889571151062396, 10159688738464070440, 14427917509182297997, 6874689601963577621, 745298233749984501, 4960831845018172313, 1451394763904737446, 17942681985602265676, 17508193444101172646, 1672370857206926433, 10152063658776528390, 14576660961872281746, 13602838247655372264, 5274902253855511588, 3163862752932557920, 7292072545764012550, 6033538369482377655, 10941848106600998110, 3570589185097006252, 4587292818271677447, 16771298688176486904, 17271741639510569126, 0, 552, 10446875550887438149, 7588826506897155585, 16730914921892092280, 12511176149634059683, 1758801585754904665, 5885085633120358478, 12242421290212925246, 17368642390815603411, 11245463457685625563, 2659747577123257435, 11347669259219881571, 15449337489158534519, 17510270622758876933, 18027674089872559881, 16436012900980393273, 17430549031516796763, 17674101567742383712, 4643493040432393957, 15750016999752216538, 5970778449527916441, 7406085958721442119, 8823739942223974350, 12296950126673436366, 8362221384115403494, 2025584296720659827, 17113734046007416651, 3678646409353890898, 10191942812097658700, 1453528547827258310, 11465345153771181037, 0, 64, 5751576643258238090, 7830268710878889486, 4868320831660690795, 7042762868047858013, 1028615964620729689, 12270587957620579653, 7267371538363991280, 16125626865182516658, 16950134439933558852, 13427183447069512151, 16117382505273595827, 2222792985740553749, 6517696895688418945, 15516128650333221731, 6357034143715229949, 12960707821770488929, 12451444460344609421, 8786747128188560390, 7634329044629047826, 7741107824034642016, 10975559322169081956, 6007758954686348362, 13971256108093330407, 16868860295450858142, 434120282701603474, 11571634562637977474, 5581285869985960561, 6581368197537384623, 17661012293298952642, 9365253138981608257, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [10627125303494028926, 7089946709940699513, 16018419181163655201, 16144413208110066321, 12517012706582615280, 17466716576309862393, 18120522547066464513, 3133443529903863473, 15879773433331271008, 15058242802738637389, 16107648145131258558, 17940570471380392799, 4146898483110117869, 13355141649182107533, 4502835184975000914, 11529786935650512206, 6872828020563546843, 4179930870000296671, 14088376982248436722, 3284393269772901229, 9233870580127604406, 8040351000384949099, 2082747769118638584, 9037700404196650899, 17868569356942562984, 3031609089566191882, 15372246715962319753, 5259611931696930736, 14882250288085472215, 10288285656672707851, 11046557109431487119, 4891889892170146481, 40, 803284148597046, 10010111294767420802, 16943179644353820008, 8996122336997085030, 17350347680949584060, 13520911097528541892, 14769691589967587136, 81685142906752346, 7559897225353479520, 128512095027132822, 9792116363139842106, 4634576985104787587, 8679380235287294885, 1134592111928495305, 4684288247441474792, 15613043314698948257, 4841731940180862534, 5786518576333159075, 12666070374819933283, 2487841274273895537, 5690982477694717281, 5924572671969496500, 8629130978595053833, 18206699227813987098, 14234831161984809711, 16798226782780142546, 9330568307929665420, 9731250716956559616, 12286920896461242142, 1919835269886444210, 10627125303494028926, 0, 276, 5572533910279649175, 2665502751151845058, 3420041171743926975, 13105841064724313047, 10443718589068788975, 16410831941400613845, 8706919134091371207, 5424121700527660040, 12860111264033880808, 468662522013222574, 14746212538756510443, 1337341156189505070, 5208953037158023510, 6068232083162993748, 9678821925451981470, 17715598857116570054, 17221271024145736360, 1975930269787186400, 3526946062060894178, 12647721578094853267, 13858063547960126340, 1348240088196356067, 15972449905513110374, 2515565498382079126, 9279746140911612054, 3713543423691008796, 3233112695116768266, 1858231082388626584, 17742257866254572336, 16104169334207009019, 0, 16, 7110029021941723513, 10115409991715085575, 11428668827299215140, 4015039023438705588, 3732466887400149035, 5870841944205588609, 8421627027326523148, 8231214549142439222, 10318470559229280016, 15171283498151438808, 12477430934852872037, 3853779543897991795, 14662750186533371679, 7423988381383082226, 13549468426633458145, 11079168775731474830, 12471207782095033761, 17595325414333663547, 7042468264080735391, 17650115337646869205, 14946074228061446423, 4655654314239637986, 11187552516160183253, 18115881480442018545, 899748567092010447, 14020868337400209874, 15417366235984526759, 3331301994171189600, 15814677761660135474, 4243893038989355703, 40, 40, 4294967292, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [12334791106787903660, 16314186579682789689, 16046055491183908407, 6937908670684349781, 9428962583778419369, 12671344758477488595, 7729650243590863324, 11715634485135010533, 2133167353214657976, 4100349204869170028, 14110128220081934719, 3223264940814324611, 4013852846792290230, 3963283702543497203, 11663083613788432971, 7907953758158564716, 13628053756450739862, 11139084033219732849, 3452979822093558380, 14346711487449348492, 15207411620676648511, 501329811930827740, 7758369216397164239, 10815732145433955496, 4610905976152412334, 17935722133204612030, 4407166322243232537, 13210703243795283421, 2674423901749705077, 3504222453682520691, 2024557484059292221, 11712807151087072240, 0, 803284148596806, 2549897079792572603, 5670682422759337153, 4249626004536644548, 9138873913574622404, 1343119293110958009, 15707367360995172765, 2149720931386886989, 12579497520806083785, 14990373923527496282, 7330871518527332444, 5790961380321049961, 5495469617420264118, 10789212522972025785, 4356961356341052500, 8032044444015716361, 5554647570062987979, 1022644107902166331, 6764324513849573852, 14002884382934858252, 14316154512513580139, 8331374540726760892, 13067519389098510351, 8671032013540344722, 13457978878695920483, 16399505509770566014, 10578307416004071064, 11950037765875050974, 12195903600484928258, 17694444981837938563, 12334791106787903660, 0, 92, 13491880295779941671, 17558274388625518928, 2846824553470173952, 3523509076537079172, 9799038632780562513, 13535672937351711649, 9746772683078209435, 16106002567881560829, 8079784996354006751, 4777591649493566963, 1345156373992429389, 15297897479538231384, 13973483607215960244, 18340152543215802049, 5000946629530062426, 15890473733699877306, 14902294728590831204, 3011516360220729965, 17542926168179991242, 6657567861688973613, 8835168761010196729, 8826324103843911331, 9882179407362466285, 11897066781203331526, 3536220024494542760, 11424483570196748419, 294092485488322279, 12149225804903469645, 3036839951080750932, 2750797734633655770, 0, 16, 3208043314804619251, 6920597847411412414, 17985619796195836408, 11907191178709112742, 16377455862733420451, 15572876043608056600, 9466912758182965715, 17480763791598773801, 15029113851915312964, 1953587265841775225, 7175742902791404624, 6820764940134875350, 16069841829669607101, 15548451706938320654, 11760680638795846495, 1560700914733041660, 762367990279432470, 2603436428456411224, 6200990949184863170, 11673627333152839295, 7804486006334068097, 1006207264024395366, 11193609705356653459, 5704515878100803393, 14918729158665343812, 10658508130485449873, 380737719356524599, 12870561906904032245, 6984680585936259437, 2372900269115514267, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [14319792288905293245, 13415211686073742374, 3149648302915651279, 2183945468601797792, 13296390406171247483, 1854573623301018325, 6584248684794021237, 16089856164543344516, 4773455775437745378, 8456999553910293319, 5311613736439167674, 332137947454970287, 18353623873984208545, 6936763828562118650, 7803450627715630286, 2809593074760044198, 17403350541234273237, 4739616627721376242, 12174946372048241570, 9146291209906782044, 16719606593630884665, 8010607335321228412, 8980769147119509995, 6575555704765488965, 5801827901371738935, 11455982787078836790, 8211250723004787137, 6151514289078604478, 17915715126849699543, 12433676256235881077, 7933147088254086263, 11509025001394472292, 0, 2008210371491335, 16850544756775285522, 652387120995254672, 4188956971131276775, 18389965100329173053, 852421464532798418, 17258729097516267384, 11347427093515448316, 13908538323250058716, 6558337355650114042, 4089976927111145333, 17816809041231283545, 12843997071522346840, 1655996231185402724, 11256141768734986569, 3019459069615110433, 16778373777892540383, 10175251160015024193, 11396702708789693017, 16481019216530994753, 5122353003150766192, 17913616556333538828, 6485826671956173957, 15738756542654855641, 12199621872357116369, 12077164016468113545, 8907315944885273345, 4878983963291132913, 1618531819557712390, 565132887411573955, 7288090792972058500, 0, 644, 8698112979694512183, 1484832724912073400, 17559905242927504135, 8301224421374966792, 9399236208058450174, 2669398055632380115, 11307131702448115253, 11217016437113601321, 5789099451732089955, 4549622233314763492, 1239065339957448367, 4175942380264380439, 14889292305938541714, 4531363562013687755, 5140869640511317393, 11140388332008156040, 9692465784954462068, 9297910418252147698, 13488989169427894096, 3552900044190654848, 6760710657831378657, 12121966587219528787, 15900962396386651595, 6608207234386334072, 8800758533265494982, 16201621108022440385, 6765154775891776468, 15354276103682076009, 7645122244202370271, 15666451408857108222, 0, 40, 18130890293586930078, 18252951749527557342, 4460903658820341507, 859505755654562117, 5961685480015386121, 12134776249586726543, 11174658189737631113, 18385152961050631924, 9881471501704199804, 9636744945302995714, 12323181865658998064, 14903454669611502952, 1490539036394497080, 11688514875590095153, 16093513520259190726, 7731471377060742735, 5247500963110975116, 5269361527156951110, 13733877647296302634, 11865469401112846356, 7643242142337524006, 15572658687280648106, 9345628789826937825, 3291248301730279223, 16808111015808513609, 16274730253017522022, 12243901590027926887, 6559275936659510680, 17224785255700525855, 1390310476158884261, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [11465345153771181037, 14098642529467391391, 5535026374122183926, 15092496102668051355, 257473274985355223, 10260436313437728882, 6731908034259211771, 11264349046953665415, 10299240179448618610, 5126151224060117218, 14121035940755315114, 8209352310311089013, 14971697601659082585, 1100050914291650821, 5035373507226681389, 16042249687109751437, 8837503665608453676, 2504937998242193140, 16526648943653417718, 2452121396486117195, 11029884787275710886, 2085781890586074785, 13162154469730856465, 7946539915965721335, 17992914229117852310, 7142641763418660559, 16732929992769459335, 1127063970169475225, 7467959617957012266, 9462884495447906259, 17277989807306885144, 1657723241998675022, 0, 1606568297193092, 1076973899277284702, 14086579741019377519, 3818478693739735842, 5593621083784091164, 11728670858811596587, 12625736484548160126, 968047239546776409, 15493380284459454506, 15542100289574010625, 15053368214221814937, 17388070103506970075, 4738318434573394804, 15389814481683087606, 14763812299525073807, 384493414835098150, 7660052382355122994, 7691788916209089905, 14721544157906502013, 737940994724202658, 3221762534387838371, 7517398897305596666, 13211005290810103003, 12141388589516060378, 13672030567886044471, 12296311093518063031, 6143526203440544581, 5554567664494429423, 12302163852964786956, 14310991091785572129, 7008881577152522467, 0, 552, 126724644436205205, 10241199256484865800, 11710755472728257079, 9814439449693896294, 4184208894850372064, 13142997752644266770, 12969767250590673327, 16308338449341618327, 2857514379308674181, 3609195066294253037, 185228684080860642, 1613944213773308204, 17903436875856263069, 4515533500061955413, 12536726874363800554, 15437904745147545753, 7830085342542866777, 6536598727940018370, 1711823131760196898, 7709623033392346991, 8552967012655997274, 8947445239291587989, 4670000389326714804, 12010856128816592344, 13269571463782090254, 13867391969199306543, 17267661857179267882, 10036416896754782473, 18012966148946012188, 5229864730287063918, 0, 32, 10452764368937945515, 6969997263492352670, 15570786589164252178, 16136993048454358354, 16378352067056606124, 11747573379431147483, 12296464969648251345, 8155132212936940581, 2470200969414032680, 18126939303114916528, 16736276280592238734, 15549342782445497049, 9033882039108268313, 5121596298161079296, 14336897502470956191, 6301009824137139871, 16614860627935231068, 10383378433371415142, 10330363517752279308, 10937466001850040595, 16305844076412050396, 7189713532379018536, 7568236447715590536, 10805187342082326609, 7424874700566577356, 13861219118264849665, 7052270251739242825, 17586339544079318164, 14071176523136369481, 12282546735285148319, 3, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [16104169334207009019, 14145804402236837957, 638510963943763558, 18152457079207292292, 13178378367745074892, 13292769663331639140, 2409570605742285812, 18386931186537975697, 6045651321104574873, 10576311525321301834, 6759560187812996269, 265277838027200178, 15857438057860901996, 1037029241838654580, 6225168341521517925, 6895514801579803384, 1550665420642344807, 3231597075356238257, 4166180297101468799, 3189361261612592850, 5442307944523583224, 12110265058053493581, 12478481205289622727, 17774723700903466966, 13236760767894900950, 1895278615969967832, 5078948249831860209, 3481261074349261153, 11754602214149170613, 1831143805055270726, 14579426980777214583, 7525141456947324339, 0, 401642074298523, 16072847024087248681, 1047399340937520223, 13840617071834531990, 13835424809772757395, 12438858367585478828, 14080077230806112448, 11208516754282785707, 7691155727086178136, 17898846423848868766, 13990233438164144322, 14765296463244153634, 10144768301469359068, 16658833476738371029, 4674204014270448977, 12722211832796318871, 492549161703070590, 13986658207276323375, 14512155514173182920, 13983563295828088546, 2440687363152463730, 15931932209781173412, 11078906302351818677, 3584926465549602493, 6813538466449503008, 2334817027508375898, 12619526317209583817, 6515674137823977144, 393947096345211186, 1951192747307666741, 7526556702499462773, 0, 276, 12147025678885387063, 1963067308825972547, 4225984201120753953, 1196744323913827820, 5548577578393956861, 12196421586952833282, 6686048917052134288, 13682276749649062124, 18305115060607268181, 15701263684091820063, 4379325401380154240, 12368723875816287010, 10456077510396891682, 15257688804823183049, 14739472440526637936, 9698983999555494854, 6114823860832404997, 17890984706651436184, 7279056890420718668, 14586346563305650786, 7193610841629628055, 794393058555157904, 8446464239566334422, 18360375401158087305, 12786208149678159110, 8127795658820139321, 10374412076721466090, 10797782388389379392, 14917361677919134410, 4435027266040030689, 0, 8, 9114363797835460134, 5446076396314160376, 12863008906537145423, 10008421878335836436, 9952321233871043669, 12872379155893703237, 7266552182027361169, 1266036355585216796, 2621902104176569009, 8791105532651972211, 6351975813451610601, 11821139808280113179, 11281913023757770338, 3277134497757048289, 13219080767636598429, 10181825490691565485, 2766637533497216499, 5527857141123489970, 8463471033597650592, 16863468430858262436, 4521466714741486225, 2112404415880305855, 6776665887355979100, 4283028800297139078, 17448147405455891940, 2672696094870261596, 654959311657763753, 15404879372302137522, 458610335793450516, 11708893791522292939, 3358534066525179769, 3358534066525179769, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [2750797734633655770, 2196298446069803466, 11838988982732965160, 8838579915162662604, 9645282237960382599, 1452793205233705375, 13043673489495767039, 6914761656747274754, 6462510494810546740, 11542677354694298953, 10084597289196425304, 6187212959913925984, 13253251914245887991, 13426752715944801915, 14540441677731288899, 1687158516877835494, 5237558114922547298, 17657306689192164966, 13600283758187380877, 498396070609474559, 2816716335908718574, 2201796413416910298, 9217066277303434638, 1438935019962455534, 18328852556584031255, 6915155572789963327, 10360494843504659614, 14112471018395370124, 4296220331020841697, 13555983847490106392, 10974207239020571710, 4762963524641036906, 0, 401642074298403, 6959791354043610236, 1843180796447728437, 9556362158826632350, 3220022195391792741, 6012411438022691140, 4309223969498591447, 7596903557041777533, 18393682838284953355, 3973832102121938954, 12190997158276486897, 15972235844585587264, 14899488070931524727, 17337514399056563302, 10500237188498665928, 18440452962210035879, 7481614450647261413, 65300580117832193, 14713590013611289205, 13086268929321267306, 17247769089209001713, 11421561962034654967, 4561010052951998759, 9562817622798343284, 3062054327467638127, 6016566887476098647, 5513989129644936969, 13097123292793361360, 17631302057213141907, 8382824402074565601, 16136160484984138575, 0, 92, 1552825087809033479, 9447273069996733529, 6419011263238967677, 6692866018192235946, 7156821319138712192, 979552938298149105, 16414416705576227412, 12277732972115645845, 16390940174922802980, 3487294253425873238, 6189899981788830548, 5202139200141296429, 10911204476854742317, 1721085402837891517, 8352902245765240122, 11853370831480580617, 12549880386282601398, 182861448076475833, 907162566851125145, 5998456693193037487, 2770786935363726809, 7400519332304830077, 359467329647437035, 1312252687673992186, 7328500979632536073, 8813774793495812162, 6984573596316331699, 14977076517134741377, 16254221298013000537, 5001523311460849924, 0, 8, 6104172690014223231, 3119855977255645286, 2700229040680838768, 4228220371303630837, 12976691418076017877, 15391527008624099592, 15522155400452634037, 17655908650961725957, 5157987610310047621, 13664486701019622043, 12908699189677656287, 14840926611057477527, 6092037682822283700, 15181448373122947619, 2083722204849270202, 1893419523737526751, 11329911669537538562, 12331432886354737271, 9636585409664050258, 5131588463040403759, 10248116973079783912, 2136665268102207704, 17448444978654544666, 11945433761064128885, 4462464721020457233, 17579935132869425842, 7098417589530391109, 15343623253038912080, 7762335122892638892, 10310226363807226654, 9365253138981608257, 9365253138981608257, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 3222968251772292059, 4659330917232488313, 18368728739119945660, 6368972875636062959, 4707200061081251786, 7837376579209547587, 12248323053399392025, 13659284260102405271, 3268373156044973502, 1283746275992984836, 6075821593933813225, 16314284187241223265, 5494222736271176220, 13120146179040509426, 11410636383049345368, 825507757879255520, 10747531529265802304, 7673382754837099366, 15156055697659221375, 1718675228113159248, 4201859160733141037, 5300265117402310501, 7272994976566716580, 14871183427463612333, 3498894361287896100, 15218257307939313170, 1772539751900737248, 1975418926721182099, 12089371041955731221, 15888265955091463133, 16091581530351759692, 0, 2008210371491335, 13098960849839742034, 9449621519891201049, 2814310786559014444, 5305842545683321494, 4969236906288915907, 1243780951433164967, 6167749875842285147, 9490220981060631819, 3665259354621890034, 7437125179920904126, 12655958476488865400, 17935537000594940941, 91614862745339577, 1869550524566103495, 17384150297165671545, 1154605885284628266, 8665046436862728398, 6741156569294553317, 9490927005547387767, 8947900188307771735, 13752550215202657538, 7714188412126691626, 12225947487197390724, 13509943592829854189, 7120740401378484294, 6789669275155346195, 2929601484581949152, 1077164174037184778, 7253613682453412944, 12957959164911169922, 0, 1288, 2467314028170731200, 16601393295490334589, 410862426300963016, 6715125970066025284, 668903147624506142, 12095483928402104962, 1613631742115437617, 3060858350461432106, 14519578477424544472, 1246482959663576649, 10151539857350203993, 14524407161343324874, 10767371226180010877, 8883572370406050272, 7634465548311616828, 13778778399918900014, 17362186831679047435, 7577173806777510989, 14020627064222792913, 15976021831713665696, 7948772943735475729, 1437804116009572564, 6007143667192036573, 16589616747039104611, 12022435130037250391, 11127010123944496312, 433966021407007016, 17962467459011056432, 2310073430536633551, 16159283724457640221, 0, 40, 1560947813056021755, 6935064976442414148, 9999441144135002932, 10354700837586583171, 6040781227937012106, 4698117391978117444, 4735711626023545756, 11217844833019453026, 3130590714605394722, 2809204122464618686, 10935232469327759448, 18335893537613898174, 10868401885487323501, 15799177281014635734, 17187052562019754838, 4027411046406207040, 11879721967266924677, 3613659344771632047, 1846469577394958972, 14668357323201408029, 14939045883642543835, 2885718226990976376, 4969257074069595075, 10824274197210729467, 13212275138420405274, 10563919532671437398, 12234598862193668129, 14653607410806008848, 2498958194485300229, 3512215170452429648, 4243893038989355703, 4243893038989355703, 2147483648, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [87, 16746387937695142490, 9155393387906219784, 13386503743719781199, 2643395754600898300, 8948310776749535742, 8784880786966306238, 1110225852810378745, 17164574292834012429, 5226876132626050588, 13521863983694335346, 1499535172174489924, 16371752154949209907, 1465531721291669927, 16357468590797302295, 15603236927467279886, 750159427723404852, 2426484208226890587, 18279268404534332738, 4383807752256753313, 14980454155356662645, 5638763115145836005, 309850158776234346, 17414628586841602406, 4488055553392002721, 6099746236569370915, 9391735730020210762, 6993986830519314663, 2701106116508976741, 1898134322103701335, 12702609090402714686, 16079373865472459546, 0, 1606568297193092, 17457628753812655267, 5096693283465186518, 12947605480618213072, 13490514080936595140, 16186587491946121120, 10245245868334896235, 6026705707665599719, 9827345407768028181, 2812471843237874845, 12940670116574659651, 2714930976118111710, 11931084046533097040, 5957825878304116293, 4815270995456833861, 3281433232253188744, 1527514044633931889, 3155608937877823823, 496495357063373704, 12643114535206930756, 2926290280590787897, 4481685646324082958, 2913086696180341350, 4929647997916999987, 9053067786296036128, 12860916533743270733, 13426707234447106813, 15934882759672330788, 2173747106952139997, 5260381980138555939, 9238536158694879401, 92, 1104, 16216562119055243322, 9113898857319116772, 17132700957014282816, 16961354324299843537, 8958491673128745523, 6084177919166198949, 4492424574001173259, 2065688581293602436, 433616324011879356, 12151404659680738203, 3770309554737682698, 5300222935868897680, 2845921321939758123, 9028103117859423722, 9867617548439033893, 12400304789414303503, 14859150043279622231, 5014308339038672362, 6600097648382112815, 1659304607975522629, 1739219815660099577, 10359847956037447171, 11590294256574231363, 3647107356246152267, 15247865541233938330, 14069295620220509130, 2869001919576405519, 17417648807118850139, 14370760106653398402, 11118838785729522730, 0, 32, 9302012295643728416, 424328237663665361, 17748121622218558811, 6681769685034042719, 10907932526941371789, 14996603190997478665, 13982878080104642188, 3336783822228111865, 7403528606603453519, 7309352233404946366, 11509327586943808925, 6803943428138467537, 12870260590513220077, 3798257798625653324, 15652192157997003684, 8260391000410661595, 9099897743400681933, 16067207775248165408, 7640841583197908852, 16739199083410292994, 1998275509994500625, 10688417071827877337, 16160081185811655577, 2725954513011781037, 3040692668058239811, 15097072321276989567, 7813293313258815644, 15261763399945716285, 2258772319189190202, 6756061023037720295, 2372900269115514267, 2372900269115514267, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 13227498393864040945, 3236590870033651606, 18316422071602565784, 15701603594857309722, 5947972608122843521, 13523535320233199342, 3753934081047057169, 10936885931162702722, 5866281172578018338, 5131575035018446451, 9418660414070260899, 17291665633130001335, 16478272933178360032, 12493684045311157256, 12080786119242190524, 9808426190668729634, 10916182427754190208, 7949752104566735434, 16437679885653014489, 2197742477585333602, 11623912681484131137, 4866858089907087491, 7615091160766850619, 6639738661085122604, 6056593816756490758, 18265959195035569409, 439634521044110926, 12264490131121739608, 16106017656155713552, 1042562102193278240, 16047641734485800692, 0, 401642074298523, 10076989882539553734, 13617634258944637452, 11664888937794835322, 6832371865971954132, 7435465380685145582, 8856983143236954540, 15647394574465449881, 5004639611979401749, 16333513927375132208, 11586223746088007538, 17258599442845821467, 10089347514894229223, 8927362828162004403, 1274761678102044944, 13987176689734561031, 968318691601385838, 17920302096119022338, 18172419653743826470, 5238866342343116613, 4715585282245523496, 6782917713521523376, 845034972551066538, 8264516316211712068, 4395820162956710988, 17367170950581948054, 11715439359473390301, 4924405821869545305, 1674381281184830519, 4077397353846458666, 16570851802495678006, 0, 552, 18364539353432252959, 1551875687645078236, 5908552039479525180, 13623916550628200923, 4699969004069575100, 11630278164657820063, 5891234840048028912, 654092830709235842, 2412613677542740798, 9533885383398026397, 3477862308755521454, 3931695716927095485, 10207454088372242899, 17803175762377303845, 11036943293777954420, 16245042535546460743, 17267071485922545111, 3154671719447430275, 2667361456561557318, 8203075576459419142, 12382743643920078317, 9185031367250188962, 2354486840330493509, 13031927341928448984, 6462695849105922235, 17450486765305121779, 4895010392763653973, 14926331475286732296, 13033597008762597331, 7576593531686797042, 0, 8, 7519454690376123692, 7627104070861575574, 17604686071836489236, 14277148259130460564, 8312218486680706135, 8395439642754559152, 17307771294890409643, 9298206908486537717, 3027629924013931359, 2933551330348935458, 1450485994192951386, 8585052201707081835, 10624425952582111111, 16773523322999621677, 13337622149287916761, 17874287708894504070, 14164897610403484003, 11216401648549709020, 911970190394256131, 3202853507803349037, 14616902435260689479, 14924823153427050614, 4881022900440414264, 9723366934152472594, 16335725686098559697, 8087897843744270993, 11437013713086863200, 7627258546495067733, 18044191572661655945, 16490279521751489469, 1, 9, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 6170161675250864501, 11961896515966597756, 4654018437841213862, 5272790938970678408, 4281766794113009188, 11245796702384795879, 4856060583384283422, 17886680608631893125, 9261060821859854748, 14424996735749284440, 13746660795296557163, 4823043606851802454, 14938663460886908360, 7270036416424823086, 9523212457335079367, 9139548031431133148, 208295785334160234, 15753650123272304050, 10546365909049493247, 13322595239551652280, 13989288587795691202, 3906006690782976298, 17297950766482640011, 13938287014198326904, 16696817761315412012, 13953265341705633702, 4268569962168779654, 14232230927042798671, 6488214721912194407, 10956084748384074170, 17343413733132688543, 0, 401642074298403, 9851586117636382793, 7414079509745519565, 10414894202973226643, 11403399710197601656, 10230759118395809329, 4887466173119518776, 12376579030877442488, 15222686873173021915, 11343634646223977946, 15054143113295762432, 8578483304162845495, 8187399805941604842, 17460975957431844228, 12368453570037757143, 4715095521846408852, 10685847052710927197, 5160934306801665605, 12877482432527277885, 1026289052488784895, 12183816968946827507, 954239020314042893, 1899038343674936222, 3582199871763692750, 10141562795735590523, 5883730844910027408, 10313342961711791200, 10308552102917724507, 1101239144209002141, 16732112788727027442, 6132059608254040410, 0, 184, 9694623828077467233, 3675008886325466594, 9937899669773170043, 7849591422987652597, 15287367360056796639, 1702914822524674176, 10568464651116235631, 18376268405209394446, 17468515571505079540, 13349382737895871506, 10773310703441442177, 77415128127038826, 10067581411407423596, 2132439228676468850, 16446262234583425617, 15913203609357376990, 4328537832216989268, 14309894248163942626, 17219034350459931223, 16386215198201980227, 7529941270179488242, 3713349402354236945, 13565147716704204129, 3968526144162291548, 10616453538138359448, 16438784497837992964, 3058320693955246873, 4965950384458944745, 16872816814243270280, 6712929990112816841, 0, 8, 17781582622500481192, 12847902632736061277, 12021499907877242591, 16751519355106661703, 9062087890172095618, 3834953580385337540, 2969703856153678454, 11604562295556139307, 10447912046373566534, 12987934619706800857, 12352596220492768030, 14816150974992525275, 2172600571554701126, 18086375044546604023, 16313093185369681775, 14997664071320688070, 347950016295486690, 9206182676441692601, 3566552483989599402, 4925983231752336365, 1728701557101400581, 7087476601458867917, 9759961360999781392, 12569092891286895547, 14206292953735333262, 16422952955631166803, 6294107725304445883, 9537940691512987143, 15535806100011306333, 7080716573279759555, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4099276459869907627, 11351842504255128813, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] }, last_program_row: RowIndex(18) }, program_info: ProgramInfo { program_hash: Word([4192437018821097220, 9480578168622006864, 4891889892170146481, 11712807151087072240]), kernel: Kernel([]) }, stack_outputs: StackOutputs { elements: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, merkle_store_nodes: {Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571]): (Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350]), Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350])), Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484]): (Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693]), Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693])), Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781]): (Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874]), Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874])), Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171]): (Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361]), Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361])), Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815]): (Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305]), Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305])), Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689]): (Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195]), Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195])), Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362]): (Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063]), Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063])), Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848]): (Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661]), Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661])), Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352]): (Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829]), Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829])), Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444]): (Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223]), Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223])), Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386]): (Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388]), Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388])), Word([13190842942618341421, 17548956981569849952, 15418963848144418856, 730733050713174879]): (Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144]), Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144])), Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874]): (Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675]), Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675])), Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594]): (Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115]), Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115])), Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809]): (Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257]), Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257])), Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777]): (Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555]), Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555])), Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509]): (Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882]), Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882])), Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725]): (Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979]), Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979])), Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134]): (Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987]), Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987])), Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828]): (Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910]), Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910])), Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830]): (Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054]), Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054])), Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228]): (Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742]), Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742])), Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443]): (Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928]), Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928])), Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643]): (Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979]), Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979])), Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758]): (Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106]), Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106])), Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580]): (Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594]), Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594])), Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765]): (Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045]), Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045])), Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766]): (Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281]), Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281])), Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385]): (Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828]), Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828])), Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579]): (Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171]), Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171])), Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212]): (Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992]), Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992])), Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463]): (Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004]), Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004])), Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502]): (Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023]), Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023])), Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539]): (Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537]), Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537])), Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865]): (Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225]), Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225])), Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690]): (Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947]), Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947])), Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202]): (Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552]), Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552])), Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079]): (Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444]), Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444])), Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850]): (Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548]), Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548])), Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448]): (Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987]), Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987])), Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041]): (Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035]), Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035])), Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301]): (Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414]), Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414])), Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414]): (Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212]), Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212])), Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703]): (Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439]), Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439])), Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271]): (Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955]), Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955])), Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882]): (Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802]), Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802])), Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152]): (Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887]), Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887])), Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028]): (Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948]), Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948])), Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331]): (Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093]), Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093])), Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394]): (Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134]), Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134])), Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546]): (Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228]), Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228])), Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620]): (Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414]), Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414])), Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800]): (Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703]), Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703])), Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671]): (Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205]), Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205])), Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537]): (Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011]), Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011])), Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516]): (Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301]), Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301])), Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831]): (Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986]), Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986])), Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415]): (Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057]), Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057])), Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722]): (Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689]), Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689])), Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144]): (Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682]), Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682])), Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295]): (Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268]), Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268])), Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818]): (Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513]), Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513])), Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241]): (Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565]), Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565])), Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439]): (Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012]), Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012])), Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512]): (Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850]), Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850])), Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986]): (Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865]), Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865])), Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982]): (Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777]), Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777])), Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808]): (Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394]), Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394])), Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979]): (Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690]), Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690])), Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093]): (Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620]), Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620])), Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902]): (Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789]), Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789])), Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542]): (Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094]), Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094])), Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057]): (Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362]), Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362])), Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205]): (Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961]), Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961])), Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401]): (Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580]), Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580])), Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553]): (Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960]), Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960])), Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169]): (Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031]), Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031])), Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682]): (Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053]), Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053])), Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118]): (Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562]), Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562])), Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725]): (Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666]), Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666])), Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661]): (Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897]), Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897])), Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981]): (Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447]), Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447])), Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072]): (Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646]), Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646])), Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140]): (Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404]), Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404])), Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515]): (Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152]), Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152])), Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709]): (Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664]), Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664])), Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800]): (Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103]), Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103])), Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741]): (Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169]), Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169])), Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005]): (Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758]), Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758])), Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802]): (Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070]), Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070])), Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159]): (Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005]), Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005])), Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350]): (Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443]), Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443])), Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697]): (Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573]), Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573])), Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928]): (Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331]), Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331])), Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320]): (Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166]), Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166])), Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814]): (Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079]), Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079])), Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447]): (Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820]), Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820])), Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284]): (Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057]), Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057])), Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697]): (Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131]), Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131])), Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955]): (Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290]), Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290])), Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910]): (Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202]), Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202])), Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910]): (Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822]), Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822])), Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106]): (Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847]), Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847])), Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404]): (Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441]), Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441])), Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796]): (Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186]), Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186])), Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053]): (Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516]), Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516])), Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992]): (Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818]), Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818])), Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957]): (Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315]), Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315])), Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709]): (Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794]), Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794])), Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091]): (Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539]), Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539])), Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664]): (Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558]), Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558])), Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294]): (Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579]), Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579])), Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947]): (Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502]), Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502])), Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829]): (Word([0, 0, 0, 0]), Word([0, 0, 0, 0])), Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045]): (Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137]), Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137])), Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914]): (Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041]), Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041])), Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573]): (Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378]), Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378])), Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699]): (Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873]), Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873])), Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225]): (Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262]), Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262])), Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057]): (Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692]), Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692])), Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131]): (Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997]), Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997])), Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555]): (Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385]), Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385])), Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195]): (Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709]), Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709])), Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166]): (Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542]), Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542])), Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027]): (Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373]), Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373])), Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378]): (Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509]), Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509])), Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097]): (Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553]), Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553])), Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217]): (Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815]), Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815])), Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873]): (Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864]), Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864])), Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997]): (Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722]), Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722])), Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887]): (Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766]), Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766])), Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589]): (Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757]), Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757])), Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539]): (Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665]), Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665])), Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129]): (Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229]), Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229])), Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137]): (Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312]), Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312])), Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019]): (Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378]), Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378])), Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331]): (Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713]), Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713])), Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]): (Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980]), Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980])), Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325]): (Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546]), Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546])), Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170]): (Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822]), Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822])), Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054]): (Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295]), Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295])), Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925]): (Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848]), Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848])), Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909]): (Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796]), Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796])), Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540]): (Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170]), Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170])), Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214]): (Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448]), Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448])), Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317]): (Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294]), Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294])), Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757]): (Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416]), Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416])), Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378]): (Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091]), Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091])), Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263]): (Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463]), Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463])), Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666]): (Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361]), Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361])), Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174]): (Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992]), Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992])), Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470]): (Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401]), Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401])), Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665]): (Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957]), Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957])), Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262]): (Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144]), Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144])), Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229]): (Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284]), Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284])), Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134]): (Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325]), Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325])), Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855]): (Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765]), Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765])), Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115]): (Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814]), Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814])), Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441]): (Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831]), Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831])), Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977]): (Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446]), Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446])), Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880]): (Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005]), Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005])), Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789]): (Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995]), Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995])), Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000]): (Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267]), Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267])), Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998]): (Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982]), Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982])), Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995]): (Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539]), Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539])), Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507]): (Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512]), Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512])), Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305]): (Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118]), Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118])), Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219]): (Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009]), Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009])), Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416]): (Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089]), Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089])), Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980]): (Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445]), Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445])), Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063]): (Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140]), Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140])), Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713]): (Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159]), Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159])), Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031]): (Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809]), Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809])), Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932]): (Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037]), Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037])), Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094]): (Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925]), Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925])), Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315]): (Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386]), Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386])), Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446]): (Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721]), Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721])), Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742]): (Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981]), Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981])), Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661]): (Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072]), Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072])), Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979]): (Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671]), Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671])), Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361]): (Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269]), Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269])), Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558]): (Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571]), Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571])), Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290]): (Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902]), Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902])), Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987]): (Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741]), Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741])), Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902]): (Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515]), Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515])), Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497]): (Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028]), Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028])), Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948]): (Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709]), Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709])), Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009]): (Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725]), Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725])), Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387]): (Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317]), Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317])), Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159]): (Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808]), Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808])), Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394]): (Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699]), Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699])), Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312]): (Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000]), Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000])), Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987]): (Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821]), Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821])), Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046]): (Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909]), Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909])), Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565]): (Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028]), Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028])), Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269]): (Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352]), Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352])), Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847]): (Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271]), Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271])), Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513]): (Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800]), Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800])), Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054]): (Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394]), Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394])), Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004]): (Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977]), Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977])), Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675]): (Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800]), Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800])), Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692]): (Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159]), Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159])), Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909]): (Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932]), Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932])), Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814]): (Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697]), Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697])), Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186]): (Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387]), Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387])), Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445]): (Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470]), Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470])), Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966]): (Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507]), Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507])), Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548]): (Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253]), Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253])), Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897]): (Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783]), Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783])), Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208]): (Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054]), Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054])), Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268]): (Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661]), Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661])), Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388]): (Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643]), Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643])), Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257]): (Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174]), Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174])), Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960]): (Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241]), Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241])), Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721]): (Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046]), Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046])), Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822]): (Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217]), Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217])), Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253]): (Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697]), Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697])), Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054]): (Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019]), Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019])), Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821]): (Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432]), Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432])), Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864]): (Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105]), Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105])), Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373]): (Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855]), Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855])), Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646]): (Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830]), Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830])), Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460]): (Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208]), Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208])), Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033]): (Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214]), Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214])), Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105]): (Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129]), Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129])), Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281]): (Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909]), Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909])), Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028]): (Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027]), Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027])), Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012]): (Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054]), Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054])), Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562]): (Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589]), Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589])), Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037]): (Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097]), Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097])), Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355]): (Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460]), Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460])), Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223]): (Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355]), Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355])), Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089]): (Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306]), Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306])), Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035]): (Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219]), Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219])), Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432]): (Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297]), Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297])), Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693]): (Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263]), Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263])), Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794]): (Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484]), Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484])), Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552]): (Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941]), Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941])), Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267]): (Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814]), Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814])), Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992]): (Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415]), Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415])), Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941]): (Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966]), Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966])), Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822]): (Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320]), Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320])), Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306]): (Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902]), Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902])), Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820]): (Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880]), Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880])), Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361]): (Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725]), Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725])), Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005]): (Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914]), Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914])), Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783]): (Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781]), Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781])), Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011]): (Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033]), Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033])), Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297]): (Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910]), Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910])), Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070]): (Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134]), Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134])), Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144]): (Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331]), Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331])), Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023]): (Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497]), Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497])), Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103]): (Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540]), Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540])), Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961]): (Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998]), Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998])), Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414]): (Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]), Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]))}, trace_len_summary: TraceLenSummary { main_trace_len: 19, range_trace_len: 49, chiplets_trace_len: ChipletsLengths { hash_chiplet_len: 128, bitwise_chiplet_len: 0, memory_chiplet_len: 3, kernel_rom_len: 0 } } } +ExecutionTrace { main_trace: MainTrace { storage: Parts { core_rm: [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 3987768130567869605, 17866922374020149524, 8514580104850791069, 13475546435959911551, 16830415514927835337, 12164645914672292987, 13192574193032437705, 4604554596675732269, 0, 0, 0, 0, 0, 0, 1, 0, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 401642074298203, 40, 40, 0, 0, 0, 0, 0, 0, 4, 0, 0, 1, 0, 1, 0, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 2, 0, 0, 0, 0, 0, 3, 1, 1, 0, 1, 1, 0, 1, 3137828705454, 1, 0, 0, 0, 0, 0, 0, 1, 3, 0, 0, 0, 0, 1, 0, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 3, 0, 0, 0, 0, 0, 3, 0, 1, 1, 1, 0, 1, 0, 24514286761, 1, 0, 0, 0, 0, 0, 0, 1, 2, 1, 0, 0, 0, 0, 0, 40, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 2, 1, 4, 0, 0, 0, 0, 0, 3, 1, 0, 0, 1, 0, 1, 0, 191517865, 1, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 5, 0, 0, 0, 0, 0, 3, 1, 0, 0, 1, 0, 1, 0, 1496233, 1, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 8451315773087502901, 3716949716844628593, 10394526050930609580, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 6, 0, 0, 0, 0, 0, 3, 1, 0, 0, 1, 0, 1, 0, 11689, 1, 0, 0, 0, 0, 0, 0, 1, 2, 4, 0, 0, 0, 0, 0, 3716949716844628593, 10394526050930609580, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 7, 0, 0, 0, 0, 0, 3, 1, 0, 0, 1, 0, 1, 0, 91, 1, 0, 0, 0, 0, 0, 0, 1, 2, 5, 0, 0, 0, 0, 0, 10394526050930609580, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 8, 0, 0, 0, 0, 0, 3, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 2, 6, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 9, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 7, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 8, 1, 10, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 8, 1, 11, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 1, 1, 1, 3987768130567869605, 17866922374020149524, 8514580104850791069, 13475546435959911551, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 8, 1, 12, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 8, 1, 13, 13, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 5, 0, 1, 1, 0, 1, 0, 1, 8, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 14, 13, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 7, 0, 0, 0, 1, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 15, 13, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 7, 0, 0, 0, 0, 1, 1, 1, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 16, 13, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 5, 0, 0, 0, 0, 1, 1, 1, 16830415514927835337, 12164645914672292987, 13192574193032437705, 4604554596675732269, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 17, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 31, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 33, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 39, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 43, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 47, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 50, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 51, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 53, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 54, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 55, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 59, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 60, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 61, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 67, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 69, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 70, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 71, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 72, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 73, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 74, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 75, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 76, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 77, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 78, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 79, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 81, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 82, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 83, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 86, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 87, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 88, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 89, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 90, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 91, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 92, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 93, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 94, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 97, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 98, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 99, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 101, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 102, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 103, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 104, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 105, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 106, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 107, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 108, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 109, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 110, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 111, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 112, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 113, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 114, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 115, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 116, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 117, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 118, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 119, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 120, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 121, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 122, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 123, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 124, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 125, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 126, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 127, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0], chiplets_rm: [1, 1, 0, 0, 3987768130567869605, 17866922374020149524, 8514580104850791069, 13475546435959911551, 16830415514927835337, 12164645914672292987, 13192574193032437705, 4604554596675732269, 0, 87, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 17706856450849328104, 14041629472916080872, 17169788735560756890, 10821476187673211944, 4183993524573793794, 16789443777672453768, 2161849376993207123, 5833790386150273010, 0, 0, 1, 0, 0, 1, 1, 0, 0, 401642074298203, 40, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 3987768130567869605, 17866922374020149524, 8514580104850791069, 13475546435959911551, 7789855707707231369, 4610326148461237922, 1784941811671601269, 9924745492516640019, 7791549396364371277, 2968443994649453078, 1308562153347600605, 4332337354844628651, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 92, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 16830415514927835337, 12164645914672292987, 13192574193032437705, 4604554596675732269, 7157681808383834781, 13054530803491118896, 15318932090721652605, 12540678638271855535, 5420606508990450533, 8111458574185220575, 1323824759339937182, 8059544659088724214, 0, 0, 1, 0, 0, 1, 1, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 1244837894821529086, 14023738310468542470, 9319458442815716445, 5220020845190256514, 18381067342435073896, 15418184987737128626, 17753079332212842976, 12382717352847060954, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 92, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 5484645610689645032, 17933046996545101157, 16339706652094815250, 13544759331160301838, 8141870999174257740, 14107144578121799305, 396274001381699938, 3634103446560049839, 12745031702117932636, 7036828309739934078, 17841617974172171166, 16843483981996999201, 1, 0, 0, 0, 1, 0, 0, 0, 0, 12255467604292037599, 3221298496122688675, 18213293887213037791, 10454832113088907686, 14197766824477982368, 12632563328014721824, 15223540981653283332, 8415652435043313252, 15072376706785505714, 499064301441796851, 6019679623316230571, 2863989181285908285, 1, 0, 0, 0, 1, 0, 0, 0, 0, 3504307811212845679, 9887651557123705338, 15415704462638107150, 10451874340315180119, 14715205669302787941, 676415209440449451, 13877510800170645203, 5795890553064646410, 8168893483976559005, 11011177719900268394, 3075618990528033611, 13809591299651900358, 1, 0, 0, 0, 1, 0, 11532942913722119887, 15706785780181646320, 8500217623199961915, 16385837637275803212, 12589553581452432263, 9328358778203457601, 4811677924202588651, 15954150986266248336, 13054476292017527619, 13801463134030240262, 1165498946375484511, 12668987530028315258, 9041501660033602067, 11828980449399846157, 712948025072919412, 1, 0, 0, 0, 1, 0, 13546468777259703303, 2130139338200141332, 1677916746575397392, 15603598095391109763, 8982008132746506464, 9534409456230159171, 15953027744665381494, 2210202967686246336, 18201859605319735335, 2613650507633583447, 13470511188219884259, 17792240681335161918, 5597430705303759588, 17058784685043687544, 18076014205743588541, 1, 0, 0, 0, 1, 0, 17150592872874668692, 373328191372179539, 9925944180761826662, 4881622279674020310, 1461351575215552783, 7028330826866827934, 17321922102323360926, 11861279589925081154, 4211482457682169121, 857582657567428474, 6294745292695606830, 3964499899330796305, 8694904038920718173, 12798363385221373595, 11519040844019198794, 1, 0, 0, 0, 1, 0, 17812065447696919081, 10476573304851565336, 4050248765677305785, 3052409033334460214, 17899456176840307949, 14272332536807405334, 5268789410078450933, 1960893658848125895, 10357280402715567165, 1946175234480737485, 3509255218615138356, 13648578922017807026, 1792108781827785515, 7848717464050352065, 2115979595816627252, 1, 0, 0, 0, 1, 0, 14304145735363415364, 3123264749675353443, 15633057486969346389, 5590715938569744686, 16360479359047183989, 17571597847320321793, 7491081885321669942, 2792014203761376516, 7481817557178743487, 14182256043130615816, 2113355324306522062, 7590704234440296353, 6731946370858393481, 2307380299587089154, 1457958177788302268, 1, 0, 0, 0, 1, 0, 9128626640352709923, 17530806268802285328, 5521142562674286822, 7672965447668905839, 18202802305345820600, 10939917215126760263, 5454274694799635961, 15045803504594761609, 6031972736818829176, 6487707463900256145, 6513518689484649191, 12115325694601327017, 2589258613727050076, 9795696285187372082, 9346079458114114095, 1, 0, 0, 0, 1, 0, 3585032113304036127, 878423030197307407, 7753214053553689965, 13826096403235050003, 13292980836066262078, 17878862886173733195, 17335963671141011125, 15552187222984804077, 8300146209691975643, 14310135663256964431, 5324444741120757504, 15200025136962894389, 9211865123544848832, 757820306026356015, 15906091739671321314, 1, 0, 0, 0, 1, 0, 5864686728114583749, 0, 0, 9139354100126637124, 11662388403276284204, 1053421858759551477, 14098346563780750400, 5067426764888134185, 6134229022916026981, 16277189846925996385, 13161575946730874384, 8492889920316449728, 8738608316156486979, 11361904455207330488, 4644160712918564720, 1, 0, 0, 0, 1, 0, 0, 0, 0, 15069412541248179329, 17636221918015671474, 2493488421765413820, 14256642798665897034, 13029707287964752636, 9441335230719905711, 12416439742779279248, 10080344719141565596, 10015871472133787582, 394932958898495590, 2354587967963224922, 18089767607933127470, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1637053654417823543, 820038718609189039, 339980141328036028, 10322493293137382631, 12718954196218876787, 6796168876136445697, 15420463740865030232, 3252331356198972205, 14227267699888656475, 2559427160509359301, 17590552952398131648, 159003707103255077, 1, 0, 0, 0, 1, 0, 0, 0, 0, 3016912966792386460, 4113629697054036494, 8930528385757741316, 3280375997019352338, 13486210659622411055, 15849561705591959734, 12565096618949859493, 317383372660570130, 13178345540153474546, 7712839197105005349, 13963542465081735925, 5137866587539026744, 1, 0, 0, 0, 1, 0, 0, 0, 0, 16830415514927835337, 12164645914672292987, 13192574193032437705, 4604554596675732269, 7157681808383834781, 13054530803491118896, 15318932090721652605, 12540678638271855535, 5420606508990450533, 8111458574185220575, 1323824759339937182, 8059544659088724214, 1, 0, 0, 0, 1, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1532070872953744281, 11675978725956395507, 8258108365434236190, 8977540451988253054, 8832291907404336605, 16801197610032323372, 8498902414702613411, 2217861947967210820, 14648106445605106304, 5194857384255130698, 4543357020291533691, 1677011855369223059, 1, 0, 0, 0, 1, 0, 0, 0, 0, 18164368745351378969, 665130184182531292, 14548211377038648988, 9026463808500414994, 12372059324693434695, 8512906579977137276, 10951940384741553765, 2990681100436043903, 15463650459774420968, 6115025020360005524, 13619612156045325099, 9915559200666512746, 1, 0, 0, 0, 1, 0, 0, 0, 0, 73542357038484620, 16275608702285065538, 15615370514429573107, 11554047591217380375, 9626234372118459069, 14043139718664795091, 7172345985251039651, 13714446996516992992, 14079807935308074442, 17175342044195045043, 16936021968982853164, 3883665509408281322, 1, 0, 0, 0, 1, 0, 8133824218287649370, 1205363866316521559, 7923953289074004648, 1611370566290075655, 12516876786630134052, 16156412840636435500, 16066365782016562356, 12209717470970729826, 648151295134950813, 8424608506935970051, 941071657155810425, 12476535243066524999, 13046835168670418046, 13563090428318398174, 10213204276953300366, 1, 0, 0, 0, 1, 0, 11656233811569695541, 16780366708706866018, 10469348806910132738, 12317597613336433996, 16800450568443907772, 7958196127911254005, 5580405360121542127, 17991322909541306091, 9587008055009063413, 917862094456531518, 17636182943787095305, 5347924966817937746, 15791860137463552476, 5352122275530338033, 8207615265206228485, 1, 0, 0, 0, 1, 0, 13280747180546192023, 13818056542207317059, 12768869371961439487, 2029833730308772760, 3067168931363951888, 630426464913806566, 13807710542081112496, 10340529818978391824, 8301137772228612306, 18032943025979156234, 5571856761516233924, 15102755171792177729, 1386022355796901548, 10780164990569095481, 14005839963275167003, 1, 0, 0, 0, 1, 0, 8161514060541966002, 5430054846479849757, 855673369941768792, 8583346124368767357, 7152703336258374657, 4793816855328822248, 1475819744300266017, 5162097063446717296, 9158417383194264473, 17323069022182310843, 17309666448184518221, 16540233824244985004, 13271685073550397851, 3683818685539825395, 12883632168742702763, 1, 0, 0, 0, 1, 0, 14889661894667616899, 13319328534492736282, 511216470843933116, 5414088302741599345, 16030190225904238830, 6111859869108706126, 4321093113239299552, 4706826096768711507, 11021679444547674749, 15678561454143187205, 15168765916033556420, 7046395423559884948, 3431032212531228618, 9443306432483343000, 6291224588853575811, 1, 0, 0, 0, 1, 0, 11384512740043719026, 17996531901144166752, 4183594834611630116, 17695445402585642319, 15258305803668890228, 17106752205417894410, 13259786553689259064, 15859967842550332610, 5138368225191856866, 8345451659183769670, 4299979085769618674, 10058172520180004407, 16132576493934338934, 312707111584502977, 8025187035739711204, 1, 0, 0, 0, 1, 0, 17152042124522816142, 9826569971726481595, 8959076337043698126, 1987260706895490300, 17423289859865292784, 12258188545233319580, 4291864820252135891, 2950910453815263271, 852440029525711434, 1223549137263517018, 605327998629874385, 3009980753663636725, 8722464778364467857, 17216818427461180092, 13380853612843880678, 1, 0, 0, 0, 1, 0, 7979264206910945674, 0, 0, 7448791324579059841, 1050285053399784347, 16767087000176263535, 14849165193424062452, 2498996933077132011, 13658177069616805094, 495936213960522537, 13576872019913404781, 7640966386182958606, 4271515987309482058, 13463445006653778819, 12292225704634605892, 1, 0, 0, 0, 1, 0, 0, 0, 0, 6053040396430810733, 2172892474788961636, 18161859984545851402, 13488248907260320483, 8430623432188198915, 3055646124754645267, 4245215712607391946, 2243958878529225177, 14990440908620774864, 3080921390696878855, 595284666932255390, 6192940699035995377, 1, 0, 0, 0, 1, 0, 0, 0, 0, 14921496778760644502, 16662036864627516510, 6434377642684009725, 1840544361770929313, 15074823591915634941, 5258982948465254673, 2683768063818053258, 238295676214993337, 17552036469726894364, 15877921873938893194, 14734786106453693759, 1371624439541100057, 1, 0, 0, 0, 1, 0, 0, 0, 0, 516742705862090749, 5947805230277704319, 5952541516123965670, 9026915957393505056, 5986317686192419732, 75717367401824328, 8923961895635206791, 17106810061565988432, 7157463081631406163, 150940732863733992, 15657864298531798718, 12227344478922314236, 1, 0, 0, 0, 1, 0, 0, 0, 0, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 1244837894821529086, 14023738310468542470, 9319458442815716445, 5220020845190256514, 18381067342435073896, 15418184987737128626, 17753079332212842976, 12382717352847060954, 1, 0, 0, 0, 1, 0, 0, 0, 0, 401642074298203, 40, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 5792301967904643716, 14513996957604530562, 6300577652167374432, 1030532363437082530, 9868636994953646365, 13312054463817713847, 1163060834237983926, 17159751124589539180, 15748271025379903662, 15673345155938926996, 15542740004802895548, 4070736982096634948, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1453121677659348577, 17403066345171442603, 9526966027631081464, 4562917345183859100, 16736668858502190206, 12710250320191836356, 9043028743666878997, 9570842800862454404, 10889819954451461225, 1374882310944969176, 11041329929342678296, 6376909268692149801, 1, 0, 0, 0, 1, 0, 0, 0, 0, 6798464049283172704, 10094602609597426273, 5441108908322692152, 13319823174770042865, 3687504758717747002, 11828007000931365406, 15642196062511550808, 4387538442135057894, 12016453509822632603, 16688879161845796765, 15353663875595798268, 9433687029957117661, 1, 0, 0, 0, 1, 0, 11436455846193695609, 17419948132223780613, 10707930966158261719, 7805136509413905123, 10748223278202845625, 5102455166015213038, 16060345288112427467, 9937020917196030767, 13713675713530315700, 11873887283723171030, 6245447289360608210, 2758175399376775060, 6794131889413756751, 6954584401067417189, 5092580402017360453, 1, 0, 0, 0, 1, 0, 138168370802146349, 561179642041056504, 13282391328952434407, 3586306435690112870, 17278658194357811156, 2504635638454636683, 7235500145280211409, 11191458759516692993, 6465450803792948194, 2111071922636782066, 11802465958807233213, 9116942394473193925, 11145482942031811955, 14726020691764699927, 16903672043479974450, 1, 0, 0, 0, 1, 0, 263960295682680947, 15697220842527476860, 17868088579823291326, 2175933588395873247, 8749749468735109989, 11010166446741390499, 17943104442301856895, 15821423767384514021, 16018668147064525478, 5560768172433028490, 5619212355349254932, 17391285462458271036, 2603291588626814071, 5238953246197227863, 5602891381109897586, 1, 0, 0, 0, 1, 0, 12301036190174877474, 12651281118484863330, 11983275442902746825, 9125195986387370903, 2181062690427536463, 13921861517061570826, 350891571660248295, 11013048057925712708, 11055047889476803308, 15398332646604634982, 5808711407549689243, 8949777591082911961, 14824627964979845981, 8130365156760288485, 3947069696768920416, 1, 0, 0, 0, 1, 0, 753507401801380169, 11557202300537182401, 12635550211207024884, 13277984171307670821, 2631795936834054713, 14094327291919754106, 12673624581190519723, 4509450209340246689, 10606486226190872261, 889124163739951988, 12547380261461657128, 16829937485708676196, 15832095999334895743, 5377353767201125639, 11053610747785598805, 1, 0, 0, 0, 1, 0, 17726880391953768878, 13956049620380258223, 11273932727072475337, 6855896085734577371, 1129400045567810133, 16519057148475618054, 10699416941054230316, 17256608828803451668, 6887723245936746466, 552364255868028623, 17909079490987407142, 9570595819850351164, 8654686163127378448, 16203109760043627710, 8480295614280342552, 1, 0, 0, 0, 1, 0, 5047048529377126902, 2720906371958061367, 10084181298533567509, 10367672116357405411, 11036446985399396097, 13294567520571596163, 17521531050433436007, 1868701710513242496, 5411603901210245247, 11609599138736895146, 16874855234706410918, 4393409689646403917, 9543195090298605247, 7478523150127634789, 2693101708644875762, 1, 0, 0, 0, 1, 0, 3528724572660247995, 0, 0, 12432722351030045, 1367308201666984940, 3681473655802754494, 15340518851882934883, 12978887161137913348, 15761699408266065961, 3053535844413236872, 13043307337058007179, 1605626291192886407, 3512088686484392896, 17370072541480613908, 15945489250832697271, 1, 0, 0, 0, 1, 0, 0, 0, 0, 18236855931369748683, 5145738009993425605, 9599849581440088949, 7181962801200058100, 7842895042061868932, 12656177266019986902, 8530248384503061153, 7088178758240165913, 8843525768370306419, 9760798177389960884, 15297557810674980998, 17513790474795511142, 1, 0, 0, 0, 1, 0, 0, 0, 0, 11582029127760482436, 12210748157899031357, 9473509448225646970, 17514007687115301207, 15252116786733410669, 10068681917011840638, 5010610666981558682, 14100290159714849481, 10038370148733513877, 4164887708143705047, 12759194225663538416, 5155504400103783318, 1, 0, 0, 0, 1, 0, 0, 0, 0, 2256431941220947766, 13487119117857302457, 10370113277604876234, 1506538453550143326, 9611088164777633619, 9944172425891749050, 2585766031776029836, 7469792865149057403, 3748706915022560085, 480217827283441208, 7902514309755880799, 16608422580379539141, 1, 0, 0, 0, 1, 0, 0, 0, 0, 3987768130567869605, 17866922374020149524, 8514580104850791069, 13475546435959911551, 7789855707707231369, 4610326148461237922, 1784941811671601269, 9924745492516640019, 7791549396364371277, 2968443994649453078, 1308562153347600605, 4332337354844628651, 1, 0, 0, 0, 1, 0, 0, 0, 0, 3987768130567869605, 17866922374020149524, 8514580104850791069, 13475546435959911551, 16830415514927835337, 12164645914672292987, 13192574193032437705, 4604554596675732269, 0, 87, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 8975931939487847577, 826624107367617870, 6313882907599268049, 12374350641898187577, 6034656875513245768, 2025404333603011219, 5567780117684101433, 10039943328136801127, 14519832948855618026, 8345489883032353865, 1527060375424943961, 12170781137980926170, 1, 0, 0, 0, 1, 0, 0, 0, 0, 18439179491774692160, 5894239126603330321, 4540558979809060030, 10279540138716552456, 987473941784029527, 12525995964141116915, 5290090394268808541, 306655326230637762, 16338547772125377607, 11596138255917963766, 8713064878787635294, 14621378300733812762, 1, 0, 0, 0, 1, 0, 0, 0, 0, 8625597143277853412, 13696710862406782461, 7964746106575152337, 2172419373723337128, 8054193852364041914, 13837151904574880265, 12082541315152330288, 459946368827837708, 13160722284184094440, 266800667110584625, 14057659934195137969, 2295454423550348086, 1, 0, 0, 0, 1, 0, 12664681110997539525, 17076348030538024207, 5540238696466037530, 12503523823545562389, 174867091135528982, 16590140589764950480, 8259361233182789197, 11645736243489132578, 14290054611959227376, 9180054963981299553, 7522469136295030791, 7105443855795968859, 891467184376357898, 17670655597278868995, 2342025702421944092, 1, 0, 0, 0, 1, 0, 6508510408052687169, 6204789958331974035, 9346507142457173461, 4301401385637777690, 14660092386018225126, 12495473851795317931, 5022633921442224796, 17917849216228407802, 12792959527605319782, 15230911336735940949, 8204016232934091863, 15412033900392896865, 3505376367314785905, 6238911281890404928, 5298514099659693687, 1, 0, 0, 0, 1, 0, 13799242140675876876, 11967308820225399198, 2683546121072105123, 1729755848300507463, 12870359338704016369, 8941470466611331698, 2180957237381332114, 15146008237095844208, 16160269208928910981, 18327684313482854134, 16833658748571454034, 2228273861931392047, 15731171584455796770, 995005991601822991, 1325734405437759991, 1, 0, 0, 0, 1, 0, 17987851369139942407, 13398331003343876993, 5367943995780444036, 2448619251293596415, 6376925844201940434, 4660951209572130343, 6692287909250102466, 14264867975601246507, 7450682030114986603, 13850479752308263747, 2354486568908427148, 15162745955260128567, 7073739487284518498, 7349823339847667270, 7432121536738542934, 1, 0, 0, 0, 1, 0, 12779330473845195196, 13333298498050625857, 8497017356295886418, 198682296436078421, 6785250810511202548, 8675942375264798154, 1902172958020633282, 13878123715732752934, 2669364003539959841, 2919541857723463762, 15553639772246407252, 4490985143636591731, 14759010930598801048, 3644113642401147053, 11725546181585461527, 1, 0, 0, 0, 1, 0, 4348612304082720967, 7000799207553416727, 409433143803986808, 11098012124426545813, 13705626808705343574, 14914614989311581118, 15856657657850435817, 15647302365239384916, 1922093161120523126, 16304799558618217551, 2058076621629364563, 13235199499072181459, 2014579064718604783, 17528668302117330167, 4502687057104666043, 1, 0, 0, 0, 1, 0, 4374227242554438847, 11512800943126678297, 5364118459222264456, 15735518607595531127, 17687628157036575189, 4316235176215213500, 16328191111758429737, 8296514219182559014, 4219319863447058339, 17792101410240385031, 5877693942919568575, 362532686167476669, 9295444241326410471, 13461509482997484750, 2976690162409908995, 1, 0, 0, 0, 1, 0, 7104659116945783510, 0, 0, 16126650333942571964, 5373159454984485726, 8554791451595603222, 13040170352872131666, 6964722638533720778, 16565181844214358545, 5358624883000304708, 9590418361165280265, 9589196611956250594, 8187047052130427056, 2952681060946246957, 2014692216792503027, 1, 0, 0, 0, 1, 0, 0, 0, 0, 12840173240488470337, 1377635413060797359, 305354737769078594, 2796157645377513585, 17792025031160030650, 4262069196839993466, 15334521966674573711, 10417895735626853679, 15985686557567316940, 9198468442856654979, 18432371762950474462, 3913809235807315417, 1, 0, 0, 0, 1, 0, 0, 0, 0, 14482582745895144215, 1416945927177854081, 14328454743983709378, 2239851991461863112, 14449374510435378, 103561798029274946, 8636099973921767577, 18014864567131597051, 3269781373289032262, 11277949075475123849, 18052298919183707862, 1465413476437382760, 1, 0, 0, 0, 1, 0, 0, 0, 0, 17039932339331186847, 17502136381770894171, 9167041279176111993, 5466495695730086964, 16979151180084274449, 12264098443872388690, 7613839079126372753, 8653310637125687540, 13994165437176517647, 8342109517639396353, 1226521077945764801, 2704640960151854871, 1, 0, 0, 0, 1, 0, 0, 0, 0, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 17706856450849328104, 14041629472916080872, 17169788735560756890, 10821476187673211944, 4183993524573793794, 16789443777672453768, 2161849376993207123, 5833790386150273010, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 40, 0, 0, 3, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 1, 0, 1, 1, 10, 0, 0, 0, 1, 0, 1, 1, 0, 40, 0, 0, 12, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 9, 0, 4099276459869907627, 1, 10, 0, 0, 0, 1, 0, 0, 0, 13, 4294967292, 0, 1, 12, 0, 0, 2147483648, 0, 13, 0, 11351842504255128813, 0, 65535, 16383, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], range_checker_cols: [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 1, 0, 0, 0, 1, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 7, 8, 9, 10, 13, 2200, 4387, 6574, 8761, 10948, 13135, 15322, 16051, 16294, 16375, 16378, 16381, 16382, 16383, 18570, 20757, 22944, 25131, 27318, 29505, 31692, 33879, 36066, 38253, 40440, 42627, 44814, 47001, 49188, 51375, 53562, 55749, 57936, 60123, 62310, 64497, 65226, 65469, 65496, 65523, 65532, 65535, 65535]], num_rows: 128 }, last_program_row: RowIndex(18) }, program_info: ProgramInfo { program_hash: Word([10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993]), kernel: Kernel([]) }, stack_outputs: StackOutputs { elements: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, precompile_requests: [], final_precompile_transcript: PrecompileTranscript { state: Word([0, 0, 0, 0]) }, trace_len_summary: TraceLenSummary { main_trace_len: 19, range_trace_len: 51, chiplets_trace_len: ChipletsLengths { hash_chiplet_len: 80, bitwise_chiplet_len: 0, memory_chiplet_len: 3, ace_chiplet_len: 0, kernel_rom_len: 0 } } } diff --git a/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_25.snap b/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_25.snap index 2d5bc4bfe7..d7925f3428 100644 --- a/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_25.snap +++ b/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_25.snap @@ -2,4 +2,4 @@ source: processor/src/trace/parallel/tests.rs expression: DeterministicTrace(&trace_from_fragments) --- -ExecutionTrace { main_trace: MainTrace { columns: ColMatrix { columns: [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3358534066525179769, 3358534066525179769, 3358534066525179769, 3358534066525179769, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9365253138981608257, 9365253138981608257, 9365253138981608257, 9365253138981608257, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4243893038989355703, 4243893038989355703, 4243893038989355703, 4243893038989355703, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2372900269115514267, 2372900269115514267, 2372900269115514267, 2372900269115514267, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 1, 65, 97, 97, 65, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [5482243896119908732, 401642074298203, 3137828705454, 24514286761, 191517865, 1496233, 11689, 91, 0, 0, 0, 5482243896119908732, 3358534066525179769, 8, 0, 3358534066525179769, 14319792288905293245, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220, 4192437018821097220], [17271741639510569126, 40, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17271741639510569126, 9365253138981608257, 0, 65, 9365253138981608257, 11465345153771181037, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864, 9480578168622006864], [10627125303494028926, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10627125303494028926, 4243893038989355703, 0, 0, 4243893038989355703, 16104169334207009019, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481, 4891889892170146481], [12334791106787903660, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12334791106787903660, 2372900269115514267, 0, 0, 2372900269115514267, 2750797734633655770, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240, 11712807151087072240], [14319792288905293245, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [11465345153771181037, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [16104169334207009019, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [2750797734633655770, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 4, 3, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [3358534066525179769, 3358534066525179769, 3358534066525179769, 40, 3358534066525179769, 9365253138981608257, 4243893038989355703, 2372900269115514267, 0, 40, 40, 40, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [9365253138981608257, 9365253138981608257, 9365253138981608257, 3358534066525179769, 9365253138981608257, 4243893038989355703, 2372900269115514267, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [4243893038989355703, 4243893038989355703, 4243893038989355703, 9365253138981608257, 4243893038989355703, 2372900269115514267, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [2372900269115514267, 2372900269115514267, 2372900269115514267, 4243893038989355703, 2372900269115514267, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 2372900269115514267, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [16, 16, 16, 17, 16, 16, 16, 16, 16, 17, 17, 17, 17, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16], [0, 0, 0, 2, 0, 0, 0, 0, 0, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 7, 8, 9, 12, 13, 2200, 4387, 6574, 8761, 10948, 13135, 15322, 17509, 19696, 21883, 24070, 26257, 28444, 30631, 32818, 35005, 37192, 39379, 41566, 43753, 45940, 48127, 50314, 52501, 54688, 56875, 59062, 61249, 63436, 64165, 64894, 65137, 65380, 65461, 65488, 65515, 65524, 65533, 65534, 65535, 65535], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [5482243896119908732, 14700437138657715688, 4194228403373198226, 4321424756204952178, 17106991433953495229, 480007043786623808, 9077933169163287651, 10301794879477559358, 7837641036032671415, 9957661348832415284, 3403527796290311921, 8465759122953264103, 9491055353357939181, 14342984469850983837, 9771451080159159411, 8537706246195014625, 11423410855123831518, 17765926817646991510, 8321792161956545451, 13783267673851502179, 4529776878769021619, 8116795789739369570, 3611313486028920718, 14057252888063062893, 13188102157225090063, 40859616366247747, 9776318485951152693, 14134961488520769281, 14580812564900766592, 6012095218278392893, 12583880807825187559, 4192437018821097220, 401642074298203, 4016420742982670, 14280802901810915241, 7925919485060883878, 9094034340168608638, 6650811367268781560, 13344927435882217244, 15870694671012449597, 13091389828882674218, 168434371192049215, 13973668876111195937, 680445747454648704, 15441309962929722976, 15749770188837954531, 5233297770622824375, 3367253731665130938, 5066484463076591248, 9867160564810673994, 16707816004584596036, 6832899290197418961, 10263347723858682786, 6209209797490182000, 8678413656546712232, 9643915442530902318, 17208626611000903707, 11389822518212260982, 887493237489321299, 48736118273260452, 13483864438078018308, 8159241411748295729, 10385528691577928985, 5482243896119908732, 0, 644, 13398731741387911383, 1702596310854469483, 5960531672215414966, 14152498107176274636, 12742762049153184106, 747050504586908561, 5800650255543088287, 16122619596578164144, 6772875084421984040, 288495594474105189, 8600976689152153054, 3411751581427101134, 10304697226126818963, 3398791421797336513, 4476944395780698788, 7796778119718125747, 5617773719451830708, 18153429098783777295, 11043847812690714922, 1719133760987188643, 10906522308373106683, 16409243384953073963, 916060433516903836, 6973907531599316043, 9109780042108713794, 17099296735351468833, 15306362721670767113, 2730832614768234730, 479016032615721743, 14319792288905293245, 8, 80, 16253482711025978099, 16690839578921925157, 11755424915479552417, 17934377671577204140, 15509754874715907467, 6426721221030580337, 11049594146888643723, 14912334368661229147, 17657273147290084056, 9105126057127804171, 13430225876739607206, 3614830725909060912, 14569284676797348998, 4705513459362295944, 424917224365117418, 2835737623710330612, 1964100172858915134, 14896843043547784767, 15482419984058848245, 18437547705335910066, 3162257106529980441, 5297995970636059087, 9661978795293871188, 10128143329575104151, 770728251595531533, 9782965673735423214, 1347942901513492691, 12086966446141742548, 10239457018222882008, 3358534066525179769, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [17271741639510569126, 17693777214203449670, 17446294671039685780, 12180657588796280274, 3901851127268644692, 15132938321031306327, 4529077938382910243, 1349343284414021678, 12010127700996563076, 3802141577517901644, 10153500743657060380, 1665683881724788425, 2536206416673670232, 6321132288631485459, 1484367395490874035, 9791226137836052251, 10111774824823842282, 16052656468702535281, 10276660848524574906, 11241218962943578830, 169695422976636841, 7241344066748902545, 3569311910587147072, 8215766650263520356, 2619309237284639419, 1962296512232188159, 12890305973496102809, 11438817727011493827, 15861640058126249653, 14517213901488835116, 6582109139928846076, 9480578168622006864, 40, 3213136594386184, 1835177830541154044, 826263100281998566, 9612296353153372169, 2509054224639990472, 11363599377854067153, 5593295816013818122, 4611398810491526224, 17064807786960234347, 18427889571151062396, 10159688738464070440, 14427917509182297997, 6874689601963577621, 745298233749984501, 4960831845018172313, 1451394763904737446, 17942681985602265676, 17508193444101172646, 1672370857206926433, 10152063658776528390, 14576660961872281746, 13602838247655372264, 5274902253855511588, 3163862752932557920, 7292072545764012550, 6033538369482377655, 10941848106600998110, 3570589185097006252, 4587292818271677447, 16771298688176486904, 17271741639510569126, 0, 552, 10446875550887438149, 7588826506897155585, 16730914921892092280, 12511176149634059683, 1758801585754904665, 5885085633120358478, 12242421290212925246, 17368642390815603411, 11245463457685625563, 2659747577123257435, 11347669259219881571, 15449337489158534519, 17510270622758876933, 18027674089872559881, 16436012900980393273, 17430549031516796763, 17674101567742383712, 4643493040432393957, 15750016999752216538, 5970778449527916441, 7406085958721442119, 8823739942223974350, 12296950126673436366, 8362221384115403494, 2025584296720659827, 17113734046007416651, 3678646409353890898, 10191942812097658700, 1453528547827258310, 11465345153771181037, 0, 64, 5751576643258238090, 7830268710878889486, 4868320831660690795, 7042762868047858013, 1028615964620729689, 12270587957620579653, 7267371538363991280, 16125626865182516658, 16950134439933558852, 13427183447069512151, 16117382505273595827, 2222792985740553749, 6517696895688418945, 15516128650333221731, 6357034143715229949, 12960707821770488929, 12451444460344609421, 8786747128188560390, 7634329044629047826, 7741107824034642016, 10975559322169081956, 6007758954686348362, 13971256108093330407, 16868860295450858142, 434120282701603474, 11571634562637977474, 5581285869985960561, 6581368197537384623, 17661012293298952642, 9365253138981608257, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [10627125303494028926, 7089946709940699513, 16018419181163655201, 16144413208110066321, 12517012706582615280, 17466716576309862393, 18120522547066464513, 3133443529903863473, 15879773433331271008, 15058242802738637389, 16107648145131258558, 17940570471380392799, 4146898483110117869, 13355141649182107533, 4502835184975000914, 11529786935650512206, 6872828020563546843, 4179930870000296671, 14088376982248436722, 3284393269772901229, 9233870580127604406, 8040351000384949099, 2082747769118638584, 9037700404196650899, 17868569356942562984, 3031609089566191882, 15372246715962319753, 5259611931696930736, 14882250288085472215, 10288285656672707851, 11046557109431487119, 4891889892170146481, 40, 803284148597046, 10010111294767420802, 16943179644353820008, 8996122336997085030, 17350347680949584060, 13520911097528541892, 14769691589967587136, 81685142906752346, 7559897225353479520, 128512095027132822, 9792116363139842106, 4634576985104787587, 8679380235287294885, 1134592111928495305, 4684288247441474792, 15613043314698948257, 4841731940180862534, 5786518576333159075, 12666070374819933283, 2487841274273895537, 5690982477694717281, 5924572671969496500, 8629130978595053833, 18206699227813987098, 14234831161984809711, 16798226782780142546, 9330568307929665420, 9731250716956559616, 12286920896461242142, 1919835269886444210, 10627125303494028926, 0, 276, 5572533910279649175, 2665502751151845058, 3420041171743926975, 13105841064724313047, 10443718589068788975, 16410831941400613845, 8706919134091371207, 5424121700527660040, 12860111264033880808, 468662522013222574, 14746212538756510443, 1337341156189505070, 5208953037158023510, 6068232083162993748, 9678821925451981470, 17715598857116570054, 17221271024145736360, 1975930269787186400, 3526946062060894178, 12647721578094853267, 13858063547960126340, 1348240088196356067, 15972449905513110374, 2515565498382079126, 9279746140911612054, 3713543423691008796, 3233112695116768266, 1858231082388626584, 17742257866254572336, 16104169334207009019, 0, 16, 7110029021941723513, 10115409991715085575, 11428668827299215140, 4015039023438705588, 3732466887400149035, 5870841944205588609, 8421627027326523148, 8231214549142439222, 10318470559229280016, 15171283498151438808, 12477430934852872037, 3853779543897991795, 14662750186533371679, 7423988381383082226, 13549468426633458145, 11079168775731474830, 12471207782095033761, 17595325414333663547, 7042468264080735391, 17650115337646869205, 14946074228061446423, 4655654314239637986, 11187552516160183253, 18115881480442018545, 899748567092010447, 14020868337400209874, 15417366235984526759, 3331301994171189600, 15814677761660135474, 4243893038989355703, 40, 40, 4294967292, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [12334791106787903660, 16314186579682789689, 16046055491183908407, 6937908670684349781, 9428962583778419369, 12671344758477488595, 7729650243590863324, 11715634485135010533, 2133167353214657976, 4100349204869170028, 14110128220081934719, 3223264940814324611, 4013852846792290230, 3963283702543497203, 11663083613788432971, 7907953758158564716, 13628053756450739862, 11139084033219732849, 3452979822093558380, 14346711487449348492, 15207411620676648511, 501329811930827740, 7758369216397164239, 10815732145433955496, 4610905976152412334, 17935722133204612030, 4407166322243232537, 13210703243795283421, 2674423901749705077, 3504222453682520691, 2024557484059292221, 11712807151087072240, 0, 803284148596806, 2549897079792572603, 5670682422759337153, 4249626004536644548, 9138873913574622404, 1343119293110958009, 15707367360995172765, 2149720931386886989, 12579497520806083785, 14990373923527496282, 7330871518527332444, 5790961380321049961, 5495469617420264118, 10789212522972025785, 4356961356341052500, 8032044444015716361, 5554647570062987979, 1022644107902166331, 6764324513849573852, 14002884382934858252, 14316154512513580139, 8331374540726760892, 13067519389098510351, 8671032013540344722, 13457978878695920483, 16399505509770566014, 10578307416004071064, 11950037765875050974, 12195903600484928258, 17694444981837938563, 12334791106787903660, 0, 92, 13491880295779941671, 17558274388625518928, 2846824553470173952, 3523509076537079172, 9799038632780562513, 13535672937351711649, 9746772683078209435, 16106002567881560829, 8079784996354006751, 4777591649493566963, 1345156373992429389, 15297897479538231384, 13973483607215960244, 18340152543215802049, 5000946629530062426, 15890473733699877306, 14902294728590831204, 3011516360220729965, 17542926168179991242, 6657567861688973613, 8835168761010196729, 8826324103843911331, 9882179407362466285, 11897066781203331526, 3536220024494542760, 11424483570196748419, 294092485488322279, 12149225804903469645, 3036839951080750932, 2750797734633655770, 0, 16, 3208043314804619251, 6920597847411412414, 17985619796195836408, 11907191178709112742, 16377455862733420451, 15572876043608056600, 9466912758182965715, 17480763791598773801, 15029113851915312964, 1953587265841775225, 7175742902791404624, 6820764940134875350, 16069841829669607101, 15548451706938320654, 11760680638795846495, 1560700914733041660, 762367990279432470, 2603436428456411224, 6200990949184863170, 11673627333152839295, 7804486006334068097, 1006207264024395366, 11193609705356653459, 5704515878100803393, 14918729158665343812, 10658508130485449873, 380737719356524599, 12870561906904032245, 6984680585936259437, 2372900269115514267, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [14319792288905293245, 13415211686073742374, 3149648302915651279, 2183945468601797792, 13296390406171247483, 1854573623301018325, 6584248684794021237, 16089856164543344516, 4773455775437745378, 8456999553910293319, 5311613736439167674, 332137947454970287, 18353623873984208545, 6936763828562118650, 7803450627715630286, 2809593074760044198, 17403350541234273237, 4739616627721376242, 12174946372048241570, 9146291209906782044, 16719606593630884665, 8010607335321228412, 8980769147119509995, 6575555704765488965, 5801827901371738935, 11455982787078836790, 8211250723004787137, 6151514289078604478, 17915715126849699543, 12433676256235881077, 7933147088254086263, 11509025001394472292, 0, 2008210371491335, 16850544756775285522, 652387120995254672, 4188956971131276775, 18389965100329173053, 852421464532798418, 17258729097516267384, 11347427093515448316, 13908538323250058716, 6558337355650114042, 4089976927111145333, 17816809041231283545, 12843997071522346840, 1655996231185402724, 11256141768734986569, 3019459069615110433, 16778373777892540383, 10175251160015024193, 11396702708789693017, 16481019216530994753, 5122353003150766192, 17913616556333538828, 6485826671956173957, 15738756542654855641, 12199621872357116369, 12077164016468113545, 8907315944885273345, 4878983963291132913, 1618531819557712390, 565132887411573955, 7288090792972058500, 0, 644, 8698112979694512183, 1484832724912073400, 17559905242927504135, 8301224421374966792, 9399236208058450174, 2669398055632380115, 11307131702448115253, 11217016437113601321, 5789099451732089955, 4549622233314763492, 1239065339957448367, 4175942380264380439, 14889292305938541714, 4531363562013687755, 5140869640511317393, 11140388332008156040, 9692465784954462068, 9297910418252147698, 13488989169427894096, 3552900044190654848, 6760710657831378657, 12121966587219528787, 15900962396386651595, 6608207234386334072, 8800758533265494982, 16201621108022440385, 6765154775891776468, 15354276103682076009, 7645122244202370271, 15666451408857108222, 0, 40, 18130890293586930078, 18252951749527557342, 4460903658820341507, 859505755654562117, 5961685480015386121, 12134776249586726543, 11174658189737631113, 18385152961050631924, 9881471501704199804, 9636744945302995714, 12323181865658998064, 14903454669611502952, 1490539036394497080, 11688514875590095153, 16093513520259190726, 7731471377060742735, 5247500963110975116, 5269361527156951110, 13733877647296302634, 11865469401112846356, 7643242142337524006, 15572658687280648106, 9345628789826937825, 3291248301730279223, 16808111015808513609, 16274730253017522022, 12243901590027926887, 6559275936659510680, 17224785255700525855, 1390310476158884261, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [11465345153771181037, 14098642529467391391, 5535026374122183926, 15092496102668051355, 257473274985355223, 10260436313437728882, 6731908034259211771, 11264349046953665415, 10299240179448618610, 5126151224060117218, 14121035940755315114, 8209352310311089013, 14971697601659082585, 1100050914291650821, 5035373507226681389, 16042249687109751437, 8837503665608453676, 2504937998242193140, 16526648943653417718, 2452121396486117195, 11029884787275710886, 2085781890586074785, 13162154469730856465, 7946539915965721335, 17992914229117852310, 7142641763418660559, 16732929992769459335, 1127063970169475225, 7467959617957012266, 9462884495447906259, 17277989807306885144, 1657723241998675022, 0, 1606568297193092, 1076973899277284702, 14086579741019377519, 3818478693739735842, 5593621083784091164, 11728670858811596587, 12625736484548160126, 968047239546776409, 15493380284459454506, 15542100289574010625, 15053368214221814937, 17388070103506970075, 4738318434573394804, 15389814481683087606, 14763812299525073807, 384493414835098150, 7660052382355122994, 7691788916209089905, 14721544157906502013, 737940994724202658, 3221762534387838371, 7517398897305596666, 13211005290810103003, 12141388589516060378, 13672030567886044471, 12296311093518063031, 6143526203440544581, 5554567664494429423, 12302163852964786956, 14310991091785572129, 7008881577152522467, 0, 552, 126724644436205205, 10241199256484865800, 11710755472728257079, 9814439449693896294, 4184208894850372064, 13142997752644266770, 12969767250590673327, 16308338449341618327, 2857514379308674181, 3609195066294253037, 185228684080860642, 1613944213773308204, 17903436875856263069, 4515533500061955413, 12536726874363800554, 15437904745147545753, 7830085342542866777, 6536598727940018370, 1711823131760196898, 7709623033392346991, 8552967012655997274, 8947445239291587989, 4670000389326714804, 12010856128816592344, 13269571463782090254, 13867391969199306543, 17267661857179267882, 10036416896754782473, 18012966148946012188, 5229864730287063918, 0, 32, 10452764368937945515, 6969997263492352670, 15570786589164252178, 16136993048454358354, 16378352067056606124, 11747573379431147483, 12296464969648251345, 8155132212936940581, 2470200969414032680, 18126939303114916528, 16736276280592238734, 15549342782445497049, 9033882039108268313, 5121596298161079296, 14336897502470956191, 6301009824137139871, 16614860627935231068, 10383378433371415142, 10330363517752279308, 10937466001850040595, 16305844076412050396, 7189713532379018536, 7568236447715590536, 10805187342082326609, 7424874700566577356, 13861219118264849665, 7052270251739242825, 17586339544079318164, 14071176523136369481, 12282546735285148319, 3, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [16104169334207009019, 14145804402236837957, 638510963943763558, 18152457079207292292, 13178378367745074892, 13292769663331639140, 2409570605742285812, 18386931186537975697, 6045651321104574873, 10576311525321301834, 6759560187812996269, 265277838027200178, 15857438057860901996, 1037029241838654580, 6225168341521517925, 6895514801579803384, 1550665420642344807, 3231597075356238257, 4166180297101468799, 3189361261612592850, 5442307944523583224, 12110265058053493581, 12478481205289622727, 17774723700903466966, 13236760767894900950, 1895278615969967832, 5078948249831860209, 3481261074349261153, 11754602214149170613, 1831143805055270726, 14579426980777214583, 7525141456947324339, 0, 401642074298523, 16072847024087248681, 1047399340937520223, 13840617071834531990, 13835424809772757395, 12438858367585478828, 14080077230806112448, 11208516754282785707, 7691155727086178136, 17898846423848868766, 13990233438164144322, 14765296463244153634, 10144768301469359068, 16658833476738371029, 4674204014270448977, 12722211832796318871, 492549161703070590, 13986658207276323375, 14512155514173182920, 13983563295828088546, 2440687363152463730, 15931932209781173412, 11078906302351818677, 3584926465549602493, 6813538466449503008, 2334817027508375898, 12619526317209583817, 6515674137823977144, 393947096345211186, 1951192747307666741, 7526556702499462773, 0, 276, 12147025678885387063, 1963067308825972547, 4225984201120753953, 1196744323913827820, 5548577578393956861, 12196421586952833282, 6686048917052134288, 13682276749649062124, 18305115060607268181, 15701263684091820063, 4379325401380154240, 12368723875816287010, 10456077510396891682, 15257688804823183049, 14739472440526637936, 9698983999555494854, 6114823860832404997, 17890984706651436184, 7279056890420718668, 14586346563305650786, 7193610841629628055, 794393058555157904, 8446464239566334422, 18360375401158087305, 12786208149678159110, 8127795658820139321, 10374412076721466090, 10797782388389379392, 14917361677919134410, 4435027266040030689, 0, 8, 9114363797835460134, 5446076396314160376, 12863008906537145423, 10008421878335836436, 9952321233871043669, 12872379155893703237, 7266552182027361169, 1266036355585216796, 2621902104176569009, 8791105532651972211, 6351975813451610601, 11821139808280113179, 11281913023757770338, 3277134497757048289, 13219080767636598429, 10181825490691565485, 2766637533497216499, 5527857141123489970, 8463471033597650592, 16863468430858262436, 4521466714741486225, 2112404415880305855, 6776665887355979100, 4283028800297139078, 17448147405455891940, 2672696094870261596, 654959311657763753, 15404879372302137522, 458610335793450516, 11708893791522292939, 3358534066525179769, 3358534066525179769, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [2750797734633655770, 2196298446069803466, 11838988982732965160, 8838579915162662604, 9645282237960382599, 1452793205233705375, 13043673489495767039, 6914761656747274754, 6462510494810546740, 11542677354694298953, 10084597289196425304, 6187212959913925984, 13253251914245887991, 13426752715944801915, 14540441677731288899, 1687158516877835494, 5237558114922547298, 17657306689192164966, 13600283758187380877, 498396070609474559, 2816716335908718574, 2201796413416910298, 9217066277303434638, 1438935019962455534, 18328852556584031255, 6915155572789963327, 10360494843504659614, 14112471018395370124, 4296220331020841697, 13555983847490106392, 10974207239020571710, 4762963524641036906, 0, 401642074298403, 6959791354043610236, 1843180796447728437, 9556362158826632350, 3220022195391792741, 6012411438022691140, 4309223969498591447, 7596903557041777533, 18393682838284953355, 3973832102121938954, 12190997158276486897, 15972235844585587264, 14899488070931524727, 17337514399056563302, 10500237188498665928, 18440452962210035879, 7481614450647261413, 65300580117832193, 14713590013611289205, 13086268929321267306, 17247769089209001713, 11421561962034654967, 4561010052951998759, 9562817622798343284, 3062054327467638127, 6016566887476098647, 5513989129644936969, 13097123292793361360, 17631302057213141907, 8382824402074565601, 16136160484984138575, 0, 92, 1552825087809033479, 9447273069996733529, 6419011263238967677, 6692866018192235946, 7156821319138712192, 979552938298149105, 16414416705576227412, 12277732972115645845, 16390940174922802980, 3487294253425873238, 6189899981788830548, 5202139200141296429, 10911204476854742317, 1721085402837891517, 8352902245765240122, 11853370831480580617, 12549880386282601398, 182861448076475833, 907162566851125145, 5998456693193037487, 2770786935363726809, 7400519332304830077, 359467329647437035, 1312252687673992186, 7328500979632536073, 8813774793495812162, 6984573596316331699, 14977076517134741377, 16254221298013000537, 5001523311460849924, 0, 8, 6104172690014223231, 3119855977255645286, 2700229040680838768, 4228220371303630837, 12976691418076017877, 15391527008624099592, 15522155400452634037, 17655908650961725957, 5157987610310047621, 13664486701019622043, 12908699189677656287, 14840926611057477527, 6092037682822283700, 15181448373122947619, 2083722204849270202, 1893419523737526751, 11329911669537538562, 12331432886354737271, 9636585409664050258, 5131588463040403759, 10248116973079783912, 2136665268102207704, 17448444978654544666, 11945433761064128885, 4462464721020457233, 17579935132869425842, 7098417589530391109, 15343623253038912080, 7762335122892638892, 10310226363807226654, 9365253138981608257, 9365253138981608257, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 3222968251772292059, 4659330917232488313, 18368728739119945660, 6368972875636062959, 4707200061081251786, 7837376579209547587, 12248323053399392025, 13659284260102405271, 3268373156044973502, 1283746275992984836, 6075821593933813225, 16314284187241223265, 5494222736271176220, 13120146179040509426, 11410636383049345368, 825507757879255520, 10747531529265802304, 7673382754837099366, 15156055697659221375, 1718675228113159248, 4201859160733141037, 5300265117402310501, 7272994976566716580, 14871183427463612333, 3498894361287896100, 15218257307939313170, 1772539751900737248, 1975418926721182099, 12089371041955731221, 15888265955091463133, 16091581530351759692, 0, 2008210371491335, 13098960849839742034, 9449621519891201049, 2814310786559014444, 5305842545683321494, 4969236906288915907, 1243780951433164967, 6167749875842285147, 9490220981060631819, 3665259354621890034, 7437125179920904126, 12655958476488865400, 17935537000594940941, 91614862745339577, 1869550524566103495, 17384150297165671545, 1154605885284628266, 8665046436862728398, 6741156569294553317, 9490927005547387767, 8947900188307771735, 13752550215202657538, 7714188412126691626, 12225947487197390724, 13509943592829854189, 7120740401378484294, 6789669275155346195, 2929601484581949152, 1077164174037184778, 7253613682453412944, 12957959164911169922, 0, 1288, 2467314028170731200, 16601393295490334589, 410862426300963016, 6715125970066025284, 668903147624506142, 12095483928402104962, 1613631742115437617, 3060858350461432106, 14519578477424544472, 1246482959663576649, 10151539857350203993, 14524407161343324874, 10767371226180010877, 8883572370406050272, 7634465548311616828, 13778778399918900014, 17362186831679047435, 7577173806777510989, 14020627064222792913, 15976021831713665696, 7948772943735475729, 1437804116009572564, 6007143667192036573, 16589616747039104611, 12022435130037250391, 11127010123944496312, 433966021407007016, 17962467459011056432, 2310073430536633551, 16159283724457640221, 0, 40, 1560947813056021755, 6935064976442414148, 9999441144135002932, 10354700837586583171, 6040781227937012106, 4698117391978117444, 4735711626023545756, 11217844833019453026, 3130590714605394722, 2809204122464618686, 10935232469327759448, 18335893537613898174, 10868401885487323501, 15799177281014635734, 17187052562019754838, 4027411046406207040, 11879721967266924677, 3613659344771632047, 1846469577394958972, 14668357323201408029, 14939045883642543835, 2885718226990976376, 4969257074069595075, 10824274197210729467, 13212275138420405274, 10563919532671437398, 12234598862193668129, 14653607410806008848, 2498958194485300229, 3512215170452429648, 4243893038989355703, 4243893038989355703, 2147483648, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [87, 16746387937695142490, 9155393387906219784, 13386503743719781199, 2643395754600898300, 8948310776749535742, 8784880786966306238, 1110225852810378745, 17164574292834012429, 5226876132626050588, 13521863983694335346, 1499535172174489924, 16371752154949209907, 1465531721291669927, 16357468590797302295, 15603236927467279886, 750159427723404852, 2426484208226890587, 18279268404534332738, 4383807752256753313, 14980454155356662645, 5638763115145836005, 309850158776234346, 17414628586841602406, 4488055553392002721, 6099746236569370915, 9391735730020210762, 6993986830519314663, 2701106116508976741, 1898134322103701335, 12702609090402714686, 16079373865472459546, 0, 1606568297193092, 17457628753812655267, 5096693283465186518, 12947605480618213072, 13490514080936595140, 16186587491946121120, 10245245868334896235, 6026705707665599719, 9827345407768028181, 2812471843237874845, 12940670116574659651, 2714930976118111710, 11931084046533097040, 5957825878304116293, 4815270995456833861, 3281433232253188744, 1527514044633931889, 3155608937877823823, 496495357063373704, 12643114535206930756, 2926290280590787897, 4481685646324082958, 2913086696180341350, 4929647997916999987, 9053067786296036128, 12860916533743270733, 13426707234447106813, 15934882759672330788, 2173747106952139997, 5260381980138555939, 9238536158694879401, 92, 1104, 16216562119055243322, 9113898857319116772, 17132700957014282816, 16961354324299843537, 8958491673128745523, 6084177919166198949, 4492424574001173259, 2065688581293602436, 433616324011879356, 12151404659680738203, 3770309554737682698, 5300222935868897680, 2845921321939758123, 9028103117859423722, 9867617548439033893, 12400304789414303503, 14859150043279622231, 5014308339038672362, 6600097648382112815, 1659304607975522629, 1739219815660099577, 10359847956037447171, 11590294256574231363, 3647107356246152267, 15247865541233938330, 14069295620220509130, 2869001919576405519, 17417648807118850139, 14370760106653398402, 11118838785729522730, 0, 32, 9302012295643728416, 424328237663665361, 17748121622218558811, 6681769685034042719, 10907932526941371789, 14996603190997478665, 13982878080104642188, 3336783822228111865, 7403528606603453519, 7309352233404946366, 11509327586943808925, 6803943428138467537, 12870260590513220077, 3798257798625653324, 15652192157997003684, 8260391000410661595, 9099897743400681933, 16067207775248165408, 7640841583197908852, 16739199083410292994, 1998275509994500625, 10688417071827877337, 16160081185811655577, 2725954513011781037, 3040692668058239811, 15097072321276989567, 7813293313258815644, 15261763399945716285, 2258772319189190202, 6756061023037720295, 2372900269115514267, 2372900269115514267, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 13227498393864040945, 3236590870033651606, 18316422071602565784, 15701603594857309722, 5947972608122843521, 13523535320233199342, 3753934081047057169, 10936885931162702722, 5866281172578018338, 5131575035018446451, 9418660414070260899, 17291665633130001335, 16478272933178360032, 12493684045311157256, 12080786119242190524, 9808426190668729634, 10916182427754190208, 7949752104566735434, 16437679885653014489, 2197742477585333602, 11623912681484131137, 4866858089907087491, 7615091160766850619, 6639738661085122604, 6056593816756490758, 18265959195035569409, 439634521044110926, 12264490131121739608, 16106017656155713552, 1042562102193278240, 16047641734485800692, 0, 401642074298523, 10076989882539553734, 13617634258944637452, 11664888937794835322, 6832371865971954132, 7435465380685145582, 8856983143236954540, 15647394574465449881, 5004639611979401749, 16333513927375132208, 11586223746088007538, 17258599442845821467, 10089347514894229223, 8927362828162004403, 1274761678102044944, 13987176689734561031, 968318691601385838, 17920302096119022338, 18172419653743826470, 5238866342343116613, 4715585282245523496, 6782917713521523376, 845034972551066538, 8264516316211712068, 4395820162956710988, 17367170950581948054, 11715439359473390301, 4924405821869545305, 1674381281184830519, 4077397353846458666, 16570851802495678006, 0, 552, 18364539353432252959, 1551875687645078236, 5908552039479525180, 13623916550628200923, 4699969004069575100, 11630278164657820063, 5891234840048028912, 654092830709235842, 2412613677542740798, 9533885383398026397, 3477862308755521454, 3931695716927095485, 10207454088372242899, 17803175762377303845, 11036943293777954420, 16245042535546460743, 17267071485922545111, 3154671719447430275, 2667361456561557318, 8203075576459419142, 12382743643920078317, 9185031367250188962, 2354486840330493509, 13031927341928448984, 6462695849105922235, 17450486765305121779, 4895010392763653973, 14926331475286732296, 13033597008762597331, 7576593531686797042, 0, 8, 7519454690376123692, 7627104070861575574, 17604686071836489236, 14277148259130460564, 8312218486680706135, 8395439642754559152, 17307771294890409643, 9298206908486537717, 3027629924013931359, 2933551330348935458, 1450485994192951386, 8585052201707081835, 10624425952582111111, 16773523322999621677, 13337622149287916761, 17874287708894504070, 14164897610403484003, 11216401648549709020, 911970190394256131, 3202853507803349037, 14616902435260689479, 14924823153427050614, 4881022900440414264, 9723366934152472594, 16335725686098559697, 8087897843744270993, 11437013713086863200, 7627258546495067733, 18044191572661655945, 16490279521751489469, 1, 9, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 6170161675250864501, 11961896515966597756, 4654018437841213862, 5272790938970678408, 4281766794113009188, 11245796702384795879, 4856060583384283422, 17886680608631893125, 9261060821859854748, 14424996735749284440, 13746660795296557163, 4823043606851802454, 14938663460886908360, 7270036416424823086, 9523212457335079367, 9139548031431133148, 208295785334160234, 15753650123272304050, 10546365909049493247, 13322595239551652280, 13989288587795691202, 3906006690782976298, 17297950766482640011, 13938287014198326904, 16696817761315412012, 13953265341705633702, 4268569962168779654, 14232230927042798671, 6488214721912194407, 10956084748384074170, 17343413733132688543, 0, 401642074298403, 9851586117636382793, 7414079509745519565, 10414894202973226643, 11403399710197601656, 10230759118395809329, 4887466173119518776, 12376579030877442488, 15222686873173021915, 11343634646223977946, 15054143113295762432, 8578483304162845495, 8187399805941604842, 17460975957431844228, 12368453570037757143, 4715095521846408852, 10685847052710927197, 5160934306801665605, 12877482432527277885, 1026289052488784895, 12183816968946827507, 954239020314042893, 1899038343674936222, 3582199871763692750, 10141562795735590523, 5883730844910027408, 10313342961711791200, 10308552102917724507, 1101239144209002141, 16732112788727027442, 6132059608254040410, 0, 184, 9694623828077467233, 3675008886325466594, 9937899669773170043, 7849591422987652597, 15287367360056796639, 1702914822524674176, 10568464651116235631, 18376268405209394446, 17468515571505079540, 13349382737895871506, 10773310703441442177, 77415128127038826, 10067581411407423596, 2132439228676468850, 16446262234583425617, 15913203609357376990, 4328537832216989268, 14309894248163942626, 17219034350459931223, 16386215198201980227, 7529941270179488242, 3713349402354236945, 13565147716704204129, 3968526144162291548, 10616453538138359448, 16438784497837992964, 3058320693955246873, 4965950384458944745, 16872816814243270280, 6712929990112816841, 0, 8, 17781582622500481192, 12847902632736061277, 12021499907877242591, 16751519355106661703, 9062087890172095618, 3834953580385337540, 2969703856153678454, 11604562295556139307, 10447912046373566534, 12987934619706800857, 12352596220492768030, 14816150974992525275, 2172600571554701126, 18086375044546604023, 16313093185369681775, 14997664071320688070, 347950016295486690, 9206182676441692601, 3566552483989599402, 4925983231752336365, 1728701557101400581, 7087476601458867917, 9759961360999781392, 12569092891286895547, 14206292953735333262, 16422952955631166803, 6294107725304445883, 9537940691512987143, 15535806100011306333, 7080716573279759555, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4099276459869907627, 11351842504255128813, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] }, last_program_row: RowIndex(18) }, program_info: ProgramInfo { program_hash: Word([4192437018821097220, 9480578168622006864, 4891889892170146481, 11712807151087072240]), kernel: Kernel([]) }, stack_outputs: StackOutputs { elements: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, merkle_store_nodes: {Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571]): (Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350]), Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350])), Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484]): (Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693]), Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693])), Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781]): (Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874]), Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874])), Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171]): (Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361]), Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361])), Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815]): (Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305]), Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305])), Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689]): (Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195]), Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195])), Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362]): (Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063]), Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063])), Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848]): (Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661]), Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661])), Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352]): (Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829]), Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829])), Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444]): (Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223]), Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223])), Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386]): (Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388]), Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388])), Word([13190842942618341421, 17548956981569849952, 15418963848144418856, 730733050713174879]): (Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144]), Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144])), Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874]): (Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675]), Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675])), Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594]): (Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115]), Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115])), Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809]): (Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257]), Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257])), Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777]): (Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555]), Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555])), Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509]): (Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882]), Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882])), Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725]): (Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979]), Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979])), Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134]): (Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987]), Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987])), Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828]): (Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910]), Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910])), Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830]): (Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054]), Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054])), Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228]): (Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742]), Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742])), Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443]): (Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928]), Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928])), Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643]): (Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979]), Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979])), Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758]): (Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106]), Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106])), Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580]): (Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594]), Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594])), Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765]): (Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045]), Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045])), Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766]): (Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281]), Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281])), Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385]): (Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828]), Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828])), Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579]): (Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171]), Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171])), Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212]): (Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992]), Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992])), Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463]): (Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004]), Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004])), Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502]): (Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023]), Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023])), Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539]): (Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537]), Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537])), Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865]): (Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225]), Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225])), Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690]): (Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947]), Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947])), Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202]): (Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552]), Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552])), Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079]): (Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444]), Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444])), Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850]): (Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548]), Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548])), Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448]): (Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987]), Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987])), Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041]): (Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035]), Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035])), Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301]): (Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414]), Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414])), Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414]): (Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212]), Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212])), Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703]): (Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439]), Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439])), Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271]): (Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955]), Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955])), Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882]): (Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802]), Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802])), Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152]): (Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887]), Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887])), Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028]): (Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948]), Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948])), Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331]): (Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093]), Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093])), Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394]): (Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134]), Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134])), Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546]): (Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228]), Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228])), Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620]): (Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414]), Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414])), Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800]): (Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703]), Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703])), Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671]): (Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205]), Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205])), Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537]): (Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011]), Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011])), Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516]): (Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301]), Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301])), Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831]): (Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986]), Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986])), Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415]): (Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057]), Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057])), Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722]): (Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689]), Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689])), Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144]): (Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682]), Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682])), Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295]): (Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268]), Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268])), Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818]): (Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513]), Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513])), Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241]): (Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565]), Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565])), Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439]): (Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012]), Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012])), Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512]): (Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850]), Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850])), Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986]): (Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865]), Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865])), Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982]): (Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777]), Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777])), Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808]): (Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394]), Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394])), Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979]): (Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690]), Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690])), Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093]): (Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620]), Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620])), Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902]): (Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789]), Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789])), Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542]): (Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094]), Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094])), Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057]): (Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362]), Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362])), Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205]): (Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961]), Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961])), Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401]): (Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580]), Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580])), Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553]): (Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960]), Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960])), Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169]): (Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031]), Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031])), Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682]): (Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053]), Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053])), Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118]): (Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562]), Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562])), Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725]): (Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666]), Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666])), Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661]): (Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897]), Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897])), Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981]): (Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447]), Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447])), Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072]): (Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646]), Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646])), Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140]): (Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404]), Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404])), Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515]): (Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152]), Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152])), Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709]): (Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664]), Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664])), Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800]): (Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103]), Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103])), Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741]): (Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169]), Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169])), Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005]): (Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758]), Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758])), Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802]): (Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070]), Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070])), Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159]): (Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005]), Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005])), Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350]): (Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443]), Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443])), Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697]): (Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573]), Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573])), Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928]): (Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331]), Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331])), Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320]): (Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166]), Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166])), Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814]): (Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079]), Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079])), Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447]): (Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820]), Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820])), Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284]): (Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057]), Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057])), Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697]): (Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131]), Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131])), Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955]): (Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290]), Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290])), Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910]): (Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202]), Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202])), Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910]): (Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822]), Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822])), Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106]): (Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847]), Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847])), Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404]): (Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441]), Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441])), Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796]): (Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186]), Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186])), Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053]): (Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516]), Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516])), Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992]): (Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818]), Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818])), Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957]): (Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315]), Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315])), Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709]): (Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794]), Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794])), Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091]): (Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539]), Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539])), Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664]): (Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558]), Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558])), Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294]): (Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579]), Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579])), Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947]): (Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502]), Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502])), Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829]): (Word([0, 0, 0, 0]), Word([0, 0, 0, 0])), Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045]): (Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137]), Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137])), Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914]): (Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041]), Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041])), Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573]): (Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378]), Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378])), Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699]): (Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873]), Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873])), Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225]): (Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262]), Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262])), Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057]): (Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692]), Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692])), Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131]): (Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997]), Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997])), Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555]): (Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385]), Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385])), Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195]): (Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709]), Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709])), Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166]): (Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542]), Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542])), Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027]): (Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373]), Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373])), Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378]): (Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509]), Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509])), Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097]): (Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553]), Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553])), Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217]): (Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815]), Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815])), Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873]): (Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864]), Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864])), Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997]): (Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722]), Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722])), Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887]): (Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766]), Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766])), Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589]): (Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757]), Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757])), Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539]): (Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665]), Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665])), Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129]): (Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229]), Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229])), Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137]): (Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312]), Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312])), Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019]): (Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378]), Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378])), Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331]): (Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713]), Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713])), Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]): (Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980]), Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980])), Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325]): (Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546]), Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546])), Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170]): (Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822]), Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822])), Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054]): (Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295]), Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295])), Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925]): (Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848]), Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848])), Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909]): (Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796]), Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796])), Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540]): (Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170]), Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170])), Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214]): (Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448]), Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448])), Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317]): (Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294]), Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294])), Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757]): (Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416]), Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416])), Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378]): (Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091]), Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091])), Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263]): (Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463]), Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463])), Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666]): (Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361]), Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361])), Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174]): (Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992]), Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992])), Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470]): (Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401]), Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401])), Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665]): (Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957]), Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957])), Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262]): (Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144]), Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144])), Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229]): (Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284]), Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284])), Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134]): (Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325]), Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325])), Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855]): (Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765]), Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765])), Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115]): (Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814]), Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814])), Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441]): (Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831]), Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831])), Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977]): (Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446]), Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446])), Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880]): (Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005]), Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005])), Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789]): (Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995]), Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995])), Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000]): (Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267]), Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267])), Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998]): (Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982]), Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982])), Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995]): (Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539]), Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539])), Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507]): (Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512]), Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512])), Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305]): (Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118]), Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118])), Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219]): (Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009]), Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009])), Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416]): (Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089]), Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089])), Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980]): (Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445]), Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445])), Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063]): (Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140]), Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140])), Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713]): (Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159]), Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159])), Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031]): (Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809]), Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809])), Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932]): (Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037]), Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037])), Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094]): (Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925]), Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925])), Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315]): (Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386]), Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386])), Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446]): (Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721]), Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721])), Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742]): (Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981]), Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981])), Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661]): (Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072]), Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072])), Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979]): (Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671]), Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671])), Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361]): (Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269]), Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269])), Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558]): (Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571]), Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571])), Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290]): (Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902]), Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902])), Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987]): (Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741]), Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741])), Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902]): (Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515]), Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515])), Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497]): (Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028]), Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028])), Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948]): (Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709]), Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709])), Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009]): (Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725]), Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725])), Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387]): (Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317]), Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317])), Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159]): (Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808]), Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808])), Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394]): (Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699]), Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699])), Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312]): (Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000]), Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000])), Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987]): (Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821]), Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821])), Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046]): (Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909]), Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909])), Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565]): (Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028]), Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028])), Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269]): (Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352]), Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352])), Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847]): (Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271]), Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271])), Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513]): (Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800]), Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800])), Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054]): (Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394]), Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394])), Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004]): (Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977]), Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977])), Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675]): (Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800]), Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800])), Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692]): (Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159]), Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159])), Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909]): (Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932]), Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932])), Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814]): (Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697]), Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697])), Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186]): (Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387]), Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387])), Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445]): (Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470]), Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470])), Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966]): (Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507]), Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507])), Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548]): (Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253]), Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253])), Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897]): (Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783]), Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783])), Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208]): (Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054]), Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054])), Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268]): (Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661]), Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661])), Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388]): (Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643]), Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643])), Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257]): (Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174]), Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174])), Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960]): (Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241]), Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241])), Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721]): (Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046]), Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046])), Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822]): (Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217]), Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217])), Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253]): (Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697]), Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697])), Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054]): (Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019]), Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019])), Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821]): (Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432]), Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432])), Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864]): (Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105]), Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105])), Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373]): (Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855]), Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855])), Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646]): (Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830]), Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830])), Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460]): (Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208]), Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208])), Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033]): (Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214]), Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214])), Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105]): (Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129]), Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129])), Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281]): (Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909]), Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909])), Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028]): (Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027]), Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027])), Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012]): (Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054]), Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054])), Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562]): (Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589]), Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589])), Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037]): (Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097]), Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097])), Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355]): (Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460]), Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460])), Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223]): (Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355]), Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355])), Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089]): (Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306]), Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306])), Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035]): (Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219]), Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219])), Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432]): (Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297]), Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297])), Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693]): (Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263]), Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263])), Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794]): (Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484]), Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484])), Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552]): (Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941]), Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941])), Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267]): (Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814]), Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814])), Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992]): (Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415]), Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415])), Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941]): (Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966]), Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966])), Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822]): (Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320]), Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320])), Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306]): (Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902]), Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902])), Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820]): (Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880]), Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880])), Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361]): (Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725]), Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725])), Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005]): (Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914]), Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914])), Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783]): (Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781]), Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781])), Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011]): (Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033]), Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033])), Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297]): (Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910]), Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910])), Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070]): (Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134]), Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134])), Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144]): (Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331]), Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331])), Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023]): (Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497]), Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497])), Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103]): (Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540]), Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540])), Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961]): (Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998]), Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998])), Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414]): (Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]), Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]))}, trace_len_summary: TraceLenSummary { main_trace_len: 19, range_trace_len: 49, chiplets_trace_len: ChipletsLengths { hash_chiplet_len: 128, bitwise_chiplet_len: 0, memory_chiplet_len: 3, kernel_rom_len: 0 } } } +ExecutionTrace { main_trace: MainTrace { storage: Parts { core_rm: [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 3987768130567869605, 17866922374020149524, 8514580104850791069, 13475546435959911551, 16830415514927835337, 12164645914672292987, 13192574193032437705, 4604554596675732269, 0, 0, 0, 0, 0, 0, 1, 0, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 401642074298203, 40, 40, 0, 0, 0, 0, 0, 0, 4, 0, 0, 1, 0, 1, 0, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 2, 0, 0, 0, 0, 0, 3, 1, 1, 0, 1, 1, 0, 1, 3137828705454, 1, 0, 0, 0, 0, 0, 0, 1, 3, 0, 0, 0, 0, 1, 0, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 3, 0, 0, 0, 0, 0, 3, 0, 1, 1, 1, 0, 1, 0, 24514286761, 1, 0, 0, 0, 0, 0, 0, 1, 2, 1, 0, 0, 0, 0, 0, 40, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 2, 1, 4, 0, 0, 0, 0, 0, 3, 1, 0, 0, 1, 0, 1, 0, 191517865, 1, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 5, 0, 0, 0, 0, 0, 3, 1, 0, 0, 1, 0, 1, 0, 1496233, 1, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 8451315773087502901, 3716949716844628593, 10394526050930609580, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 6, 0, 0, 0, 0, 0, 3, 1, 0, 0, 1, 0, 1, 0, 11689, 1, 0, 0, 0, 0, 0, 0, 1, 2, 4, 0, 0, 0, 0, 0, 3716949716844628593, 10394526050930609580, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 7, 0, 0, 0, 0, 0, 3, 1, 0, 0, 1, 0, 1, 0, 91, 1, 0, 0, 0, 0, 0, 0, 1, 2, 5, 0, 0, 0, 0, 0, 10394526050930609580, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 8, 0, 0, 0, 0, 0, 3, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 2, 6, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 9, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 7, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 8, 1, 10, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 8, 1, 11, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 1, 1, 1, 3987768130567869605, 17866922374020149524, 8514580104850791069, 13475546435959911551, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 8, 1, 12, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 8, 1, 13, 13, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 5, 0, 1, 1, 0, 1, 0, 1, 8, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 14, 13, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 7, 0, 0, 0, 1, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 15, 13, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 7, 0, 0, 0, 0, 1, 1, 1, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 16, 13, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 5, 0, 0, 0, 0, 1, 1, 1, 16830415514927835337, 12164645914672292987, 13192574193032437705, 4604554596675732269, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 17, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 31, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 33, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 39, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 43, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 47, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 50, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 51, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 53, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 54, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 55, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 59, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 60, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 61, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 67, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 69, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 70, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 71, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 72, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 73, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 74, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 75, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 76, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 77, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 78, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 79, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 81, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 82, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 83, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 86, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 87, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 88, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 89, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 90, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 91, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 92, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 93, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 94, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 97, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 98, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 99, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 101, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 102, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 103, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 104, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 105, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 106, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 107, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 108, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 109, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 110, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 111, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 112, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 113, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 114, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 115, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 116, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 117, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 118, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 119, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 120, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 121, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 122, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 123, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 124, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 125, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 126, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 127, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0], chiplets_rm: [1, 1, 0, 0, 3987768130567869605, 17866922374020149524, 8514580104850791069, 13475546435959911551, 16830415514927835337, 12164645914672292987, 13192574193032437705, 4604554596675732269, 0, 87, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 17706856450849328104, 14041629472916080872, 17169788735560756890, 10821476187673211944, 4183993524573793794, 16789443777672453768, 2161849376993207123, 5833790386150273010, 0, 0, 1, 0, 0, 1, 1, 0, 0, 401642074298203, 40, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 3987768130567869605, 17866922374020149524, 8514580104850791069, 13475546435959911551, 7789855707707231369, 4610326148461237922, 1784941811671601269, 9924745492516640019, 7791549396364371277, 2968443994649453078, 1308562153347600605, 4332337354844628651, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 92, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 16830415514927835337, 12164645914672292987, 13192574193032437705, 4604554596675732269, 7157681808383834781, 13054530803491118896, 15318932090721652605, 12540678638271855535, 5420606508990450533, 8111458574185220575, 1323824759339937182, 8059544659088724214, 0, 0, 1, 0, 0, 1, 1, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 1244837894821529086, 14023738310468542470, 9319458442815716445, 5220020845190256514, 18381067342435073896, 15418184987737128626, 17753079332212842976, 12382717352847060954, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 92, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 5484645610689645032, 17933046996545101157, 16339706652094815250, 13544759331160301838, 8141870999174257740, 14107144578121799305, 396274001381699938, 3634103446560049839, 12745031702117932636, 7036828309739934078, 17841617974172171166, 16843483981996999201, 1, 0, 0, 0, 1, 0, 0, 0, 0, 12255467604292037599, 3221298496122688675, 18213293887213037791, 10454832113088907686, 14197766824477982368, 12632563328014721824, 15223540981653283332, 8415652435043313252, 15072376706785505714, 499064301441796851, 6019679623316230571, 2863989181285908285, 1, 0, 0, 0, 1, 0, 0, 0, 0, 3504307811212845679, 9887651557123705338, 15415704462638107150, 10451874340315180119, 14715205669302787941, 676415209440449451, 13877510800170645203, 5795890553064646410, 8168893483976559005, 11011177719900268394, 3075618990528033611, 13809591299651900358, 1, 0, 0, 0, 1, 0, 11532942913722119887, 15706785780181646320, 8500217623199961915, 16385837637275803212, 12589553581452432263, 9328358778203457601, 4811677924202588651, 15954150986266248336, 13054476292017527619, 13801463134030240262, 1165498946375484511, 12668987530028315258, 9041501660033602067, 11828980449399846157, 712948025072919412, 1, 0, 0, 0, 1, 0, 13546468777259703303, 2130139338200141332, 1677916746575397392, 15603598095391109763, 8982008132746506464, 9534409456230159171, 15953027744665381494, 2210202967686246336, 18201859605319735335, 2613650507633583447, 13470511188219884259, 17792240681335161918, 5597430705303759588, 17058784685043687544, 18076014205743588541, 1, 0, 0, 0, 1, 0, 17150592872874668692, 373328191372179539, 9925944180761826662, 4881622279674020310, 1461351575215552783, 7028330826866827934, 17321922102323360926, 11861279589925081154, 4211482457682169121, 857582657567428474, 6294745292695606830, 3964499899330796305, 8694904038920718173, 12798363385221373595, 11519040844019198794, 1, 0, 0, 0, 1, 0, 17812065447696919081, 10476573304851565336, 4050248765677305785, 3052409033334460214, 17899456176840307949, 14272332536807405334, 5268789410078450933, 1960893658848125895, 10357280402715567165, 1946175234480737485, 3509255218615138356, 13648578922017807026, 1792108781827785515, 7848717464050352065, 2115979595816627252, 1, 0, 0, 0, 1, 0, 14304145735363415364, 3123264749675353443, 15633057486969346389, 5590715938569744686, 16360479359047183989, 17571597847320321793, 7491081885321669942, 2792014203761376516, 7481817557178743487, 14182256043130615816, 2113355324306522062, 7590704234440296353, 6731946370858393481, 2307380299587089154, 1457958177788302268, 1, 0, 0, 0, 1, 0, 9128626640352709923, 17530806268802285328, 5521142562674286822, 7672965447668905839, 18202802305345820600, 10939917215126760263, 5454274694799635961, 15045803504594761609, 6031972736818829176, 6487707463900256145, 6513518689484649191, 12115325694601327017, 2589258613727050076, 9795696285187372082, 9346079458114114095, 1, 0, 0, 0, 1, 0, 3585032113304036127, 878423030197307407, 7753214053553689965, 13826096403235050003, 13292980836066262078, 17878862886173733195, 17335963671141011125, 15552187222984804077, 8300146209691975643, 14310135663256964431, 5324444741120757504, 15200025136962894389, 9211865123544848832, 757820306026356015, 15906091739671321314, 1, 0, 0, 0, 1, 0, 5864686728114583749, 0, 0, 9139354100126637124, 11662388403276284204, 1053421858759551477, 14098346563780750400, 5067426764888134185, 6134229022916026981, 16277189846925996385, 13161575946730874384, 8492889920316449728, 8738608316156486979, 11361904455207330488, 4644160712918564720, 1, 0, 0, 0, 1, 0, 0, 0, 0, 15069412541248179329, 17636221918015671474, 2493488421765413820, 14256642798665897034, 13029707287964752636, 9441335230719905711, 12416439742779279248, 10080344719141565596, 10015871472133787582, 394932958898495590, 2354587967963224922, 18089767607933127470, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1637053654417823543, 820038718609189039, 339980141328036028, 10322493293137382631, 12718954196218876787, 6796168876136445697, 15420463740865030232, 3252331356198972205, 14227267699888656475, 2559427160509359301, 17590552952398131648, 159003707103255077, 1, 0, 0, 0, 1, 0, 0, 0, 0, 3016912966792386460, 4113629697054036494, 8930528385757741316, 3280375997019352338, 13486210659622411055, 15849561705591959734, 12565096618949859493, 317383372660570130, 13178345540153474546, 7712839197105005349, 13963542465081735925, 5137866587539026744, 1, 0, 0, 0, 1, 0, 0, 0, 0, 16830415514927835337, 12164645914672292987, 13192574193032437705, 4604554596675732269, 7157681808383834781, 13054530803491118896, 15318932090721652605, 12540678638271855535, 5420606508990450533, 8111458574185220575, 1323824759339937182, 8059544659088724214, 1, 0, 0, 0, 1, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1532070872953744281, 11675978725956395507, 8258108365434236190, 8977540451988253054, 8832291907404336605, 16801197610032323372, 8498902414702613411, 2217861947967210820, 14648106445605106304, 5194857384255130698, 4543357020291533691, 1677011855369223059, 1, 0, 0, 0, 1, 0, 0, 0, 0, 18164368745351378969, 665130184182531292, 14548211377038648988, 9026463808500414994, 12372059324693434695, 8512906579977137276, 10951940384741553765, 2990681100436043903, 15463650459774420968, 6115025020360005524, 13619612156045325099, 9915559200666512746, 1, 0, 0, 0, 1, 0, 0, 0, 0, 73542357038484620, 16275608702285065538, 15615370514429573107, 11554047591217380375, 9626234372118459069, 14043139718664795091, 7172345985251039651, 13714446996516992992, 14079807935308074442, 17175342044195045043, 16936021968982853164, 3883665509408281322, 1, 0, 0, 0, 1, 0, 8133824218287649370, 1205363866316521559, 7923953289074004648, 1611370566290075655, 12516876786630134052, 16156412840636435500, 16066365782016562356, 12209717470970729826, 648151295134950813, 8424608506935970051, 941071657155810425, 12476535243066524999, 13046835168670418046, 13563090428318398174, 10213204276953300366, 1, 0, 0, 0, 1, 0, 11656233811569695541, 16780366708706866018, 10469348806910132738, 12317597613336433996, 16800450568443907772, 7958196127911254005, 5580405360121542127, 17991322909541306091, 9587008055009063413, 917862094456531518, 17636182943787095305, 5347924966817937746, 15791860137463552476, 5352122275530338033, 8207615265206228485, 1, 0, 0, 0, 1, 0, 13280747180546192023, 13818056542207317059, 12768869371961439487, 2029833730308772760, 3067168931363951888, 630426464913806566, 13807710542081112496, 10340529818978391824, 8301137772228612306, 18032943025979156234, 5571856761516233924, 15102755171792177729, 1386022355796901548, 10780164990569095481, 14005839963275167003, 1, 0, 0, 0, 1, 0, 8161514060541966002, 5430054846479849757, 855673369941768792, 8583346124368767357, 7152703336258374657, 4793816855328822248, 1475819744300266017, 5162097063446717296, 9158417383194264473, 17323069022182310843, 17309666448184518221, 16540233824244985004, 13271685073550397851, 3683818685539825395, 12883632168742702763, 1, 0, 0, 0, 1, 0, 14889661894667616899, 13319328534492736282, 511216470843933116, 5414088302741599345, 16030190225904238830, 6111859869108706126, 4321093113239299552, 4706826096768711507, 11021679444547674749, 15678561454143187205, 15168765916033556420, 7046395423559884948, 3431032212531228618, 9443306432483343000, 6291224588853575811, 1, 0, 0, 0, 1, 0, 11384512740043719026, 17996531901144166752, 4183594834611630116, 17695445402585642319, 15258305803668890228, 17106752205417894410, 13259786553689259064, 15859967842550332610, 5138368225191856866, 8345451659183769670, 4299979085769618674, 10058172520180004407, 16132576493934338934, 312707111584502977, 8025187035739711204, 1, 0, 0, 0, 1, 0, 17152042124522816142, 9826569971726481595, 8959076337043698126, 1987260706895490300, 17423289859865292784, 12258188545233319580, 4291864820252135891, 2950910453815263271, 852440029525711434, 1223549137263517018, 605327998629874385, 3009980753663636725, 8722464778364467857, 17216818427461180092, 13380853612843880678, 1, 0, 0, 0, 1, 0, 7979264206910945674, 0, 0, 7448791324579059841, 1050285053399784347, 16767087000176263535, 14849165193424062452, 2498996933077132011, 13658177069616805094, 495936213960522537, 13576872019913404781, 7640966386182958606, 4271515987309482058, 13463445006653778819, 12292225704634605892, 1, 0, 0, 0, 1, 0, 0, 0, 0, 6053040396430810733, 2172892474788961636, 18161859984545851402, 13488248907260320483, 8430623432188198915, 3055646124754645267, 4245215712607391946, 2243958878529225177, 14990440908620774864, 3080921390696878855, 595284666932255390, 6192940699035995377, 1, 0, 0, 0, 1, 0, 0, 0, 0, 14921496778760644502, 16662036864627516510, 6434377642684009725, 1840544361770929313, 15074823591915634941, 5258982948465254673, 2683768063818053258, 238295676214993337, 17552036469726894364, 15877921873938893194, 14734786106453693759, 1371624439541100057, 1, 0, 0, 0, 1, 0, 0, 0, 0, 516742705862090749, 5947805230277704319, 5952541516123965670, 9026915957393505056, 5986317686192419732, 75717367401824328, 8923961895635206791, 17106810061565988432, 7157463081631406163, 150940732863733992, 15657864298531798718, 12227344478922314236, 1, 0, 0, 0, 1, 0, 0, 0, 0, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 1244837894821529086, 14023738310468542470, 9319458442815716445, 5220020845190256514, 18381067342435073896, 15418184987737128626, 17753079332212842976, 12382717352847060954, 1, 0, 0, 0, 1, 0, 0, 0, 0, 401642074298203, 40, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 5792301967904643716, 14513996957604530562, 6300577652167374432, 1030532363437082530, 9868636994953646365, 13312054463817713847, 1163060834237983926, 17159751124589539180, 15748271025379903662, 15673345155938926996, 15542740004802895548, 4070736982096634948, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1453121677659348577, 17403066345171442603, 9526966027631081464, 4562917345183859100, 16736668858502190206, 12710250320191836356, 9043028743666878997, 9570842800862454404, 10889819954451461225, 1374882310944969176, 11041329929342678296, 6376909268692149801, 1, 0, 0, 0, 1, 0, 0, 0, 0, 6798464049283172704, 10094602609597426273, 5441108908322692152, 13319823174770042865, 3687504758717747002, 11828007000931365406, 15642196062511550808, 4387538442135057894, 12016453509822632603, 16688879161845796765, 15353663875595798268, 9433687029957117661, 1, 0, 0, 0, 1, 0, 11436455846193695609, 17419948132223780613, 10707930966158261719, 7805136509413905123, 10748223278202845625, 5102455166015213038, 16060345288112427467, 9937020917196030767, 13713675713530315700, 11873887283723171030, 6245447289360608210, 2758175399376775060, 6794131889413756751, 6954584401067417189, 5092580402017360453, 1, 0, 0, 0, 1, 0, 138168370802146349, 561179642041056504, 13282391328952434407, 3586306435690112870, 17278658194357811156, 2504635638454636683, 7235500145280211409, 11191458759516692993, 6465450803792948194, 2111071922636782066, 11802465958807233213, 9116942394473193925, 11145482942031811955, 14726020691764699927, 16903672043479974450, 1, 0, 0, 0, 1, 0, 263960295682680947, 15697220842527476860, 17868088579823291326, 2175933588395873247, 8749749468735109989, 11010166446741390499, 17943104442301856895, 15821423767384514021, 16018668147064525478, 5560768172433028490, 5619212355349254932, 17391285462458271036, 2603291588626814071, 5238953246197227863, 5602891381109897586, 1, 0, 0, 0, 1, 0, 12301036190174877474, 12651281118484863330, 11983275442902746825, 9125195986387370903, 2181062690427536463, 13921861517061570826, 350891571660248295, 11013048057925712708, 11055047889476803308, 15398332646604634982, 5808711407549689243, 8949777591082911961, 14824627964979845981, 8130365156760288485, 3947069696768920416, 1, 0, 0, 0, 1, 0, 753507401801380169, 11557202300537182401, 12635550211207024884, 13277984171307670821, 2631795936834054713, 14094327291919754106, 12673624581190519723, 4509450209340246689, 10606486226190872261, 889124163739951988, 12547380261461657128, 16829937485708676196, 15832095999334895743, 5377353767201125639, 11053610747785598805, 1, 0, 0, 0, 1, 0, 17726880391953768878, 13956049620380258223, 11273932727072475337, 6855896085734577371, 1129400045567810133, 16519057148475618054, 10699416941054230316, 17256608828803451668, 6887723245936746466, 552364255868028623, 17909079490987407142, 9570595819850351164, 8654686163127378448, 16203109760043627710, 8480295614280342552, 1, 0, 0, 0, 1, 0, 5047048529377126902, 2720906371958061367, 10084181298533567509, 10367672116357405411, 11036446985399396097, 13294567520571596163, 17521531050433436007, 1868701710513242496, 5411603901210245247, 11609599138736895146, 16874855234706410918, 4393409689646403917, 9543195090298605247, 7478523150127634789, 2693101708644875762, 1, 0, 0, 0, 1, 0, 3528724572660247995, 0, 0, 12432722351030045, 1367308201666984940, 3681473655802754494, 15340518851882934883, 12978887161137913348, 15761699408266065961, 3053535844413236872, 13043307337058007179, 1605626291192886407, 3512088686484392896, 17370072541480613908, 15945489250832697271, 1, 0, 0, 0, 1, 0, 0, 0, 0, 18236855931369748683, 5145738009993425605, 9599849581440088949, 7181962801200058100, 7842895042061868932, 12656177266019986902, 8530248384503061153, 7088178758240165913, 8843525768370306419, 9760798177389960884, 15297557810674980998, 17513790474795511142, 1, 0, 0, 0, 1, 0, 0, 0, 0, 11582029127760482436, 12210748157899031357, 9473509448225646970, 17514007687115301207, 15252116786733410669, 10068681917011840638, 5010610666981558682, 14100290159714849481, 10038370148733513877, 4164887708143705047, 12759194225663538416, 5155504400103783318, 1, 0, 0, 0, 1, 0, 0, 0, 0, 2256431941220947766, 13487119117857302457, 10370113277604876234, 1506538453550143326, 9611088164777633619, 9944172425891749050, 2585766031776029836, 7469792865149057403, 3748706915022560085, 480217827283441208, 7902514309755880799, 16608422580379539141, 1, 0, 0, 0, 1, 0, 0, 0, 0, 3987768130567869605, 17866922374020149524, 8514580104850791069, 13475546435959911551, 7789855707707231369, 4610326148461237922, 1784941811671601269, 9924745492516640019, 7791549396364371277, 2968443994649453078, 1308562153347600605, 4332337354844628651, 1, 0, 0, 0, 1, 0, 0, 0, 0, 3987768130567869605, 17866922374020149524, 8514580104850791069, 13475546435959911551, 16830415514927835337, 12164645914672292987, 13192574193032437705, 4604554596675732269, 0, 87, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 8975931939487847577, 826624107367617870, 6313882907599268049, 12374350641898187577, 6034656875513245768, 2025404333603011219, 5567780117684101433, 10039943328136801127, 14519832948855618026, 8345489883032353865, 1527060375424943961, 12170781137980926170, 1, 0, 0, 0, 1, 0, 0, 0, 0, 18439179491774692160, 5894239126603330321, 4540558979809060030, 10279540138716552456, 987473941784029527, 12525995964141116915, 5290090394268808541, 306655326230637762, 16338547772125377607, 11596138255917963766, 8713064878787635294, 14621378300733812762, 1, 0, 0, 0, 1, 0, 0, 0, 0, 8625597143277853412, 13696710862406782461, 7964746106575152337, 2172419373723337128, 8054193852364041914, 13837151904574880265, 12082541315152330288, 459946368827837708, 13160722284184094440, 266800667110584625, 14057659934195137969, 2295454423550348086, 1, 0, 0, 0, 1, 0, 12664681110997539525, 17076348030538024207, 5540238696466037530, 12503523823545562389, 174867091135528982, 16590140589764950480, 8259361233182789197, 11645736243489132578, 14290054611959227376, 9180054963981299553, 7522469136295030791, 7105443855795968859, 891467184376357898, 17670655597278868995, 2342025702421944092, 1, 0, 0, 0, 1, 0, 6508510408052687169, 6204789958331974035, 9346507142457173461, 4301401385637777690, 14660092386018225126, 12495473851795317931, 5022633921442224796, 17917849216228407802, 12792959527605319782, 15230911336735940949, 8204016232934091863, 15412033900392896865, 3505376367314785905, 6238911281890404928, 5298514099659693687, 1, 0, 0, 0, 1, 0, 13799242140675876876, 11967308820225399198, 2683546121072105123, 1729755848300507463, 12870359338704016369, 8941470466611331698, 2180957237381332114, 15146008237095844208, 16160269208928910981, 18327684313482854134, 16833658748571454034, 2228273861931392047, 15731171584455796770, 995005991601822991, 1325734405437759991, 1, 0, 0, 0, 1, 0, 17987851369139942407, 13398331003343876993, 5367943995780444036, 2448619251293596415, 6376925844201940434, 4660951209572130343, 6692287909250102466, 14264867975601246507, 7450682030114986603, 13850479752308263747, 2354486568908427148, 15162745955260128567, 7073739487284518498, 7349823339847667270, 7432121536738542934, 1, 0, 0, 0, 1, 0, 12779330473845195196, 13333298498050625857, 8497017356295886418, 198682296436078421, 6785250810511202548, 8675942375264798154, 1902172958020633282, 13878123715732752934, 2669364003539959841, 2919541857723463762, 15553639772246407252, 4490985143636591731, 14759010930598801048, 3644113642401147053, 11725546181585461527, 1, 0, 0, 0, 1, 0, 4348612304082720967, 7000799207553416727, 409433143803986808, 11098012124426545813, 13705626808705343574, 14914614989311581118, 15856657657850435817, 15647302365239384916, 1922093161120523126, 16304799558618217551, 2058076621629364563, 13235199499072181459, 2014579064718604783, 17528668302117330167, 4502687057104666043, 1, 0, 0, 0, 1, 0, 4374227242554438847, 11512800943126678297, 5364118459222264456, 15735518607595531127, 17687628157036575189, 4316235176215213500, 16328191111758429737, 8296514219182559014, 4219319863447058339, 17792101410240385031, 5877693942919568575, 362532686167476669, 9295444241326410471, 13461509482997484750, 2976690162409908995, 1, 0, 0, 0, 1, 0, 7104659116945783510, 0, 0, 16126650333942571964, 5373159454984485726, 8554791451595603222, 13040170352872131666, 6964722638533720778, 16565181844214358545, 5358624883000304708, 9590418361165280265, 9589196611956250594, 8187047052130427056, 2952681060946246957, 2014692216792503027, 1, 0, 0, 0, 1, 0, 0, 0, 0, 12840173240488470337, 1377635413060797359, 305354737769078594, 2796157645377513585, 17792025031160030650, 4262069196839993466, 15334521966674573711, 10417895735626853679, 15985686557567316940, 9198468442856654979, 18432371762950474462, 3913809235807315417, 1, 0, 0, 0, 1, 0, 0, 0, 0, 14482582745895144215, 1416945927177854081, 14328454743983709378, 2239851991461863112, 14449374510435378, 103561798029274946, 8636099973921767577, 18014864567131597051, 3269781373289032262, 11277949075475123849, 18052298919183707862, 1465413476437382760, 1, 0, 0, 0, 1, 0, 0, 0, 0, 17039932339331186847, 17502136381770894171, 9167041279176111993, 5466495695730086964, 16979151180084274449, 12264098443872388690, 7613839079126372753, 8653310637125687540, 13994165437176517647, 8342109517639396353, 1226521077945764801, 2704640960151854871, 1, 0, 0, 0, 1, 0, 0, 0, 0, 10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993, 17706856450849328104, 14041629472916080872, 17169788735560756890, 10821476187673211944, 4183993524573793794, 16789443777672453768, 2161849376993207123, 5833790386150273010, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 40, 0, 0, 3, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 1, 0, 1, 1, 10, 0, 0, 0, 1, 0, 1, 1, 0, 40, 0, 0, 12, 16913455875204140146, 8451315773087502901, 3716949716844628593, 10394526050930609580, 9, 0, 4099276459869907627, 1, 10, 0, 0, 0, 1, 0, 0, 0, 13, 4294967292, 0, 1, 12, 0, 0, 2147483648, 0, 13, 0, 11351842504255128813, 0, 65535, 16383, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], range_checker_cols: [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 1, 0, 0, 0, 1, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 7, 8, 9, 10, 13, 2200, 4387, 6574, 8761, 10948, 13135, 15322, 16051, 16294, 16375, 16378, 16381, 16382, 16383, 18570, 20757, 22944, 25131, 27318, 29505, 31692, 33879, 36066, 38253, 40440, 42627, 44814, 47001, 49188, 51375, 53562, 55749, 57936, 60123, 62310, 64497, 65226, 65469, 65496, 65523, 65532, 65535, 65535]], num_rows: 128 }, last_program_row: RowIndex(18) }, program_info: ProgramInfo { program_hash: Word([10283482931168313515, 11478835923086610240, 11364418273176134048, 7500322654022518993]), kernel: Kernel([]) }, stack_outputs: StackOutputs { elements: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, precompile_requests: [], final_precompile_transcript: PrecompileTranscript { state: Word([0, 0, 0, 0]) }, trace_len_summary: TraceLenSummary { main_trace_len: 19, range_trace_len: 51, chiplets_trace_len: ChipletsLengths { hash_chiplet_len: 80, bitwise_chiplet_len: 0, memory_chiplet_len: 3, ace_chiplet_len: 0, kernel_rom_len: 0 } } } diff --git a/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_26.snap b/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_26.snap index 96623ed227..91e962268e 100644 --- a/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_26.snap +++ b/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_26.snap @@ -2,4 +2,4 @@ source: processor/src/trace/parallel/tests.rs expression: DeterministicTrace(&trace_from_fragments) --- -ExecutionTrace { main_trace: MainTrace { columns: ColMatrix { columns: [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 33, 33, 33, 1, 65, 65, 65, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [665741763369239996, 5296, 41, 0, 665741763369239996, 1032, 8, 0, 7458506668679174706, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676, 7894050562420362676], [5831108162926480783, 0, 1, 1, 5831108162926480783, 0, 1, 1, 18375473735916206629, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271, 4416250439475247271], [7330889791923421278, 0, 0, 0, 7330889791923421278, 0, 0, 0, 2105717247508690050, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565, 2326332951934988565], [13218130135561237014, 0, 0, 0, 13218130135561237014, 0, 0, 0, 1679902783560062568, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905, 9381983878411686905], [7458506668679174706, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [18375473735916206629, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [2105717247508690050, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1679902783560062568, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 0, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [2, 2, 2, 1, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2], [3, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3], [0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [16, 16, 16, 17, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16], [0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2187, 4374, 6561, 8748, 10935, 13122, 15309, 17496, 19683, 21870, 24057, 26244, 28431, 30618, 32805, 34992, 37179, 39366, 41553, 43740, 45927, 48114, 50301, 52488, 54675, 56862, 59049, 61236, 63423, 64152, 64881, 65124, 65367, 65448, 65529, 65532, 65535, 65535], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [665741763369239996, 4841630085998491759, 6465560042516376876, 16331008790693949850, 6970683036804102439, 8497009269728596384, 1748714548692072347, 13048694814734168842, 2851620155234231146, 12440189078605506740, 7150883378538807680, 15495282497840653987, 17768685484250522227, 2793475893411298471, 14225437221510868328, 2199342294693565806, 6757917767565409963, 8625575291436195558, 9995878327716902758, 13201046879819468564, 585466765571734889, 137907905271081689, 6716945316985023829, 15397869777828729446, 8165247034144091221, 14277934820647399743, 14219322642025824233, 17615631325693698036, 2441238758278104147, 2775370016004740491, 14369612123276038546, 7894050562420362676, 5296, 52960, 6811813611500970866, 12330218901740233931, 16287800225917557614, 2390658038828763199, 4670881323897574211, 15935136064817789611, 2699367049541735206, 5505690989019187676, 4740977976888162022, 5734803687955113279, 14716704723144357988, 4469212567425053522, 15617193812494172197, 4848896952878415343, 18385001813020718595, 3406927099241203725, 6500845817907766790, 14130590127555482700, 10343975768128176185, 15693873175844605389, 2059720903132940981, 3757345954094976880, 3089069334759629752, 18141223932492835937, 11387279664761561894, 5402048984901238600, 12664138717389652380, 8299034149894841811, 4141583402420192864, 665741763369239996, 1032, 10320, 13024110921086730221, 3587442816163675215, 512402747638547729, 9217956011885162917, 3925750957223009950, 8674177413178223320, 12846799727083908462, 9116601283268739756, 2958792353189815054, 1720195204565087693, 7696852080146622077, 2890877729556257606, 16676527939404087356, 223754558788184593, 4767414622778376421, 14072300156908432530, 16856861612825314654, 11910434229443384600, 15658716527747040980, 14322127566252286435, 4770460127206402609, 10805338145914832851, 1391598300875421210, 18211456042978337510, 11866022853402812888, 6438324596032750504, 13328288515202849800, 17331158106613184460, 18344276842462151560, 7458506668679174706, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [5831108162926480783, 2015344066519517192, 10751299519219102331, 3856188963254020539, 4769583868215503893, 244163607749525539, 2275307600658358093, 14687360957082158138, 1446211823843582468, 9065094748168193518, 13172417511285944435, 6283226934869114102, 17912900233620106299, 8537437460267509495, 14429029577374864048, 12296947853479463704, 782626069616211185, 8418933870535928003, 8486366749806429302, 5183416470700366595, 8007220776657207831, 17387803153141845177, 11798268456173906310, 2039526413662718418, 1969662736637306049, 3736305836880398319, 16894861457913198121, 7547361473669724663, 553494724036872290, 13690090054816609773, 10710009389473682712, 4416250439475247271, 0, 42368, 9860311344216082483, 4356844177334189800, 8724150062868049447, 3846911055059526201, 16861225296757755735, 16925961143355054643, 7763338432894318220, 7504506723642096670, 11045006668578082721, 15092595329879644577, 4298948569114582870, 17810272068739440989, 13969944955380272714, 12356982018953263244, 16520418754635432271, 4689628285093180625, 7190852124445770478, 13072354659666011192, 1524422576558323017, 4274963317195893198, 12684756825761097033, 3511571172448102031, 823386573204270152, 9615020079928624381, 16119779393022010645, 17295023900181003317, 16373019178487693626, 13423474518210064130, 10379152206886126257, 5831108162926480783, 0, 8256, 1131208899036558480, 1667157010810320250, 2053960715201569301, 1526213270499333709, 69813565043892453, 14925652377538846871, 1380252317064967448, 9902934070223067140, 3786794161520721521, 664031068804619792, 8470323998416702977, 4965297830526000942, 9404280000999464502, 8244737495337250711, 4784363486033662704, 4680481291290566437, 15373555507761845373, 8780119261264514018, 729009684537575982, 18306419558979237700, 15407410920890065538, 2509966126115291236, 12709897403480972846, 11498596868429821859, 6606875518512322314, 13880694912200059110, 6972406840307481976, 14148490408465275064, 2917966740410115114, 18375473735916206629, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [7330889791923421278, 10618804531988892326, 6829597264991376521, 7276367259939934310, 4372128272177755375, 13867864482574853380, 11515384977073734030, 2326647313830366386, 13816377619801393141, 12980893881100963179, 10932000450943930101, 8130570750653425723, 5357774255557548944, 7155850970105010704, 14398424816766135464, 17567990292669453433, 3968215852282073691, 14805102781885121051, 4151289254235444823, 18353166840871736216, 10039237550878760371, 13168620354442609447, 6577939425615831706, 9059653401043810135, 6948526767387800120, 8497839100864599482, 7049306369106895867, 17755292521806365866, 11522074935679212862, 12318001418161393796, 4090852078585609018, 2326332951934988565, 0, 10592, 279816225750213135, 3650402777016745376, 1781472746866786234, 10113987313323159199, 9398274187564883752, 16748408482785331310, 30358156203896034, 3074595635178688035, 6205342630873024293, 1697370376582801763, 8815094577559083340, 449557436115663881, 2151092097708635255, 7636620675010033430, 2307825524015342399, 8991051645303444091, 2473911126910605027, 2375720167990024221, 10037026397378548640, 14834683004264726058, 6907102329277961715, 18213897356329070177, 5667698909130756383, 4686287875705541143, 12476469095199609689, 17702654136961983716, 5311930945536331644, 7223353560134237057, 13509433978352760019, 7330889791923421278, 0, 2064, 18136552782870868471, 952274539956745973, 15933282259815262093, 9924516287334785738, 18064603646801610993, 5114527609957824263, 11816233963570869158, 17699527003452380450, 14533708946479200173, 17484213571014188868, 832814531422633701, 1508169308733590908, 8423043379628164525, 12595277727969636921, 14226276023010866965, 10485112285448962747, 1783527593060720204, 10145484005384627580, 7463752398658534839, 17345550819494003223, 4432309123412733588, 7086318781105575433, 8830891075082588619, 310185093236608634, 16683125300631590273, 7786799186167080425, 29465347809991832, 8090161351836983773, 8665315444141111469, 2105717247508690050, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [13218130135561237014, 16340228938899992486, 10079854000224610696, 5386106271938997570, 13529324029352761767, 1658368978401400644, 5806843431688025252, 731555729686954734, 16408636790989999614, 1194390383615742435, 1479991350936063621, 12665328444727065725, 16508621306808630414, 4524096300448710209, 3702021734644395951, 99320064886013740, 5380967634808025409, 4525525454001958153, 6245097092663538640, 15391685819936748296, 4523823347492887021, 7935485252853114521, 15349701448315707717, 6654503633133174944, 7791852406585602976, 16388618934142889960, 5021320952913191057, 13823616735181633506, 14978021216926555772, 7066479221415084403, 6595027110114265051, 9381983878411686905, 0, 10592, 1439899159397533405, 14727094498238943916, 10746359213734270257, 1223812058834541930, 1848521703701691504, 1128334504960281357, 6743090978755405998, 7738088049886519458, 17939832698319978092, 13966013418513317366, 2011070876654233589, 12183169551034808723, 9308934663460035993, 3987409101004068842, 6640678206253988218, 15420175838347825984, 2447243913023891846, 16080138638164650345, 11821902144147060712, 5951909302827919869, 138258931412597884, 10064659859509677191, 6862491015452895794, 10574916399821725047, 3278355048806054125, 6884933911815373710, 4616652429570306671, 3777113587480581710, 7620976189553973499, 13218130135561237014, 0, 2064, 9594118340025725004, 16218246678075491818, 11582919835122342747, 5661452934218108707, 3714647928422746674, 13689184893219719187, 1899963197709801965, 8313716591368695784, 17822645741084942000, 18354595702287703799, 12620512717427217848, 10145637708639089787, 1735222492513760332, 14681927838838900060, 9262747238997471758, 11498487923782501751, 8924101344488972446, 2592517964915386184, 4276681409258176044, 3764365715267793208, 3120204268813370353, 6019260256544801113, 2801984351776029768, 16979166255722313516, 2813750347113564525, 16588139065369475399, 12012198471360912693, 2492059183640657261, 16968938268466755316, 1679902783560062568, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [7458506668679174706, 12989182745399654381, 6424017883760389900, 6741329107631246959, 2996250744135171229, 11762321965912593392, 17214407784785549766, 4826665026771379242, 9455401689567173595, 17742880368513082962, 7202242154518776273, 14002540095489523576, 3368748681496606930, 2793317503187347986, 16090845688839933396, 12134490130702476802, 15025977060468605061, 761594659039248271, 8180292319292192183, 14097353951522347141, 13117220339118972087, 384261509201784382, 16218010128879575176, 18344680919635320495, 5612935174283274627, 13280794019151693778, 2181822407068201872, 16366192073566944614, 16350540043631590898, 1702177008576096978, 9457579135023296174, 3261819110951294965, 0, 26480, 4254579990847524851, 17114576923598071233, 14501968992007296006, 7693932549469059792, 10678009787450266287, 2595890940213877342, 12027612752909244618, 11942792976788752435, 8893673039996221512, 15212529265532680398, 977526836722797909, 3774006073579156026, 17701622526704384546, 15389797735547254619, 13767602282518466067, 10581163748471525208, 4912900994653972152, 1666712169140912317, 11001907572334629439, 18179452850399895424, 1689425248988491264, 724394552750888620, 13424695554257597947, 17992577679858152184, 11468668142758644503, 12524389240992679275, 2671393322368710032, 1059544940949021637, 18127894597596272634, 16116071169182046485, 0, 5160, 1190658701913535022, 9371121588404883743, 7133056533056999470, 7380100170229652082, 14719783382686670107, 4693530971176924881, 11125714198188567552, 2434816259070577714, 17927785478103501878, 834873962620943786, 1091858408197145201, 9293176204765248193, 11318806736621162148, 979530496520387452, 8328113718786640843, 15870139479256453021, 7754853849459016697, 2742936430580983415, 6806060556807781604, 5089080673677611112, 16430235900965466453, 309743103212430298, 15664803780047891222, 3113571524475220627, 17862871362988443440, 1231393200801541530, 15779352999894925288, 6026600320279882336, 6970552753544824994, 4949154992619464010, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [18375473735916206629, 13902220951623368150, 9495085361050600704, 3391853806089667516, 13729765936120520417, 141485484147552889, 8243287694337026956, 17175627109346761312, 1439539174789061366, 6607136348572801106, 14086551303627540921, 309044684967905465, 5340645128846635068, 15553295046773556517, 5353983225038020876, 12076475202363433555, 17294466125434314538, 584139155794109734, 17915920879523460833, 12949450161627397881, 14451576196834978134, 16264914328198243389, 11711541659758389228, 2740918710541851833, 6686302351373959991, 2544440258979831472, 414394141903116109, 10279567131504627079, 17390992297262099104, 2087983965311367455, 746869062219182741, 2044213372194154011, 0, 21184, 13079805966919738688, 12218492589526939611, 1562069618543971026, 952986602744509450, 16155494143085714581, 13684626716727802900, 2303575863276843576, 10596243276715621734, 17646165020998189117, 11814345067449767109, 11825442891411236224, 17347702280974326762, 10643130636190759117, 10594562435231095624, 4601317543004968907, 2494640429618639710, 7283529819405604014, 12179021258304518015, 15808731023964574299, 17252671119722267451, 2994890735774817444, 1595171953489970254, 11834064729547782130, 3702466161428093475, 4997071000317359325, 9247736708382385184, 7020445890779083806, 13774982404484476980, 17184349270149775183, 13243492223453509904, 0, 4128, 1352424102745866255, 13301242752201603536, 5420135027930584396, 17078794493496835379, 4779811836607866048, 3650219859599657886, 13618468821889769363, 11429589192023659923, 8853101337885331080, 9650238821992519861, 14401087967309285252, 12035560952634921032, 15407186837043713393, 15711028160746246110, 5396976350889627712, 15903424027416555998, 11304777107657759509, 9857843669692965578, 12605480788735099613, 14618970056708743810, 8493993205782554647, 6059068631740368787, 18316971448227884023, 12499808993385025318, 4210674244211222629, 18405965507148502967, 173097048437312502, 15568437290332308327, 11532601739151124629, 10000279862191744493, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [2105717247508690050, 3491444178429880275, 3654621520649551024, 7030657201005151820, 7637363889880507326, 315282984146600331, 17353109826910914993, 692048541551218492, 13156326072595205886, 10194990537923928883, 2922061505936462403, 15996466154888710009, 17732870380491710842, 14251791589102075671, 15172043069041220075, 12169787591194237693, 9553321287361189913, 8794979035614942225, 6361471239272081213, 405831690173848179, 16422680862829694082, 13049156127751943768, 2281938208880998131, 7298980622174255274, 14817998461955857919, 1488746864367869490, 3792000010759110764, 3437974088341498298, 12846460123869708560, 7614720757886491626, 15097645659347780347, 10091523089564062088, 0, 5296, 6743125803107521679, 1867163304908812007, 1669000574108639518, 3582028644269610893, 16317815132307200966, 7118493626667445787, 13566879202183211144, 12402898926771175303, 11408064245891139905, 12248403740758614702, 1261452888691293041, 7470708275017896296, 10608583573536775206, 12594414503848564818, 13990563506880433299, 5287408014276309700, 1194675807210157848, 13081677376179713163, 9790979724735385269, 3429994162335743101, 18282263504341243063, 11073532118063625032, 18241092167097720365, 17490629239865315061, 17451936898459652544, 3705015252668379511, 15646972017585065174, 8948369964312160088, 12421841574297279117, 11600144893983875756, 0, 1032, 4798141223555508282, 12962488577647927717, 10133257770726709126, 332864556927106185, 12116126881643349994, 6604148216925166409, 101015634312276042, 15934992137290074922, 6112274855072540816, 17762248064501548615, 13166189948742588777, 270100349969833402, 13485211244653928073, 3502306881032295169, 13607663468974078519, 8883940618995723208, 10623667092532612652, 12293715092576816840, 10386976621364522928, 9128135834925108269, 15731443845270647366, 13373704167654916087, 13746187061551926812, 11684868053863796759, 3258729720361659960, 10434904637843727165, 7034851303745741351, 16133345873308301364, 5426492436527662130, 2980140658145787783, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1679902783560062568, 887537335777434417, 7914176922452123947, 1643778320524415517, 1728436561347785451, 1408159065058053807, 9042106580667294809, 16801941014204681951, 6030138189777334274, 3444215190125446364, 13983691239825442902, 9510849878170612681, 18029733377150662644, 10959053172580000061, 18079653246948800863, 9194190146189639040, 11454548593893846798, 4069919206893812430, 12335254121418857667, 10779545165064436731, 15302642370914668430, 16699578041838378317, 15354185361540738340, 8102419126297897135, 10266466507324112160, 154956368015439874, 11229756891578734264, 16853723936443190227, 2384358946534123926, 8422791455791464432, 4547363727573445852, 12303199265142910504, 0, 5296, 4681956701739972184, 3297507518564977562, 10978317254779656082, 18354142145846877062, 18082471245109184632, 5915586390509665684, 14991347734816807516, 10215583712512422817, 10329936247150774828, 13253613960908137010, 9477407930706312020, 3959435681151189208, 2924854172257996410, 2653599560818129230, 3882603508690502535, 12153757963762118208, 5905443084652099463, 3326804770534376335, 15700324760341857643, 4711113127161390688, 14532162435088690923, 9731412496448089833, 9087293637868970990, 16672855635472301531, 16157291854026127596, 6164067506556190095, 16340142805513243131, 13982894413446367987, 16491357058269217705, 8055423479702674738, 0, 1032, 11702782905971311743, 8115486282645452027, 16425371230714077552, 10333496212804492507, 1572943607289284437, 13244361396034453954, 12880029163967100393, 14716450796809578181, 2618965885956593171, 1606019581379521796, 12562170441304287563, 4599116799417823473, 4257071131168813417, 10446583017549019711, 3570388907037362614, 11170081717188072664, 17238997244398394333, 17231192964516960933, 8123337005847551087, 7060091366977384949, 5719725530909274667, 5057603743378325948, 13848013489728729143, 17729739340387068117, 367186060507240673, 1411195984452924204, 11088333491201093194, 16575090776691519559, 16147396598096989679, 14525300817521856881, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 5943604277132716192, 4729837691331628860, 1674634776332752145, 7613188931468803736, 645295908479301016, 4819615722506419001, 11336624181859957416, 6689083876929965918, 781516977059517682, 15888367593609586862, 2073776435788654133, 5783336608935715666, 3444732223180695300, 14606979696091412365, 10168871336598875304, 6394891966766051956, 9365831893597231271, 1329427291838800772, 11227549061287359722, 13960461272960093645, 12505943444250480563, 12975117899269678548, 10167800255227906082, 13066384169754273383, 4112955199466075909, 1998678292085591025, 10054365883864272595, 12102928269928850518, 2245777887379330575, 9356606797863555676, 3073184512654327322, 0, 26480, 7418486580310857761, 17019749743168160467, 4937487787523099272, 9870317658000082520, 9027489043629892579, 4927345804956144414, 15545533182903182788, 3907169825113221089, 2896862965383757523, 13069247508460875244, 6257437454212159648, 3775904100227399669, 16966215805924461950, 5206554086085975117, 10673185398346121565, 8235209133198882488, 9483230364913556480, 10561284120293439668, 17774065041915838082, 8696583885468400324, 9686516267351636652, 5891290976833577870, 6133144642314902299, 4372983987509841442, 2945651218563202825, 17570690068387731452, 2481092360881257830, 10656699665804756215, 2380753665748314674, 14226887805014239710, 0, 5160, 18346837778669738664, 15130142357101091527, 6726588340010678615, 8394319278312203283, 15942424551308612685, 7629500615465222065, 14939877513325106589, 17048523965011794048, 2306293645521445312, 823113708878672797, 14981348226783328932, 7432878333905782051, 3482639998457803800, 632277917380007036, 18266437030920184246, 3366715262389109205, 5280275432441977334, 5379329043314533811, 13912213856326486056, 17217059915921675075, 15634373017412823086, 14981257187297131103, 16697350900700022325, 5239234081629986555, 3229291246709926782, 18373224696258292584, 6771862800272250893, 7666370275789511263, 12942227631865082960, 15190222347874856922, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [87, 17603684385657352024, 13366748441350673725, 18052526731898170651, 16785850119445204235, 17347247651058160235, 9846117923911981021, 2707934329111401539, 10990776668153918653, 16235726062564973401, 11998830268732907127, 16193884857588698661, 5666920201535196850, 9215652902428934246, 13583314662851581779, 14184614926440663892, 14812424854330405309, 11904135334311579620, 17190421092224736398, 9627221069906324225, 14645975772268327665, 16511930999984330317, 15441967984164967023, 7049611109336029555, 13611843094121287226, 4797816591436698393, 5758188707877290663, 9330189747696559974, 3650051887228749294, 2591620200177413535, 6408924248829769611, 1041809921369720709, 0, 21184, 7994119771983090684, 1155757367334915164, 14020255521522346779, 17824815497741664585, 5614135143986453745, 7146977362179517856, 3824341730458112374, 16894770516791760289, 2879202081945061688, 5646668393535724753, 1923820538236998308, 5244112822855800046, 11523838157115606042, 654162111745526915, 17566215582742419332, 16153951788992043302, 7571027843561021323, 15400774862911119623, 10370417002357863310, 16053800817166961724, 10524854462256237020, 11096622266210541923, 15395378671807683368, 6912701393383240626, 11746170412650491065, 12730613771714545378, 6535987403990440638, 10122156746538229970, 3728282910211741030, 5183721621480304370, 0, 4128, 6496253015800789210, 18063315295058131399, 14099326864720264780, 16744359797696928029, 11669954633423859445, 10923938539628559259, 10579480970462933513, 17315553376669597828, 12114095292572219189, 16129781670858537825, 67936491912723144, 6285840300661422802, 14359460599290704174, 7597471307904508314, 8469569990667894210, 9117246600999250277, 14614928058075190380, 13738364908865630160, 1806905237893315697, 261412144627674040, 8380596589382515797, 3809925330596605534, 1983199361335541287, 6337901890572878101, 17063257729896061936, 12690697575318882146, 3846044480011221270, 10729939698274680623, 5297971463863936522, 8671284646676347574, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 10852330926611119322, 12717828147245365778, 16006362017165978748, 16947261939602052576, 16534966660444334749, 6673071514994095144, 7939954455500268845, 804393087582707009, 1175191158969387310, 15407569589042353610, 6796181761165706510, 11169721396876266709, 3977957405235486697, 4025150260536840913, 10372769747575091868, 15860691988012150726, 14452440347418879120, 17083043265128501593, 15702979623219592866, 5958131302596194806, 11397091736337506145, 16755714190267385647, 2571437932894054501, 699303239030048473, 7036852882168517142, 8014024215551803682, 10588441110882001134, 8114639632202749987, 1351582854755852759, 17425991862702377038, 16698144525752928383, 0, 5296, 13498446627995378981, 6649809143130705797, 9522654220689816851, 7559480440412863769, 14249558742787467865, 4471817386074892784, 8930056613191782368, 9155852006764527165, 18377192855492301434, 12836057040498431452, 12282989683528533601, 3467617432525765103, 13766601347831535388, 2925667013227878460, 12822094630311757386, 6738693051085880966, 15661549307393278485, 7649583626848747165, 14069036937855587505, 9495341522376803417, 534616849927909964, 1899062451757954377, 6407581375465580420, 16442451038823818694, 7698809547406684914, 18232885173941026794, 3104393142368480565, 7738728989754721313, 4802195899845329288, 14925669435061449558, 0, 1032, 13084260837127404333, 4018109146681745349, 14498381569327145056, 3778421823029569719, 1344624249217908323, 3634653398484528177, 1428985706412758663, 11382569756632997337, 13894906302086601399, 3911680161282028629, 11467762927868003365, 10098326072301516020, 16073214466625742345, 16150512194511843089, 11525294274796193451, 15902507139806774023, 13926886722650908730, 2974304378722638293, 5274544965980948277, 9984170014312577610, 639485734140932316, 15088403650698955530, 17189134684458608982, 6515320870350778492, 7902492290152572474, 17310456195349246143, 4070136787975548901, 6345872167795009033, 3095930865537762353, 4232664728858134772, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 11891503448030670524, 3287860802649270664, 7152349585903556000, 3064107934796899020, 7381693478918306831, 11160134190138055922, 2311418288317025877, 705831048107886313, 3376931428262517395, 203181368331322397, 16774441650532541635, 13029333743753090049, 956539518201203404, 1805352044388884357, 2938636165292363575, 18444922890945363700, 2754923086646275489, 15332178805421692353, 10165745949485028775, 12341254189464639727, 4006244815271418796, 16087284806139179563, 5794920505966185319, 16096174561007826751, 13536289693580317045, 10216538963378596370, 17446785267706793614, 16624551875599356960, 4389250045279167249, 1839559312650246696, 3566999122524049164, 0, 5296, 12442366360197298238, 6098667720777990098, 15014871424912942550, 15008680935203256586, 5625270093505773824, 14457467770650559296, 10887298179723462085, 16706947956141547836, 13310039786220231748, 6132850845308416918, 12403357056402201263, 1240140770639885705, 15461729627686219061, 6574742069523544220, 3131690396120496930, 17758791276367026584, 10046968584624867256, 16910374147545432071, 12405462687145854473, 9006078559482542456, 13476220060215365999, 8384214154009398478, 10365404322190410833, 6851505899182549268, 18261819862243438027, 2823760450959191582, 17079185842171546000, 2573099324947734045, 9396372422985936818, 6899349384621454800, 0, 1032, 15909096041365347974, 18432189660917429733, 2798890989547891271, 10768372030970716894, 5935807051329113911, 1259182408195029650, 16024750973514577255, 6103595041913569283, 914770550723164908, 5067028895751058275, 5242612139537538536, 13359135899043031769, 4430959127423856282, 16317056360529517539, 2634255659160911215, 15590656855559575839, 6832335878067392309, 6045109056629836176, 18146646330136390606, 6482705684632040588, 2770791364887326735, 7707774010999656594, 3401430074469265273, 3500862351024377705, 5135727797169111985, 14940852959892477883, 9633218853985087472, 16966092255533854383, 3065488485208441055, 15703076512693482766, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] }, last_program_row: RowIndex(10) }, program_info: ProgramInfo { program_hash: Word([7894050562420362676, 4416250439475247271, 2326332951934988565, 9381983878411686905]), kernel: Kernel([]) }, stack_outputs: StackOutputs { elements: [1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, merkle_store_nodes: {Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571]): (Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350]), Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350])), Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484]): (Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693]), Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693])), Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781]): (Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874]), Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874])), Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171]): (Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361]), Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361])), Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815]): (Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305]), Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305])), Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689]): (Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195]), Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195])), Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362]): (Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063]), Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063])), Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848]): (Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661]), Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661])), Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352]): (Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829]), Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829])), Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444]): (Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223]), Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223])), Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386]): (Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388]), Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388])), Word([13190842942618341421, 17548956981569849952, 15418963848144418856, 730733050713174879]): (Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144]), Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144])), Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874]): (Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675]), Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675])), Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594]): (Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115]), Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115])), Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809]): (Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257]), Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257])), Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777]): (Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555]), Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555])), Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509]): (Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882]), Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882])), Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725]): (Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979]), Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979])), Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134]): (Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987]), Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987])), Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828]): (Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910]), Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910])), Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830]): (Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054]), Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054])), Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228]): (Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742]), Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742])), Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443]): (Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928]), Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928])), Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643]): (Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979]), Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979])), Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758]): (Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106]), Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106])), Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580]): (Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594]), Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594])), Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765]): (Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045]), Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045])), Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766]): (Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281]), Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281])), Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385]): (Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828]), Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828])), Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579]): (Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171]), Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171])), Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212]): (Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992]), Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992])), Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463]): (Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004]), Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004])), Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502]): (Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023]), Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023])), Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539]): (Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537]), Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537])), Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865]): (Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225]), Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225])), Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690]): (Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947]), Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947])), Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202]): (Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552]), Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552])), Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079]): (Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444]), Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444])), Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850]): (Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548]), Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548])), Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448]): (Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987]), Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987])), Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041]): (Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035]), Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035])), Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301]): (Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414]), Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414])), Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414]): (Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212]), Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212])), Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703]): (Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439]), Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439])), Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271]): (Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955]), Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955])), Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882]): (Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802]), Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802])), Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152]): (Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887]), Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887])), Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028]): (Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948]), Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948])), Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331]): (Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093]), Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093])), Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394]): (Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134]), Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134])), Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546]): (Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228]), Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228])), Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620]): (Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414]), Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414])), Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800]): (Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703]), Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703])), Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671]): (Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205]), Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205])), Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537]): (Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011]), Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011])), Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516]): (Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301]), Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301])), Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831]): (Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986]), Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986])), Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415]): (Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057]), Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057])), Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722]): (Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689]), Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689])), Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144]): (Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682]), Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682])), Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295]): (Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268]), Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268])), Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818]): (Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513]), Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513])), Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241]): (Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565]), Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565])), Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439]): (Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012]), Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012])), Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512]): (Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850]), Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850])), Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986]): (Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865]), Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865])), Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982]): (Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777]), Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777])), Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808]): (Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394]), Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394])), Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979]): (Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690]), Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690])), Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093]): (Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620]), Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620])), Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902]): (Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789]), Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789])), Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542]): (Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094]), Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094])), Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057]): (Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362]), Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362])), Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205]): (Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961]), Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961])), Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401]): (Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580]), Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580])), Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553]): (Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960]), Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960])), Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169]): (Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031]), Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031])), Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682]): (Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053]), Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053])), Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118]): (Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562]), Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562])), Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725]): (Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666]), Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666])), Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661]): (Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897]), Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897])), Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981]): (Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447]), Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447])), Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072]): (Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646]), Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646])), Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140]): (Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404]), Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404])), Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515]): (Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152]), Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152])), Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709]): (Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664]), Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664])), Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800]): (Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103]), Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103])), Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741]): (Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169]), Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169])), Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005]): (Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758]), Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758])), Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802]): (Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070]), Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070])), Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159]): (Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005]), Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005])), Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350]): (Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443]), Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443])), Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697]): (Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573]), Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573])), Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928]): (Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331]), Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331])), Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320]): (Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166]), Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166])), Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814]): (Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079]), Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079])), Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447]): (Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820]), Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820])), Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284]): (Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057]), Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057])), Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697]): (Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131]), Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131])), Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955]): (Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290]), Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290])), Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910]): (Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202]), Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202])), Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910]): (Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822]), Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822])), Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106]): (Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847]), Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847])), Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404]): (Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441]), Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441])), Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796]): (Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186]), Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186])), Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053]): (Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516]), Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516])), Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992]): (Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818]), Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818])), Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957]): (Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315]), Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315])), Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709]): (Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794]), Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794])), Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091]): (Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539]), Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539])), Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664]): (Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558]), Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558])), Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294]): (Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579]), Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579])), Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947]): (Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502]), Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502])), Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829]): (Word([0, 0, 0, 0]), Word([0, 0, 0, 0])), Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045]): (Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137]), Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137])), Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914]): (Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041]), Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041])), Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573]): (Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378]), Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378])), Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699]): (Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873]), Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873])), Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225]): (Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262]), Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262])), Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057]): (Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692]), Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692])), Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131]): (Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997]), Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997])), Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555]): (Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385]), Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385])), Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195]): (Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709]), Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709])), Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166]): (Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542]), Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542])), Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027]): (Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373]), Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373])), Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378]): (Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509]), Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509])), Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097]): (Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553]), Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553])), Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217]): (Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815]), Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815])), Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873]): (Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864]), Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864])), Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997]): (Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722]), Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722])), Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887]): (Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766]), Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766])), Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589]): (Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757]), Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757])), Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539]): (Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665]), Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665])), Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129]): (Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229]), Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229])), Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137]): (Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312]), Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312])), Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019]): (Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378]), Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378])), Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331]): (Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713]), Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713])), Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]): (Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980]), Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980])), Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325]): (Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546]), Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546])), Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170]): (Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822]), Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822])), Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054]): (Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295]), Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295])), Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925]): (Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848]), Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848])), Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909]): (Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796]), Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796])), Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540]): (Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170]), Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170])), Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214]): (Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448]), Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448])), Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317]): (Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294]), Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294])), Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757]): (Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416]), Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416])), Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378]): (Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091]), Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091])), Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263]): (Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463]), Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463])), Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666]): (Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361]), Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361])), Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174]): (Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992]), Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992])), Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470]): (Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401]), Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401])), Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665]): (Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957]), Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957])), Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262]): (Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144]), Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144])), Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229]): (Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284]), Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284])), Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134]): (Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325]), Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325])), Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855]): (Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765]), Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765])), Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115]): (Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814]), Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814])), Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441]): (Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831]), Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831])), Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977]): (Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446]), Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446])), Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880]): (Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005]), Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005])), Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789]): (Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995]), Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995])), Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000]): (Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267]), Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267])), Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998]): (Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982]), Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982])), Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995]): (Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539]), Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539])), Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507]): (Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512]), Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512])), Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305]): (Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118]), Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118])), Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219]): (Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009]), Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009])), Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416]): (Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089]), Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089])), Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980]): (Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445]), Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445])), Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063]): (Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140]), Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140])), Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713]): (Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159]), Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159])), Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031]): (Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809]), Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809])), Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932]): (Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037]), Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037])), Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094]): (Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925]), Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925])), Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315]): (Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386]), Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386])), Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446]): (Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721]), Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721])), Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742]): (Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981]), Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981])), Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661]): (Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072]), Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072])), Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979]): (Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671]), Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671])), Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361]): (Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269]), Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269])), Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558]): (Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571]), Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571])), Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290]): (Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902]), Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902])), Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987]): (Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741]), Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741])), Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902]): (Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515]), Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515])), Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497]): (Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028]), Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028])), Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948]): (Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709]), Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709])), Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009]): (Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725]), Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725])), Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387]): (Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317]), Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317])), Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159]): (Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808]), Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808])), Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394]): (Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699]), Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699])), Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312]): (Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000]), Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000])), Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987]): (Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821]), Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821])), Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046]): (Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909]), Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909])), Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565]): (Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028]), Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028])), Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269]): (Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352]), Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352])), Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847]): (Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271]), Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271])), Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513]): (Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800]), Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800])), Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054]): (Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394]), Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394])), Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004]): (Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977]), Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977])), Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675]): (Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800]), Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800])), Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692]): (Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159]), Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159])), Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909]): (Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932]), Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932])), Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814]): (Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697]), Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697])), Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186]): (Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387]), Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387])), Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445]): (Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470]), Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470])), Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966]): (Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507]), Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507])), Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548]): (Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253]), Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253])), Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897]): (Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783]), Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783])), Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208]): (Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054]), Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054])), Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268]): (Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661]), Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661])), Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388]): (Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643]), Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643])), Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257]): (Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174]), Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174])), Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960]): (Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241]), Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241])), Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721]): (Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046]), Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046])), Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822]): (Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217]), Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217])), Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253]): (Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697]), Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697])), Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054]): (Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019]), Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019])), Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821]): (Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432]), Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432])), Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864]): (Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105]), Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105])), Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373]): (Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855]), Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855])), Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646]): (Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830]), Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830])), Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460]): (Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208]), Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208])), Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033]): (Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214]), Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214])), Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105]): (Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129]), Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129])), Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281]): (Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909]), Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909])), Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028]): (Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027]), Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027])), Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012]): (Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054]), Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054])), Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562]): (Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589]), Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589])), Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037]): (Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097]), Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097])), Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355]): (Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460]), Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460])), Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223]): (Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355]), Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355])), Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089]): (Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306]), Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306])), Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035]): (Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219]), Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219])), Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432]): (Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297]), Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297])), Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693]): (Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263]), Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263])), Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794]): (Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484]), Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484])), Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552]): (Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941]), Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941])), Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267]): (Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814]), Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814])), Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992]): (Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415]), Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415])), Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941]): (Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966]), Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966])), Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822]): (Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320]), Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320])), Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306]): (Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902]), Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902])), Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820]): (Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880]), Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880])), Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361]): (Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725]), Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725])), Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005]): (Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914]), Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914])), Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783]): (Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781]), Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781])), Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011]): (Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033]), Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033])), Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297]): (Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910]), Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910])), Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070]): (Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134]), Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134])), Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144]): (Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331]), Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331])), Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023]): (Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497]), Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497])), Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103]): (Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540]), Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540])), Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961]): (Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998]), Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998])), Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414]): (Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]), Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]))}, trace_len_summary: TraceLenSummary { main_trace_len: 11, range_trace_len: 39, chiplets_trace_len: ChipletsLengths { hash_chiplet_len: 96, bitwise_chiplet_len: 0, memory_chiplet_len: 0, kernel_rom_len: 0 } } } +ExecutionTrace { main_trace: MainTrace { storage: Parts { core_rm: [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 16362180982079134587, 16601100057639640520, 5521682503008444658, 3792208660074152519, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 0, 0, 0, 0, 0, 0, 1, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 5296, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 2, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 1, 1, 0, 41, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 3, 0, 0, 0, 0, 0, 3, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 2, 1, 4, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 1, 1, 1, 16362180982079134587, 16601100057639640520, 5521682503008444658, 3792208660074152519, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 5, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1032, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 6, 0, 0, 0, 0, 0, 5, 0, 0, 0, 1, 0, 0, 0, 8, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 7, 0, 0, 0, 0, 0, 5, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 8, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 1, 1, 1, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 9, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 31, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 33, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 39, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 43, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 47, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 50, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 51, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 53, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 54, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 55, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 59, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 60, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 61, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 67, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 69, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 70, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 71, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 72, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 73, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 74, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 75, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 76, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 77, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 78, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 79, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 81, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 82, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 83, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 86, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 87, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 88, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 89, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 90, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 91, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 92, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 93, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 94, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 97, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 98, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 99, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 101, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 102, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 103, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 104, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 105, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 106, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 107, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 108, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 109, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 110, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 111, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 112, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 113, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 114, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 115, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 116, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 117, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 118, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 119, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 120, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 121, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 122, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 123, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 124, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 125, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 126, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 127, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0], chiplets_rm: [1, 1, 0, 0, 16362180982079134587, 16601100057639640520, 5521682503008444658, 3792208660074152519, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 0, 87, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 270895689018017911, 16986171160676071137, 7387278922185249498, 17172605884943369535, 17619702065145827445, 16331429716507735697, 3432600375819256090, 8340422935034340708, 0, 0, 1, 0, 0, 1, 1, 0, 0, 5296, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 16362180982079134587, 16601100057639640520, 5521682503008444658, 3792208660074152519, 6708412556839205818, 3204764821942414262, 2382590011410319125, 5080678178504844773, 6374574376632329694, 13516826603120023138, 12611398678228181741, 13552592212104960667, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1032, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 11116382020814057190, 14732796941305378371, 13074361791711182490, 6715193688317415490, 1571558009365433839, 13285275197432594374, 15905141483335727027, 2507840277166973476, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1032, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 15913981378790993016, 12701179462806902902, 9645342555817022514, 6889850077248808033, 678249829196625442, 8726676798253716750, 14136118088409135949, 1027279235140821190, 8048729929177993405, 2542525775606472849, 3283471062508934848, 18058280687405074483, 1, 0, 0, 0, 1, 0, 0, 0, 0, 11899090779839289087, 1701090513954162998, 6953639183117323837, 11460660778637092812, 8345945186928076892, 11308243255833047975, 5734666540714547293, 1546649737555419076, 14643837757854608147, 7477230882792828789, 2359592855656894189, 12732146754685591216, 1, 0, 0, 0, 1, 0, 0, 0, 0, 16283412161296764998, 17261112905912533997, 1498213616014501531, 7707889409925905689, 16090493533591377617, 525010687572874692, 5228788497345464933, 13051466527897639054, 3560924095387897187, 12551242480725370445, 4038828260160651477, 6132317990703151787, 1, 0, 0, 0, 1, 0, 14261694278902826987, 16097544111075686229, 16632169854204459773, 14265791174051766329, 14732671264513481238, 15642599276989292777, 7593738854072541043, 11440582168151819564, 18258483622390056257, 6851601084855956341, 10463349537167637967, 10032876585525342603, 825669147467031185, 16271217766495541082, 9021089524754424392, 1, 0, 0, 0, 1, 0, 16780109665356203593, 16025948514351396737, 4256182047405196535, 4919013996388780384, 6974015548720770018, 10189882052640604940, 12288632186238773648, 7055558833039165669, 9820743264545515107, 7353106531603230851, 5612808106478211181, 362487531847990854, 10259224130335842891, 2374318293393776907, 16208179153232019183, 1, 0, 0, 0, 1, 0, 9496969110446094198, 10424961628901078909, 7587726188775237019, 13423955604028434301, 12288543613568774022, 4068762405627465026, 7288480650179820504, 1035430088689333582, 2651098721515326755, 4524440782000877024, 3013038852551457145, 12536534023666437466, 6560028330562582937, 9090521726813489969, 17634755409309861791, 1, 0, 0, 0, 1, 0, 15761194215082968049, 15796684185970405493, 1294179585337070936, 5701860167148115542, 17707247215386403887, 18419960639673587986, 14570347312565937582, 8634142387233894354, 11938075017385927203, 8060480374868324599, 16699922976999064541, 14234489074154948378, 17210389744085299852, 17331527780947314617, 16356838976302290254, 1, 0, 0, 0, 1, 0, 6184336662619539433, 7106147576739595100, 18237994300618329820, 9768155666925548219, 226714884885574576, 11169479382209254075, 5756676929838789145, 29803495366482069, 13128905441940840949, 18304516631519674746, 3177693875357946498, 10624850715031233718, 16956738608020324589, 10558540052020438814, 7826502712354673600, 1, 0, 0, 0, 1, 0, 1980308537464408089, 6810023246846442283, 9400257804338494201, 11246932855318952856, 7504545710540897051, 5823677062954428984, 9151299935574592196, 15905322272715446259, 18174748553199601666, 9877077233183640995, 2431998410719122545, 3541292002384422941, 5416588529930333172, 15788517205879313917, 2490575598934209003, 1, 0, 0, 0, 1, 0, 17950140321155419078, 9014768943295123367, 10707122777228105884, 10701204914974985643, 15060806908759160804, 7011191650405807117, 13598159658926423040, 3947314552577424057, 12985682730462769834, 18264715466581442035, 7667189540353817157, 7685483800933651249, 16085167604591833455, 16105855167414075111, 16215395602017884846, 1, 0, 0, 0, 1, 0, 8676227747932036802, 0, 0, 11504729673400082663, 3659553513673892306, 10374352082945691939, 15819529278889203623, 18107940902385670152, 8889798095480337831, 12737345777792032790, 456604824069734238, 2859376131275373721, 8758251935142908528, 2364536875264708997, 2435873391009301907, 1, 0, 0, 0, 1, 0, 0, 0, 0, 16797630026773069829, 16954579754978210547, 4393671449525183699, 6245909065255485436, 8311309349844601638, 3305827896314343556, 1615477551160071258, 3897903986825909618, 13015230208471866351, 13839070994009764281, 2415598337053791919, 5526300544248852335, 1, 0, 0, 0, 1, 0, 0, 0, 0, 12827873667465929582, 15892701250663610383, 549489834728826775, 9425334953627649153, 15402634395731091512, 11814416271399500934, 14597718118926923662, 4726679541432826422, 342915941842538663, 11221492717904369823, 17188959961041335276, 13559932473868727168, 1, 0, 0, 0, 1, 0, 0, 0, 0, 8689096602925893779, 4096531352684607500, 8424481237826564505, 15238165026175259240, 10985176737527635898, 2672540837788784952, 6649439643634522762, 7581835251244605715, 17671970641549389116, 18069913154458602790, 749417941228438762, 6150863900366154379, 1, 0, 0, 0, 1, 0, 0, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 11116382020814057190, 14732796941305378371, 13074361791711182490, 6715193688317415490, 1571558009365433839, 13285275197432594374, 15905141483335727027, 2507840277166973476, 1, 0, 0, 0, 1, 0, 0, 0, 0, 5296, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 9406198837081470939, 12454644480646831381, 5357297729805547264, 15695767008081417024, 17081781165782008305, 18173774266735228622, 6597958223090468622, 10058815580948772803, 9341085403015625984, 17305809056185869492, 16092333721991261411, 14466140396882267896, 1, 0, 0, 0, 1, 0, 0, 0, 0, 10022220918800215931, 6625466299838152616, 14873368774111773763, 13822207310342005989, 11851640107665623803, 4144160359412257714, 1001954617881206717, 2558852513241095712, 8048571622541726255, 3796262690630383451, 12690029978283677858, 7698456735078463171, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1529838978363474364, 5877585793149040063, 11620602129319348479, 3184399423922769699, 4766473366160256877, 7300042540399827448, 2462275239493078851, 11288811565422176008, 16822095754433680909, 18301782264345075251, 18087044935643148806, 510047809549721667, 1, 0, 0, 0, 1, 0, 17625583494235189807, 10622457062204255065, 2653216356844660597, 9475027500051639757, 10463750966311648190, 11600868756246964674, 15662168292079378087, 14737424852298451342, 117344945972585870, 3251083096698399603, 12684542007451613640, 4788924408482455108, 6902797868122893844, 15800238251163812693, 12046292011878974455, 1, 0, 0, 0, 1, 0, 7496472832454263388, 12998172934440185624, 17507911152779544052, 16456090005001040440, 16590029451027219509, 2617628953138715244, 622817961215058190, 1598986500188737220, 17607068252592942451, 15060402253986549440, 16875740049367006869, 4040451923151286438, 5925341866968505601, 14259707661873610422, 10732873470134113982, 1, 0, 0, 0, 1, 0, 1452526314939094806, 1479000593888603377, 246310986971833963, 4152569545950646704, 4118156517299583310, 17663239633609473365, 8127661496786659791, 17689549836214880979, 14746946312861632567, 602662289136933629, 11216558892028292475, 5188174964157774722, 7100861533945618475, 3714941418598094928, 1377039040653060055, 1, 0, 0, 0, 1, 0, 2930684747787414446, 1754494303819808128, 669923854651336066, 5941781742039952076, 876859729835418933, 790907098378102911, 115518666891692872, 16890877536441094576, 16820881161920465009, 241154565549913410, 44006951265386772, 5087127128059490065, 18106355872892957036, 3269612205224843731, 8638796096796806719, 1, 0, 0, 0, 1, 0, 2414727401863600363, 7617116592575512612, 18041147314657306922, 15957716643783059543, 11912796059449786962, 11153176059938326063, 14174738803865199162, 11999349000942665761, 17632700466101721722, 6582530104605672978, 16757182470542785800, 12431955029502155155, 17163152133935520513, 1237894940644049096, 6188646281997977531, 1, 0, 0, 0, 1, 0, 2319532296399149270, 9283783715220787949, 810281363185644618, 4756894436878044936, 12165478487736095233, 13041376666032139342, 3740623961436206385, 6384260880460211781, 17121495806538343926, 14583996149149192254, 11562370595738293151, 8268709300694246348, 17892562184847802024, 3859704522936614211, 7366245284644652757, 1, 0, 0, 0, 1, 0, 949011576700156842, 1533322811274401426, 15060757839378359292, 1432035093691797337, 206692693307936550, 378907012515670704, 10248912138703390835, 10128144445036454539, 5042107387767762304, 9843022881405494656, 11880883914254039546, 13220616153049902, 455311511731825064, 5381232113954376086, 5364482943654507461, 1, 0, 0, 0, 1, 0, 5881102500383619035, 0, 0, 2424299330597632902, 607119689966087280, 17283177276798307300, 475409702871185800, 15518804315920479075, 4578339057778509415, 4685043752195987874, 10392430241191498892, 11507515262772595129, 14439767021292397992, 13673908725375817159, 5378163831543087962, 1, 0, 0, 0, 1, 0, 0, 0, 0, 14342875730731176181, 6225072162372691712, 8577974921324183601, 751519865506756952, 9824595797538483612, 10360631973465438301, 10226703749989732907, 13840269947314152185, 1831374399934529359, 14389265827404554261, 11392184682219726353, 17676970157216697757, 1, 0, 0, 0, 1, 0, 0, 0, 0, 10605591699135631895, 525785012032090331, 1824237168047932550, 3952375305216254717, 9821754274536606782, 7855314197760224131, 17861834154975224793, 9836275050510148653, 17819027328170218375, 2840178708967434753, 15534576285961723627, 15357405679043026976, 1, 0, 0, 0, 1, 0, 0, 0, 0, 9793600913424407404, 14104167067920766779, 12309619471118709560, 12550056362664815329, 320739284087105326, 3762140957859872022, 10326389091316073307, 18366686834124399227, 5296819603037261258, 8152022108836431115, 8031664516364171852, 12133015237048791800, 1, 0, 0, 0, 1, 0, 0, 0, 0, 16362180982079134587, 16601100057639640520, 5521682503008444658, 3792208660074152519, 6708412556839205818, 3204764821942414262, 2382590011410319125, 5080678178504844773, 6374574376632329694, 13516826603120023138, 12611398678228181741, 13552592212104960667, 1, 0, 0, 0, 1, 0, 0, 0, 0, 16362180982079134587, 16601100057639640520, 5521682503008444658, 3792208660074152519, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 0, 87, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 5280636662479905706, 3208946253109296695, 44103566269295951, 8046898230781913002, 15629760132913319055, 5754006142005012359, 4960387371191928838, 12044833413185230105, 5988669310706667741, 7178713832374603093, 1499340432943046009, 15290921832139631954, 1, 0, 0, 0, 1, 0, 0, 0, 0, 12274425802069166728, 3367752336261825184, 16579036642617539107, 7124592674113435496, 10035448811625737492, 8017671631288520014, 9272171596648318476, 6358741555586760965, 16325845662291591088, 4014426828241438738, 6907778321050040150, 12997760219342012306, 1, 0, 0, 0, 1, 0, 0, 0, 0, 2176397147817918311, 2192485617758155336, 17969022685205918060, 6464283742144581389, 2109163784868901208, 11044629350832782826, 2248948014446662823, 5516997715507416326, 11498340355286698940, 5954493359923909552, 4318577229044781948, 14331740095364914796, 1, 0, 0, 0, 1, 0, 15727595203408215825, 9811429029669387676, 4886620126458192524, 1121106984162438633, 9478326137574155357, 706512062896000227, 14294402532847550113, 11325030759426275997, 9908982434490094917, 5184067341385391623, 15811174175866362728, 7786341500203621121, 9631713068946389767, 8350671705757524875, 610675163789242378, 1, 0, 0, 0, 1, 0, 9419550357552199501, 13884451166149337500, 13261505407679254512, 15138595031782285856, 9638738489607553127, 14224629401571933098, 3259952174062033150, 5435890109442621260, 2745773389620535771, 5264849973136923248, 372870694419626773, 12567338000929831119, 5677329704113932287, 3580982943501747208, 14168803743321808630, 1, 0, 0, 0, 1, 0, 214648213772151071, 9543737828461147127, 11333349087355777134, 15764101235302912716, 1346328633318951702, 6277592578923318686, 9650725925684916249, 2055511090009067667, 514617177313254191, 11782462042260078709, 2753568216187945242, 5284870871448414001, 13827287292645159301, 1158005921868139193, 14225231634659489628, 1, 0, 0, 0, 1, 0, 998480186550655863, 3968564533603669024, 2425949437762237323, 14847329995972443256, 16326624456603980216, 14828306678723121383, 7874947329495583100, 15681614550741791960, 16194798321399891585, 18421718483980330016, 11308851359826131934, 9089337376280278077, 17700960267716780428, 7362413073571978741, 16936105257000977856, 1, 0, 0, 0, 1, 0, 393462918438193792, 14322328616984094066, 5472399224197240752, 3828884631367775458, 16321054874314811915, 9554475914976531614, 17869482233905720382, 12651432232289897972, 2293765132611666398, 748840778855599757, 12564242331003874045, 7434557179126682320, 3514266332620367171, 10329160438125455687, 9658837437554457100, 1, 0, 0, 0, 1, 0, 15860404195257896467, 16923363290217451744, 841463536446684601, 13000674532675750449, 8065321292721727536, 2838349880812772334, 11915276632142850778, 3488275055947029711, 9119208073836395784, 4466347092748054798, 6746559560032541915, 9616253319110065687, 8392481333103453284, 14262269490948820721, 7916501065102864900, 1, 0, 0, 0, 1, 0, 532287514050577245, 15085895713878874464, 17590572537032490330, 4226373080885343357, 9380232824716169134, 3440887107266285287, 16323191812792483589, 1456768111828341165, 14073851560129966734, 10876660044242359342, 18317909842795274420, 5298800569408909376, 17919778829682069979, 3472477774948948832, 4639454579562223508, 1, 0, 0, 0, 1, 0, 16748404491550645246, 0, 0, 15873447561070617842, 10001505760538725803, 4712210543341171144, 12974471662606351082, 1632109833251222173, 8140316977094914489, 6636942852512856391, 17327901225127233301, 17615542852500047001, 7660468230079681452, 10180896197919295321, 17774693611921464468, 1, 0, 0, 0, 1, 0, 0, 0, 0, 8662694481754592838, 12516366834863895671, 2000888369135426073, 16304957355072116537, 13467318392446768934, 4669018267279247802, 759537667994255909, 12348490174409586861, 3423256327042481469, 10635367728060221815, 14235848048115144607, 6912758962031377553, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1881834778803900215, 17355952588513451063, 16405127277136654428, 194581642639662916, 15158806773712481550, 11933986213097978283, 3508790529629961569, 409832381455824948, 4006717935701390494, 7120290581360084054, 4327466384601495267, 8076774583647541443, 1, 0, 0, 0, 1, 0, 0, 0, 0, 18011433719189930145, 12389346829573749449, 16145798482927391337, 3674491480050181048, 17622026395027469996, 15174342736410977829, 131879685133129686, 324195302411172888, 3312147262151389147, 7226855266313529425, 14636917808291645366, 18393317638728824676, 1, 0, 0, 0, 1, 0, 0, 0, 0, 17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468, 270895689018017911, 16986171160676071137, 7387278922185249498, 17172605884943369535, 17619702065145827445, 16331429716507735697, 3432600375819256090, 8340422935034340708, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], range_checker_cols: [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2187, 4374, 6561, 8748, 10935, 13122, 15309, 17496, 19683, 21870, 24057, 26244, 28431, 30618, 32805, 34992, 37179, 39366, 41553, 43740, 45927, 48114, 50301, 52488, 54675, 56862, 59049, 61236, 63423, 64152, 64881, 65124, 65367, 65448, 65529, 65532, 65535, 65535]], num_rows: 128 }, last_program_row: RowIndex(10) }, program_info: ProgramInfo { program_hash: Word([17146985813539672977, 8172330287639288363, 8293767836317219752, 13949550608398456468]), kernel: Kernel([]) }, stack_outputs: StackOutputs { elements: [1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, precompile_requests: [], final_precompile_transcript: PrecompileTranscript { state: Word([0, 0, 0, 0]) }, trace_len_summary: TraceLenSummary { main_trace_len: 11, range_trace_len: 39, chiplets_trace_len: ChipletsLengths { hash_chiplet_len: 64, bitwise_chiplet_len: 0, memory_chiplet_len: 0, ace_chiplet_len: 0, kernel_rom_len: 0 } } } diff --git a/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_27.snap b/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_27.snap index c983811d07..bd67a6f3d2 100644 --- a/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_27.snap +++ b/processor/src/trace/parallel/snapshots/miden_processor__trace__parallel__tests__trace__parallel__tests__test_trace_generation_at_fragment_boundaries__case_27.snap @@ -2,4 +2,4 @@ source: processor/src/trace/parallel/tests.rs expression: DeterministicTrace(&trace_from_fragments) --- -ExecutionTrace { main_trace: MainTrace { columns: ColMatrix { columns: [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 1, 65, 97, 97, 97, 65, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [5482243896119908732, 401642074298203, 3137828705454, 24514286761, 191517865, 1496233, 11689, 91, 0, 0, 0, 5482243896119908732, 7458506668679174706, 1032, 8, 0, 7458506668679174706, 13210061556570014836, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525, 9874694795284567525], [17271741639510569126, 40, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17271741639510569126, 18375473735916206629, 0, 65, 65, 18375473735916206629, 16003296542960478536, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728, 11914585017133270728], [10627125303494028926, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10627125303494028926, 2105717247508690050, 0, 0, 0, 2105717247508690050, 6732564319544917702, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410, 14619522228640933410], [12334791106787903660, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12334791106787903660, 1679902783560062568, 0, 0, 0, 1679902783560062568, 16687523027086140644, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683, 6636010883309744683], [13210061556570014836, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [16003296542960478536, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [6732564319544917702, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [16687523027086140644, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 4, 3, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [7458506668679174706, 7458506668679174706, 7458506668679174706, 40, 7458506668679174706, 18375473735916206629, 2105717247508690050, 1679902783560062568, 0, 40, 40, 40, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [18375473735916206629, 18375473735916206629, 18375473735916206629, 7458506668679174706, 18375473735916206629, 2105717247508690050, 1679902783560062568, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [2105717247508690050, 2105717247508690050, 2105717247508690050, 18375473735916206629, 2105717247508690050, 1679902783560062568, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1679902783560062568, 1679902783560062568, 1679902783560062568, 2105717247508690050, 1679902783560062568, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1679902783560062568, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [16, 16, 16, 17, 16, 16, 16, 16, 16, 17, 17, 17, 17, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16], [0, 0, 0, 2, 0, 0, 0, 0, 0, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 7, 8, 9, 2196, 4383, 6570, 8757, 10944, 13131, 15318, 17505, 19692, 21879, 24066, 26253, 28440, 30627, 32814, 35001, 37188, 39375, 41562, 43749, 45936, 48123, 50310, 52497, 54684, 56871, 59058, 61245, 63432, 64161, 64890, 65133, 65376, 65457, 65484, 65511, 65520, 65529, 65532, 65535, 65535], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [5482243896119908732, 18015781855758016478, 4383606322674378669, 11282929110176162954, 17215248529293365853, 13193227772306657556, 11735240166769603875, 3717289286029653294, 5492874275384737590, 12486768927296380145, 7992161010257837902, 5965860733558915216, 13973209423992708161, 5139670008027876415, 6906630570311142812, 808538110186084468, 2187643142553675840, 11028121748345672612, 18181286167455191614, 15014367804365107227, 10866688391213961683, 16520440189869744108, 5493823407617825232, 501346961392724628, 18105097706170191265, 13534558354914049543, 3820689183586493894, 16784019981734849061, 2862138511955678409, 7758258992155315690, 17115115516972321026, 9874694795284567525, 401642074298203, 4016420742982670, 14280802901810915241, 7925919485060883878, 9094034340168608638, 6650811367268781560, 13344927435882217244, 15870694671012449597, 13091389828882674218, 168434371192049215, 13973668876111195937, 680445747454648704, 15441309962929722976, 15749770188837954531, 5233297770622824375, 3367253731665130938, 5066484463076591248, 9867160564810673994, 16707816004584596036, 6832899290197418961, 10263347723858682786, 6209209797490182000, 8678413656546712232, 9643915442530902318, 17208626611000903707, 11389822518212260982, 887493237489321299, 48736118273260452, 13483864438078018308, 8159241411748295729, 10385528691577928985, 5482243896119908732, 0, 616, 13342492399873323769, 1439796670523758837, 2591609871503882494, 5919456033500076693, 5232333079875635931, 12079101376381790329, 5687909194194711965, 13514584364960626778, 10501272396704173758, 7941686916236651549, 11501430483965911830, 10227424397178507773, 10471520652203868473, 14226149352545573719, 5877312072455938554, 4586059525590481046, 1601223390241498740, 2723805050156540964, 14314758709191331837, 15918659712373688555, 3030433806959200828, 16403500445172050158, 4533755278593082652, 10807446599885826609, 6981555831806437627, 13412972662619459764, 13711912288503888270, 7425430573821419685, 16752277069679715408, 13210061556570014836, 1032, 10320, 13024110921086730221, 3587442816163675215, 512402747638547729, 9217956011885162917, 3925750957223009950, 8674177413178223320, 12846799727083908462, 9116601283268739756, 2958792353189815054, 1720195204565087693, 7696852080146622077, 2890877729556257606, 16676527939404087356, 223754558788184593, 4767414622778376421, 14072300156908432530, 16856861612825314654, 11910434229443384600, 15658716527747040980, 14322127566252286435, 4770460127206402609, 10805338145914832851, 1391598300875421210, 18211456042978337510, 11866022853402812888, 6438324596032750504, 13328288515202849800, 17331158106613184460, 18344276842462151560, 7458506668679174706, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [17271741639510569126, 8154194758959345943, 13264028927506398677, 5896249534368220847, 11382862066285680273, 5436084715181539253, 3806787319072410229, 6511238228694043548, 9049442861863566881, 3576764171564075210, 450124369605914003, 3732227441816681926, 14029816209330408163, 8200782329890006994, 10416842793286403595, 6907512650407721813, 5351083897603196824, 9182929970775715030, 16141859999570517823, 9888871621811661249, 4078956937078417294, 5937931242192299623, 3211370055999743360, 12301747922262729865, 11292399879083020280, 5346237718208015471, 8535816953133153286, 9097410120098142273, 2554244438665697829, 6695383891040002341, 9265251570417433175, 11914585017133270728, 40, 3213136594386184, 1835177830541154044, 826263100281998566, 9612296353153372169, 2509054224639990472, 11363599377854067153, 5593295816013818122, 4611398810491526224, 17064807786960234347, 18427889571151062396, 10159688738464070440, 14427917509182297997, 6874689601963577621, 745298233749984501, 4960831845018172313, 1451394763904737446, 17942681985602265676, 17508193444101172646, 1672370857206926433, 10152063658776528390, 14576660961872281746, 13602838247655372264, 5274902253855511588, 3163862752932557920, 7292072545764012550, 6033538369482377655, 10941848106600998110, 3570589185097006252, 4587292818271677447, 16771298688176486904, 17271741639510569126, 0, 528, 4511615971967153504, 11189511375577512439, 14523290705070057408, 11602649596278030541, 15937333004537029302, 7414360896531864023, 7973996941547777109, 691576170553327010, 16392526795103433215, 3672880019205947738, 3018308815206440911, 15753827566219281917, 12969815742735761919, 16814873348334179176, 9850453545266944859, 10757916804785969985, 15838808218411872755, 4464803664915013475, 1326425913004665964, 12560438841096766551, 448453576971543277, 8998725782446855275, 14421875759181138198, 3100710952877190431, 3320646806195653797, 11565789183953445370, 502156843765695809, 13147348360138928114, 11903841834984596874, 16003296542960478536, 0, 8256, 1131208899036558480, 1667157010810320250, 2053960715201569301, 1526213270499333709, 69813565043892453, 14925652377538846871, 1380252317064967448, 9902934070223067140, 3786794161520721521, 664031068804619792, 8470323998416702977, 4965297830526000942, 9404280000999464502, 8244737495337250711, 4784363486033662704, 4680481291290566437, 15373555507761845373, 8780119261264514018, 729009684537575982, 18306419558979237700, 15407410920890065538, 2509966126115291236, 12709897403480972846, 11498596868429821859, 6606875518512322314, 13880694912200059110, 6972406840307481976, 14148490408465275064, 2917966740410115114, 18375473735916206629, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [10627125303494028926, 14952889910786498171, 4766776471757604196, 12230245468863423579, 18104224094677170296, 15873409126341319274, 10073785188538358192, 9346697284679931865, 9007898958502691821, 18310381669862731969, 6720634958674998611, 4972858056675247397, 3284008361973965746, 14482858214234206831, 15154449156086880838, 5792220624700559072, 12843525862417693577, 642245012387336876, 14582627702688057517, 2964899186980974939, 8169860993617536308, 10855885493426519851, 1871971423867885122, 7909458165142256993, 3879457158905131550, 11439385698067115077, 12781603895645888322, 12658641528827989062, 9129723360543316479, 2424787611628537668, 16343713044075599831, 14619522228640933410, 40, 803284148597046, 10010111294767420802, 16943179644353820008, 8996122336997085030, 17350347680949584060, 13520911097528541892, 14769691589967587136, 81685142906752346, 7559897225353479520, 128512095027132822, 9792116363139842106, 4634576985104787587, 8679380235287294885, 1134592111928495305, 4684288247441474792, 15613043314698948257, 4841731940180862534, 5786518576333159075, 12666070374819933283, 2487841274273895537, 5690982477694717281, 5924572671969496500, 8629130978595053833, 18206699227813987098, 14234831161984809711, 16798226782780142546, 9330568307929665420, 9731250716956559616, 12286920896461242142, 1919835269886444210, 10627125303494028926, 0, 264, 9085863547783897978, 4029278259426396811, 16053154709446024998, 15730095788089532534, 1184856151594203190, 7658158244024203478, 7908104163460391198, 11768448888839053133, 15952542848401697239, 2236539493336923746, 12654027314481387133, 183479441840898968, 12829755263022627333, 14927722658095997307, 8579481663516436508, 2326984138263422166, 12584151503586926798, 5547037854005909933, 18320766430359725566, 16436941964924985549, 2398490839703252269, 15603212774947060210, 2697950444757558845, 7336230381913860230, 2577750295211676178, 16469775866150825791, 360850050916534143, 7183698983616787617, 9070535322622906244, 6732564319544917702, 0, 2064, 18136552782870868471, 952274539956745973, 15933282259815262093, 9924516287334785738, 18064603646801610993, 5114527609957824263, 11816233963570869158, 17699527003452380450, 14533708946479200173, 17484213571014188868, 832814531422633701, 1508169308733590908, 8423043379628164525, 12595277727969636921, 14226276023010866965, 10485112285448962747, 1783527593060720204, 10145484005384627580, 7463752398658534839, 17345550819494003223, 4432309123412733588, 7086318781105575433, 8830891075082588619, 310185093236608634, 16683125300631590273, 7786799186167080425, 29465347809991832, 8090161351836983773, 8665315444141111469, 2105717247508690050, 40, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [12334791106787903660, 10536106724359599792, 14660905060901389201, 17357985657180629743, 10490790376815116141, 8856174280738574418, 17564486157138470037, 2383050989032417578, 9423711593310475409, 4142017075081989212, 6217567350304044823, 15435624740876731287, 3215908606625999288, 11222238183310766613, 17187582840477322187, 11654551786904653634, 6201498867875513095, 9940061963065628902, 1432819846316931691, 5068010018173215582, 13903556343063122489, 8872060411343823556, 17720392065240548352, 17643816943101201258, 1449530809054027683, 17965277233811019017, 4895491920411997249, 10751559368097521724, 16513197729164811328, 4815287357290896051, 3003012580421078075, 6636010883309744683, 0, 803284148596806, 2549897079792572603, 5670682422759337153, 4249626004536644548, 9138873913574622404, 1343119293110958009, 15707367360995172765, 2149720931386886989, 12579497520806083785, 14990373923527496282, 7330871518527332444, 5790961380321049961, 5495469617420264118, 10789212522972025785, 4356961356341052500, 8032044444015716361, 5554647570062987979, 1022644107902166331, 6764324513849573852, 14002884382934858252, 14316154512513580139, 8331374540726760892, 13067519389098510351, 8671032013540344722, 13457978878695920483, 16399505509770566014, 10578307416004071064, 11950037765875050974, 12195903600484928258, 17694444981837938563, 12334791106787903660, 0, 88, 13728083094831419091, 5555139373262852832, 2905384006316447019, 12155959663009124293, 13187847930197094867, 15053688477158705110, 5239197399579256268, 18372875045424962848, 6782570937531856778, 5670979983981263850, 10968120781620208764, 2099848306821515114, 7984319522957739004, 14143871504578433969, 14093328990578646811, 5769086287272836702, 13010501651213663576, 16984828703781093727, 13803823311240773956, 17471084929704555662, 5508754216278517899, 14994098977964244257, 8220163139135834751, 17625713553185819225, 15041604777168753281, 17976701769209321205, 10958079103202840999, 17793074612839242130, 3601655880141993647, 16687523027086140644, 0, 2064, 9594118340025725004, 16218246678075491818, 11582919835122342747, 5661452934218108707, 3714647928422746674, 13689184893219719187, 1899963197709801965, 8313716591368695784, 17822645741084942000, 18354595702287703799, 12620512717427217848, 10145637708639089787, 1735222492513760332, 14681927838838900060, 9262747238997471758, 11498487923782501751, 8924101344488972446, 2592517964915386184, 4276681409258176044, 3764365715267793208, 3120204268813370353, 6019260256544801113, 2801984351776029768, 16979166255722313516, 2813750347113564525, 16588139065369475399, 12012198471360912693, 2492059183640657261, 16968938268466755316, 1679902783560062568, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [13210061556570014836, 1599157050859759633, 12446750015896088802, 10353774239160274935, 11424271721157330669, 15057005486179715954, 8861044108273791962, 12243038632327996294, 6387235594535598756, 10620968503766467282, 10090957857949391364, 610949617653761740, 2641692952954235941, 16682338453560518377, 1667764180674112574, 3944406972826047531, 7937338373741897463, 677543792580138430, 16064632909904135712, 18144484844415291494, 7226453148331774623, 1179808805540104806, 2700524299164928450, 739842910379542056, 18551850792840682, 16856435263285305760, 6893839572721182305, 14666214556500183752, 10619536471246139015, 4063396021928247911, 1116280449848444285, 11377866377890790275, 0, 2008210371491335, 16850544756775285522, 652387120995254672, 4188956971131276775, 18389965100329173053, 852421464532798418, 17258729097516267384, 11347427093515448316, 13908538323250058716, 6558337355650114042, 4089976927111145333, 17816809041231283545, 12843997071522346840, 1655996231185402724, 11256141768734986569, 3019459069615110433, 16778373777892540383, 10175251160015024193, 11396702708789693017, 16481019216530994753, 5122353003150766192, 17913616556333538828, 6485826671956173957, 15738756542654855641, 12199621872357116369, 12077164016468113545, 8907315944885273345, 4878983963291132913, 1618531819557712390, 565132887411573955, 7288090792972058500, 0, 616, 4968648927826019469, 17195207199910519646, 6734621562241387182, 9715952180361858627, 2034771934048449998, 13730246563790151743, 15224252119305799711, 16575323315490024998, 9453153207794904511, 8194394828646838882, 1235308382947710635, 134218781076142871, 12444330148186854115, 16838588367568106248, 3274404606032631663, 8680261223649739505, 13512134067010568333, 15074317169196019601, 3919235389861209780, 14979187502739607198, 1116932806094012842, 12657319342943489784, 998626228777839492, 2347840117369842691, 15743276195226846510, 9881270424621082635, 2778123425092199841, 2613774562373586415, 1448060333031158668, 6190635258012880107, 0, 5160, 1190658701913535022, 9371121588404883743, 7133056533056999470, 7380100170229652082, 14719783382686670107, 4693530971176924881, 11125714198188567552, 2434816259070577714, 17927785478103501878, 834873962620943786, 1091858408197145201, 9293176204765248193, 11318806736621162148, 979530496520387452, 8328113718786640843, 15870139479256453021, 7754853849459016697, 2742936430580983415, 6806060556807781604, 5089080673677611112, 16430235900965466453, 309743103212430298, 15664803780047891222, 3113571524475220627, 17862871362988443440, 1231393200801541530, 15779352999894925288, 6026600320279882336, 6970552753544824994, 4949154992619464010, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [16003296542960478536, 13466221688393768258, 12927954860087459534, 3759003303159369746, 1148549753827007441, 7129001791528740265, 5281592040827142238, 16203079979032760691, 7039074043166063940, 9054598259215599503, 2018397558465392243, 16413792935045431209, 12604373665766922919, 1493466405559625913, 11868526707386259660, 3043746450373199613, 8246328563832581273, 5887036391937389613, 2796053561793572028, 7645118395649289364, 12303475117195379639, 207358776078213315, 9218579057118601952, 14479451218433079532, 2031744097966400086, 2566041186493151514, 17259376159632543425, 10376116775360567681, 11289943669462175698, 10804772324353478999, 17288383771256214060, 9885671831159451104, 0, 1606568297193092, 1076973899277284702, 14086579741019377519, 3818478693739735842, 5593621083784091164, 11728670858811596587, 12625736484548160126, 968047239546776409, 15493380284459454506, 15542100289574010625, 15053368214221814937, 17388070103506970075, 4738318434573394804, 15389814481683087606, 14763812299525073807, 384493414835098150, 7660052382355122994, 7691788916209089905, 14721544157906502013, 737940994724202658, 3221762534387838371, 7517398897305596666, 13211005290810103003, 12141388589516060378, 13672030567886044471, 12296311093518063031, 6143526203440544581, 5554567664494429423, 12302163852964786956, 14310991091785572129, 7008881577152522467, 0, 528, 12828040835569540857, 15946070950510533025, 6868712626693654693, 16719465941571322506, 15929304398043808838, 7333330621525318559, 8574904634803746916, 11585949634519199591, 14215120915846294561, 15431555872184246136, 556415272972402332, 13729762303106745810, 1895854814022398925, 16120810718921859928, 14563556215553868244, 9584551737159741567, 1050656582218051719, 2849157683178260515, 4987801895818641338, 3252006976820452311, 4232022539410523688, 12145542090324719848, 13475056960068950678, 4212050629407893798, 18068871666013902057, 4214295938146797537, 13664544216029702565, 1391392205806749871, 3418909895274525076, 4840757955412667387, 0, 4128, 1352424102745866255, 13301242752201603536, 5420135027930584396, 17078794493496835379, 4779811836607866048, 3650219859599657886, 13618468821889769363, 11429589192023659923, 8853101337885331080, 9650238821992519861, 14401087967309285252, 12035560952634921032, 15407186837043713393, 15711028160746246110, 5396976350889627712, 15903424027416555998, 11304777107657759509, 9857843669692965578, 12605480788735099613, 14618970056708743810, 8493993205782554647, 6059068631740368787, 18316971448227884023, 12499808993385025318, 4210674244211222629, 18405965507148502967, 173097048437312502, 15568437290332308327, 11532601739151124629, 10000279862191744493, 3, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [6732564319544917702, 11424946734513850952, 14751589151467562513, 3091073535594807983, 17274728363719186424, 6785780051417756764, 15374515033027594653, 12476673273305390844, 11491856728648046938, 889587581187765015, 1832729573374625479, 11964718430105317483, 10284914521902415429, 4989117988224154817, 7310308994414837120, 4896165117485439507, 781193619199190152, 4972018469228063343, 11237024791849123316, 8136517227202567877, 12980119595156137175, 5277784125198234251, 8730957263237386090, 6627357084936364627, 9579937749716133270, 13182791294901350976, 7788172704304532836, 1814160375547940386, 7818804555865981505, 11573391963135759227, 18390005084876364234, 49905639292627904, 0, 401642074298523, 16072847024087248681, 1047399340937520223, 13840617071834531990, 13835424809772757395, 12438858367585478828, 14080077230806112448, 11208516754282785707, 7691155727086178136, 17898846423848868766, 13990233438164144322, 14765296463244153634, 10144768301469359068, 16658833476738371029, 4674204014270448977, 12722211832796318871, 492549161703070590, 13986658207276323375, 14512155514173182920, 13983563295828088546, 2440687363152463730, 15931932209781173412, 11078906302351818677, 3584926465549602493, 6813538466449503008, 2334817027508375898, 12619526317209583817, 6515674137823977144, 393947096345211186, 1951192747307666741, 7526556702499462773, 0, 264, 14858685484860085108, 16638144790071955925, 14803289513390493682, 7947368985060100292, 8540021318758160201, 1005829865088874654, 2182109332887118586, 2709878912677862734, 8639678844062658411, 1087022739668739893, 10504771173378443613, 10062807734250201377, 7979854057356878352, 5264886220300798691, 17178601938487182393, 14209807647112141969, 364963036030481104, 6977342036970944167, 9475211165936098151, 2067156367555811068, 13444810812224497486, 17338503932931685384, 18075892757378330321, 5992364927925930356, 280994234174845985, 4192504288997153355, 10293012497513243194, 12632074680840502609, 12384471116364520725, 14304772746964984975, 0, 1032, 4798141223555508282, 12962488577647927717, 10133257770726709126, 332864556927106185, 12116126881643349994, 6604148216925166409, 101015634312276042, 15934992137290074922, 6112274855072540816, 17762248064501548615, 13166189948742588777, 270100349969833402, 13485211244653928073, 3502306881032295169, 13607663468974078519, 8883940618995723208, 10623667092532612652, 12293715092576816840, 10386976621364522928, 9128135834925108269, 15731443845270647366, 13373704167654916087, 13746187061551926812, 11684868053863796759, 3258729720361659960, 10434904637843727165, 7034851303745741351, 16133345873308301364, 5426492436527662130, 2980140658145787783, 7458506668679174706, 7458506668679174706, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [16687523027086140644, 9086882804838007993, 18208410790236506017, 3398985649909830369, 11870335859895317550, 1782594595734670280, 7950908231675299553, 11699755763721080867, 5559192297727634984, 15856483324254330201, 3827177513892222045, 8697421447132597636, 6525137006607571383, 9739016092723027913, 37096681180297292, 5998909423699657245, 1737478325904747641, 9603988472267868801, 14612309354257526062, 963817021754931361, 2954837086209820968, 11485058781500311480, 10011022503247302490, 6596157637386353039, 2185026052398200396, 8667196121129603577, 17444739644589522901, 17384087895468261804, 4673396992430997118, 5652365973964779246, 14148401294484512817, 594790136239256278, 0, 401642074298403, 6959791354043610236, 1843180796447728437, 9556362158826632350, 3220022195391792741, 6012411438022691140, 4309223969498591447, 7596903557041777533, 18393682838284953355, 3973832102121938954, 12190997158276486897, 15972235844585587264, 14899488070931524727, 17337514399056563302, 10500237188498665928, 18440452962210035879, 7481614450647261413, 65300580117832193, 14713590013611289205, 13086268929321267306, 17247769089209001713, 11421561962034654967, 4561010052951998759, 9562817622798343284, 3062054327467638127, 6016566887476098647, 5513989129644936969, 13097123292793361360, 17631302057213141907, 8382824402074565601, 16136160484984138575, 0, 88, 11332670461359993442, 14431967032738938661, 10393518078208184991, 2462224494429193628, 2381519205788696693, 5156397633515475273, 13071332837477200404, 6583788956280193302, 8309261923972302555, 7204946769828595498, 10143223184962015615, 2291749916011172217, 12651590612371699683, 1757329184049619756, 8575055855333374088, 10782010546727900871, 11693001677843026089, 13372591108841832182, 6745878472543166577, 17326074735792689056, 17178266551378060244, 9012900451066906030, 9513119903156534723, 14316793092410720577, 15850020848376370982, 5093266838540794296, 2953143545478827927, 9172592184988170325, 3259030218090439002, 13670896049781213124, 0, 1032, 11702782905971311743, 8115486282645452027, 16425371230714077552, 10333496212804492507, 1572943607289284437, 13244361396034453954, 12880029163967100393, 14716450796809578181, 2618965885956593171, 1606019581379521796, 12562170441304287563, 4599116799417823473, 4257071131168813417, 10446583017549019711, 3570388907037362614, 11170081717188072664, 17238997244398394333, 17231192964516960933, 8123337005847551087, 7060091366977384949, 5719725530909274667, 5057603743378325948, 13848013489728729143, 17729739340387068117, 367186060507240673, 1411195984452924204, 11088333491201093194, 16575090776691519559, 16147396598096989679, 14525300817521856881, 18375473735916206629, 18375473735916206629, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 6538312968872592849, 8060897427763484267, 15694315280551902473, 15462035367190511759, 16783127636073026773, 10756964923802715923, 4768450986425500783, 586150029444692874, 14745636460228146879, 5204776334183399126, 7685703760533694936, 16111592919872596132, 6944599323919802145, 1254987403839644538, 9402574875622777470, 16210856058698621820, 6207690803740787708, 5909774410804808527, 11610503998702777421, 686805010274260483, 8419527378140004636, 6342702858222909287, 8706567413279745902, 8451985615096117101, 8796637399824800240, 15979424445015031332, 13704751155696621736, 18261872069356847559, 7568935938034555881, 3939988349760901151, 3558778201956820739, 0, 2008210371491335, 13098960849839742034, 9449621519891201049, 2814310786559014444, 5305842545683321494, 4969236906288915907, 1243780951433164967, 6167749875842285147, 9490220981060631819, 3665259354621890034, 7437125179920904126, 12655958476488865400, 17935537000594940941, 91614862745339577, 1869550524566103495, 17384150297165671545, 1154605885284628266, 8665046436862728398, 6741156569294553317, 9490927005547387767, 8947900188307771735, 13752550215202657538, 7714188412126691626, 12225947487197390724, 13509943592829854189, 7120740401378484294, 6789669275155346195, 2929601484581949152, 1077164174037184778, 7253613682453412944, 12957959164911169922, 0, 1232, 6031863247325663438, 674016650738724202, 9655491867310024790, 4753798685424869288, 10749041705000945043, 14520855376130294244, 1540176383869885892, 10236894625417199268, 9196614711423540610, 7978597004657283049, 6086008265617713639, 14043785705271347590, 10693788391520380705, 12309293813476849789, 12287432898048046644, 12476380710530844150, 2814554338965902349, 12370730861881949935, 13055692992345669402, 801564953257569940, 10614676804436196472, 7985393687855976209, 16788264280259941604, 4042445936043537075, 17844212763579117389, 14723420347046552696, 2456530167870834703, 7343890316269580191, 6483315548845037473, 9440211366785524370, 0, 5160, 18346837778669738664, 15130142357101091527, 6726588340010678615, 8394319278312203283, 15942424551308612685, 7629500615465222065, 14939877513325106589, 17048523965011794048, 2306293645521445312, 823113708878672797, 14981348226783328932, 7432878333905782051, 3482639998457803800, 632277917380007036, 18266437030920184246, 3366715262389109205, 5280275432441977334, 5379329043314533811, 13912213856326486056, 17217059915921675075, 15634373017412823086, 14981257187297131103, 16697350900700022325, 5239234081629986555, 3229291246709926782, 18373224696258292584, 6771862800272250893, 7666370275789511263, 12942227631865082960, 15190222347874856922, 2105717247508690050, 2105717247508690050, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [87, 7206805482451038763, 10391043349415287037, 17044036436784806527, 13171139175044072684, 2094744771380247596, 13239410091625892436, 168039991714389118, 9272483157421678641, 9491323991579079848, 16844742792488708348, 9520544349855559315, 792788122696624862, 16163267682416611248, 7281147841738764349, 9382208451579624348, 15681622260194273891, 1390751769269680465, 8196141638178857464, 15172831853577650839, 12922697597526240324, 7829823799088278618, 1783927422614660621, 4975249353684987436, 13048186608776014077, 3034445649013398243, 6966167031354634355, 7794510095811729812, 8010670397007670803, 871847630272290682, 18441078654886601219, 1106728433230065324, 0, 1606568297193092, 17457628753812655267, 5096693283465186518, 12947605480618213072, 13490514080936595140, 16186587491946121120, 10245245868334896235, 6026705707665599719, 9827345407768028181, 2812471843237874845, 12940670116574659651, 2714930976118111710, 11931084046533097040, 5957825878304116293, 4815270995456833861, 3281433232253188744, 1527514044633931889, 3155608937877823823, 496495357063373704, 12643114535206930756, 2926290280590787897, 4481685646324082958, 2913086696180341350, 4929647997916999987, 9053067786296036128, 12860916533743270733, 13426707234447106813, 15934882759672330788, 2173747106952139997, 5260381980138555939, 9238536158694879401, 88, 1056, 10194964851803169917, 2476887483552371976, 9610004573075108621, 4964236593939309395, 10117579878001530331, 8588168632019162203, 7961669463441676499, 8688363314921128388, 7669238601546834041, 15117861700401653408, 7267798175629900560, 18420331634788000621, 2168204218347522931, 13774182815867438503, 11793649490935032382, 264326996749206681, 422815844549413164, 11144132125283193307, 16600930886850462534, 14741236577529096830, 7550071867985447349, 10163945784944658272, 8810849992229527370, 979169410947035438, 18181508983255172512, 10501853123801116024, 10292737970295456228, 632012914013142222, 9098012027422757538, 7698805642109006453, 0, 4128, 6496253015800789210, 18063315295058131399, 14099326864720264780, 16744359797696928029, 11669954633423859445, 10923938539628559259, 10579480970462933513, 17315553376669597828, 12114095292572219189, 16129781670858537825, 67936491912723144, 6285840300661422802, 14359460599290704174, 7597471307904508314, 8469569990667894210, 9117246600999250277, 14614928058075190380, 13738364908865630160, 1806905237893315697, 261412144627674040, 8380596589382515797, 3809925330596605534, 1983199361335541287, 6337901890572878101, 17063257729896061936, 12690697575318882146, 3846044480011221270, 10729939698274680623, 5297971463863936522, 8671284646676347574, 1679902783560062568, 1679902783560062568, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 2643697525295255282, 7848268271641614303, 1670964981039714496, 12506995107569119516, 16020980424362300069, 3910461774754452973, 14887150284650111993, 11430895388638705560, 15925982986489674986, 559122298435457095, 16369319727902045750, 5911900249842037740, 9993545485068101534, 16804807948024450931, 6109216944498588777, 6962786378900996817, 14779846517676698965, 14597810963258762343, 16333362039819991192, 2239891938742671995, 8902636803530046125, 12348911713752556021, 9576130314342554279, 9464686824958661262, 14724291818312841818, 5956660324772534609, 5179789141411429720, 14891365206755013222, 833106187556617464, 14690990432528119604, 7399742180187746173, 0, 401642074298523, 10076989882539553734, 13617634258944637452, 11664888937794835322, 6832371865971954132, 7435465380685145582, 8856983143236954540, 15647394574465449881, 5004639611979401749, 16333513927375132208, 11586223746088007538, 17258599442845821467, 10089347514894229223, 8927362828162004403, 1274761678102044944, 13987176689734561031, 968318691601385838, 17920302096119022338, 18172419653743826470, 5238866342343116613, 4715585282245523496, 6782917713521523376, 845034972551066538, 8264516316211712068, 4395820162956710988, 17367170950581948054, 11715439359473390301, 4924405821869545305, 1674381281184830519, 4077397353846458666, 16570851802495678006, 0, 528, 3020492374890726247, 15867024276402164724, 2691485309401819348, 10383311521670833729, 16323720466012865692, 12111425008963394821, 6863497050423701439, 4068736078963485223, 6871052579055075230, 11135759119963236724, 8026699645344521142, 4857505768584918289, 10792639723427933554, 15144263097518946995, 2672819086738268108, 9175748808845810742, 8523928999979138359, 5837654600063955860, 4020408003683484830, 6777545915715419993, 16222025381660955186, 14681340973312169871, 11211579677305883898, 8623233971250462580, 418056849863168392, 2919384330136358405, 2666974936005298869, 14966813495153624489, 13584072213050301608, 17057575786157171701, 0, 1032, 13084260837127404333, 4018109146681745349, 14498381569327145056, 3778421823029569719, 1344624249217908323, 3634653398484528177, 1428985706412758663, 11382569756632997337, 13894906302086601399, 3911680161282028629, 11467762927868003365, 10098326072301516020, 16073214466625742345, 16150512194511843089, 11525294274796193451, 15902507139806774023, 13926886722650908730, 2974304378722638293, 5274544965980948277, 9984170014312577610, 639485734140932316, 15088403650698955530, 17189134684458608982, 6515320870350778492, 7902492290152572474, 17310456195349246143, 4070136787975548901, 6345872167795009033, 3095930865537762353, 4232664728858134772, 1, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 392081819927674604, 13621084556403650323, 17078772340992927473, 862170971660204027, 5676881743340217488, 5517012370953012053, 3863387227510711423, 6521284656283570782, 17282496836457066698, 8668839984066399279, 10481218501610762636, 13268880552322298648, 9575112247205521418, 14191613402325013881, 17855143966403217682, 8464300128340058390, 4400313738036540825, 14739186344673284697, 1501891124109012983, 9798699259742823392, 8843421723884165135, 7746605484191389759, 8323169935435436763, 15323881858459172368, 8509325593168557185, 14233099751914870044, 12164983556041574509, 17356025534910089368, 2031310896521954322, 16067965450256037769, 8147499972447601337, 0, 401642074298403, 9851586117636382793, 7414079509745519565, 10414894202973226643, 11403399710197601656, 10230759118395809329, 4887466173119518776, 12376579030877442488, 15222686873173021915, 11343634646223977946, 15054143113295762432, 8578483304162845495, 8187399805941604842, 17460975957431844228, 12368453570037757143, 4715095521846408852, 10685847052710927197, 5160934306801665605, 12877482432527277885, 1026289052488784895, 12183816968946827507, 954239020314042893, 1899038343674936222, 3582199871763692750, 10141562795735590523, 5883730844910027408, 10313342961711791200, 10308552102917724507, 1101239144209002141, 16732112788727027442, 6132059608254040410, 0, 176, 14015299246960655077, 18240053740881435667, 9264051620447261114, 3770835013589498382, 14269426645353023865, 1064418857115644823, 9055361938666247589, 1923541152082479674, 7329032621716426413, 14147095007921770778, 12290092320014837503, 14167154425694482177, 2008826339817234435, 12727493810822145141, 13765995246049388004, 5723824967382588797, 11506863252089006870, 13547802874613831044, 2099106023167119258, 6345494554579617353, 13921991112058773762, 5885105447661412229, 8709961227558437878, 9751610933111772233, 13912537796384226859, 5691895930177454540, 2936046437280927758, 7163672760378086559, 12965649133168865250, 17131584050600476194, 0, 1032, 15909096041365347974, 18432189660917429733, 2798890989547891271, 10768372030970716894, 5935807051329113911, 1259182408195029650, 16024750973514577255, 6103595041913569283, 914770550723164908, 5067028895751058275, 5242612139537538536, 13359135899043031769, 4430959127423856282, 16317056360529517539, 2634255659160911215, 15590656855559575839, 6832335878067392309, 6045109056629836176, 18146646330136390606, 6482705684632040588, 2770791364887326735, 7707774010999656594, 3401430074469265273, 3500862351024377705, 5135727797169111985, 14940852959892477883, 9633218853985087472, 16966092255533854383, 3065488485208441055, 15703076512693482766, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4099276459869907627, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] }, last_program_row: RowIndex(19) }, program_info: ProgramInfo { program_hash: Word([9874694795284567525, 11914585017133270728, 14619522228640933410, 6636010883309744683]), kernel: Kernel([]) }, stack_outputs: StackOutputs { elements: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, merkle_store_nodes: {Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571]): (Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350]), Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350])), Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484]): (Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693]), Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693])), Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781]): (Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874]), Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874])), Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171]): (Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361]), Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361])), Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815]): (Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305]), Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305])), Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689]): (Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195]), Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195])), Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362]): (Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063]), Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063])), Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848]): (Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661]), Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661])), Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352]): (Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829]), Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829])), Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444]): (Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223]), Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223])), Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386]): (Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388]), Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388])), Word([13190842942618341421, 17548956981569849952, 15418963848144418856, 730733050713174879]): (Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144]), Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144])), Word([17191480143063228124, 12589680459716948133, 10946639844735547820, 787516000067494874]): (Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675]), Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675])), Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594]): (Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115]), Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115])), Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809]): (Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257]), Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257])), Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777]): (Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555]), Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555])), Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509]): (Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882]), Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882])), Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725]): (Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979]), Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979])), Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134]): (Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987]), Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987])), Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828]): (Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910]), Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910])), Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830]): (Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054]), Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054])), Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228]): (Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742]), Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742])), Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443]): (Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928]), Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928])), Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643]): (Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979]), Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979])), Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758]): (Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106]), Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106])), Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580]): (Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594]), Word([14699717555081076654, 4746435082174818730, 813708662788963698, 810806105436991594])), Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765]): (Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045]), Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045])), Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766]): (Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281]), Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281])), Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385]): (Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828]), Word([7481106124656138857, 15701278658979622977, 10594307887748114695, 1271681404559784828])), Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579]): (Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171]), Word([8685862689121056404, 22002718222056080, 6470349339189627848, 162171956419094171])), Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212]): (Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992]), Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992])), Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463]): (Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004]), Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004])), Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502]): (Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023]), Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023])), Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539]): (Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537]), Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537])), Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865]): (Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225]), Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225])), Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690]): (Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947]), Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947])), Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202]): (Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552]), Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552])), Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079]): (Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444]), Word([16982412062719753139, 14539706782548677236, 9516947633545542451, 568128984770113444])), Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850]): (Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548]), Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548])), Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448]): (Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987]), Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987])), Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041]): (Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035]), Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035])), Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301]): (Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414]), Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414])), Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414]): (Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212]), Word([7901669741913940275, 2676076790248429841, 7183611356696016060, 1938288097969569212])), Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703]): (Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439]), Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439])), Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271]): (Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955]), Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955])), Word([16002133484205557268, 8413116937675482636, 12449052044564295509, 3039249045473298882]): (Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802]), Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802])), Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152]): (Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887]), Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887])), Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028]): (Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948]), Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948])), Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331]): (Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093]), Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093])), Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394]): (Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134]), Word([12526278552863588878, 1670719453400392876, 18358823493852521322, 1240067944793321134])), Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546]): (Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228]), Word([17993017087997641271, 5808763436878906560, 11543739521656962714, 1405103854912651228])), Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620]): (Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414]), Word([2591375019783745655, 8015778681285537565, 17578080770996639687, 2928872354236574414])), Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800]): (Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703]), Word([9136672917227524458, 6030009050554484352, 12435125861127256693, 2974051506150805703])), Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671]): (Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205]), Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205])), Word([15674463781995314698, 14464505438699472696, 6467194644802591262, 3528302404251149537]): (Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011]), Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011])), Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516]): (Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301]), Word([1405699014889740084, 14013046305941666355, 10417414171593962773, 2844878341839501301])), Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831]): (Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986]), Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986])), Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415]): (Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057]), Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057])), Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722]): (Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689]), Word([3597515369448291039, 1667495422733289765, 17303218237506387342, 468912532899078689])), Word([6986051014421313943, 678198511255499146, 5261836282734195530, 3810997979073436144]): (Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682]), Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682])), Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295]): (Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268]), Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268])), Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818]): (Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513]), Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513])), Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241]): (Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565]), Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565])), Word([14300690858557908768, 10507781723268256024, 15904113820267812857, 3969227413967165439]): (Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012]), Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012])), Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512]): (Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850]), Word([11934214708621870744, 691331677734325115, 17965922536791202949, 2742604638132828850])), Word([3597148481979750018, 7983354472796334988, 13544278068440573252, 4056655181729488986]): (Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865]), Word([11569107685829756166, 7187477731240244145, 8326334713638926095, 2239973196746300865])), Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982]): (Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777]), Word([6071348004122092698, 13039859062734201588, 5633518569501799708, 1072811608667331777])), Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808]): (Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394]), Word([5009154494627340044, 3172285993689068837, 12977328012193691236, 3399602256565600394])), Word([16568590159814885376, 13276446786965344698, 6390176043704481341, 4236530685983566979]): (Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690]), Word([1531096329227431566, 10396279320957153079, 11399097763451460827, 2476342835701309690])), Word([3192208859458128235, 11728532665092266005, 492034778879809254, 4243878262948068093]): (Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620]), Word([8322091277119180762, 11729978832222981985, 15954928019202204932, 3416208934581357620])), Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902]): (Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789]), Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789])), Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542]): (Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094]), Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094])), Word([12080505668088055898, 571051185085206587, 11035321487777199720, 4426183469020559057]): (Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362]), Word([3535038408270342604, 7568123861223701339, 3597813201789850256, 490415785320792362])), Word([15704141825016550533, 9702133105467572793, 17112005317888626361, 4547270738239016205]): (Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961]), Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961])), Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401]): (Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580]), Word([8408046365471540227, 2662292955057793903, 4226388297479576450, 1459746174763861580])), Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553]): (Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960]), Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960])), Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169]): (Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031]), Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031])), Word([4045587508292687318, 3477196676977645246, 6296685615391332282, 4667648627484990682]): (Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053]), Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053])), Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118]): (Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562]), Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562])), Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725]): (Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666]), Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666])), Word([10047598218150573206, 4530551255734412008, 5135152177315026244, 5136529096604752661]): (Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897]), Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897])), Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981]): (Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447]), Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447])), Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072]): (Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646]), Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646])), Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140]): (Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404]), Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404])), Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515]): (Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152]), Word([9394589772933367669, 14579018520272275408, 3210908204569932003, 3050114434918646152])), Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709]): (Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664]), Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664])), Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800]): (Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103]), Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103])), Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741]): (Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169]), Word([4587622888555803751, 13610098627129405084, 9171377283614195668, 4591758751870604169])), Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005]): (Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758]), Word([10804380279573693722, 14483852602370717051, 3369269827863158856, 1456394486912900758])), Word([3432350596910229027, 17916861794212443713, 13786973740436472151, 5850439935268184802]): (Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070]), Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070])), Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159]): (Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005]), Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005])), Word([17200367375744481466, 7173935273650285464, 4919254770572885679, 5994506765282741350]): (Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443]), Word([7390567561970872999, 6922246493794922144, 3453421506602300723, 1408350034180458443])), Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697]): (Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573]), Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573])), Word([12633292943917459679, 6439871695557339929, 6944991753981667445, 6046843502017063928]): (Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331]), Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331])), Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320]): (Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166]), Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166])), Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814]): (Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079]), Word([6361589938523777660, 11807529033202791288, 7989433571969962515, 2699251935539566079])), Word([10077688234816402506, 3867170110404705980, 14977857572922113715, 6426617178264224447]): (Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820]), Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820])), Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284]): (Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057]), Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057])), Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697]): (Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131]), Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131])), Word([143481666315169289, 5622547778651542966, 7101493876925952456, 6502742246135181955]): (Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290]), Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290])), Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910]): (Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202]), Word([2852976121295438129, 2806800050654790917, 13240785659200951958, 2486261825154534202])), Word([11258275789878222563, 6126155174074085420, 16166207024589258835, 6538548660514489910]): (Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822]), Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822])), Word([7889430716910419531, 14576813768493677077, 12290049844847582983, 6589448232299292106]): (Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847]), Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847])), Word([9787733042104514727, 6685242697806496612, 17803905955470949916, 6680588871692614404]): (Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441]), Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441])), Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796]): (Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186]), Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186])), Word([15695915255737157591, 10149314375997995607, 5171427370319057728, 6967789539213736053]): (Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516]), Word([13320800758773165257, 5213392577382401121, 6696982961545949080, 3699901592208350516])), Word([17802550886941079335, 14293116379440073386, 6936688310934136274, 7127639471265202992]): (Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818]), Word([605386594765628255, 1095435790537612282, 7912669391696546979, 3964434845610204818])), Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957]): (Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315]), Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315])), Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709]): (Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794]), Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794])), Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091]): (Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539]), Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539])), Word([3841149689888075775, 3494874406965850237, 3216622481702810440, 7458636614191504664]): (Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558]), Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558])), Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294]): (Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579]), Word([3840533837275016078, 6742379836675073178, 12727866131421682079, 1908063110750251579])), Word([5566342864887828581, 2912451680115539017, 13467125261803475601, 7568088041353600947]): (Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502]), Word([11346815749277083123, 859117116051274381, 3376052340934782986, 2095734609894136502])), Word([17235583951376661684, 10083644464194131865, 11409601709860874655, 7577240030531334829]): (Word([0, 0, 0, 0]), Word([0, 0, 0, 0])), Word([6773343764150970507, 5433787848085812740, 13359755994482809459, 7786556093092244045]): (Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137]), Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137])), Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914]): (Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041]), Word([10498953993187227208, 7966893092136728999, 12995544634956206557, 2841797288974373041])), Word([6279479133009007084, 11401662032408237226, 9565267648644581712, 7830928412974239573]): (Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378]), Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378])), Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699]): (Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873]), Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873])), Word([7983625839178916306, 5764166547129930953, 4707620800940860897, 8172658278540769225]): (Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262]), Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262])), Word([7278338892935452771, 6745373714943841014, 1010566802979034079, 8532110148832582057]): (Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692]), Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692])), Word([8169136595508989707, 8243120424069329723, 8738550448108656333, 8576884522729946131]): (Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997]), Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997])), Word([9752828135749747582, 3710927128543391430, 18247880090110070989, 8784551664702000555]): (Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385]), Word([1363381549187485019, 5341376580899763503, 10266127647741586957, 1664715822757989385])), Word([10714400302651658947, 12896032539950153667, 14644371771687359561, 8853254989027832195]): (Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709]), Word([17697452907874426808, 5956252311079559799, 16951130280809220578, 7324270570011397709])), Word([11415858355095084095, 4594972467727466179, 12150072248829203101, 8947813715439776166]): (Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542]), Word([14521673759358910476, 17640957108605213856, 4488010974505873773, 4402194598394806542])), Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027]): (Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373]), Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373])), Word([9997025551367286476, 12250115225408866497, 14539938448104360178, 9017805745904219378]): (Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509]), Word([6529321350747691322, 2369118314416134221, 14749665906520275381, 1098621791380571509])), Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097]): (Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553]), Word([11776240979341984975, 16634362485568577506, 11760547346592305266, 4571184991775900553])), Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217]): (Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815]), Word([14164690091458710855, 12742723480735450594, 1355101223253774660, 327051675466461815])), Word([15303291583700576086, 16612499901671360858, 6444928163424779134, 9217688198259020873]): (Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864]), Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864])), Word([16921285376760315539, 4445695104649211786, 15002322448892175266, 9222584557072414997]): (Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722]), Word([9719038431785031627, 3235103812655532636, 10151263309029441796, 3780158187757522722])), Word([11746894431582240550, 737232193019922226, 13442402277669779496, 9299070803547773887]): (Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766]), Word([8701907534575455700, 8883164660418241821, 1737881807742287125, 1539262223102213766])), Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589]): (Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757]), Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757])), Word([17826823084639578348, 5184636437620014612, 14308957397020647307, 9402732915173653539]): (Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665]), Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665])), Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129]): (Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229]), Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229])), Word([13747670991316450712, 1172354525619892499, 685177444088537696, 9494811788571855137]): (Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312]), Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312])), Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019]): (Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378]), Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378])), Word([9809010169677958571, 11614032490706782401, 1432535583307813560, 9584838209789571331]): (Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713]), Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713])), Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]): (Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980]), Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980])), Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325]): (Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546]), Word([11291658160204975080, 3319227360579127132, 10320124664591158457, 3409955787521638546])), Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170]): (Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822]), Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822])), Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054]): (Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295]), Word([16903610831203055692, 2734332116881329900, 7700021291788863086, 3862018245546197295])), Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925]): (Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848]), Word([16294653838354045684, 2193197165210075221, 1264111440551853574, 525086553076832848])), Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909]): (Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796]), Word([5893039117368206833, 7604725979619535425, 11729567497137566546, 6896335025392018796])), Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540]): (Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170]), Word([4026809165176549162, 6722818553137845987, 8947073501882758180, 9636655244062289170])), Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214]): (Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448]), Word([13463115553848141913, 2234313826766699609, 6628397615987899732, 2827452548907499448])), Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317]): (Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294]), Word([4895802800415601645, 15476509782342646098, 17969866374575441833, 7532225864810560294])), Word([6278199066229041760, 16311980358263143866, 3873428331219235942, 10293564703875496757]): (Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416]), Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416])), Word([16783688595993307882, 16683666618221250293, 2037538602671525616, 10332684425259766378]): (Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091]), Word([11306294485504183418, 14372508567226056949, 10257673953775170961, 7347952386823745091])), Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263]): (Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463]), Word([156695302078341182, 2614653764812468045, 12582648781927804036, 2041201760208061463])), Word([17847783635742578791, 6982390677875977265, 5346405803827927574, 10389968640106345666]): (Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361]), Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361])), Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174]): (Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992]), Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992])), Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470]): (Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401]), Word([13576424288885502032, 16034758793396238238, 7359912013279161995, 4551344463330998401])), Word([16682490504911598337, 12553235793846729151, 1125267884919010622, 10704544007021652665]): (Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957]), Word([1515263932974556950, 13802305078162013256, 14155267753658493882, 7258483858411019957])), Word([7713356742107933684, 14394767747119872906, 7633447735505415433, 10711135650256356262]): (Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144]), Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144])), Word([7968615064424337937, 1702639151308436124, 14573334289005817978, 10800717278082241229]): (Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284]), Word([11170981928111944793, 5148523130693116298, 15871367056359503175, 6485250385093061284])), Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134]): (Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325]), Word([9233812072842079621, 6671569500746161189, 645737594433289846, 9593384516431683325])), Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855]): (Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765]), Word([3491467487177008025, 18221406568666854232, 16356397084417252234, 1538761618144968765])), Word([17261598987103457340, 16170722649741451802, 7398412186345361478, 11258799517657859115]): (Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814]), Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814])), Word([1975195610270384701, 109494945442785198, 1622259821444479979, 11299246364087669441]): (Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831]), Word([14531577091064785866, 14478329038843742212, 15573902416339116519, 3707642964779488831])), Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977]): (Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446]), Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446])), Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880]): (Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005]), Word([3991610620715329894, 18343802458191631930, 2595781633135092903, 5785277143495754005])), Word([6451687531525031522, 16102586076766998309, 10877292644997462254, 11456053754555611789]): (Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995]), Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995])), Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000]): (Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267]), Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267])), Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998]): (Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982]), Word([7585549374847224159, 3047288099099161097, 13431868204571712333, 4173972336275478982])), Word([17311662800950957701, 9666810111057935870, 8790320373617118241, 12036014063162441995]): (Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539]), Word([10775960781917369910, 15745271547738838628, 18214585570410449253, 2141128241026376539])), Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507]): (Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512]), Word([5205848095116621817, 6632852171799423847, 5538816239062299913, 4040900473486356512])), Word([1363116324348425804, 16843841372177310645, 11225339855204849383, 12098256081247237305]): (Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118]), Word([15759245781060327053, 8651306991551919473, 1007632711365386409, 5059048402164262118])), Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219]): (Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009]), Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009])), Word([14916473491970765698, 16808426016846303935, 13175204391709088148, 12165836579790674416]): (Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089]), Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089])), Word([14278149425947938131, 8830543101101850994, 4247579024591319165, 12421494154636998980]): (Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445]), Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445])), Word([6701305982140326477, 16209852248089411584, 9367486892136859931, 12475359606430236063]): (Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140]), Word([16104115186119694102, 3385365138628625844, 4047451188020276989, 5283833390754661140])), Word([1418777206478642671, 1086272827953357414, 13333986128605291175, 12622204459545563713]): (Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159]), Word([14599286198013947524, 5478159134755618088, 5822970462210837761, 5932077771754348159])), Word([8184150047773628941, 5309851822823304166, 734579595355185414, 12645397502010029031]): (Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809]), Word([13819563594593520825, 178930620081345139, 17928149299158490145, 966461501228531809])), Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932]): (Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037]), Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037])), Word([3631709318383903915, 1479741680283558651, 6316109116759262169, 12908519712326182094]): (Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925]), Word([13487209600383596313, 7884156680105936667, 7807194553872838561, 9988673253211151925])), Word([16364072711563314218, 8680826946768008494, 8827581652194015975, 12917736039460991315]): (Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386]), Word([10175931699548654034, 15162046055971105538, 1194257770182870069, 638415270357423386])), Word([10240399888579978058, 11980913266776497326, 15817676351110653867, 12961983625333298446]): (Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721]), Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721])), Word([7061863827368340100, 568026302621690235, 7892835898224002733, 13098998435586379742]): (Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981]), Word([4587034485726845202, 5452720220830946319, 15622535499012086715, 5163318747710759981])), Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661]): (Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072]), Word([1799612852864078116, 8911988199792566140, 2770645853688704834, 5245350660620269072])), Word([8501354343463522082, 14164101075188730599, 12540449626688486894, 13264416375505828979]): (Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671]), Word([6890338765285148676, 16465305462210979340, 1559857762145226502, 3464029730236878671])), Word([6384975908774756962, 11522441658859715689, 971642957603512741, 13313175758860095361]): (Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269]), Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269])), Word([769773935990321492, 13982548694223290638, 9191429625447033826, 13477213882525530558]): (Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571]), Word([4660997969723963906, 7795863912383732003, 7651144559093280129, 12058532240616571])), Word([10095110350197481234, 16754927149671889804, 5794054697993172373, 13697490197149520290]): (Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902]), Word([11518398729237529927, 6461960461150937577, 11234208699685110116, 4379160819171915902])), Word([783872972672570241, 17009386614070788809, 1620451599046508738, 14097521971534230987]): (Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741]), Word([13171191895283252343, 4967471993524838998, 17039560476853477706, 5637000416510512741])), Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902]): (Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515]), Word([9857272261467358701, 4691189963638172987, 3394470452303829436, 5439877186966589515])), Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497]): (Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028]), Word([15593989025428686711, 6830942213549652008, 13114383859060884199, 3053506549353753028])), Word([2210664882600769081, 1970940532663876801, 9698543107861049951, 14215078170257699948]): (Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709]), Word([6715480276341239622, 17622296017563716652, 2870119458052011204, 5463024993890883709])), Word([4155805307514823775, 13767673705116584912, 2128908174209062000, 14280577264721470009]): (Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725]), Word([17943605159295944272, 2543536838982224250, 12028953864078157333, 5075009933050053725])), Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387]): (Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317]), Word([5458312965436071919, 12180002662844597029, 14440000721594118913, 10232651548933972317])), Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159]): (Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808]), Word([6737563254999857180, 17617716535832219618, 10622562591474756769, 4224277995775353808])), Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394]): (Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699]), Word([10713348141912934044, 3912178578481351300, 4766343807006379639, 8152946901198636699])), Word([8092582813770725163, 18320289632286565682, 18342659779394639565, 14403144114495728312]): (Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000]), Word([3769945351214152035, 7469202120892526624, 379029646267533068, 11467831642914811000])), Word([11906383717123954639, 4495840065004669051, 10229404979573251436, 14549831649316276987]): (Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821]), Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821])), Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046]): (Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909]), Word([3049191375891481776, 6027646082252118273, 14017620000446571203, 10046411696974019909])), Word([8093713986304565024, 6683480815383198279, 16585223719164161917, 14699734404521972565]): (Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028]), Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028])), Word([852551854027645333, 15499351590521579421, 1342383109919052612, 14788025673029660269]): (Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352]), Word([12203744453072453296, 7141863219303444631, 501288423901964251, 563960044861138352])), Word([8928843363506044055, 3149275884893389422, 4993712340608026279, 14799179392886088847]): (Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271]), Word([5424641566596402017, 2303287366273484453, 12354701310739373196, 3011434336524422271])), Word([3188955840837796722, 17640893095583126920, 14690471846913619905, 14941338482845832513]): (Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800]), Word([14963986415178008725, 14532956656774501606, 10043099537758467008, 3446615689751686800])), Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054]): (Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394]), Word([16481480371722421471, 12962335603630703335, 382365863238141755, 14401146627915118394])), Word([16275765473469464592, 2953078902181057893, 3981926055582992410, 15023519093029762004]): (Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977]), Word([15841404828892380962, 13123234819662369960, 5456641096570689114, 11300052908284048977])), Word([14721666955669192867, 8455854366770470773, 524097494637038517, 15108014279657316675]): (Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800]), Word([3099556779638818133, 14570418459022495509, 17209356172849038591, 5636050577868052800])), Word([5457450126874468407, 10689625788190426235, 1310738296969150738, 15177267085502055692]): (Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159]), Word([4102268297800748332, 16322356494526406732, 16994087482505079850, 14329684231729862159])), Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909]): (Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932]), Word([4268006992851463842, 14506457128915819607, 13668536977299122052, 12708449346165229932])), Word([13142100355974731164, 7373782609404016168, 12137034191284675235, 15267584243587914814]): (Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697]), Word([9914883151124511737, 2520862578017620080, 3049925336228865628, 6501333336014617697])), Word([11531698103252198029, 514765863543485731, 12625400259302497735, 15274735534568445186]): (Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387]), Word([9212177872611643581, 10985447739281342247, 11607925359102538960, 14316484072878608387])), Word([4927041635269984615, 14115328727242206825, 15507827819493700235, 15288167886564912445]): (Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470]), Word([6035546400232273884, 5494370888984847475, 5027959732064350199, 10648340619464421470])), Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966]): (Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507]), Word([1632352272931598773, 13373839708502289855, 10272230035455739196, 12044926024433128507])), Word([5404036605550742542, 5072779045409325594, 2007486859543667101, 15485723958086254548]): (Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253]), Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253])), Word([7380494641903612464, 6658051037189709530, 1598345256024049520, 15544884248567796897]): (Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783]), Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783])), Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208]): (Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054]), Word([6510245351129855014, 14499781813891764676, 15415444664024674250, 15020644957368440054])), Word([15182906631253422133, 11210863479776221297, 9705815985032988063, 15681564952203239268]): (Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661]), Word([7762110520822785747, 15429768501160942121, 12180343601146840686, 13110597419621835661])), Word([1647346434040935821, 9479485455816730668, 1481410489053062942, 15698839004775251388]): (Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643]), Word([6391490631968727471, 10635523455095202572, 17817390745962571400, 1455820373918112643])), Word([11217554745661218137, 1254401472818238349, 11780985643636624657, 15930386039286304257]): (Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174]), Word([7524977039508561914, 3055387227595582549, 5337721299951095982, 10414890455199545174])), Word([11193463709754597275, 4687622073211056750, 9119685337510911899, 15984916424506674960]): (Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241]), Word([15359909534839720370, 18318319650890754454, 2680287043082032897, 3966575381596623241])), Word([15588393932722205321, 3014421399727113191, 16974809683756463518, 16027452425640143721]): (Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046]), Word([7506857997622957556, 10875981862989180914, 8286973802024589221, 14625951212107957046])), Word([3860596429637617372, 6554947514780740919, 13784339542180683209, 16095390482634395822]): (Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217]), Word([6232524979177425513, 12527657586268026488, 7199273373983737623, 9110556028668813217])), Word([2716770394206193982, 362567518346453877, 14278130375786750283, 16157765803262987253]): (Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697]), Word([10285273574406477445, 10358085193884076336, 2434476537487209654, 6026720306787293697])), Word([18014981229509410732, 14176208642919289188, 14793532609372582788, 16258038996058589054]): (Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019]), Word([6624360674817694443, 13995138081824377721, 8793226512399568408, 9523299032065916019])), Word([12896783327193558842, 14223520847319929296, 5231161851247674324, 16351311593357593821]): (Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432]), Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432])), Word([15292884165239381677, 17354017007365527649, 18235283403765031924, 16502052609200735864]): (Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105]), Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105])), Word([8175639808607885231, 15057488524410397820, 3256086896525912308, 16549058435568464373]): (Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855]), Word([5165403483994067838, 8621833651061017483, 10386289880036139513, 11199579522064000855])), Word([6495367580430056673, 5076188903290142617, 12440597605435697544, 16626831055447852646]): (Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830]), Word([15261229425597066902, 6277908017697274409, 4227476040890544387, 1351103020348566830])), Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460]): (Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208]), Word([1164247015370135465, 7799612277036514947, 11420825300197983897, 15668721591952065208])), Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033]): (Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214]), Word([14885546587311653320, 3739514343695545938, 11011166341483442498, 10150425085211425214])), Word([3145763642359150001, 7897572988335042336, 6193288093009236035, 16994348488259690105]): (Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129]), Word([6693828566576478062, 9974347315015299018, 16810437251415499748, 9485179093745367129])), Word([10798749058444003951, 6168130450702141604, 7408954842695441275, 17026147563136962281]): (Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909]), Word([9731053615716631609, 2500177426364872764, 4074597168154615882, 15227453932851378909])), Word([17008098382907755429, 1028295502599238628, 12638566816978689597, 17145758341827756028]): (Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027]), Word([13765044287689523240, 10143406322268804702, 17537689849071213425, 8975210496588340027])), Word([111967274994054564, 9536248623982663598, 6042602402422585474, 17200272701522564012]): (Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054]), Word([1870082289396567722, 14064949003056156855, 14126921475482258001, 9848833093575165054])), Word([14313238461606681048, 10538247441300629090, 17720672251454816062, 17238261909384191562]): (Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589]), Word([5583119793707713195, 14875734569327540391, 1745113605406493161, 9308105398669557589])), Word([8072532674895849860, 5223941016633909464, 12797973693661944820, 17332086611511481037]): (Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097]), Word([17785069920353893885, 12181610511466211054, 14696766909203382452, 9052223307518092097])), Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355]): (Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460]), Word([13146029447454426688, 13929020329594806690, 7535585724124566531, 16861943362254986460])), Word([10993240108549911562, 6065557944400892830, 7941258837795145679, 17448192827019270223]): (Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355]), Word([1196614781450255080, 15954236593773889073, 6595781758631550588, 17371251785288749355])), Word([3888425849842771009, 16996682999008100764, 7098985071818251871, 17459654002179420089]): (Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306]), Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306])), Word([2019362789636238252, 4881686650820287406, 4909133469122434095, 17473436797172613035]): (Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219]), Word([9817293520112454397, 18000244251434114627, 8726413454644140082, 12102270733961459219])), Word([7487425037348922165, 1956217638218512959, 123048945093955622, 17522180546005380432]): (Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297]), Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297])), Word([9730477409177006857, 17480075229477193722, 6186479790878476117, 17555344782525054693]): (Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263]), Word([1534320704104329911, 1067167308616339937, 17417664834701232933, 10334563823251782263])), Word([16729297220020279609, 9101907995765144749, 18227949116633400486, 17698385478566617794]): (Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484]), Word([14194125215964987460, 15844283789357152624, 10326080260423903048, 76481665721782484])), Word([5459324076910258714, 2715526985710463271, 8706353568913208333, 17707468888855250552]): (Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941]), Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941])), Word([18262299801479393995, 2548638218321300653, 6321476038940663933, 17719903204537459267]): (Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814]), Word([3259840020995850274, 1955770763221708273, 16741517283537178957, 6208262575450146814])), Word([17867126075653024918, 13358502965677383543, 1509302598027765781, 17728311630022719992]): (Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415]), Word([12551890022622607975, 7741993066542755358, 17047903593589748855, 3755644490112375415])), Word([17764660672296400890, 2270358193567233748, 1759338745692426825, 17743296383167139941]): (Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966]), Word([9580231643078727010, 11299141597397477477, 10734894173851293848, 15367839016167866966])), Word([10485961955196622691, 13441840831192481511, 6078856539768404764, 17864427699814990822]): (Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320]), Word([380242875898080855, 17055454844409939598, 15136303572069031901, 6114301609965976320])), Word([2856609154075759039, 12776076242729478628, 15730939018297634347, 17876993614336549306]): (Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902]), Word([14865076421927260997, 6733926354869989791, 6031424015752692995, 14169937261764597902])), Word([8210210402666457757, 12346888287403415558, 9171514665786205857, 17919227531564609820]): (Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880]), Word([5831686759021827687, 2007745977793688231, 4531961776655959371, 11419029465616987880])), Word([12224078686353806515, 11451311687035481131, 9321073197525705635, 17950958067790911361]): (Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725]), Word([15843536302707163227, 11250410302008099333, 17454633778507679755, 1136761107663850725])), Word([10838788592058011920, 17324949700844653466, 2414632977575414655, 18140940028430619005]): (Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914]), Word([7878858208803821817, 15778070601049834593, 4818331171663007243, 7791574802681449914])), Word([9704899558699429294, 888934449251485682, 431693366268687850, 18154544112943616783]): (Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781]), Word([570501813714977969, 1871407190021905056, 16365155059730069592, 96373817867264781])), Word([18046796134595922123, 149177996845839981, 7131765588342576721, 18231795817679852011]): (Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033]), Word([16083490555960573055, 10554044942365811137, 6717174434164247328, 16887281882883677033])), Word([9792536038170012532, 5334903103249849494, 3126812150848513643, 18231944901762444297]): (Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910]), Word([4582144536293102146, 9269530318385652642, 12118844264596008701, 6522025486101713910])), Word([2007554302483830424, 5859686910273439185, 18262930357764454476, 18235967302672812070]): (Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134]), Word([15944157248647461489, 1398275880958592016, 1909535179135680085, 11052039712054633134])), Word([7844338342611588357, 2340596165485472322, 13679522615119311893, 18241876085345904144]): (Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331]), Word([2875079704164660567, 14166261742124196884, 12383124306027484830, 3184947252558081331])), Word([2490458683104779985, 16738008805434919226, 2700599825558420210, 18254091674337546023]): (Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497]), Word([6111503942509124479, 7703676124098578528, 15836918219455478393, 14199796850044420497])), Word([9701025282533463304, 6908536088374387903, 16649151904726767446, 18339908092645480103]): (Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540]), Word([12365615317603094162, 15233395488851602361, 12718548272404288288, 10086125990937166540])), Word([2406555040894638492, 13046612881607389552, 4647344913357899135, 18390947994356851961]): (Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998]), Word([3698679818884153447, 2854011133060452491, 9705870317226154568, 11829774003193377998])), Word([6301397172966377848, 13179298638617871403, 208561277675731807, 18401460835794969414]): (Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]), Word([17586296187399257435, 8046751734003554711, 8621731950173158251, 9588298017293500959]))}, trace_len_summary: TraceLenSummary { main_trace_len: 20, range_trace_len: 47, chiplets_trace_len: ChipletsLengths { hash_chiplet_len: 128, bitwise_chiplet_len: 0, memory_chiplet_len: 2, kernel_rom_len: 0 } } } +ExecutionTrace { main_trace: MainTrace { storage: Parts { core_rm: [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 3987768130567869605, 17866922374020149524, 8514580104850791069, 13475546435959911551, 16952228088962355159, 5793482471479538911, 14446299416172848527, 13522295374716441620, 0, 0, 0, 0, 0, 0, 1, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 401642074298203, 40, 40, 0, 0, 0, 0, 0, 0, 4, 0, 0, 1, 0, 1, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 2, 0, 0, 0, 0, 0, 3, 1, 1, 0, 1, 1, 0, 1, 3137828705454, 1, 0, 0, 0, 0, 0, 0, 1, 3, 0, 0, 0, 0, 1, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 3, 0, 0, 0, 0, 0, 3, 0, 1, 1, 1, 0, 1, 0, 24514286761, 1, 0, 0, 0, 0, 0, 0, 1, 2, 1, 0, 0, 0, 0, 0, 40, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 2, 1, 4, 0, 0, 0, 0, 0, 3, 1, 0, 0, 1, 0, 1, 0, 191517865, 1, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 5, 0, 0, 0, 0, 0, 3, 1, 0, 0, 1, 0, 1, 0, 1496233, 1, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 13736132481315974302, 7221098028825620478, 15161595578319487008, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 6, 0, 0, 0, 0, 0, 3, 1, 0, 0, 1, 0, 1, 0, 11689, 1, 0, 0, 0, 0, 0, 0, 1, 2, 4, 0, 0, 0, 0, 0, 7221098028825620478, 15161595578319487008, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 7, 0, 0, 0, 0, 0, 3, 1, 0, 0, 1, 0, 1, 0, 91, 1, 0, 0, 0, 0, 0, 0, 1, 2, 5, 0, 0, 0, 0, 0, 15161595578319487008, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 8, 0, 0, 0, 0, 0, 3, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 2, 6, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 9, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 7, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 8, 1, 10, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 8, 1, 11, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 1, 1, 1, 3987768130567869605, 17866922374020149524, 8514580104850791069, 13475546435959911551, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 8, 1, 12, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 8, 1, 13, 0, 0, 0, 0, 0, 5, 0, 1, 1, 0, 1, 0, 1, 1032, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 14, 0, 0, 0, 0, 0, 7, 0, 0, 0, 1, 0, 0, 0, 8, 5, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 15, 0, 0, 0, 0, 0, 7, 0, 0, 0, 1, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 16, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 1, 1, 1, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 17, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 1, 1, 1, 16952228088962355159, 5793482471479538911, 14446299416172848527, 13522295374716441620, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 18, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 31, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 33, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 39, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 43, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 47, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 50, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 51, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 53, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 54, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 55, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 59, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 60, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 61, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 67, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 69, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 70, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 71, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 72, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 73, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 74, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 75, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 76, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 77, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 78, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 79, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 81, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 82, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 83, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 86, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 87, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 88, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 89, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 90, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 91, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 92, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 93, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 94, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 97, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 98, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 99, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 101, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 102, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 103, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 104, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 105, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 106, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 107, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 108, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 109, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 110, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 111, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 112, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 113, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 114, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 115, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 116, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 117, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 118, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 119, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 120, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 121, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 122, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 123, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 124, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 125, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 126, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 127, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0], chiplets_rm: [1, 1, 0, 0, 3987768130567869605, 17866922374020149524, 8514580104850791069, 13475546435959911551, 16952228088962355159, 5793482471479538911, 14446299416172848527, 13522295374716441620, 0, 87, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 8242146665224381578, 15911532375448333238, 1386357366995233596, 8611444126933110985, 4676083100930238397, 6139688846062542757, 9002714910392091903, 5823797362462191159, 0, 0, 1, 0, 0, 1, 1, 0, 0, 401642074298203, 40, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 3987768130567869605, 17866922374020149524, 8514580104850791069, 13475546435959911551, 7789855707707231369, 4610326148461237922, 1784941811671601269, 9924745492516640019, 7791549396364371277, 2968443994649453078, 1308562153347600605, 4332337354844628651, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 88, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 16952228088962355159, 5793482471479538911, 14446299416172848527, 13522295374716441620, 5915784406748100112, 6722847756588924736, 14012694245464324059, 2066991057620171669, 7739875740167294943, 7018932903636824263, 3536373181423802149, 16715512295218120604, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1032, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 11116382020814057190, 14732796941305378371, 13074361791711182490, 6715193688317415490, 1571558009365433839, 13285275197432594374, 15905141483335727027, 2507840277166973476, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 88, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1744857570235497404, 7224541920618385714, 6671488038711247732, 9418477143622752895, 9703867417214980336, 12489503772578086800, 7630918900393673526, 922936908940985560, 13119444482451573268, 8102518886279384149, 1794056580842530013, 6019859370758513415, 1, 0, 0, 0, 1, 0, 0, 0, 0, 11225476840467288604, 1258325688295597329, 127125292503096007, 14464605090260677523, 1356149198325814678, 16210500530871871700, 7703315482792482057, 9670557752572652209, 14715521009568351134, 5622479790818646070, 1994313401293831292, 12198921534065454764, 1, 0, 0, 0, 1, 0, 0, 0, 0, 6475944301769848126, 2915217068128247285, 10539364050497833639, 1329434144584264601, 4724829826743698824, 11656831663640211358, 18159325948688903721, 2263120035450455133, 3044551438691886778, 1378219755367734085, 27066760951347720, 7594002804590750508, 1, 0, 0, 0, 1, 0, 7094992666845579929, 10682949197627750021, 15511495322322885910, 15870512746805692064, 4742278351791462207, 7505045441162082383, 9115585980456141894, 11819132067426344142, 5933534952755427427, 5289666558408553872, 13337066958757631081, 6199794689781794653, 5527421833010022906, 4651988931660818160, 2987054724042595780, 1, 0, 0, 0, 1, 0, 3458358424286082329, 7093523218540709637, 10672998680593063500, 9582569954668317010, 13201115384751580570, 1845418544539288297, 9232442292023153805, 12186827811356238706, 10935576324406113028, 8489922013276339729, 12624430369688872770, 17630820426326624548, 2455558777867773614, 8013720398498280010, 12827655532307024322, 1, 0, 0, 0, 1, 0, 5785580083697586953, 5496776863607614961, 13562358148399326759, 9619728790481291702, 7348374190345066861, 13428391720342760502, 1625987251039265071, 4628549345299080849, 1482769832760029881, 15392110855022396191, 11685531496513883979, 16631929378585709364, 1206841992098443123, 9033969076040507441, 132716663048694064, 1, 0, 0, 0, 1, 0, 4935270318350649204, 11208979634658466526, 15063992759093620930, 69377025486693860, 2005546075822572073, 6505215078608999447, 5174094099800739640, 13001606491845435526, 1072287532585676149, 8674354724303146421, 2891558581869634704, 12003109342828923560, 2795184266895760838, 8907697550851381515, 7407535969740942827, 1, 0, 0, 0, 1, 0, 12928689569348120744, 18117769253874083942, 6430757471563325625, 11001198331791943845, 5782583463951144663, 3192834997426419970, 13479879407860298287, 12933861238108488467, 16278293297035470863, 6876436357683812502, 1917626248124261877, 7470768955678552355, 11361229958543541222, 7877487828305683469, 12846364871258595728, 1, 0, 0, 0, 1, 0, 3208246304442396143, 602388884213530987, 15428433977489879680, 13971985988839335428, 2737452825195583328, 15596845393022603175, 10706929119701705862, 4857505199118487438, 17086155371834155818, 14942339901122070806, 18093611989159833406, 8678554698795861566, 2399201986323959674, 14423713805583819215, 13940821782800746629, 1, 0, 0, 0, 1, 0, 5752176924989565290, 4446226812085120357, 4892387022627626332, 12766647202711608745, 16601117776639897488, 11733197324703429636, 12249169652316186841, 15421392054100411011, 10950661145505749420, 8676915018037525034, 2287206221212892475, 840670749677123625, 14199538947967054445, 11736020252788430378, 8602113489330523197, 1, 0, 0, 0, 1, 0, 16339610044914982284, 0, 0, 17640015747325898849, 16347444792678324740, 8885896841027368623, 10718432816977168969, 5156908241230918449, 17013559050399408119, 14174891037708262638, 1568239283519947871, 11922342832652198664, 17716568425187950727, 14294596817162139623, 8762912941700788919, 1, 0, 0, 0, 1, 0, 0, 0, 0, 10691440065277113539, 11571864114015088873, 14769641188290399688, 15214258832131517513, 16096616261062028405, 17526009277172454447, 7932842201848681903, 7306503137329194055, 13369935276997096320, 15066831218638174923, 9520626635373991696, 13296433431293103463, 1, 0, 0, 0, 1, 0, 0, 0, 0, 15457748872647003252, 12161715639235802937, 14007251173141324536, 1685517899923633866, 5112172969895687532, 5291999820044553537, 8437113893887445899, 3726439603382583733, 8404976155487828619, 7450257481186581855, 18356039864791793168, 15198056038162548435, 1, 0, 0, 0, 1, 0, 0, 0, 0, 12039411220003022329, 844322165626728828, 6152440980082407113, 11008191087326916441, 15301657567101812620, 7647514108863503629, 11736853678981601451, 13408456878721317654, 137431712022909617, 9004259806363632349, 994790402583656889, 3215329497276289397, 1, 0, 0, 0, 1, 0, 0, 0, 0, 16952228088962355159, 5793482471479538911, 14446299416172848527, 13522295374716441620, 5915784406748100112, 6722847756588924736, 14012694245464324059, 2066991057620171669, 7739875740167294943, 7018932903636824263, 3536373181423802149, 16715512295218120604, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1032, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 15913981378790993016, 12701179462806902902, 9645342555817022514, 6889850077248808033, 678249829196625442, 8726676798253716750, 14136118088409135949, 1027279235140821190, 8048729929177993405, 2542525775606472849, 3283471062508934848, 18058280687405074483, 1, 0, 0, 0, 1, 0, 0, 0, 0, 11899090779839289087, 1701090513954162998, 6953639183117323837, 11460660778637092812, 8345945186928076892, 11308243255833047975, 5734666540714547293, 1546649737555419076, 14643837757854608147, 7477230882792828789, 2359592855656894189, 12732146754685591216, 1, 0, 0, 0, 1, 0, 0, 0, 0, 16283412161296764998, 17261112905912533997, 1498213616014501531, 7707889409925905689, 16090493533591377617, 525010687572874692, 5228788497345464933, 13051466527897639054, 3560924095387897187, 12551242480725370445, 4038828260160651477, 6132317990703151787, 1, 0, 0, 0, 1, 0, 14261694278902826987, 16097544111075686229, 16632169854204459773, 14265791174051766329, 14732671264513481238, 15642599276989292777, 7593738854072541043, 11440582168151819564, 18258483622390056257, 6851601084855956341, 10463349537167637967, 10032876585525342603, 825669147467031185, 16271217766495541082, 9021089524754424392, 1, 0, 0, 0, 1, 0, 16780109665356203593, 16025948514351396737, 4256182047405196535, 4919013996388780384, 6974015548720770018, 10189882052640604940, 12288632186238773648, 7055558833039165669, 9820743264545515107, 7353106531603230851, 5612808106478211181, 362487531847990854, 10259224130335842891, 2374318293393776907, 16208179153232019183, 1, 0, 0, 0, 1, 0, 9496969110446094198, 10424961628901078909, 7587726188775237019, 13423955604028434301, 12288543613568774022, 4068762405627465026, 7288480650179820504, 1035430088689333582, 2651098721515326755, 4524440782000877024, 3013038852551457145, 12536534023666437466, 6560028330562582937, 9090521726813489969, 17634755409309861791, 1, 0, 0, 0, 1, 0, 15761194215082968049, 15796684185970405493, 1294179585337070936, 5701860167148115542, 17707247215386403887, 18419960639673587986, 14570347312565937582, 8634142387233894354, 11938075017385927203, 8060480374868324599, 16699922976999064541, 14234489074154948378, 17210389744085299852, 17331527780947314617, 16356838976302290254, 1, 0, 0, 0, 1, 0, 6184336662619539433, 7106147576739595100, 18237994300618329820, 9768155666925548219, 226714884885574576, 11169479382209254075, 5756676929838789145, 29803495366482069, 13128905441940840949, 18304516631519674746, 3177693875357946498, 10624850715031233718, 16956738608020324589, 10558540052020438814, 7826502712354673600, 1, 0, 0, 0, 1, 0, 1980308537464408089, 6810023246846442283, 9400257804338494201, 11246932855318952856, 7504545710540897051, 5823677062954428984, 9151299935574592196, 15905322272715446259, 18174748553199601666, 9877077233183640995, 2431998410719122545, 3541292002384422941, 5416588529930333172, 15788517205879313917, 2490575598934209003, 1, 0, 0, 0, 1, 0, 17950140321155419078, 9014768943295123367, 10707122777228105884, 10701204914974985643, 15060806908759160804, 7011191650405807117, 13598159658926423040, 3947314552577424057, 12985682730462769834, 18264715466581442035, 7667189540353817157, 7685483800933651249, 16085167604591833455, 16105855167414075111, 16215395602017884846, 1, 0, 0, 0, 1, 0, 8676227747932036802, 0, 0, 11504729673400082663, 3659553513673892306, 10374352082945691939, 15819529278889203623, 18107940902385670152, 8889798095480337831, 12737345777792032790, 456604824069734238, 2859376131275373721, 8758251935142908528, 2364536875264708997, 2435873391009301907, 1, 0, 0, 0, 1, 0, 0, 0, 0, 16797630026773069829, 16954579754978210547, 4393671449525183699, 6245909065255485436, 8311309349844601638, 3305827896314343556, 1615477551160071258, 3897903986825909618, 13015230208471866351, 13839070994009764281, 2415598337053791919, 5526300544248852335, 1, 0, 0, 0, 1, 0, 0, 0, 0, 12827873667465929582, 15892701250663610383, 549489834728826775, 9425334953627649153, 15402634395731091512, 11814416271399500934, 14597718118926923662, 4726679541432826422, 342915941842538663, 11221492717904369823, 17188959961041335276, 13559932473868727168, 1, 0, 0, 0, 1, 0, 0, 0, 0, 8689096602925893779, 4096531352684607500, 8424481237826564505, 15238165026175259240, 10985176737527635898, 2672540837788784952, 6649439643634522762, 7581835251244605715, 17671970641549389116, 18069913154458602790, 749417941228438762, 6150863900366154379, 1, 0, 0, 0, 1, 0, 0, 0, 0, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 11116382020814057190, 14732796941305378371, 13074361791711182490, 6715193688317415490, 1571558009365433839, 13285275197432594374, 15905141483335727027, 2507840277166973476, 1, 0, 0, 0, 1, 0, 0, 0, 0, 401642074298203, 40, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 5792301967904643716, 14513996957604530562, 6300577652167374432, 1030532363437082530, 9868636994953646365, 13312054463817713847, 1163060834237983926, 17159751124589539180, 15748271025379903662, 15673345155938926996, 15542740004802895548, 4070736982096634948, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1453121677659348577, 17403066345171442603, 9526966027631081464, 4562917345183859100, 16736668858502190206, 12710250320191836356, 9043028743666878997, 9570842800862454404, 10889819954451461225, 1374882310944969176, 11041329929342678296, 6376909268692149801, 1, 0, 0, 0, 1, 0, 0, 0, 0, 6798464049283172704, 10094602609597426273, 5441108908322692152, 13319823174770042865, 3687504758717747002, 11828007000931365406, 15642196062511550808, 4387538442135057894, 12016453509822632603, 16688879161845796765, 15353663875595798268, 9433687029957117661, 1, 0, 0, 0, 1, 0, 11436455846193695609, 17419948132223780613, 10707930966158261719, 7805136509413905123, 10748223278202845625, 5102455166015213038, 16060345288112427467, 9937020917196030767, 13713675713530315700, 11873887283723171030, 6245447289360608210, 2758175399376775060, 6794131889413756751, 6954584401067417189, 5092580402017360453, 1, 0, 0, 0, 1, 0, 138168370802146349, 561179642041056504, 13282391328952434407, 3586306435690112870, 17278658194357811156, 2504635638454636683, 7235500145280211409, 11191458759516692993, 6465450803792948194, 2111071922636782066, 11802465958807233213, 9116942394473193925, 11145482942031811955, 14726020691764699927, 16903672043479974450, 1, 0, 0, 0, 1, 0, 263960295682680947, 15697220842527476860, 17868088579823291326, 2175933588395873247, 8749749468735109989, 11010166446741390499, 17943104442301856895, 15821423767384514021, 16018668147064525478, 5560768172433028490, 5619212355349254932, 17391285462458271036, 2603291588626814071, 5238953246197227863, 5602891381109897586, 1, 0, 0, 0, 1, 0, 12301036190174877474, 12651281118484863330, 11983275442902746825, 9125195986387370903, 2181062690427536463, 13921861517061570826, 350891571660248295, 11013048057925712708, 11055047889476803308, 15398332646604634982, 5808711407549689243, 8949777591082911961, 14824627964979845981, 8130365156760288485, 3947069696768920416, 1, 0, 0, 0, 1, 0, 753507401801380169, 11557202300537182401, 12635550211207024884, 13277984171307670821, 2631795936834054713, 14094327291919754106, 12673624581190519723, 4509450209340246689, 10606486226190872261, 889124163739951988, 12547380261461657128, 16829937485708676196, 15832095999334895743, 5377353767201125639, 11053610747785598805, 1, 0, 0, 0, 1, 0, 17726880391953768878, 13956049620380258223, 11273932727072475337, 6855896085734577371, 1129400045567810133, 16519057148475618054, 10699416941054230316, 17256608828803451668, 6887723245936746466, 552364255868028623, 17909079490987407142, 9570595819850351164, 8654686163127378448, 16203109760043627710, 8480295614280342552, 1, 0, 0, 0, 1, 0, 5047048529377126902, 2720906371958061367, 10084181298533567509, 10367672116357405411, 11036446985399396097, 13294567520571596163, 17521531050433436007, 1868701710513242496, 5411603901210245247, 11609599138736895146, 16874855234706410918, 4393409689646403917, 9543195090298605247, 7478523150127634789, 2693101708644875762, 1, 0, 0, 0, 1, 0, 3528724572660247995, 0, 0, 12432722351030045, 1367308201666984940, 3681473655802754494, 15340518851882934883, 12978887161137913348, 15761699408266065961, 3053535844413236872, 13043307337058007179, 1605626291192886407, 3512088686484392896, 17370072541480613908, 15945489250832697271, 1, 0, 0, 0, 1, 0, 0, 0, 0, 18236855931369748683, 5145738009993425605, 9599849581440088949, 7181962801200058100, 7842895042061868932, 12656177266019986902, 8530248384503061153, 7088178758240165913, 8843525768370306419, 9760798177389960884, 15297557810674980998, 17513790474795511142, 1, 0, 0, 0, 1, 0, 0, 0, 0, 11582029127760482436, 12210748157899031357, 9473509448225646970, 17514007687115301207, 15252116786733410669, 10068681917011840638, 5010610666981558682, 14100290159714849481, 10038370148733513877, 4164887708143705047, 12759194225663538416, 5155504400103783318, 1, 0, 0, 0, 1, 0, 0, 0, 0, 2256431941220947766, 13487119117857302457, 10370113277604876234, 1506538453550143326, 9611088164777633619, 9944172425891749050, 2585766031776029836, 7469792865149057403, 3748706915022560085, 480217827283441208, 7902514309755880799, 16608422580379539141, 1, 0, 0, 0, 1, 0, 0, 0, 0, 3987768130567869605, 17866922374020149524, 8514580104850791069, 13475546435959911551, 7789855707707231369, 4610326148461237922, 1784941811671601269, 9924745492516640019, 7791549396364371277, 2968443994649453078, 1308562153347600605, 4332337354844628651, 1, 0, 0, 0, 1, 0, 0, 0, 0, 3987768130567869605, 17866922374020149524, 8514580104850791069, 13475546435959911551, 16952228088962355159, 5793482471479538911, 14446299416172848527, 13522295374716441620, 0, 87, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 15982823105988775806, 8055676711367425373, 17941169771108522281, 17144527358953736194, 14947610898944891577, 971614072768782170, 6527463406041159829, 3832659229659994697, 4267689650839244805, 7476341399175005462, 13956706726156239325, 1362637335972540923, 1, 0, 0, 0, 1, 0, 0, 0, 0, 5870626296958083933, 15831852620745746684, 3185498590211330291, 4142206734944835575, 1703654304778633946, 16779850255772273060, 17529309452142070777, 3820424470916782417, 13044986967311981583, 16932680220731892573, 15512851049245904995, 4407692356467248372, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1222210540818995679, 9596558254971998891, 17836151103719299929, 972583351096828487, 16036135922289885914, 9046461447407029762, 13420377050848926972, 8268741668021650938, 15162095256779392528, 6250951389520005938, 4880080490180073887, 5079644903468213758, 1, 0, 0, 0, 1, 0, 4277112440869277830, 16975894093684028062, 17916235475615809558, 14524910789332636826, 11691364468631390887, 7787341040263241822, 9379002423052238093, 9978142397546997785, 13711991341735230802, 2995007776024477424, 4712167935694753945, 1064069264700679460, 16784239691558161828, 13171136420515290288, 7377465172358292401, 1, 0, 0, 0, 1, 0, 7863758113629837220, 34545184916281199, 3993169000277716254, 7364322756301525079, 10650631026443210837, 1517619643121483559, 17270732420407911054, 4258304245011181242, 5161000027742486976, 8399067086847534736, 11003984578732833046, 15464732564240072836, 6182941569324809186, 11275803822943060218, 158655113981893701, 1, 0, 0, 0, 1, 0, 2476402089664475908, 9916425135419809036, 3028465534706354547, 15472564680003668093, 6373098182685681762, 12520752577019080054, 5394462987259780313, 4831149567958541538, 12904631563004530976, 13837253351754641870, 3923208428450719385, 3554976680697606440, 17043251418254499417, 5302393607875037297, 8096532195498204177, 1, 0, 0, 0, 1, 0, 5401472078486138644, 17911378919292638386, 1604440114467418180, 4779855905656105676, 6025526479746347251, 4449154494231990099, 11830346459740212406, 2743894608322163398, 10184996808268436049, 3882545820330029085, 5202687146936953923, 777280530525071979, 9570037184747372126, 10484193697881848161, 11860662735451501625, 1, 0, 0, 0, 1, 0, 15748781809771449617, 12223876502815956005, 8462728310504683652, 13057156105981161589, 11957472249295015469, 11549246553227545561, 15033014935301073849, 423385249083279348, 10856312299574527186, 2052856619870651334, 10305616267836960765, 14352183358244000568, 1261949652056609866, 916956049912161855, 3353438403242689585, 1, 0, 0, 0, 1, 0, 11740120563940364368, 1391869256781506493, 11057309605482706459, 17704317629486807708, 6564342187673520486, 2792692044523533343, 12797232677587390356, 14797653849693720774, 9082763018815888798, 17062564998145646419, 17163741437026102402, 14920816938307553514, 18409839409942969565, 16099949995219613642, 9387728217249208068, 1, 0, 0, 0, 1, 0, 3254516890705807916, 7365800426850749937, 15974018227958845798, 8444961928162939943, 8050679843713964343, 1245616094758475931, 2976182234519674621, 11861324009571007650, 18000519861091284933, 10809856712858383834, 6898855362441294480, 13146633521971264482, 11152948692891359460, 10343969929561703022, 10591999464601502689, 1, 0, 0, 0, 1, 0, 13540695320312597078, 0, 0, 933984176226341473, 4938354828005165424, 3057022637731780053, 18149554045659845084, 9709632327217036413, 16645387828565996715, 10873951879782645518, 214597493824524577, 7950640568527571392, 15274457345887794634, 9280090582838465603, 1242243096703449887, 1, 0, 0, 0, 1, 0, 0, 0, 0, 5626861946644684679, 9519120652743404725, 3153363644848796249, 16387713581663902851, 10655954775576173219, 16168525333832765040, 7013656376478213608, 7333415223195735541, 9069684467099779645, 10706178255503280152, 17753787514920247819, 16088561184006536263, 1, 0, 0, 0, 1, 0, 0, 0, 0, 10636061157542345097, 15008846988127407811, 16614085001509596773, 12600455057253767871, 13458552295186750925, 10343839881402182751, 1108696518251840495, 9621971582260379329, 11613485699478956673, 16861381831518076617, 17933004011918959112, 18255208815154765383, 1, 0, 0, 0, 1, 0, 0, 0, 0, 10509741793670097910, 12960656197959013774, 9112727654277900213, 14176014235755683408, 9647930301481695061, 10818726819316593067, 11744599510375600263, 2780827620762362248, 60352997716668050, 2064777537623220055, 12394773470270210064, 15490398721638241462, 1, 0, 0, 0, 1, 0, 0, 0, 0, 14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674, 8242146665224381578, 15911532375448333238, 1386357366995233596, 8611444126933110985, 4676083100930238397, 6139688846062542757, 9002714910392091903, 5823797362462191159, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 40, 0, 0, 3, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 1, 0, 1, 1, 10, 0, 0, 0, 1, 0, 1, 1, 0, 40, 0, 0, 12, 13219816384148928727, 13736132481315974302, 7221098028825620478, 15161595578319487008, 9, 0, 4099276459869907627, 1, 10, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], range_checker_cols: [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 1, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 7, 8, 9, 10, 2197, 4384, 6571, 8758, 10945, 13132, 15319, 17506, 19693, 21880, 24067, 26254, 28441, 30628, 32815, 35002, 37189, 39376, 41563, 43750, 45937, 48124, 50311, 52498, 54685, 56872, 59059, 61246, 63433, 64162, 64891, 65134, 65377, 65458, 65485, 65512, 65521, 65530, 65533, 65534, 65535, 65535]], num_rows: 128 }, last_program_row: RowIndex(19) }, program_info: ProgramInfo { program_hash: Word([14484889142457247702, 15709744442370709082, 8733775926567848981, 10277802787184533674]), kernel: Kernel([]) }, stack_outputs: StackOutputs { elements: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, precompile_requests: [], final_precompile_transcript: PrecompileTranscript { state: Word([0, 0, 0, 0]) }, trace_len_summary: TraceLenSummary { main_trace_len: 20, range_trace_len: 49, chiplets_trace_len: ChipletsLengths { hash_chiplet_len: 80, bitwise_chiplet_len: 0, memory_chiplet_len: 2, ace_chiplet_len: 0, kernel_rom_len: 0 } } } diff --git a/processor/src/trace/parallel/tests.rs b/processor/src/trace/parallel/tests.rs index c3abcf4c76..d3b96c960c 100644 --- a/processor/src/trace/parallel/tests.rs +++ b/processor/src/trace/parallel/tests.rs @@ -1,14 +1,25 @@ use alloc::{string::String, sync::Arc}; -use miden_air::trace::{AUX_TRACE_RAND_CHALLENGES, chiplets::hasher::HASH_CYCLE_LEN}; +use miden_air::{ + ProcessorAir, + lookup::build_logup_aux_trace, + trace::{ + DECODER_TRACE_OFFSET, + chiplets::hasher::HASH_CYCLE_LEN, + decoder::{HASHER_STATE_OFFSET, NUM_OP_BITS, OP_BITS_OFFSET}, + }, +}; use miden_core::{ - Felt, + Felt, Word, + events::EventId, + field::QuadFelt, mast::{ BasicBlockNodeBuilder, CallNodeBuilder, DynNodeBuilder, ExternalNodeBuilder, JoinNodeBuilder, LoopNodeBuilder, MastForest, MastForestContributor, MastNodeExt, SplitNodeBuilder, }, - operations::Operation, + operations::{Operation, opcodes}, + precompile::PrecompileRequest, program::{Kernel, Program, StackInputs}, }; use miden_utils_testing::{get_column_name, rand::rand_array}; @@ -17,16 +28,17 @@ use rstest::{fixture, rstest}; use super::*; use crate::{ - AdviceInputs, DefaultHost, ExecutionOptions, FastProcessor, HostLibrary, + AdviceInputs, DefaultHost, ExecutionOptions, FastProcessor, HostLibrary, TraceBuildInputs, trace::trace_state::MemoryReadsReplay, }; -const DEFAULT_STACK: &[Felt] = &[Felt::new(1), Felt::new(2), Felt::new(3)]; +const DEFAULT_STACK: &[Felt] = + &[Felt::new_unchecked(1), Felt::new_unchecked(2), Felt::new_unchecked(3)]; /// A sentinel value mainly used to catch when a ZERO is dropped from the stack but shouldn't have /// been. That is, if the stack is only ZEROs, we can't tell if a ZERO was dropped or not. Using a /// sentinel value makes it obvious when an unexpected ZERO is dropped. -const SENTINEL_VALUE: Felt = Felt::new(9999); +const SENTINEL_VALUE: Felt = Felt::new_unchecked(9999); /// Returns the procedure hash that DYN and DYNCALL will call. /// The digest is computed dynamically from the target basic block (single SWAP operation). @@ -324,13 +336,12 @@ fn test_trace_generation_at_fragment_boundaries( ExecutionOptions::default() .with_core_trace_fragment_size(fragment_size) .unwrap(), - ); + ) + .expect("processor advice inputs should fit advice map limits"); let mut host = DefaultHost::default(); host.load_library(create_simple_library()).unwrap(); - let (execution_output, trace_fragment_contexts) = - processor.execute_for_trace_sync(&program, &mut host).unwrap(); - - build_trace(execution_output, trace_fragment_contexts, program.to_info()).unwrap() + let trace_inputs = processor.execute_trace_inputs_sync(&program, &mut host).unwrap(); + build_trace(trace_inputs).unwrap() }; let trace_from_single_fragment = { @@ -340,14 +351,14 @@ fn test_trace_generation_at_fragment_boundaries( ExecutionOptions::default() .with_core_trace_fragment_size(MAX_FRAGMENT_SIZE) .unwrap(), - ); + ) + .expect("processor advice inputs should fit advice map limits"); let mut host = DefaultHost::default(); host.load_library(create_simple_library()).unwrap(); - let (execution_output, trace_fragment_contexts) = - processor.execute_for_trace_sync(&program, &mut host).unwrap(); - assert!(trace_fragment_contexts.core_trace_contexts.len() == 1); + let trace_inputs = processor.execute_trace_inputs_sync(&program, &mut host).unwrap(); + assert!(trace_inputs.trace_generation_context().core_trace_contexts.len() == 1); - build_trace(execution_output, trace_fragment_contexts, program.to_info()).unwrap() + build_trace(trace_inputs).unwrap() }; // Ensure that the trace generated from multiple fragments is identical to the one generated @@ -395,31 +406,15 @@ fn test_trace_generation_at_fragment_boundaries( trace_from_single_fragment.trace_len_summary(), ); - // Verify merkle store data match deterministically. - let merkle_nodes_from_fragments: alloc::collections::BTreeMap<_, _> = trace_from_fragments - .advice_provider() - .merkle_store() - .inner_nodes() - .map(|info| (info.value, (info.left, info.right))) - .collect(); - let merkle_nodes_from_single: alloc::collections::BTreeMap<_, _> = trace_from_single_fragment - .advice_provider() - .merkle_store() - .inner_nodes() - .map(|info| (info.value, (info.left, info.right))) - .collect(); - assert_eq!(merkle_nodes_from_fragments, merkle_nodes_from_single,); - - // Verify aux trace columns match. - let rand_elements = rand_array::(); - let aux_from_fragments = trace_from_fragments.build_aux_trace(&rand_elements).unwrap(); - let aux_from_single_fragment = - trace_from_single_fragment.build_aux_trace(&rand_elements).unwrap(); - let aux_from_fragments = - aux_from_fragments.columns().map(|col| col.to_vec()).collect::>(); - let aux_from_single_fragment = - aux_from_single_fragment.columns().map(|col| col.to_vec()).collect::>(); - assert_eq!(aux_from_fragments, aux_from_single_fragment,); + // Verify deferred precompile data match deterministically. + assert_eq!( + trace_from_fragments.precompile_requests(), + trace_from_single_fragment.precompile_requests(), + ); + assert_eq!( + trace_from_fragments.final_precompile_transcript, + trace_from_single_fragment.final_precompile_transcript, + ); // Compare deterministic traces as a compact sanity check and to keep the snapshot stable. assert_eq!( @@ -428,12 +423,98 @@ fn test_trace_generation_at_fragment_boundaries( "Deterministic trace mismatch between fragments and single fragment" ); + // Build the LogUp aux trace from each main trace under identical random challenges and + // verify every column matches row-for-row. Catches fragment-boundary nondeterminism in + // lookup collection that `DeterministicTrace` (main-trace only) would miss. + let raw = rand_array::(); + let challenges = [QuadFelt::new([raw[0], raw[1]]), QuadFelt::new([raw[2], raw[3]])]; + let main_from_fragments = trace_from_fragments.main_trace().to_row_major(); + let main_from_single = trace_from_single_fragment.main_trace().to_row_major(); + let (aux_from_fragments, committed_from_fragments) = + build_logup_aux_trace(&ProcessorAir, &main_from_fragments, &challenges); + let (aux_from_single, committed_from_single) = + build_logup_aux_trace(&ProcessorAir, &main_from_single, &challenges); + assert_eq!( + aux_from_fragments.values, aux_from_single.values, + "LogUp aux trace mismatch between fragments and single fragment" + ); + assert_eq!( + committed_from_fragments, committed_from_single, + "LogUp committed finals mismatch between fragments and single fragment" + ); + // Snapshot testing to ensure that future changes don't unexpectedly change the trace. // We use DeterministicTrace to produce stable Debug output, since ExecutionTrace contains // a MerkleStore backed by HashMap whose iteration order is non-deterministic. insta::assert_compact_debug_snapshot!(testname, DeterministicTrace(&trace_from_fragments)); } +#[test] +fn test_nested_loop_end_flags_stable_across_fragmentation() { + // Small fragment size is chosen so that the fragment boundaries land on the outer loop replay: + // rows [0..6], [7..13], [14..]. + // + // Execution for the chosen stack inputs: + // 0: LOOP + // 1: LOOP + // 2: BLOCK PAD DROP END + // 6: END + // 7: REPEAT + // 8: LOOP + // 9: BLOCK PAD DROP END + // 13: END + // 14: END + // 15: HALT + // + // Stack inputs, top first: + // 1) enter outer loop + // 2) enter inner loop + // 3) exit inner loop + // 4) repeat outer loop + // 5) enter inner loop + // 6) exit inner loop + // 7) exit outer loop + const SMALL_FRAGMENT_SIZE: usize = 7; + const LARGE_FRAGMENT_SIZE: usize = 1 << 20; + + let program = nested_loop_program(); + let stack_inputs = &[ONE, ONE, ZERO, ONE, ONE, ZERO, ZERO, SENTINEL_VALUE]; + + let trace_from_fragments = build_trace_for_program(&program, stack_inputs, SMALL_FRAGMENT_SIZE); + let trace_from_single_fragment = + build_trace_for_program(&program, stack_inputs, LARGE_FRAGMENT_SIZE); + + let columns_from_fragments = trace_from_fragments + .main_trace() + .columns() + .map(|col| col.to_vec()) + .collect::>(); + let columns_from_single_fragment = trace_from_single_fragment + .main_trace() + .columns() + .map(|col| col.to_vec()) + .collect::>(); + + assert_eq!( + columns_from_fragments, columns_from_single_fragment, + "nested-loop trace changed across fragment boundaries" + ); + + let end_flags = collect_end_flags(&trace_from_fragments); + assert!( + end_flags.contains(&[ONE, ZERO, ZERO, ZERO].into()), + "expected an END row for loop body basic block (is_loop_body=1)" + ); + assert!( + end_flags.contains(&[ONE, ONE, ZERO, ZERO].into()), + "expected an END row for inner loop node (is_loop_body=1, loop_entered=1)" + ); + assert!( + end_flags.contains(&[ZERO, ONE, ZERO, ZERO].into()), + "expected an END row for outer loop node (is_loop_body=0, loop_entered=1)" + ); +} + #[test] fn test_partial_last_fragment_exists_for_h0_inversion_path() { // Keep this > 1 and non-dividing for join_program() to guarantee a short final fragment. @@ -446,19 +527,19 @@ fn test_partial_last_fragment_exists_for_h0_inversion_path() { ExecutionOptions::default() .with_core_trace_fragment_size(FRAGMENT_SIZE) .unwrap(), - ); + ) + .expect("processor advice inputs should fit advice map limits"); let mut host = DefaultHost::default(); host.load_library(create_simple_library()).unwrap(); - let (execution_output, trace_fragment_contexts) = - processor.execute_for_trace_sync(&program, &mut host).unwrap(); + let trace_inputs = processor.execute_trace_inputs_sync(&program, &mut host).unwrap(); assert!( - trace_fragment_contexts.core_trace_contexts.len() > 1, + trace_inputs.trace_generation_context().core_trace_contexts.len() > 1, "repro precondition requires multiple fragments" ); - let trace = build_trace(execution_output, trace_fragment_contexts, program.to_info()).unwrap(); + let trace = build_trace(trace_inputs).unwrap(); let total_rows_without_halt = trace.main_trace().num_rows() - 1; assert_ne!( @@ -482,15 +563,15 @@ fn miri_repro_uninitialized_tail_read_during_h0_inversion() { ExecutionOptions::default() .with_core_trace_fragment_size(FRAGMENT_SIZE) .unwrap(), - ); + ) + .expect("processor advice inputs should fit advice map limits"); let mut host = DefaultHost::default(); host.load_library(create_simple_library()).unwrap(); - let (execution_output, trace_fragment_contexts) = - processor.execute_for_trace_sync(&program, &mut host).unwrap(); + let trace_inputs = processor.execute_trace_inputs_sync(&program, &mut host).unwrap(); - assert!(trace_fragment_contexts.core_trace_contexts.len() > 1); + assert!(trace_inputs.trace_generation_context().core_trace_contexts.len() > 1); - let _ = build_trace(execution_output, trace_fragment_contexts, program.to_info()); + let _ = build_trace(trace_inputs); } /// Creates a library with a single procedure containing just a SWAP operation. @@ -598,6 +679,25 @@ fn loop_program() -> Program { Program::new(Arc::new(program), root_join_node) } +/// (loop (loop (block pad drop))) +fn nested_loop_program() -> Program { + let mut program = MastForest::new(); + + let inner_loop = { + let basic_block_pad_drop = + BasicBlockNodeBuilder::new(vec![Operation::Pad, Operation::Drop], Vec::new()) + .add_to_forest(&mut program) + .unwrap(); + + LoopNodeBuilder::new(basic_block_pad_drop).add_to_forest(&mut program).unwrap() + }; + + let outer_loop = LoopNodeBuilder::new(inner_loop).add_to_forest(&mut program).unwrap(); + + program.make_root(outer_loop); + Program::new(Arc::new(program), outer_loop) +} + /// (join ( /// (block swap swap) /// (call ()) @@ -717,7 +817,7 @@ fn basic_block_program_multiple_batches() -> Program { /// (dyn) /// ) fn dyn_program() -> Program { - const HASH_ADDR: Felt = Felt::new(40); + const HASH_ADDR: Felt = Felt::new_unchecked(40); let mut program = MastForest::new(); @@ -759,7 +859,7 @@ fn dyn_program() -> Program { /// (dyncall) /// ) fn dyncall_program() -> Program { - const HASH_ADDR: Felt = Felt::new(40); + const HASH_ADDR: Felt = Felt::new_unchecked(40); let mut program = MastForest::new(); @@ -840,18 +940,18 @@ fn test_build_trace_returns_err_on_empty_memory_reads_replay() { ExecutionOptions::default() .with_core_trace_fragment_size(MAX_FRAGMENT_SIZE) .unwrap(), - ); + ) + .expect("processor advice inputs should fit advice map limits"); let mut host = DefaultHost::default(); - let (execution_output, mut trace_generation_context) = - processor.execute_for_trace_sync(&program, &mut host).unwrap(); + let mut trace_inputs = processor.execute_trace_inputs_sync(&program, &mut host).unwrap(); // Clear the memory reads replay so the replay processor will fail when the DYN node tries to // read the callee hash from memory. - for ctx in &mut trace_generation_context.core_trace_contexts { + for ctx in &mut trace_inputs.trace_generation_context_mut().core_trace_contexts { ctx.replay.memory_reads = MemoryReadsReplay::default(); } - let result = build_trace(execution_output, trace_generation_context, program.to_info()); + let result = build_trace(trace_inputs); assert!( result.is_err(), "build_trace should return Err when hasher replay has bad node ID" @@ -873,10 +973,10 @@ fn test_build_trace_returns_err_on_bad_node_id_in_hasher_replay() { ExecutionOptions::default() .with_core_trace_fragment_size(MAX_FRAGMENT_SIZE) .unwrap(), - ); + ) + .expect("processor advice inputs should fit advice map limits"); let mut host = DefaultHost::default(); - let (execution_output, mut trace_generation_context) = - processor.execute_for_trace_sync(&program, &mut host).unwrap(); + let mut trace_inputs = processor.execute_trace_inputs_sync(&program, &mut host).unwrap(); // Inject a HashBasicBlock entry with a node ID that points to a non-existent node in an empty // forest. @@ -886,19 +986,60 @@ fn test_build_trace_returns_err_on_bad_node_id_in_hasher_replay() { let valid_id = BasicBlockNodeBuilder::new(vec![Operation::Noop], Vec::new()) .add_to_forest(&mut temp_forest) .unwrap(); - trace_generation_context.hasher_for_chiplet.record_hash_basic_block( - empty_forest, - valid_id, - [ZERO; 4].into(), - ); + trace_inputs + .trace_generation_context_mut() + .hasher_for_chiplet + .record_hash_basic_block(empty_forest, valid_id, [ZERO; 4].into()); - let result = build_trace(execution_output, trace_generation_context, program.to_info()); + let result = build_trace(trace_inputs); assert!( result.is_err(), "build_trace should return Err when hasher replay has bad node ID" ); } +/// Verifies that `build_trace` rejects compatibility bundles that reuse matching public outputs +/// but carry different deferred precompile requests. +#[test] +fn test_build_trace_rejects_mismatched_precompile_requests() { + const MAX_FRAGMENT_SIZE: usize = 1 << 20; + + let program = basic_block_program_small(); + + let processor = FastProcessor::new_with_options( + StackInputs::new(DEFAULT_STACK).unwrap(), + AdviceInputs::default(), + ExecutionOptions::default() + .with_core_trace_fragment_size(MAX_FRAGMENT_SIZE) + .unwrap(), + ) + .expect("processor advice inputs should fit advice map limits"); + let mut host = DefaultHost::default(); + let trace_inputs = processor.execute_trace_inputs_sync(&program, &mut host).unwrap(); + let (trace_output, trace_generation_context, program_info) = trace_inputs.into_parts(); + + let mut other_trace_output = trace_output; + other_trace_output + .precompile_requests + .push(PrecompileRequest::new(EventId::from_u64(7), vec![1, 2, 3])); + + let result = build_trace(TraceBuildInputs::from_parts( + other_trace_output, + trace_generation_context, + program_info, + )); + + assert!( + matches!( + result, + Err(ExecutionError::Internal( + "trace inputs do not match deferred precompile requests" + )) + ), + "expected deferred-precompile-request mismatch error, got: {result:?}" + ); +} + /// Tests `build_trace_with_max_len` behavior at various `max_trace_len` boundaries relative to the /// core trace length. `core_trace_len` is the number of core trace rows including the HALT row /// appended by `build_trace_with_max_len`. @@ -925,26 +1066,21 @@ fn test_build_trace_with_max_len_corner_cases( ExecutionOptions::default() .with_core_trace_fragment_size(MAX_FRAGMENT_SIZE) .unwrap(), - ); + ) + .expect("processor advice inputs should fit advice map limits"); let mut host = DefaultHost::default(); - let (execution_output, trace_generation_context) = - processor.execute_for_trace_sync(&program, &mut host).unwrap(); + let trace_inputs = processor.execute_trace_inputs_sync(&program, &mut host).unwrap(); // Compute the number of core trace rows generated, which includes the HALT row inserted by // `build_trace_with_max_len`. - let core_trace_len = trace_generation_context.core_trace_contexts.len() - * trace_generation_context.fragment_size + let core_trace_len = trace_inputs.trace_generation_context().core_trace_contexts.len() + * trace_inputs.trace_generation_context().fragment_size + 1; let max_trace_len = core_trace_len .checked_add_signed(max_trace_len_offset_from_core_trace_len) .unwrap(); - let result = build_trace_with_max_len( - execution_output, - trace_generation_context, - program.to_info(), - max_trace_len, - ); + let result = build_trace_with_max_len(trace_inputs, max_trace_len); assert_eq!( result.is_ok(), @@ -977,20 +1113,15 @@ fn test_build_trace_returns_err_on_fragment_size_overflow() { ExecutionOptions::default() .with_core_trace_fragment_size(MAX_FRAGMENT_SIZE) .unwrap(), - ); + ) + .expect("processor advice inputs should fit advice map limits"); let mut host = DefaultHost::default(); - let (execution_output, mut trace_generation_context) = - processor.execute_for_trace_sync(&program, &mut host).unwrap(); + let mut trace_inputs = processor.execute_trace_inputs_sync(&program, &mut host).unwrap(); // Set fragment_size to usize::MAX so that `len() * fragment_size` overflows. - trace_generation_context.fragment_size = usize::MAX; + trace_inputs.trace_generation_context_mut().fragment_size = usize::MAX; - let result = build_trace_with_max_len( - execution_output, - trace_generation_context, - program.to_info(), - usize::MAX, - ); + let result = build_trace_with_max_len(trace_inputs, usize::MAX); assert!( matches!(result, Err(ExecutionError::TraceLenExceeded(_))), @@ -1014,15 +1145,15 @@ fn test_build_trace_returns_err_when_chiplets_trace_exceeds_max_len() { ExecutionOptions::default() .with_core_trace_fragment_size(MAX_FRAGMENT_SIZE) .unwrap(), - ); + ) + .expect("processor advice inputs should fit advice map limits"); let mut host = DefaultHost::default(); - let (execution_output, mut trace_generation_context) = - processor.execute_for_trace_sync(&program, &mut host).unwrap(); + let mut trace_inputs = processor.execute_trace_inputs_sync(&program, &mut host).unwrap(); // Note: the last fragment may have fewer rows than the fragment size, so this is really an // upper bound on the number of core trace rows - let core_trace_rows = - trace_generation_context.core_trace_contexts.len() * trace_generation_context.fragment_size; + let core_trace_rows = trace_inputs.trace_generation_context().core_trace_contexts.len() + * trace_inputs.trace_generation_context().fragment_size; // Inject enough hasher permutations so the chiplets trace exceeds core_trace_rows. // Each permute adds HASH_CYCLE_LEN rows to the hasher chiplet trace, so we need @@ -1030,19 +1161,17 @@ fn test_build_trace_returns_err_when_chiplets_trace_exceeds_max_len() { // limit. let num_permutations = core_trace_rows / HASH_CYCLE_LEN + 1; for _ in 0..num_permutations { - trace_generation_context.hasher_for_chiplet.record_permute_input([ZERO; 12]); + trace_inputs + .trace_generation_context_mut() + .hasher_for_chiplet + .record_permute_input([ZERO; 12]); } // Set max_trace_len equal to core_trace_rows. The core trace check passes (not strictly // greater), but the inflated chiplets trace will exceed it. let max_trace_len = core_trace_rows; - let result = build_trace_with_max_len( - execution_output, - trace_generation_context, - program.to_info(), - max_trace_len, - ); + let result = build_trace_with_max_len(trace_inputs, max_trace_len); assert!( matches!(result, Err(ExecutionError::TraceLenExceeded(_))), @@ -1064,15 +1193,15 @@ fn test_build_trace_returns_err_on_empty_core_trace_contexts() { ExecutionOptions::default() .with_core_trace_fragment_size(MAX_FRAGMENT_SIZE) .unwrap(), - ); + ) + .expect("processor advice inputs should fit advice map limits"); let mut host = DefaultHost::default(); - let (execution_output, mut trace_generation_context) = - processor.execute_for_trace_sync(&program, &mut host).unwrap(); + let mut trace_inputs = processor.execute_trace_inputs_sync(&program, &mut host).unwrap(); // Clear core_trace_contexts to simulate an empty trace. - trace_generation_context.core_trace_contexts.clear(); + trace_inputs.trace_generation_context_mut().core_trace_contexts.clear(); - let result = build_trace(execution_output, trace_generation_context, program.to_info()); + let result = build_trace(trace_inputs); assert!( matches!(result, Err(ExecutionError::Internal(_))), @@ -1089,6 +1218,63 @@ fn testname() -> String { std::thread::current().name().unwrap().replace("::", "__") } +fn build_trace_for_program( + program: &Program, + stack_inputs: &[Felt], + fragment_size: usize, +) -> ExecutionTrace { + let processor = FastProcessor::new_with_options( + StackInputs::new(stack_inputs).unwrap(), + AdviceInputs::default(), + ExecutionOptions::default() + .with_core_trace_fragment_size(fragment_size) + .unwrap(), + ) + .expect("processor advice inputs should fit advice map limits"); + let mut host = DefaultHost::default(); + host.load_library(create_simple_library()).unwrap(); + let trace_inputs = processor.execute_trace_inputs_sync(program, &mut host).unwrap(); + + build_trace(trace_inputs).unwrap() +} + +fn collect_end_flags(trace: &ExecutionTrace) -> Vec { + let main_trace = trace.main_trace(); + + (0..main_trace.num_rows()) + .filter_map(|row_idx| { + if read_opcode(main_trace, row_idx) == opcodes::END { + Some( + [ + main_trace.get_column(DECODER_TRACE_OFFSET + HASHER_STATE_OFFSET + 4) + [row_idx], + main_trace.get_column(DECODER_TRACE_OFFSET + HASHER_STATE_OFFSET + 5) + [row_idx], + main_trace.get_column(DECODER_TRACE_OFFSET + HASHER_STATE_OFFSET + 6) + [row_idx], + main_trace.get_column(DECODER_TRACE_OFFSET + HASHER_STATE_OFFSET + 7) + [row_idx], + ] + .into(), + ) + } else { + None + } + }) + .collect() +} + +fn read_opcode(main_trace: &MainTrace, row_idx: usize) -> u8 { + let mut result = 0; + for i in 0..NUM_OP_BITS { + let op_bit = main_trace.get_column(DECODER_TRACE_OFFSET + OP_BITS_OFFSET + i)[row_idx] + .as_canonical_u64(); + assert!(op_bit <= 1, "invalid op bit"); + result += op_bit << i; + } + result as u8 +} + /// Wrapper around `ExecutionTrace` that produces deterministic `Debug` output. /// /// `ExecutionTrace` contains a `MerkleStore` backed by `HashMap`, whose iteration order is @@ -1100,19 +1286,12 @@ impl core::fmt::Debug for DeterministicTrace<'_> { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { let trace = self.0; - // Collect merkle store nodes into a sorted BTreeMap for deterministic output - let sorted_nodes: alloc::collections::BTreeMap<_, _> = trace - .advice_provider() - .merkle_store() - .inner_nodes() - .map(|info| (info.value, (info.left, info.right))) - .collect(); - f.debug_struct("ExecutionTrace") .field("main_trace", trace.main_trace()) .field("program_info", &trace.program_info()) .field("stack_outputs", &trace.stack_outputs()) - .field("merkle_store_nodes", &sorted_nodes) + .field("precompile_requests", &trace.precompile_requests()) + .field("final_precompile_transcript", &trace.final_precompile_transcript) .field("trace_len_summary", &trace.trace_len_summary()) .finish() } diff --git a/processor/src/trace/parallel/tracer/mod.rs b/processor/src/trace/parallel/tracer/mod.rs index e32e46de81..29b22cbd18 100644 --- a/processor/src/trace/parallel/tracer/mod.rs +++ b/processor/src/trace/parallel/tracer/mod.rs @@ -5,12 +5,13 @@ use miden_core::program::MIN_STACK_DEPTH; use super::{ super::{ - decoder::block_stack::ExecutionContextInfo, + block_stack::ExecutionContextInfo, trace_state::{ BlockAddressReplay, BlockStackReplay, DecoderState, StackState, SystemState, }, + utils::RowMajorTraceWriter, }, - core_trace_fragment::{BasicBlockContext, CoreTraceFragment}, + core_trace_fragment::BasicBlockContext, processor::ReplayProcessor, }; use crate::{ @@ -18,6 +19,7 @@ use crate::{ continuation_stack::{Continuation, ContinuationStack}, errors::MapExecErrNoCtx, mast::{MastForest, MastNode, MastNodeExt, MastNodeId}, + trace::trace_state::NodeFlags, tracer::{OperationHelperRegisters, Tracer}, }; @@ -52,8 +54,8 @@ pub(crate) struct TracerFinalState { /// final state of the tracer (or the error, if one was encountered). #[derive(Debug)] pub(crate) struct CoreTraceGenerationTracer<'a> { - /// The trace fragment being populated with rows by this tracer. - fragment: &'a mut CoreTraceFragment<'a>, + /// The writer for the core trace fragment. + writer: RowMajorTraceWriter<'a, Felt>, /// The index of the next row to write in the trace fragment. row_write_index: usize, @@ -91,6 +93,13 @@ pub(crate) struct CoreTraceGenerationTracer<'a> { /// this cycle. continuation: Option, + /// Whether the node ending in this clock cycle is a body of a LOOP node. This is determined + /// by peeking at the continuation stack in [`start_clock_cycle`](Tracer::start_clock_cycle) + /// to check if the next clock-incrementing continuation is a `FinishLoop`. + /// + /// This is only relevant for END operations (Finish* continuations). + is_loop_body: bool, + /// If an error is encountered during trace generation, it is stored here. Once set, all /// subsequent `start_clock_cycle` and `finalize_clock_cycle` calls become no-ops, and the /// error is returned by [`into_parts`](Self::into_parts). @@ -99,13 +108,13 @@ pub(crate) struct CoreTraceGenerationTracer<'a> { impl<'a> CoreTraceGenerationTracer<'a> { pub fn new( - fragment: &'a mut CoreTraceFragment<'a>, + writer: RowMajorTraceWriter<'a, Felt>, decoder_state: DecoderState, block_address_replay: BlockAddressReplay, block_stack_replay: BlockStackReplay, ) -> Self { Self { - fragment, + writer, row_write_index: 0, decoder_state, block_address_replay, @@ -116,6 +125,7 @@ impl<'a> CoreTraceGenerationTracer<'a> { finish_loop_condition: None, dyn_callee_hash: None, continuation: None, + is_loop_body: false, error_encountered: None, } } @@ -288,6 +298,52 @@ impl<'a> CoreTraceGenerationTracer<'a> { None } + /// Returns the `NodeFlags` for an END operation based on the continuation type and state + /// captured in `start_clock_cycle`. + fn compute_node_flags( + &self, + continuation: &Continuation, + current_forest: &MastForest, + ) -> Result { + let is_loop_body = self.is_loop_body; + + match continuation { + Continuation::FinishLoop { was_entered, .. } => { + // The Loop node itself is ending. `loop_entered` = `was_entered`. + Ok(NodeFlags::new(is_loop_body, *was_entered, false, false)) + }, + Continuation::FinishCall(node_id) => { + let node = get_node_in_forest(current_forest, *node_id)?; + let MastNode::Call(call_node) = node else { + return Err(ExecutionError::Internal( + "expected call node in FinishCall continuation", + )); + }; + let is_syscall = call_node.is_syscall(); + let is_call = !is_syscall; + Ok(NodeFlags::new(is_loop_body, false, is_call, is_syscall)) + }, + Continuation::FinishDyn(node_id) => { + let node = get_node_in_forest(current_forest, *node_id)?; + let MastNode::Dyn(dyn_node) = node else { + return Err(ExecutionError::Internal( + "expected dyn node in FinishDyn continuation", + )); + }; + let is_call = dyn_node.is_dyncall(); + Ok(NodeFlags::new(is_loop_body, false, is_call, false)) + }, + Continuation::FinishJoin(_) + | Continuation::FinishSplit(_) + | Continuation::FinishBasicBlock(_) => { + Ok(NodeFlags::new(is_loop_body, false, false, false)) + }, + _ => { + Err(ExecutionError::Internal("compute_node_flags called for non-END continuation")) + }, + } + } + /// Returns the callee hash for a `Dyn` node, or `None` if the continuation is not a /// `StartNode` for a `Dyn` node. /// @@ -329,7 +385,7 @@ impl Tracer for CoreTraceGenerationTracer<'_> { &mut self, processor: &ReplayProcessor, continuation: Continuation, - _continuation_stack: &ContinuationStack, + continuation_stack: &ContinuationStack, current_forest: &Arc, ) { if self.error_encountered.is_some() { @@ -345,6 +401,13 @@ impl Tracer for CoreTraceGenerationTracer<'_> { self.dyn_callee_hash = self.get_dyn_callee_hash(&continuation, processor, current_forest)?; + // For END operations, determine if the ending node is a body of a LOOP by checking + // whether the next clock-incrementing continuation is a FinishLoop. + self.is_loop_body = matches!( + continuation_stack.iter_continuations_for_next_clock().last(), + Some(Continuation::FinishLoop { was_entered: true, .. }) + ); + // Store state for finalizing the clock cycle later. self.continuation = Some(continuation); @@ -384,11 +447,23 @@ impl Tracer for CoreTraceGenerationTracer<'_> { }, FinishJoin(node_id) => { let node = get_node_in_forest(current_forest, *node_id)?; - self.fill_end_trace_row(&processor.system, &processor.stack, node.digest())?; + let flags = self.compute_node_flags(continuation, current_forest)?; + self.fill_end_trace_row( + &processor.system, + &processor.stack, + node.digest(), + flags.to_hasher_state_second_word(), + )?; }, FinishSplit(node_id) => { let node = get_node_in_forest(current_forest, *node_id)?; - self.fill_end_trace_row(&processor.system, &processor.stack, node.digest())?; + let flags = self.compute_node_flags(continuation, current_forest)?; + self.fill_end_trace_row( + &processor.system, + &processor.stack, + node.digest(), + flags.to_hasher_state_second_word(), + )?; }, FinishLoop { node_id, was_entered: _ } => { let loop_condition = self.finish_loop_condition.take().ok_or( @@ -418,20 +493,34 @@ impl Tracer for CoreTraceGenerationTracer<'_> { } else { // Loop is finished, so fill in an END row. let node = get_node_in_forest(current_forest, *node_id)?; + let flags = self.compute_node_flags(continuation, current_forest)?; self.fill_end_trace_row( &processor.system, &processor.stack, node.digest(), + flags.to_hasher_state_second_word(), )?; } }, FinishCall(node_id) => { let node = get_node_in_forest(current_forest, *node_id)?; - self.fill_end_trace_row(&processor.system, &processor.stack, node.digest())?; + let flags = self.compute_node_flags(continuation, current_forest)?; + self.fill_end_trace_row( + &processor.system, + &processor.stack, + node.digest(), + flags.to_hasher_state_second_word(), + )?; }, FinishDyn(node_id) => { let node = get_node_in_forest(current_forest, *node_id)?; - self.fill_end_trace_row(&processor.system, &processor.stack, node.digest())?; + let flags = self.compute_node_flags(continuation, current_forest)?; + self.fill_end_trace_row( + &processor.system, + &processor.stack, + node.digest(), + flags.to_hasher_state_second_word(), + )?; }, ResumeBasicBlock { node_id, batch_index, op_idx_in_batch } => { let MastNode::Block(basic_block_node) = @@ -502,10 +591,12 @@ impl Tracer for CoreTraceGenerationTracer<'_> { )); }; + let flags = self.compute_node_flags(continuation, current_forest)?; self.fill_basic_block_end_trace_row( &processor.system, &processor.stack, basic_block_node, + flags.to_hasher_state_second_word(), )?; }, FinishExternal(_) @@ -545,7 +636,7 @@ fn get_node_in_forest( #[cfg(test)] mod tests { - use alloc::{vec, vec::Vec}; + use alloc::vec; use miden_core::mast::{DynNodeBuilder, MastForestContributor}; @@ -559,6 +650,7 @@ mod tests { MastForestResolutionReplay, MemoryReadsReplay, StackOverflowReplay, StackState, SystemState, }, + utils::RowMajorTraceWriter, }, }; @@ -591,9 +683,10 @@ mod tests { // Place an entry in the overflow replay queue that corresponds to a future pop (once the // stack will have grown beyond the minimum depth). - let overflow_addr_of_future_pop = Felt::new(42); + let overflow_addr_of_future_pop = Felt::new_unchecked(42); let mut stack_overflow_replay = StackOverflowReplay::new(); - stack_overflow_replay.record_pop_overflow(Felt::new(99), overflow_addr_of_future_pop); + stack_overflow_replay + .record_pop_overflow(Felt::new_unchecked(99), overflow_addr_of_future_pop); let system = SystemState { clk: 0u32.into(), @@ -611,21 +704,15 @@ mod tests { MemoryReadsReplay::default(), HasherResponseReplay::default(), MastForestResolutionReplay::default(), + crate::ExecutionOptions::DEFAULT_MAX_STACK_DEPTH, 1u32.into(), ); - // Create a minimal CoreTraceFragment — its contents are unused by the method under - // test. - let mut columns_data: Vec> = - (0..CORE_TRACE_WIDTH).map(|_| vec![ZERO; 1]).collect(); - let column_slices: Vec<&mut [Felt]> = - columns_data.iter_mut().map(|v| v.as_mut_slice()).collect(); - let mut fragment = CoreTraceFragment { - columns: column_slices.try_into().expect("CORE_TRACE_WIDTH columns"), - }; + let mut buffer = vec![ZERO; CORE_TRACE_WIDTH]; + let writer = RowMajorTraceWriter::new(&mut buffer, CORE_TRACE_WIDTH); let tracer = CoreTraceGenerationTracer::new( - &mut fragment, + writer, DecoderState { current_addr: ZERO, parent_addr: ZERO }, BlockAddressReplay::default(), BlockStackReplay::default(), diff --git a/processor/src/trace/parallel/tracer/trace_row.rs b/processor/src/trace/parallel/tracer/trace_row.rs index dc61ea12e0..d387bb8911 100644 --- a/processor/src/trace/parallel/tracer/trace_row.rs +++ b/processor/src/trace/parallel/tracer/trace_row.rs @@ -2,8 +2,8 @@ use miden_air::trace::{ CLK_COL_IDX, CTX_COL_IDX, DECODER_TRACE_OFFSET, FN_HASH_OFFSET, STACK_TRACE_OFFSET, - SYS_TRACE_WIDTH, - chiplets::hasher::HASH_CYCLE_LEN_FELT, + STACK_TRACE_WIDTH, SYS_TRACE_WIDTH, + chiplets::hasher::CONTROLLER_ROWS_PER_PERM_FELT, decoder::{ ADDR_COL_IDX, GROUP_COUNT_COL_IDX, HASHER_STATE_OFFSET, IN_SPAN_COL_IDX, NUM_OP_BATCH_FLAGS, NUM_OP_BITS, NUM_USER_OP_HELPERS, OP_BATCH_FLAGS_OFFSET, @@ -22,7 +22,9 @@ use miden_core::{ use super::{ExecutionContextInfo, StackState, SystemState, get_node_in_forest}; use crate::{ ExecutionError, - trace::parallel::{core_trace_fragment::BasicBlockContext, tracer::CoreTraceGenerationTracer}, + trace::parallel::{ + CORE_TRACE_WIDTH, core_trace_fragment::BasicBlockContext, tracer::CoreTraceGenerationTracer, + }, }; // DECODER ROW @@ -176,13 +178,13 @@ impl<'a> CoreTraceGenerationTracer<'a> { system: &SystemState, stack: &StackState, basic_block_node: &BasicBlockNode, + hasher_state_second_word: Word, ) -> Result<(), ExecutionError> { - let (ended_node_addr, flags) = - self.decoder_state.replay_node_end(&mut self.block_stack_replay)?; + let ended_node_addr = self.decoder_state.replay_node_end(&mut self.block_stack_replay)?; let decoder_row = DecoderRow::new_control_flow( opcodes::END, - (basic_block_node.digest(), flags.to_hasher_state_second_word()), + (basic_block_node.digest(), hasher_state_second_word), ended_node_addr, ); @@ -217,7 +219,7 @@ impl<'a> CoreTraceGenerationTracer<'a> { } // Update block address for the upcoming block - self.decoder_state.current_addr += HASH_CYCLE_LEN_FELT; + self.decoder_state.current_addr += CONTROLLER_ROWS_PER_PERM_FELT; // Update basic block context basic_block_context.group_count_in_block -= ONE; @@ -447,14 +449,14 @@ impl<'a> CoreTraceGenerationTracer<'a> { system: &SystemState, stack: &StackState, node_digest: Word, + hasher_state_second_word: Word, ) -> Result<(), ExecutionError> { // Pop the block from stack and use its info for END operations - let (ended_node_addr, flags) = - self.decoder_state.replay_node_end(&mut self.block_stack_replay)?; + let ended_node_addr = self.decoder_state.replay_node_end(&mut self.block_stack_replay)?; let decoder_row = DecoderRow::new_control_flow( opcodes::END, - (node_digest, flags.to_hasher_state_second_word()), + (node_digest, hasher_state_second_word), ended_node_addr, ); @@ -479,124 +481,96 @@ impl<'a> CoreTraceGenerationTracer<'a> { stack: &StackState, decoder_row: DecoderRow, ) { + let mut row = [ZERO; CORE_TRACE_WIDTH]; + // System trace columns (identical for all control flow operations) - self.populate_system_trace_columns(system, self.row_write_index); + if let Some(ref system_cols) = self.system_cols { + row[..SYS_TRACE_WIDTH].copy_from_slice(system_cols); + } // Decoder trace columns - self.populate_decoder_trace_columns(self.row_write_index, &decoder_row); + Self::write_decoder_to_row(&mut row, &decoder_row); // Stack trace columns (identical for all control flow operations) - self.populate_stack_trace_columns(stack, self.row_write_index); - - // Increment the row write index - self.row_write_index += 1; - } - - /// Populates the system trace columns - fn populate_system_trace_columns(&mut self, system: &SystemState, row_idx: usize) { - // If we have buffered system rows from the previous call, write them to the trace - if let Some(system_rows) = self.system_cols { - // Write buffered system rows to the trace at current row - for (i, &value) in system_rows.iter().enumerate() { - self.fragment.columns[i][row_idx] = value; - } + if let Some(ref stack_cols) = self.stack_cols { + row[STACK_TRACE_OFFSET..STACK_TRACE_OFFSET + STACK_TRACE_WIDTH] + .copy_from_slice(stack_cols); } - // Now populate the buffer with current system state for the next row - let mut new_system_rows = [ZERO; SYS_TRACE_WIDTH]; - - new_system_rows[CLK_COL_IDX] = (system.clk + 1).into(); - new_system_rows[CTX_COL_IDX] = system.ctx.into(); - new_system_rows[FN_HASH_OFFSET] = system.fn_hash[0]; - new_system_rows[FN_HASH_OFFSET + 1] = system.fn_hash[1]; - new_system_rows[FN_HASH_OFFSET + 2] = system.fn_hash[2]; - new_system_rows[FN_HASH_OFFSET + 3] = system.fn_hash[3]; + self.writer.write_row(self.row_write_index, &row); // Store the buffer for the next call - self.system_cols = Some(new_system_rows); + self.system_cols = Some(Self::build_system_buffer(system)); + self.stack_cols = Some(Self::build_stack_buffer(stack)); + + // Increment the row write index + self.row_write_index += 1; } - /// Populates the decoder trace columns with operation-specific data - fn populate_decoder_trace_columns(&mut self, row_idx: usize, row: &DecoderRow) { + fn write_decoder_to_row(row: &mut [Felt; CORE_TRACE_WIDTH], decoder_row: &DecoderRow) { // Block address - self.fragment.columns[DECODER_TRACE_OFFSET + ADDR_COL_IDX][row_idx] = row.addr; + row[DECODER_TRACE_OFFSET + ADDR_COL_IDX] = decoder_row.addr; // Decompose operation into bits - let opcode = row.opcode; + let opcode = decoder_row.opcode; for i in 0..NUM_OP_BITS { let bit = Felt::from_u8((opcode >> i) & 1); - self.fragment.columns[DECODER_TRACE_OFFSET + OP_BITS_OFFSET + i][row_idx] = bit; + row[DECODER_TRACE_OFFSET + OP_BITS_OFFSET + i] = bit; } // Hasher state - let (first_hash, second_hash) = row.hasher_state; - self.fragment.columns[DECODER_TRACE_OFFSET + HASHER_STATE_OFFSET][row_idx] = first_hash[0]; // hasher[0] - self.fragment.columns[DECODER_TRACE_OFFSET + HASHER_STATE_OFFSET + 1][row_idx] = - first_hash[1]; // hasher[1] - self.fragment.columns[DECODER_TRACE_OFFSET + HASHER_STATE_OFFSET + 2][row_idx] = - first_hash[2]; // hasher[2] - self.fragment.columns[DECODER_TRACE_OFFSET + HASHER_STATE_OFFSET + 3][row_idx] = - first_hash[3]; // hasher[3] - self.fragment.columns[DECODER_TRACE_OFFSET + HASHER_STATE_OFFSET + 4][row_idx] = - second_hash[0]; // hasher[4] - self.fragment.columns[DECODER_TRACE_OFFSET + HASHER_STATE_OFFSET + 5][row_idx] = - second_hash[1]; // hasher[5] - self.fragment.columns[DECODER_TRACE_OFFSET + HASHER_STATE_OFFSET + 6][row_idx] = - second_hash[2]; // hasher[6] - self.fragment.columns[DECODER_TRACE_OFFSET + HASHER_STATE_OFFSET + 7][row_idx] = - second_hash[3]; // hasher[7] + let (first_hash, second_hash) = decoder_row.hasher_state; + row[DECODER_TRACE_OFFSET + HASHER_STATE_OFFSET] = first_hash[0]; + row[DECODER_TRACE_OFFSET + HASHER_STATE_OFFSET + 1] = first_hash[1]; + row[DECODER_TRACE_OFFSET + HASHER_STATE_OFFSET + 2] = first_hash[2]; + row[DECODER_TRACE_OFFSET + HASHER_STATE_OFFSET + 3] = first_hash[3]; + row[DECODER_TRACE_OFFSET + HASHER_STATE_OFFSET + 4] = second_hash[0]; + row[DECODER_TRACE_OFFSET + HASHER_STATE_OFFSET + 5] = second_hash[1]; + row[DECODER_TRACE_OFFSET + HASHER_STATE_OFFSET + 6] = second_hash[2]; + row[DECODER_TRACE_OFFSET + HASHER_STATE_OFFSET + 7] = second_hash[3]; // Remaining decoder trace columns (identical for all control flow operations) - self.fragment.columns[DECODER_TRACE_OFFSET + OP_INDEX_COL_IDX][row_idx] = row.op_index; - self.fragment.columns[DECODER_TRACE_OFFSET + GROUP_COUNT_COL_IDX][row_idx] = - row.group_count; - self.fragment.columns[DECODER_TRACE_OFFSET + IN_SPAN_COL_IDX][row_idx] = - if row.in_basic_block { ONE } else { ZERO }; + row[DECODER_TRACE_OFFSET + OP_INDEX_COL_IDX] = decoder_row.op_index; + row[DECODER_TRACE_OFFSET + GROUP_COUNT_COL_IDX] = decoder_row.group_count; + row[DECODER_TRACE_OFFSET + IN_SPAN_COL_IDX] = + if decoder_row.in_basic_block { ONE } else { ZERO }; // Batch flag columns - all 0 for control flow operations for i in 0..NUM_OP_BATCH_FLAGS { - self.fragment.columns[DECODER_TRACE_OFFSET + OP_BATCH_FLAGS_OFFSET + i][row_idx] = - row.op_batch_flags[i]; + row[DECODER_TRACE_OFFSET + OP_BATCH_FLAGS_OFFSET + i] = decoder_row.op_batch_flags[i]; } // Extra bit columns - let bit6 = self.fragment.columns[DECODER_TRACE_OFFSET + OP_BITS_OFFSET + 6][row_idx]; - let bit5 = self.fragment.columns[DECODER_TRACE_OFFSET + OP_BITS_OFFSET + 5][row_idx]; - let bit4 = self.fragment.columns[DECODER_TRACE_OFFSET + OP_BITS_OFFSET + 4][row_idx]; - self.fragment.columns[DECODER_TRACE_OFFSET + OP_BITS_EXTRA_COLS_OFFSET][row_idx] = - bit6 * (ONE - bit5) * bit4; - self.fragment.columns[DECODER_TRACE_OFFSET + OP_BITS_EXTRA_COLS_OFFSET + 1][row_idx] = - bit6 * bit5; + let bit6 = Felt::from_u8((opcode >> 6) & 1); + let bit5 = Felt::from_u8((opcode >> 5) & 1); + let bit4 = Felt::from_u8((opcode >> 4) & 1); + row[DECODER_TRACE_OFFSET + OP_BITS_EXTRA_COLS_OFFSET] = bit6 * (ONE - bit5) * bit4; + row[DECODER_TRACE_OFFSET + OP_BITS_EXTRA_COLS_OFFSET + 1] = bit6 * bit5; } - /// Populates the stack trace columns - fn populate_stack_trace_columns(&mut self, stack: &StackState, row_idx: usize) { - use miden_air::trace::STACK_TRACE_WIDTH; - - // If we have buffered stack rows from the previous call, write them to the trace - if let Some(stack_rows) = self.stack_cols { - // Write buffered stack rows to the trace at current row - for (i, &value) in stack_rows.iter().enumerate() { - self.fragment.columns[STACK_TRACE_OFFSET + i][row_idx] = value; - } - } - - // Now populate the buffer with current stack state for the next row - let mut new_stack_rows = [ZERO; STACK_TRACE_WIDTH]; + fn build_system_buffer(system: &SystemState) -> [Felt; SYS_TRACE_WIDTH] { + let mut buf = [ZERO; SYS_TRACE_WIDTH]; + buf[CLK_COL_IDX] = (system.clk + 1).into(); + buf[CTX_COL_IDX] = system.ctx.into(); + buf[FN_HASH_OFFSET] = system.fn_hash[0]; + buf[FN_HASH_OFFSET + 1] = system.fn_hash[1]; + buf[FN_HASH_OFFSET + 2] = system.fn_hash[2]; + buf[FN_HASH_OFFSET + 3] = system.fn_hash[3]; + buf + } - // Stack top (16 elements) + fn build_stack_buffer(stack: &StackState) -> [Felt; STACK_TRACE_WIDTH] { + let mut buf = [ZERO; STACK_TRACE_WIDTH]; for i in STACK_TOP_RANGE { - new_stack_rows[STACK_TOP_OFFSET + i] = stack.get(i); + buf[STACK_TOP_OFFSET + i] = stack.get(i); } // Stack helpers (b0, b1, h0) // Note: H0 will be inverted using batch inversion later - new_stack_rows[B0_COL_IDX] = Felt::new(stack.stack_depth() as u64); // b0 - new_stack_rows[B1_COL_IDX] = stack.overflow_addr(); // b1 - new_stack_rows[H0_COL_IDX] = stack.overflow_helper(); // h0 - - // Store the buffer for the next call - self.stack_cols = Some(new_stack_rows); + buf[B0_COL_IDX] = Felt::new_unchecked(stack.stack_depth() as u64); + buf[B1_COL_IDX] = stack.overflow_addr(); + buf[H0_COL_IDX] = stack.overflow_helper(); + buf } } diff --git a/processor/src/trace/range/aux_trace.rs b/processor/src/trace/range/aux_trace.rs deleted file mode 100644 index f71245396f..0000000000 --- a/processor/src/trace/range/aux_trace.rs +++ /dev/null @@ -1,197 +0,0 @@ -use alloc::{collections::BTreeMap, vec::Vec}; -use core::mem::MaybeUninit; - -use miden_air::trace::{ - Challenges, MainTrace, RowIndex, - range::{M_COL_IDX, V_COL_IDX}, -}; - -use crate::{ - Felt, ZERO, - field::ExtensionField, - utils::{assume_init_vec, uninit_vector}, -}; - -// AUXILIARY TRACE BUILDER -// ================================================================================================ - -/// Describes how to construct the execution trace of columns related to the range checker in the -/// auxiliary segment of the trace. These are used in multiset checks. -#[derive(Debug, Clone)] -pub struct AuxTraceBuilder { - /// A list of the unique values for which range checks are performed. - lookup_values: Vec, - /// Range check lookups performed by all user operations, grouped and sorted by the clock cycle - /// at which they are requested. - cycle_lookups: BTreeMap>, - // The index of the first row of Range Checker's trace when the padded rows end and values to - // be range checked start. - values_start: usize, -} - -impl AuxTraceBuilder { - // CONSTRUCTOR - // -------------------------------------------------------------------------------------------- - pub fn new( - lookup_values: Vec, - cycle_lookups: BTreeMap>, - values_start: usize, - ) -> Self { - Self { - lookup_values, - cycle_lookups, - values_start, - } - } - - // AUX COLUMN BUILDERS - // -------------------------------------------------------------------------------------------- - - /// Builds and returns range checker auxiliary trace columns. Currently this consists of one - /// column: - /// - `b_range`: ensures that the range checks performed by the Range Checker match those - /// requested by the Stack and Memory processors. - pub fn build_aux_columns>( - &self, - main_trace: &MainTrace, - challenges: &Challenges, - ) -> Vec> { - let b_range = self.build_aux_col_b_range(main_trace, challenges); - vec![b_range] - } - - /// Builds the execution trace of the range check `b_range` column which ensure that the range - /// check lookups performed by user operations match those executed by the Range Checker. - fn build_aux_col_b_range>( - &self, - main_trace: &MainTrace, - challenges: &Challenges, - ) -> Vec { - // run batch inversion on the lookup values - let divisors = get_divisors(&self.lookup_values, challenges.alpha); - - // allocate memory for the running sum column and set the initial value to ZERO - let mut b_range: Vec> = uninit_vector(main_trace.num_rows()); - b_range[0].write(E::ZERO); - - // keep track of the last updated row in the `b_range` running sum column. `b_range` is - // filled with result values that are added to the next row after the operation's execution. - let mut b_range_idx = 0_usize; - // track the current running sum value to avoid reading from MaybeUninit - let mut current_value = E::ZERO; - - // the first half of the trace only includes values from the operations. - for (clk, range_checks) in - self.cycle_lookups.range(RowIndex::from(0)..RowIndex::from(self.values_start)) - { - let clk: usize = (*clk).into(); - - // if we skipped some cycles since the last update was processed, values in the last - // updated row should be copied over until the current cycle. - if b_range_idx < clk { - b_range[(b_range_idx + 1)..=clk].fill(MaybeUninit::new(current_value)); - } - - // move the column pointer to the next row. - b_range_idx = clk + 1; - - let mut new_value = current_value; - // include the operation lookups - for lookup in range_checks.iter() { - let value = divisors.get(lookup).expect("invalid lookup value"); - new_value -= *value; - } - b_range[b_range_idx].write(new_value); - current_value = new_value; - } - - // if we skipped some cycles since the last update was processed, values in the last - // updated row should by copied over until the current cycle. - if b_range_idx < self.values_start { - b_range[(b_range_idx + 1)..=self.values_start].fill(MaybeUninit::new(current_value)); - } - - // after the padded section of the range checker table, include the lookup value specified - // by the range checker into the running sum at each step, and remove lookups from user ops - // at any step where user ops were executed. - // - // Note: we take `num_rows - 1` because the loop writes to `b_range[row_idx + 1]`, so we - // need to stop one row early to avoid writing past the end of the array. - for (row_idx, (multiplicity, lookup)) in main_trace - .get_column(M_COL_IDX) - .iter() - .zip(main_trace.get_column(V_COL_IDX).iter()) - .enumerate() - .take(main_trace.num_rows() - 1) - .skip(self.values_start) - { - b_range_idx = row_idx + 1; - - let mut new_value = current_value; - if *multiplicity != ZERO { - // add the value in the range checker: multiplicity / (alpha + lookup) - let value = divisors - .get(&(lookup.as_canonical_u64() as u16)) - .expect("invalid lookup value"); - new_value = current_value + *value * *multiplicity; - } - - // subtract the range checks requested by operations - if let Some(range_checks) = self.cycle_lookups.get(&(row_idx as u32).into()) { - for lookup in range_checks.iter() { - let value = divisors.get(lookup).expect("invalid lookup value"); - new_value -= *value; - } - } - - b_range[b_range_idx].write(new_value); - current_value = new_value; - } - - // at this point, all range checks from user operations and the range checker should be - // matched - so, the last value must be ZERO; - assert_eq!(current_value, E::ZERO); - - if b_range_idx < b_range.len() - 1 { - b_range[(b_range_idx + 1)..].fill(MaybeUninit::new(E::ZERO)); - } - - // all elements are now initialized - unsafe { assume_init_vec(b_range) } - } -} - -/// Runs batch inversion on all range check lookup values and returns a map which maps each value -/// to the divisor used for including it in the LogUp lookup. In other words, the map contains -/// mappings of x to 1/(alpha + x). -fn get_divisors>(lookup_values: &[u16], alpha: E) -> BTreeMap { - // run batch inversion on the lookup values - let mut values: Vec> = uninit_vector(lookup_values.len()); - let mut inv_values: Vec> = uninit_vector(lookup_values.len()); - - let mut acc = E::ONE; - for (i, (value, inv_value)) in values.iter_mut().zip(inv_values.iter_mut()).enumerate() { - inv_value.write(acc); - let v = alpha + E::from_u16(lookup_values[i]); - value.write(v); - acc *= v; - } - - // all elements are now initialized - let values = unsafe { assume_init_vec(values) }; - let mut inv_values = unsafe { assume_init_vec(inv_values) }; - - // invert the accumulated product - acc = acc.inverse(); - - // multiply the accumulated product by the original values to compute the inverses, then - // build a map of inverses for the lookup values - let mut log_values = BTreeMap::new(); - for i in (0..lookup_values.len()).rev() { - inv_values[i] *= acc; - acc *= values[i]; - log_values.insert(lookup_values[i], inv_values[i]); - } - - log_values -} diff --git a/processor/src/trace/range/mod.rs b/processor/src/trace/range/mod.rs index 1e2146e1f2..bd8e68bd71 100644 --- a/processor/src/trace/range/mod.rs +++ b/processor/src/trace/range/mod.rs @@ -9,9 +9,6 @@ use crate::{ utils::{assume_init_vec, uninit_vector}, }; -mod aux_trace; -pub use aux_trace::AuxTraceBuilder; - #[cfg(test)] mod tests; @@ -20,7 +17,6 @@ mod tests; pub struct RangeCheckTrace { pub(crate) trace: [Vec; RANGE_CHECK_TRACE_WIDTH], - pub(crate) aux_builder: AuxTraceBuilder, } // RANGE CHECKER @@ -100,7 +96,7 @@ impl RangeChecker { // } self.cycle_lookups .entry(clk) - .and_modify(|entry| entry.append(&mut values.to_vec())) + .and_modify(|entry| entry.extend_from_slice(values)) .or_insert_with(|| values.to_vec()); } @@ -153,14 +149,7 @@ impl RangeChecker { let [t0, t1] = trace; let trace = unsafe { [assume_init_vec(t0), assume_init_vec(t1)] }; - RangeCheckTrace { - trace, - aux_builder: AuxTraceBuilder::new( - self.lookups.keys().cloned().collect(), - self.cycle_lookups, - num_padding_rows, - ), - } + RangeCheckTrace { trace } } // PUBLIC ACCESSORS @@ -265,7 +254,7 @@ fn write_trace_row( num_lookups: usize, value: u64, ) { - trace[0][*step].write(Felt::new(num_lookups as u64)); - trace[1][*step].write(Felt::new(value)); + trace[0][*step].write(Felt::new_unchecked(num_lookups as u64)); + trace[1][*step].write(Felt::new_unchecked(value)); *step += 1; } diff --git a/processor/src/trace/range/tests.rs b/processor/src/trace/range/tests.rs index 9395504990..36d054f236 100644 --- a/processor/src/trace/range/tests.rs +++ b/processor/src/trace/range/tests.rs @@ -19,7 +19,7 @@ fn range_checks() { checker.add_value(value.as_canonical_u64() as u16); } - let RangeCheckTrace { trace, aux_builder: _ } = checker.into_trace(64); + let RangeCheckTrace { trace } = checker.into_trace(64); validate_trace(&trace, &values); // skip the padded rows @@ -52,13 +52,16 @@ fn range_checks() { fn range_checks_rand() { let mut checker = RangeChecker::new(); let values = rand_array::(); - let values = values.into_iter().map(|v| Felt::new(v as u16 as u64)).collect::>(); + let values = values + .into_iter() + .map(|v| Felt::new_unchecked(v as u16 as u64)) + .collect::>(); for &value in values.iter() { checker.add_value(value.as_canonical_u64() as u16); } let trace_len = checker.trace_len().next_power_of_two(); - let RangeCheckTrace { trace, aux_builder: _ } = checker.into_trace(trace_len); + let RangeCheckTrace { trace } = checker.into_trace(trace_len); validate_trace(&trace, &values); } @@ -77,8 +80,8 @@ fn into_trace_with_table_panics_on_mismatched_len() { // ================================================================================================ fn validate_row(trace: &[Vec], row_idx: &mut usize, value: u64, num_lookups: u64) { - assert_eq!(trace[0][*row_idx], Felt::new(num_lookups)); - assert_eq!(trace[1][*row_idx], Felt::new(value)); + assert_eq!(trace[0][*row_idx], Felt::new_unchecked(num_lookups)); + assert_eq!(trace[1][*row_idx], Felt::new_unchecked(value)); *row_idx += 1; } diff --git a/processor/src/trace/stack/aux_trace.rs b/processor/src/trace/stack/aux_trace.rs deleted file mode 100644 index 5a21b27b18..0000000000 --- a/processor/src/trace/stack/aux_trace.rs +++ /dev/null @@ -1,117 +0,0 @@ -use alloc::vec::Vec; - -use miden_air::trace::{Challenges, MainTrace, RowIndex}; -use miden_core::{field::ExtensionField, operations::opcodes}; - -use super::Felt; -use crate::{debug::BusDebugger, trace::AuxColumnBuilder}; - -// AUXILIARY TRACE BUILDER -// ================================================================================================ - -/// Describes how to construct execution traces of stack-related auxiliary trace segment columns -/// (used in multiset checks). -#[derive(Debug, Clone)] -pub struct AuxTraceBuilder; - -impl AuxTraceBuilder { - /// Builds and returns stack auxiliary trace columns. Currently this consists of a single - /// column p1 describing states of the stack overflow table. - pub fn build_aux_columns>( - &self, - main_trace: &MainTrace, - challenges: &Challenges, - ) -> Vec> { - let p1 = self.build_aux_column(main_trace, challenges); - - debug_assert_eq!(*p1.last().unwrap(), E::ONE); - vec![p1] - } -} - -impl> AuxColumnBuilder for AuxTraceBuilder { - /// Removes a row from the stack overflow table. - fn get_requests_at( - &self, - main_trace: &MainTrace, - challenges: &Challenges, - i: RowIndex, - _debugger: &mut BusDebugger, - ) -> E { - let is_left_shift = main_trace.is_left_shift(i); - let is_dyncall = main_trace.get_op_code(i) == Felt::from_u8(opcodes::DYNCALL); - let is_non_empty_overflow = main_trace.is_non_empty_overflow(i); - - if is_left_shift && is_non_empty_overflow { - let b1 = main_trace.parent_overflow_address(i); - let s15_prime = main_trace.stack_element(15, i + 1); - let b1_prime = main_trace.parent_overflow_address(i + 1); - - OverflowTableRow::new(b1, s15_prime, b1_prime).to_value(challenges) - } else if is_dyncall && is_non_empty_overflow { - let b1 = main_trace.parent_overflow_address(i); - let s15_prime = main_trace.stack_element(15, i + 1); - let b1_prime = main_trace.decoder_hasher_state_element(5, i); - - OverflowTableRow::new(b1, s15_prime, b1_prime).to_value(challenges) - } else { - E::ONE - } - } - - /// Adds a row to the stack overflow table. - fn get_responses_at( - &self, - main_trace: &MainTrace, - challenges: &Challenges, - i: RowIndex, - _debugger: &mut BusDebugger, - ) -> E { - let is_right_shift = main_trace.is_right_shift(i); - - if is_right_shift { - let k0 = main_trace.clk(i); - let s15 = main_trace.stack_element(15, i); - let b1 = main_trace.parent_overflow_address(i); - - let row = OverflowTableRow::new(k0, s15, b1); - row.to_value(challenges) - } else { - E::ONE - } - } - - #[cfg(any(test, feature = "bus-debugger"))] - fn enforce_bus_balance(&self) -> bool { - true - } -} - -// OVERFLOW STACK ROW -// ================================================================================================ - -/// A single row in the stack overflow table. Each row contains the following values: -/// - The value of the stack item pushed into the overflow stack. -/// - The clock cycle at which the stack item was pushed into the overflow stack. -/// - The clock cycle of the value which was at the top of the overflow stack when this value was -/// pushed onto it. -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct OverflowTableRow { - val: Felt, - clk: Felt, - prev: Felt, -} - -impl OverflowTableRow { - pub fn new(clk: Felt, val: Felt, prev: Felt) -> Self { - Self { val, clk, prev } - } -} - -impl OverflowTableRow { - /// Reduces this row to a single field element in the field specified by E. This requires - /// at least 4 alpha values. - pub fn to_value>(&self, challenges: &Challenges) -> E { - challenges.encode([self.clk, self.val, self.prev]) - } -} diff --git a/processor/src/trace/stack/mod.rs b/processor/src/trace/stack/mod.rs index ef76a243d7..87ce4a96a4 100644 --- a/processor/src/trace/stack/mod.rs +++ b/processor/src/trace/stack/mod.rs @@ -2,8 +2,3 @@ use super::{Felt, ZERO}; mod overflow; pub(crate) use overflow::OverflowTable; - -mod aux_trace; -pub use aux_trace::AuxTraceBuilder; -#[cfg(test)] -pub(crate) use aux_trace::OverflowTableRow; diff --git a/processor/src/trace/stack/overflow.rs b/processor/src/trace/stack/overflow.rs index 7775753afd..4b9302604e 100644 --- a/processor/src/trace/stack/overflow.rs +++ b/processor/src/trace/stack/overflow.rs @@ -110,6 +110,25 @@ impl OverflowTable { .map_or(ZERO, |entry| Felt::from(entry.clk)) } + /// Returns the clock cycle that would become the new `last_update_clk_in_current_ctx` after + /// one pop from the current overflow stack, *without* actually mutating the table. + /// + /// Concretely this is the clock of the **second-to-last** entry in the current overflow stack, + /// or `ZERO` if the stack has fewer than two entries (i.e. the stack would be empty after the + /// pop). + /// + /// Used by `ExecutionTracer` to compute `parent_next_overflow_addr` for `DYNCALL` before + /// the actual pop has occurred (fixes #2813 / addresses huitseeker's review on PR #2904). + pub fn clk_after_pop_in_current_ctx(&self) -> Felt { + let stack = self.get_current_overflow_stack(); + let entries = stack.overflow.as_slice(); + if entries.len() < 2 { + ZERO + } else { + Felt::from(entries[entries.len() - 2].clk) + } + } + /// Returns the number of elements in the overflow stack for the current context. pub fn num_elements_in_current_ctx(&self) -> usize { self.get_current_overflow_stack().num_elements() diff --git a/processor/src/trace/tests/chiplets/bitwise.rs b/processor/src/trace/tests/chiplets/bitwise.rs index 5ed3ec7996..ec87f4b769 100644 --- a/processor/src/trace/tests/chiplets/bitwise.rs +++ b/processor/src/trace/tests/chiplets/bitwise.rs @@ -1,217 +1,135 @@ -use miden_air::trace::{ - Challenges, RowIndex, - chiplets::{ - BITWISE_A_COL_IDX, BITWISE_B_COL_IDX, BITWISE_OUTPUT_COL_IDX, BITWISE_TRACE_OFFSET, - bitwise::{BITWISE_AND, BITWISE_AND_LABEL, BITWISE_XOR, BITWISE_XOR_LABEL, OP_CYCLE_LEN}, - }, +//! Bitwise chiplet bus test. +//! +//! Runs a program with `U32and` + `U32xor` operations and verifies that every bitwise request +//! row emits the expected `BitwiseMsg` on the chiplet-requests side AND that every bitwise +//! chiplet cycle-end row emits the matching response on the chiplet-responses side. +//! +//! Column-blind by design: the subset matcher in `lookup_harness` compares `(mult, denom)` +//! pairs regardless of which aux column the framework routes them onto. + +use alloc::vec::Vec; + +use miden_air::{logup::BitwiseMsg, trace::chiplets::BITWISE_SELECTOR_COL_IDX}; +use miden_core::{ + Felt, + operations::{Operation, opcodes}, }; -use miden_core::field::Field; -use super::{ - AUX_TRACE_RAND_CHALLENGES, CHIPLETS_BUS_AUX_TRACE_OFFSET, ExecutionTrace, Felt, HASH_CYCLE_LEN, - LAST_CYCLE_ROW, ONE, Operation, build_trace_from_ops, rand_array, rand_value, +use super::super::{ + build_trace_from_ops, + lookup_harness::{Expectations, InteractionLog}, }; +use crate::RowIndex; + +/// Period of the bitwise chiplet cycle. The response fires on the last row of each cycle. +const BITWISE_CYCLE_LEN: usize = 8; -/// Tests the generation of the `b_chip` bus column when only bitwise lookups are included. It -/// ensures that trace generation is correct when all of the following are true. -/// -/// - All possible bitwise operations are called by the stack. -/// - Some requests from the Stack and responses from the Bitwise chiplet occur at the same cycle. -/// -/// Note: Communication with the Hash chiplet is also required, due to the span block decoding, but -/// for this test we set those values explicitly, enforcing only that the same initial and final -/// values are requested & provided. #[test] -#[expect(clippy::needless_range_loop)] -fn b_chip_trace_bitwise() { - let a = rand_value::(); - let b = rand_value::(); - let stack = [a as u64, b as u64]; - let operations = vec![ - Operation::U32and, - Operation::Push(Felt::from_u32(a)), - Operation::Push(Felt::from_u32(b)), +fn bitwise_chiplet_bus_emits_per_request_row() { + // Two distinct operand pairs for the two AND requests so per-row denominators differ: + // a copy-paste bug attaching an expectation to the wrong row can't pass the subset check. + let a1: u32 = 0x1111_2222; + let b1: u32 = 0x3333_4444; + let a2: u32 = 0x5555_6666; + let b2: u32 = 0x7777_8888; + let a3: u32 = 0xdead_beef; + let b3: u32 = 0x1234_5678; + + // `Drop` between ops isn't strictly required under subset semantics (extra pushes are + // ignored), but it keeps the stack overflow table from growing and matches sibling tests. + let ops = vec![ + Operation::Push(Felt::from_u32(a1)), + Operation::Push(Felt::from_u32(b1)), Operation::U32and, - // Add 8 padding operations so that U32xor is requested by the stack in the same cycle when - // U32and is provided by the Bitwise chiplet. - Operation::Pad, - Operation::Pad, - Operation::Pad, - Operation::Pad, - Operation::Drop, - Operation::Drop, Operation::Drop, + Operation::Push(Felt::from_u32(a2)), + Operation::Push(Felt::from_u32(b2)), + Operation::U32and, Operation::Drop, - Operation::Push(Felt::from_u32(a)), - Operation::Push(Felt::from_u32(b)), + Operation::Push(Felt::from_u32(a3)), + Operation::Push(Felt::from_u32(b3)), Operation::U32xor, - // Drop 4 values to empty the stack's overflow table. - Operation::Drop, - Operation::Drop, - Operation::Drop, Operation::Drop, ]; - let trace = build_trace_from_ops(operations, &stack); - - let challenges = rand_array::(); - let aux_columns = trace.build_aux_trace(&challenges).unwrap(); - let b_chip = aux_columns.get_column(CHIPLETS_BUS_AUX_TRACE_OFFSET); - let challenges = Challenges::::new(challenges[0], challenges[1]); - - assert_eq!(trace.length(), b_chip.len()); - assert_eq!(ONE, b_chip[0]); - - // At cycle 0 the span hash initialization is requested from the decoder and provided by the - // hash chiplet, so the trace should still equal one. - assert_eq!(ONE, b_chip[1]); - - // The first bitwise request from the stack is sent when the `U32and` operation is executed at - // cycle 1, so the request is included in the next row. (The trace begins by executing `span`). - let value = build_expected_bitwise( - &challenges, - BITWISE_AND_LABEL, - Felt::from_u32(a), - Felt::from_u32(b), - Felt::from_u32(a & b), - ); - let mut expected = value.inverse(); - assert_eq!(expected, b_chip[2]); - - // Nothing changes during user operations with no requests to the Chiplets. - for row in 3..5 { - assert_eq!(expected, b_chip[row]); + let trace = build_trace_from_ops(ops, &[]); + let log = InteractionLog::new(&trace); + let main = trace.main_trace(); + + let mut exp = Expectations::new(&log); + + // ---- Request side: decoder emits a `-1` push of `BitwiseMsg` at each U32AND/U32XOR row. + // + // Operands are hardcoded (not read back from the trace) so a bug that swaps `s0`/`s1` in + // the request emitter would produce a message with the `a`/`b` fields flipped and fail + // the subset check. The stack pushes `a` then `b`, so `b` ends up on top (`s0`) and `a` + // sits at slot 1 (`s1`); `BitwiseMsg::and(s0, s1, c)` = `BitwiseMsg::and(b, a, a & b)`. + let and_expected = [(a1, b1, a1 & b1), (a2, b2, a2 & b2)]; + let xor_expected = [(a3, b3, a3 ^ b3)]; + + let mut and_rows: Vec = Vec::new(); + let mut xor_rows: Vec = Vec::new(); + for row in 0..main.num_rows() { + let idx = RowIndex::from(row); + let op = main.get_op_code(idx).as_canonical_u64(); + if op == opcodes::U32AND as u64 { + and_rows.push(idx); + } else if op == opcodes::U32XOR as u64 { + xor_rows.push(idx); + } } - - // The second bitwise request from the stack is sent when the `U32and` operation is executed at - // cycle 4, so the request is included in the next row. - // After Push(a) then Push(b), stack is [b, a, ...] so operands are (s0=b, s1=a). - let value = build_expected_bitwise( - &challenges, - BITWISE_AND_LABEL, - Felt::from_u32(b), - Felt::from_u32(a), - Felt::from_u32(a & b), + assert_eq!( + and_rows.len(), + and_expected.len(), + "request cardinality guardrail: expected {} U32AND rows, found {}", + and_expected.len(), + and_rows.len(), ); - expected *= value.inverse(); - assert_eq!(expected, b_chip[5]); - - // Nothing changes during user operations with no requests to the Chiplets. - for row in 6..16 { - assert_eq!(expected, b_chip[row]); - } - - // The third bitwise request from the stack is sent when the `U32xor` operation is executed at - // cycle 15, so the request is included in the next row. - // After Push(a) then Push(b), stack is [b, a, ...] so operands are (s0=b, s1=a). - let value = build_expected_bitwise( - &challenges, - BITWISE_XOR_LABEL, - Felt::from_u32(b), - Felt::from_u32(a), - Felt::from_u32(a ^ b), + assert_eq!( + xor_rows.len(), + xor_expected.len(), + "request cardinality guardrail: expected {} U32XOR rows, found {}", + xor_expected.len(), + xor_rows.len(), ); - expected *= value.inverse(); - assert_eq!(expected, b_chip[16]); - - // Nothing changes until the decoder requests the result of the `SPAN` hash at cycle 21. - for row in 17..22 { - assert_eq!(expected, b_chip[row]); - } - - // At cycle 21 the decoder requests the span hash. Since this test focuses on bitwise lookups, - // we treat the hasher bus messages as a black box and extract their multiplicands directly from - // the bus column. - assert_ne!(expected, b_chip[22]); - let span_request_mult = b_chip[22] * b_chip[21].inverse(); - expected *= span_request_mult; - assert_eq!(expected, b_chip[22]); - - // Nothing changes until the hasher provides the result of the `SPAN` hash at the end of the - // hasher cycle. - for row in 23..HASH_CYCLE_LEN { - assert_eq!(expected, b_chip[row]); - } - - // At the end of the hasher cycle, the hasher provides the `SPAN` hash. Its multiplicand should - // cancel out the earlier request. - assert_ne!(expected, b_chip[HASH_CYCLE_LEN]); - let span_response_mult = b_chip[HASH_CYCLE_LEN] * b_chip[LAST_CYCLE_ROW].inverse(); - assert_eq!(span_request_mult * span_response_mult, ONE); - expected *= span_response_mult; - assert_eq!(expected, b_chip[HASH_CYCLE_LEN]); - // Bitwise responses will be provided during the bitwise segment of the Chiplets trace, which - // starts after the hash for the span block. Responses are provided at the last row of the - // Bitwise chiplet's operation cycle. - let response_1_row = HASH_CYCLE_LEN + OP_CYCLE_LEN; - let response_2_row = response_1_row + OP_CYCLE_LEN; - let response_3_row = response_2_row + OP_CYCLE_LEN; - - // Nothing changes until the Bitwise chiplet responds. - for row in (HASH_CYCLE_LEN + 1)..response_1_row { - assert_eq!(expected, b_chip[row]); + for (&row, &(a, b, c)) in and_rows.iter().zip(and_expected.iter()) { + let msg = BitwiseMsg::and(Felt::from_u32(b), Felt::from_u32(a), Felt::from_u32(c)); + exp.remove(usize::from(row), &msg); } - - // At the end of the first bitwise cycle, the response for `U32and` is provided by the Bitwise - // chiplet. - expected *= build_expected_bitwise_from_trace(&trace, &challenges, (response_1_row - 1).into()); - assert_eq!(expected, b_chip[response_1_row]); - - // At the end of the next bitwise cycle, the response for `U32and` is provided by the Bitwise - // chiplet. - for row in (response_1_row + 1)..response_2_row { - assert_eq!(expected, b_chip[row]); + for (&row, &(a, b, c)) in xor_rows.iter().zip(xor_expected.iter()) { + let msg = BitwiseMsg::xor(Felt::from_u32(b), Felt::from_u32(a), Felt::from_u32(c)); + exp.remove(usize::from(row), &msg); } - expected *= build_expected_bitwise_from_trace(&trace, &challenges, (response_2_row - 1).into()); - assert_eq!(expected, b_chip[response_2_row]); - // Nothing changes until the next time the Bitwise chiplet responds. - for row in (response_2_row + 1)..response_3_row { - assert_eq!(expected, b_chip[row]); + // ---- Response side: each bitwise-chiplet cycle-end row emits `+1 × BitwiseMsg`. + // + // Cycle-end = `row % BITWISE_CYCLE_LEN == BITWISE_CYCLE_LEN - 1` (the periodic `k_transition` + // column is `0` on the last row of every 8-row cycle, starting from trace row 0). The bitwise + // chiplet segment starts at a multiple of `HASH_CYCLE_LEN = 16`, which is a multiple of 8, + // so this alignment condition holds across the whole trace. + let mut response_rows_seen = 0usize; + for row in 0..main.num_rows() { + let idx = RowIndex::from(row); + if !main.is_bitwise_row(idx) { + continue; + } + if row % BITWISE_CYCLE_LEN != BITWISE_CYCLE_LEN - 1 { + continue; + } + response_rows_seen += 1; + + let op = main.get(idx, BITWISE_SELECTOR_COL_IDX); + let a = main.chiplet_bitwise_a(idx); + let b = main.chiplet_bitwise_b(idx); + let z = main.chiplet_bitwise_z(idx); + exp.add(row, &BitwiseMsg { op, a, b, result: z }); } + let expected_responses = and_expected.len() + xor_expected.len(); + assert_eq!( + response_rows_seen, expected_responses, + "response cardinality guardrail: expected {expected_responses} cycle-end bitwise rows, \ + found {response_rows_seen}", + ); - // At the end of the next bitwise cycle, the response for `U32and` is provided by the Bitwise - // chiplet. - expected *= build_expected_bitwise_from_trace(&trace, &challenges, (response_3_row - 1).into()); - assert_eq!(expected, b_chip[response_3_row]); - - // The value in b_chip should be ONE now and for the rest of the trace. - for row in response_3_row..trace.length() { - assert_eq!(ONE, b_chip[row]); - } -} - -// TEST HELPERS -// ================================================================================================ - -fn build_expected_bitwise( - challenges: &Challenges, - label: Felt, - s0: Felt, - s1: Felt, - result: Felt, -) -> Felt { - challenges.encode([label, s0, s1, result]) -} - -fn build_expected_bitwise_from_trace( - trace: &ExecutionTrace, - challenges: &Challenges, - row: RowIndex, -) -> Felt { - let selector = trace.main_trace.get_column(BITWISE_TRACE_OFFSET)[row]; - - let op_id = if selector == BITWISE_AND { - BITWISE_AND_LABEL - } else if selector == BITWISE_XOR { - BITWISE_XOR_LABEL - } else { - panic!("Execution trace contains an invalid bitwise operation.") - }; - - let a = trace.main_trace.get_column(BITWISE_A_COL_IDX)[row]; - let b = trace.main_trace.get_column(BITWISE_B_COL_IDX)[row]; - let output = trace.main_trace.get_column(BITWISE_OUTPUT_COL_IDX)[row]; - - build_expected_bitwise(challenges, op_id, a, b, output) + log.assert_contains(&exp); } diff --git a/processor/src/trace/tests/chiplets/hasher.rs b/processor/src/trace/tests/chiplets/hasher.rs index fd9205f1db..cf94bf005c 100644 --- a/processor/src/trace/tests/chiplets/hasher.rs +++ b/processor/src/trace/tests/chiplets/hasher.rs @@ -1,615 +1,409 @@ +//! Hasher-chiplet bus tests. +//! +//! For each of the main hasher scenarios (SPAN/END control block, RESPAN, SPLIT merge, HPERM, +//! LOGPRECOMPILE, MPVERIFY, MRUPDATE) the test registers the decoder-side `remove` requests and +//! the chiplet-side `add` responses it expects to see, then lets +//! [`InteractionLog::assert_contains`] confirm every one of them fires somewhere in the trace. +//! +//! Because request and response messages share a `bus_prefix` and the same payload shape, +//! an add at a controller row and a remove at the matching decoder row produce the same +//! encoded denominator with opposite multiplicities — which is what makes the bus balance. +//! The subset matcher verifies each claimed interaction lands; their pairing is an algebraic +//! consequence. +//! +//! Each test pairs the `assert_contains` call with explicit request/response-count guardrails +//! so a silent-pass bug (e.g. the subset matcher ignoring a whole category of expectations +//! because nothing was registered) is caught structurally, not just by shape. + use alloc::vec::Vec; -use core::ops::Range; - -use miden_air::trace::{ - CLK_COL_IDX, Challenges, DECODER_TRACE_OFFSET, RowIndex, - chiplets::{ - HASHER_NODE_INDEX_COL_IDX, HASHER_STATE_COL_RANGE, HASHER_TRACE_OFFSET, - hasher::{ - CAPACITY_DOMAIN_IDX, DIGEST_RANGE, HASH_CYCLE_LEN, HasherState, LAST_CYCLE_ROW, - LINEAR_HASH, LINEAR_HASH_LABEL, MP_VERIFY, MP_VERIFY_LABEL, MR_UPDATE_NEW, - MR_UPDATE_NEW_LABEL, MR_UPDATE_OLD, MR_UPDATE_OLD_LABEL, RATE_LEN, RETURN_HASH, - RETURN_HASH_LABEL, RETURN_STATE, RETURN_STATE_LABEL, STATE_WIDTH, Selectors, + +use miden_air::{ + logup::{HasherMsg, SiblingBit, SiblingMsg}, + trace::{ + MainTrace, + chiplets::hasher::CONTROLLER_ROWS_PER_PERM_FELT, + log_precompile::{ + HELPER_ADDR_IDX, HELPER_CAP_PREV_RANGE, STACK_CAP_NEXT_RANGE, STACK_COMM_RANGE, + STACK_R0_RANGE, STACK_R1_RANGE, STACK_TAG_RANGE, }, }, - decoder::{NUM_OP_BITS, OP_BITS_OFFSET}, }; use miden_core::{ - Word, - chiplets::hasher::apply_permutation, + Felt, ONE, Word, ZERO, crypto::merkle::{MerkleStore, MerkleTree, NodeIndex}, - field::Field, mast::{BasicBlockNodeBuilder, MastForest, MastForestContributor, SplitNodeBuilder}, - operations::opcodes, + operations::{Operation, opcodes}, program::Program, - utils::range, }; use miden_utils_testing::stack; +use rstest::rstest; -use super::{ - AUX_TRACE_RAND_CHALLENGES, AdviceInputs, CHIPLETS_BUS_AUX_TRACE_OFFSET, ExecutionTrace, Felt, - ONE, Operation, ZERO, build_span_with_respan_ops, build_trace_from_ops_with_inputs, - build_trace_from_program, init_state_from_words, rand_array, +use super::super::{ + build_trace_from_ops_with_inputs, build_trace_from_program, + lookup_harness::{Expectations, InteractionLog}, }; -use crate::StackInputs; +use crate::{AdviceInputs, RowIndex, StackInputs, trace::utils::build_span_with_respan_ops}; -// CONSTANTS +// RESPONSE-SIDE DISPATCH // ================================================================================================ -const DECODER_HASHER_STATE_RANGE: Range = range( - DECODER_TRACE_OFFSET + miden_air::trace::decoder::HASHER_STATE_OFFSET, - miden_air::trace::decoder::NUM_HASHER_COLUMNS, -); +/// Hasher controller response kinds, keyed on the emitter's `(hs0, hs1, hs2, is_boundary)` mux. +/// +/// Shared across every test so each can `match` on the semantic kind instead of re-deriving +/// the selector combinations (`ctrl · hs0 · not_hs1 · not_hs2 · is_boundary`, etc.) by hand. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum HasherResponseKind { + SpongeStart, + SpongeRespan, + MpInput, + MvOldInput, + MuNewInput, + Hout, + Sout, +} -/// Location of operation bits columns relative to the main trace. -pub const DECODER_OP_BITS_RANGE: Range = - range(DECODER_TRACE_OFFSET + OP_BITS_OFFSET, NUM_OP_BITS); +/// Walk every hasher controller row in `main` and yield a [`HasherResponseKind`] for each row +/// that matches one of the 7 emitter patterns (see `chiplet_responses.rs::emit_chiplet_responses` +/// and `docs/src/design/chiplets/hasher.md`). +/// +/// Controller rows where no response fires (e.g. Merkle tree continuation rows where +/// `is_boundary = 0`) are skipped. +fn hasher_response_rows( + main: &MainTrace, +) -> impl Iterator + '_ { + (0..main.num_rows()).filter_map(move |row| { + let idx = RowIndex::from(row); + if !is_hasher_controller_row(main, idx) { + return None; + } + let hs0 = as_bit(main.chiplet_selector_1(idx))?; + let hs1 = as_bit(main.chiplet_selector_2(idx))?; + let hs2 = as_bit(main.chiplet_selector_3(idx))?; + let is_boundary = as_bit(main.chiplet_is_boundary(idx))?; + // Selector table — see `docs/src/design/chiplets/hasher.md`. + let kind = match (hs0, hs1, hs2, is_boundary) { + (true, false, false, true) => HasherResponseKind::SpongeStart, + (true, false, false, false) => HasherResponseKind::SpongeRespan, + (true, false, true, true) => HasherResponseKind::MpInput, + (true, true, false, true) => HasherResponseKind::MvOldInput, + (true, true, true, true) => HasherResponseKind::MuNewInput, + (false, false, false, _) => HasherResponseKind::Hout, + (false, false, true, true) => HasherResponseKind::Sout, + _ => return None, + }; + Some((idx, kind)) + }) +} // TESTS // ================================================================================================ -/// Tests the generation of the `b_chip` bus column when the hasher only performs a single `SPAN` -/// with one operation batch. #[test] -#[expect(clippy::needless_range_loop)] -pub fn b_chip_span() { - let program = { - let mut mast_forest = MastForest::new(); - - let basic_block_id = - BasicBlockNodeBuilder::new(vec![Operation::Add, Operation::Mul], Vec::new()) - .add_to_forest(&mut mast_forest) - .unwrap(); - mast_forest.make_root(basic_block_id); - - Program::new(mast_forest.into(), basic_block_id) - }; +fn span_end_hasher_bus() { + let program = single_block_program(vec![Operation::Add, Operation::Mul]); let trace = build_trace_from_program(&program, &[]); - - let challenges = rand_array::(); - let aux_columns = trace.build_aux_trace(&challenges).unwrap(); - let b_chip = aux_columns.get_column(CHIPLETS_BUS_AUX_TRACE_OFFSET); - - let challenges = Challenges::::new(challenges[0], challenges[1]); - - assert_eq!(trace.length(), b_chip.len()); - assert_eq!(ONE, b_chip[0]); - - // at the first cycle the following are added for inclusion in the next row: - // - the initialization of the span hash is requested by the decoder - // - the initialization of the span hash is provided by the hasher - - // initialize the request state. - let mut state = [ZERO; STATE_WIDTH]; - fill_state_from_decoder_with_domain(&trace, &mut state, 0.into()); - // request the initialization of the span hash - let request_init = - build_expected(&challenges, LINEAR_HASH_LABEL, state, [ZERO; STATE_WIDTH], ONE, ZERO); - let mut expected = request_init.inverse(); - - // provide the initialization of the span hash - expected *= build_expected_from_trace(&trace, &challenges, 0.into()); - assert_eq!(expected, b_chip[1]); - - // Nothing changes when there is no communication with the hash chiplet. - for row in 2..4 { - assert_eq!(expected, b_chip[row]); + let log = InteractionLog::new(&trace); + let main = trace.main_trace(); + + let mut exp = Expectations::new(&log); + let mut request_count = 0usize; + + for row in 0..main.num_rows() { + let idx = RowIndex::from(row); + let op = main.get_op_code(idx).as_canonical_u64(); + + if op == opcodes::SPAN as u64 { + let addr_next = main.addr(RowIndex::from(row + 1)); + let rate = rate_from_hasher_state(main, idx); + exp.remove(row, &HasherMsg::control_block(addr_next, &rate, 0)); + request_count += 1; + } else if op == opcodes::END as u64 { + let parent = main.addr(idx) + CONTROLLER_ROWS_PER_PERM_FELT - ONE; + let h = rate_from_hasher_state(main, idx); + let digest: [Felt; 4] = [h[0], h[1], h[2], h[3]]; + exp.remove(row, &HasherMsg::return_hash(parent, digest)); + request_count += 1; + } } - // At cycle 3 the decoder requests the result of the span hash. - apply_permutation(&mut state); - let request_result = build_expected( - &challenges, - RETURN_HASH_LABEL, - state, - [ZERO; STATE_WIDTH], - Felt::new(HASH_CYCLE_LEN as u64), - ZERO, - ); - expected *= request_result.inverse(); - assert_eq!(expected, b_chip[4]); - - // Nothing changes when there is no communication with the hash chiplet. - for row in 5..HASH_CYCLE_LEN { - assert_eq!(expected, b_chip[row]); + let mut response_count = 0usize; + for (idx, kind) in hasher_response_rows(main) { + let addr = main.clk(idx) + ONE; + let state = main.chiplet_hasher_state(idx); + match kind { + HasherResponseKind::SpongeStart => { + exp.add(usize::from(idx), &HasherMsg::linear_hash_init(addr, state)); + response_count += 1; + }, + HasherResponseKind::Hout => { + let digest: [Felt; 4] = [state[0], state[1], state[2], state[3]]; + exp.add(usize::from(idx), &HasherMsg::return_hash(addr, digest)); + response_count += 1; + }, + _ => {}, + } } - // At the end of the hash cycle, the result of the span hash is provided by the hasher - expected *= build_expected_from_trace(&trace, &challenges, LAST_CYCLE_ROW.into()); - assert_eq!(expected, b_chip[HASH_CYCLE_LEN]); - - // The value in b_chip should be ONE now and for the rest of the trace. - for row in HASH_CYCLE_LEN..trace.length() { - assert_eq!(ONE, b_chip[row]); - } + assert_eq!(request_count, 2, "SPAN+END: expected 2 removes (SPAN + END)"); + assert_eq!(response_count, 2, "SPAN+END: expected 2 adds (sponge_start + HOUT)"); + log.assert_contains(&exp); } -/// Tests the generation of the `b_chip` bus column when the hasher only performs a `SPAN` but it -/// includes multiple batches. #[test] -#[expect(clippy::needless_range_loop)] -pub fn b_chip_span_with_respan() { - let program = { - let mut mast_forest = MastForest::new(); - - let (ops, _) = build_span_with_respan_ops(); - let basic_block_id = BasicBlockNodeBuilder::new(ops, Vec::new()) - .add_to_forest(&mut mast_forest) - .unwrap(); - mast_forest.make_root(basic_block_id); +fn respan_hasher_bus() { + let (ops, _iv) = build_span_with_respan_ops(); + let program = single_block_program(ops); - Program::new(mast_forest.into(), basic_block_id) - }; let trace = build_trace_from_program(&program, &[]); + let log = InteractionLog::new(&trace); + let main = trace.main_trace(); - let challenges = rand_array::(); - let aux_columns = trace.build_aux_trace(&challenges).unwrap(); - let b_chip = aux_columns.get_column(CHIPLETS_BUS_AUX_TRACE_OFFSET); - - let challenges = Challenges::::new(challenges[0], challenges[1]); - - assert_eq!(trace.length(), b_chip.len()); - assert_eq!(ONE, b_chip[0]); + let mut exp = Expectations::new(&log); + let mut respan_request_count = 0usize; - // at cycle 0 the following are added for inclusion in the next row: - // - the initialization of the span hash is requested by the decoder - // - the initialization of the span hash is provided by the hasher - - // initialize the request state. - let mut state = [ZERO; STATE_WIDTH]; - fill_state_from_decoder_with_domain(&trace, &mut state, 0.into()); - // request the initialization of the span hash - let request_init = - build_expected(&challenges, LINEAR_HASH_LABEL, state, [ZERO; STATE_WIDTH], ONE, ZERO); - let mut expected = request_init.inverse(); - - // provide the initialization of the span hash - expected *= build_expected_from_trace(&trace, &challenges, 0.into()); - assert_eq!(expected, b_chip[1]); - - // Nothing changes when there is no communication with the hash chiplet. - for row in 2..10 { - assert_eq!(expected, b_chip[row]); + for row in 0..main.num_rows() { + let idx = RowIndex::from(row); + let op = main.get_op_code(idx).as_canonical_u64(); + if op != opcodes::RESPAN as u64 { + continue; + } + let addr_next = main.addr(RowIndex::from(row + 1)); + let rate = rate_from_hasher_state(main, idx); + exp.remove(row, &HasherMsg::absorption(addr_next, rate)); + respan_request_count += 1; } - // At cycle 9, after the first operation batch, the decoder initiates a respan and requests the - // absorption of the next operation batch. - apply_permutation(&mut state); - let prev_state = state; - // get the state with the next absorbed batch. - fill_state_from_decoder(&trace, &mut state, 9.into()); - - let request_respan = build_expected( - &challenges, - LINEAR_HASH_LABEL, - prev_state, - state, - Felt::new(HASH_CYCLE_LEN as u64), - ZERO, - ); - expected *= request_respan.inverse(); - assert_eq!(expected, b_chip[10]); - - // Nothing changes when there is no communication with the hash chiplet. - for row in 11..22 { - assert_eq!(expected, b_chip[row]); + let mut sponge_respan_count = 0usize; + for (idx, kind) in hasher_response_rows(main) { + if kind != HasherResponseKind::SpongeRespan { + continue; + } + let addr = main.clk(idx) + ONE; + let state = main.chiplet_hasher_state(idx); + let rate: [Felt; 8] = + [state[0], state[1], state[2], state[3], state[4], state[5], state[6], state[7]]; + exp.add(usize::from(idx), &HasherMsg::absorption(addr, rate)); + sponge_respan_count += 1; } - // At cycle 21, after the second operation batch, the decoder ends the SPAN block and requests - // its hash. - apply_permutation(&mut state); - let request_result = build_expected( - &challenges, - RETURN_HASH_LABEL, - state, - [ZERO; STATE_WIDTH], - Felt::new((2 * HASH_CYCLE_LEN) as u64), - ZERO, + assert!(respan_request_count > 0, "multi-batch span should emit at least one RESPAN"); + assert_eq!( + respan_request_count, sponge_respan_count, + "each RESPAN request must be paired with a sponge_respan response", ); - expected *= request_result.inverse(); - assert_eq!(expected, b_chip[22]); - - // Nothing changes when there is no communication with the hash chiplet. - for row in 23..HASH_CYCLE_LEN { - assert_eq!(expected, b_chip[row]); - } - - // At the end of the first hash cycle, the absorption of the next operation batch is provided - // by the hasher. - expected *= build_expected_from_trace(&trace, &challenges, LAST_CYCLE_ROW.into()); - assert_eq!(expected, b_chip[HASH_CYCLE_LEN]); - - // Nothing changes when there is no communication with the hash chiplet. - for row in (HASH_CYCLE_LEN + 1)..(2 * HASH_CYCLE_LEN) { - assert_eq!(expected, b_chip[row]); - } - - // At the end of the second hash cycle, the result of the span hash is provided by the hasher. - expected *= - build_expected_from_trace(&trace, &challenges, (HASH_CYCLE_LEN + LAST_CYCLE_ROW).into()); - assert_eq!(expected, b_chip[2 * HASH_CYCLE_LEN]); - - // The value in b_chip should be ONE now and for the rest of the trace. - for row in (2 * HASH_CYCLE_LEN)..trace.length() { - assert_eq!(ONE, b_chip[row]); - } + log.assert_contains(&exp); } -/// Tests the generation of the `b_chip` bus column when the hasher performs a merge of two code -/// blocks requested by the decoder. (This also requires a `SPAN` block.) #[test] -#[expect(clippy::needless_range_loop)] -pub fn b_chip_merge() { +fn merge_hasher_bus() { let program = { let mut mast_forest = MastForest::new(); - - let t_branch_id = BasicBlockNodeBuilder::new(vec![Operation::Add], Vec::new()) + let t_branch = BasicBlockNodeBuilder::new(vec![Operation::Add], Vec::new()) .add_to_forest(&mut mast_forest) .unwrap(); - let f_branch_id = BasicBlockNodeBuilder::new(vec![Operation::Mul], Vec::new()) + let f_branch = BasicBlockNodeBuilder::new(vec![Operation::Mul], Vec::new()) .add_to_forest(&mut mast_forest) .unwrap(); - let split_id = SplitNodeBuilder::new([t_branch_id, f_branch_id]) + let split_id = SplitNodeBuilder::new([t_branch, f_branch]) .add_to_forest(&mut mast_forest) .unwrap(); mast_forest.make_root(split_id); - Program::new(mast_forest.into(), split_id) }; let trace = build_trace_from_program(&program, &[]); + let log = InteractionLog::new(&trace); + let main = trace.main_trace(); - let challenges = rand_array::(); - let aux_columns = trace.build_aux_trace(&challenges).unwrap(); - let b_chip = aux_columns.get_column(CHIPLETS_BUS_AUX_TRACE_OFFSET); - - let challenges = Challenges::::new(challenges[0], challenges[1]); - - assert_eq!(trace.length(), b_chip.len()); - assert_eq!(ONE, b_chip[0]); - - // at cycle 0 the following are added for inclusion in the next row: - // - the initialization of the merge of the split's child hashes is requested by the decoder - // - the initialization of the code block merge is provided by the hasher - - // initialize the request state. - let mut split_state = [ZERO; STATE_WIDTH]; - fill_state_from_decoder_with_domain(&trace, &mut split_state, 0.into()); - // request the initialization of the span hash - let split_init = - build_expected(&challenges, LINEAR_HASH_LABEL, split_state, [ZERO; STATE_WIDTH], ONE, ZERO); - let mut expected = split_init.inverse(); - - // provide the initialization of the span hash - expected *= build_expected_from_trace(&trace, &challenges, 0.into()); - assert_eq!(expected, b_chip[1]); - - // at cycle 1 the initialization of the span block hash for the false branch is requested by the - // decoder - let mut f_branch_state = [ZERO; STATE_WIDTH]; - fill_state_from_decoder_with_domain(&trace, &mut f_branch_state, 1.into()); - // request the initialization of the false branch hash - let f_branch_init = build_expected( - &challenges, - LINEAR_HASH_LABEL, - f_branch_state, - [ZERO; STATE_WIDTH], - Felt::new((HASH_CYCLE_LEN + 1) as u64), - ZERO, - ); - expected *= f_branch_init.inverse(); - assert_eq!(expected, b_chip[2]); - - // Nothing changes when there is no communication with the hash chiplet. - assert_eq!(expected, b_chip[3]); - - // at cycle 3 the result hash of the span block for the false branch is requested by the decoder - apply_permutation(&mut f_branch_state); - let f_branch_result = build_expected( - &challenges, - RETURN_HASH_LABEL, - f_branch_state, - [ZERO; STATE_WIDTH], - Felt::new((2 * HASH_CYCLE_LEN) as u64), - ZERO, - ); - expected *= f_branch_result.inverse(); - assert_eq!(expected, b_chip[4]); - - // at cycle 4 the result of the split code block's hash is requested by the decoder - apply_permutation(&mut split_state); - let split_result = build_expected( - &challenges, - RETURN_HASH_LABEL, - split_state, - [ZERO; STATE_WIDTH], - Felt::new(HASH_CYCLE_LEN as u64), - ZERO, - ); - expected *= split_result.inverse(); - assert_eq!(expected, b_chip[5]); + let mut exp = Expectations::new(&log); + let mut split_request_count = 0usize; - // Nothing changes when there is no communication with the hash chiplet. - for row in 6..HASH_CYCLE_LEN { - assert_eq!(expected, b_chip[row]); + for row in 0..main.num_rows() { + let idx = RowIndex::from(row); + let op = main.get_op_code(idx).as_canonical_u64(); + if op != opcodes::SPLIT as u64 { + continue; + } + let addr_next = main.addr(RowIndex::from(row + 1)); + let rate = rate_from_hasher_state(main, idx); + exp.remove(row, &HasherMsg::control_block(addr_next, &rate, opcodes::SPLIT)); + split_request_count += 1; } - // At the end of the merge hash cycle, the result of the merge is provided by the hasher. - expected *= build_expected_from_trace(&trace, &challenges, LAST_CYCLE_ROW.into()); - assert_eq!(expected, b_chip[HASH_CYCLE_LEN]); - - // At the start of the next hash cycle, the initialization of the hash of the span block for the - // false branch is provided by the hasher. - expected *= build_expected_from_trace(&trace, &challenges, HASH_CYCLE_LEN.into()); - assert_eq!(expected, b_chip[HASH_CYCLE_LEN + 1]); - - // Nothing changes when there is no communication with the hash chiplet. - for row in (HASH_CYCLE_LEN + 2)..(2 * HASH_CYCLE_LEN) { - assert_eq!(expected, b_chip[row]); + let mut split_response_count = 0usize; + for (idx, kind) in hasher_response_rows(main) { + if kind != HasherResponseKind::SpongeStart { + continue; + } + let addr = main.clk(idx) + ONE; + let state = main.chiplet_hasher_state(idx); + // SPLIT's own hasher response carries opcode `SPLIT` at capacity[1] (position 9 of the + // 12-lane state); sibling SPAN sponge_start rows carry opcode 0. + if state[9] == Felt::from(opcodes::SPLIT) { + exp.add(usize::from(idx), &HasherMsg::linear_hash_init(addr, state)); + split_response_count += 1; + } } - // At the end of the false branch hash cycle, the result of the span block for the false branch - // is provided by the hasher. - expected *= - build_expected_from_trace(&trace, &challenges, (HASH_CYCLE_LEN + LAST_CYCLE_ROW).into()); - assert_eq!(expected, b_chip[2 * HASH_CYCLE_LEN]); - - // The value in b_chip should be ONE now and for the rest of the trace. - for row in (2 * HASH_CYCLE_LEN)..trace.length() { - assert_eq!(ONE, b_chip[row]); - } + assert_eq!(split_request_count, 1, "single SPLIT program should emit one SPLIT remove"); + assert_eq!( + split_response_count, 1, + "single SPLIT program should emit one SPLIT-capacity sponge_start", + ); + log.assert_contains(&exp); } -/// Tests the generation of the `b_chip` bus column when the hasher performs a permutation -/// requested by the `HPerm` user operation. #[test] -#[expect(clippy::needless_range_loop)] -pub fn b_chip_permutation() { - let program = { - let mut mast_forest = MastForest::new(); - - let basic_block_id = BasicBlockNodeBuilder::new(vec![Operation::HPerm], Vec::new()) - .add_to_forest(&mut mast_forest) - .unwrap(); - mast_forest.make_root(basic_block_id); - - Program::new(mast_forest.into(), basic_block_id) - }; +fn hperm_hasher_bus() { + let program = single_block_program(vec![Operation::HPerm]); let stack = vec![8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 0, 8]; let trace = build_trace_from_program(&program, &stack); + let log = InteractionLog::new(&trace); + let main = trace.main_trace(); + + let mut exp = Expectations::new(&log); + let mut request_count = 0usize; + let mut hperm_helper0: Option = None; + for row in 0..main.num_rows() { + let idx = RowIndex::from(row); + let op = main.get_op_code(idx).as_canonical_u64(); + if op != opcodes::HPERM as u64 { + continue; + } - let mut hperm_state: [Felt; STATE_WIDTH] = stack - .iter() - .map(|v| Felt::new(*v)) - .collect::>() - .try_into() - .expect("failed to convert vector to array"); - let challenges = rand_array::(); - let aux_columns = trace.build_aux_trace(&challenges).unwrap(); - let b_chip = aux_columns.get_column(CHIPLETS_BUS_AUX_TRACE_OFFSET); - - let challenges = Challenges::::new(challenges[0], challenges[1]); - - assert_eq!(trace.length(), b_chip.len()); - assert_eq!(ONE, b_chip[0]); - - // at cycle 0 the following are added for inclusion in the next row: - // - the initialization of the span hash is requested by the decoder - // - the initialization of the span hash is provided by the hasher - - // initialize the request state. - let mut span_state = [ZERO; STATE_WIDTH]; - fill_state_from_decoder_with_domain(&trace, &mut span_state, 0.into()); - // request the initialization of the span hash - let span_init = - build_expected(&challenges, LINEAR_HASH_LABEL, span_state, [ZERO; STATE_WIDTH], ONE, ZERO); - let mut expected = span_init.inverse(); - // provide the initialization of the span hash - expected *= build_expected_from_trace(&trace, &challenges, 0.into()); - assert_eq!(expected, b_chip[1]); - - // at cycle 1 hperm is executed and the initialization and result of the hash are both - // requested by the stack. - let hperm_init = build_expected( - &challenges, - LINEAR_HASH_LABEL, - hperm_state, - [ZERO; STATE_WIDTH], - Felt::new((HASH_CYCLE_LEN + 1) as u64), - ZERO, - ); - // request the hperm initialization. - expected *= hperm_init.inverse(); - apply_permutation(&mut hperm_state); - let hperm_result = build_expected( - &challenges, - RETURN_STATE_LABEL, - hperm_state, - [ZERO; STATE_WIDTH], - Felt::new((2 * HASH_CYCLE_LEN) as u64), - ZERO, - ); - // request the hperm result. - expected *= hperm_result.inverse(); - assert_eq!(expected, b_chip[2]); - - // at cycle 2 the result of the span hash is requested by the decoder - apply_permutation(&mut span_state); - let span_result = build_expected( - &challenges, - RETURN_HASH_LABEL, - span_state, - [ZERO; STATE_WIDTH], - Felt::new(HASH_CYCLE_LEN as u64), - ZERO, - ); - expected *= span_result.inverse(); - assert_eq!(expected, b_chip[3]); - - // Nothing changes when there is no communication with the hash chiplet. - for row in 4..HASH_CYCLE_LEN { - assert_eq!(expected, b_chip[row]); + let helper0 = main.helper_register(0, idx); + hperm_helper0 = Some(helper0); + let next = RowIndex::from(row + 1); + let stk_state: [Felt; 12] = core::array::from_fn(|i| main.stack_element(i, idx)); + let stk_next_state: [Felt; 12] = core::array::from_fn(|i| main.stack_element(i, next)); + exp.remove(row, &HasherMsg::linear_hash_init(helper0, stk_state)); + exp.remove( + row, + &HasherMsg::return_state(helper0 + CONTROLLER_ROWS_PER_PERM_FELT - ONE, stk_next_state), + ); + request_count += 2; } - - // At the end of the span hash cycle, the result of the span hash is provided by the hasher. - expected *= build_expected_from_trace(&trace, &challenges, LAST_CYCLE_ROW.into()); - assert_eq!(expected, b_chip[HASH_CYCLE_LEN]); - - // At the start of the next hash cycle, the initialization of the hperm hash is provided by the - // hasher. - expected *= build_expected_from_trace(&trace, &challenges, HASH_CYCLE_LEN.into()); - assert_eq!(expected, b_chip[HASH_CYCLE_LEN + 1]); - - // Nothing changes when there is no communication with the hash chiplet. - for row in (HASH_CYCLE_LEN + 2)..(2 * HASH_CYCLE_LEN) { - assert_eq!(expected, b_chip[row]); + let hperm_helper0 = hperm_helper0.expect("program should contain an HPERM row"); + let hperm_return_addr = hperm_helper0 + CONTROLLER_ROWS_PER_PERM_FELT - ONE; + + let mut sponge_start_count = 0usize; + let mut sout_count = 0usize; + for (idx, kind) in hasher_response_rows(main) { + let addr = main.clk(idx) + ONE; + let state = main.chiplet_hasher_state(idx); + match kind { + HasherResponseKind::SpongeStart => { + exp.add(usize::from(idx), &HasherMsg::linear_hash_init(addr, state)); + // Only the HPERM-paired sponge_start matches `hperm_helper0`; the outer + // SPAN/END controller rows live on their own `addr` track. + if addr == hperm_helper0 { + sponge_start_count += 1; + } + }, + HasherResponseKind::Sout => { + exp.add(usize::from(idx), &HasherMsg::return_state(addr, state)); + if addr == hperm_return_addr { + sout_count += 1; + } + }, + _ => {}, + } } - // At the end of the hperm hash cycle, the result of the hperm hash is provided by the hasher. - expected *= - build_expected_from_trace(&trace, &challenges, (HASH_CYCLE_LEN + LAST_CYCLE_ROW).into()); - assert_eq!(expected, b_chip[2 * HASH_CYCLE_LEN]); - - // The value in b_chip should be ONE now and for the rest of the trace. - for row in (2 * HASH_CYCLE_LEN)..trace.length() { - assert_eq!(ONE, b_chip[row]); - } + assert_eq!(request_count, 2, "HPERM: expected 2 removes (init + return)"); + assert_eq!(sponge_start_count, 1, "HPERM: expected 1 HPERM-paired sponge_start"); + assert_eq!(sout_count, 1, "HPERM: expected 1 HPERM-paired SOUT"); + log.assert_contains(&exp); } -/// Tests the generation of the `b_chip` bus column when the hasher performs a log_precompile -/// operation requested by the stack. The operation absorbs TAG and COMM into a Poseidon2 -/// sponge with capacity CAP_PREV, producing (CAP_NEXT, R0, R1). #[test] -#[expect(clippy::needless_range_loop)] -pub fn b_chip_log_precompile() { - let program = { - let mut mast_forest = MastForest::new(); - - let basic_block_id = BasicBlockNodeBuilder::new(vec![Operation::LogPrecompile], Vec::new()) - .add_to_forest(&mut mast_forest) - .unwrap(); - mast_forest.make_root(basic_block_id); - - Program::new(mast_forest.into(), basic_block_id) - }; - // Runtime stack layout: [COMM(5,6,7,8), TAG(1,2,3,4)] with comm[0]=5 on top - let comm_word: Word = [Felt::new(5), Felt::new(6), Felt::new(7), Felt::new(8)].into(); - let tag_word: Word = [Felt::new(1), Felt::new(2), Felt::new(3), Felt::new(4)].into(); - // stack! takes elements in runtime order (first = top) and handles reversal +fn logprecompile_hasher_bus() { + let program = single_block_program(vec![Operation::LogPrecompile]); let stack_inputs = stack![5, 6, 7, 8, 1, 2, 3, 4]; let trace = build_trace_from_program(&program, &stack_inputs); + let log = InteractionLog::new(&trace); + let main = trace.main_trace(); + + let mut exp = Expectations::new(&log); + let mut request_count = 0usize; + let mut logprecompile_addr: Option = None; + for row in 0..main.num_rows() { + let idx = RowIndex::from(row); + let op = main.get_op_code(idx).as_canonical_u64(); + if op != opcodes::LOGPRECOMPILE as u64 { + continue; + } - let challenges = rand_array::(); - let aux_columns = trace.build_aux_trace(&challenges).unwrap(); - let b_chip = aux_columns.get_column(CHIPLETS_BUS_AUX_TRACE_OFFSET); - - let challenges = Challenges::::new(challenges[0], challenges[1]); - - assert_eq!(trace.length(), b_chip.len()); - assert_eq!(ONE, b_chip[0]); - - let mut expected = ONE; - - // at cycle 0 the following are added for inclusion in the next row: - // - the initialization of the span hash is requested by the decoder - // - the initialization of the span hash is provided by the hasher - - // initialize the request state. - let mut span_state = [ZERO; STATE_WIDTH]; - fill_state_from_decoder_with_domain(&trace, &mut span_state, 0.into()); - // request the initialization of the span hash - let span_init = - build_expected(&challenges, LINEAR_HASH_LABEL, span_state, [ZERO; STATE_WIDTH], ONE, ZERO); - expected *= span_init.inverse(); - // provide the initialization of the span hash - expected *= build_expected_from_trace(&trace, &challenges, 0.into()); - assert_eq!(expected, b_chip[1]); - - // at cycle 1 log_precompile is executed and the initialization and result of the hash are both - // requested by the stack. - - // Build the input state in sponge order: [COMM, TAG, CAP_PREV] = [RATE0, RATE1, CAP] - // CAP_PREV comes from helper registers and defaults to [0,0,0,0]. - // COMM = [5,6,7,8] is at stack positions 0-3. - // TAG = [1,2,3,4] is at stack positions 4-7. - // init_state_from_words(w1, w2) puts w1 at RATE0 and w2 at RATE1. - let log_pc_state = init_state_from_words(&comm_word, &tag_word); - - let log_pc_init = build_expected( - &challenges, - LINEAR_HASH_LABEL, - log_pc_state, - [ZERO; STATE_WIDTH], - Felt::new((HASH_CYCLE_LEN + 1) as u64), - ZERO, - ); - // request the log_precompile initialization. - expected *= log_pc_init.inverse(); - - // Compute the output state by applying the permutation - let mut log_pc_output_state = log_pc_state; - apply_permutation(&mut log_pc_output_state); - - let log_pc_result = build_expected( - &challenges, - RETURN_STATE_LABEL, - log_pc_output_state, - [ZERO; STATE_WIDTH], - Felt::new((2 * HASH_CYCLE_LEN) as u64), - ZERO, - ); - // request the log_precompile result. - expected *= log_pc_result.inverse(); - assert_eq!(expected, b_chip[2]); - - // at cycle 2 the result of the span hash is requested by the decoder - apply_permutation(&mut span_state); - let span_result = build_expected( - &challenges, - RETURN_HASH_LABEL, - span_state, - [ZERO; STATE_WIDTH], - Felt::new(HASH_CYCLE_LEN as u64), - ZERO, - ); - expected *= span_result.inverse(); - assert_eq!(expected, b_chip[3]); - - // Nothing changes when there is no communication with the hash chiplet. - for row in 4..HASH_CYCLE_LEN { - assert_eq!(expected, b_chip[row]); + let next = RowIndex::from(row + 1); + let log_addr = main.helper_register(HELPER_ADDR_IDX, idx); + logprecompile_addr = Some(log_addr); + + // Input: [COMM, TAG, CAP_PREV] — 8 stack lanes + 4 helper registers. + let input_state: [Felt; 12] = core::array::from_fn(|i| { + if i < 4 { + main.stack_element(STACK_COMM_RANGE.start + i, idx) + } else if i < 8 { + main.stack_element(STACK_TAG_RANGE.start + (i - 4), idx) + } else { + main.helper_register(HELPER_CAP_PREV_RANGE.start + (i - 8), idx) + } + }); + + // Output (next row): [R0, R1, CAP_NEXT] — all 12 lanes from stack. + let output_state: [Felt; 12] = core::array::from_fn(|i| { + if i < 4 { + main.stack_element(STACK_R0_RANGE.start + i, next) + } else if i < 8 { + main.stack_element(STACK_R1_RANGE.start + (i - 4), next) + } else { + main.stack_element(STACK_CAP_NEXT_RANGE.start + (i - 8), next) + } + }); + + exp.remove(row, &HasherMsg::linear_hash_init(log_addr, input_state)); + exp.remove( + row, + &HasherMsg::return_state(log_addr + CONTROLLER_ROWS_PER_PERM_FELT - ONE, output_state), + ); + request_count += 2; } - - // at cycle 7 the result of the span hash is provided by the hasher - expected *= build_expected_from_trace(&trace, &challenges, LAST_CYCLE_ROW.into()); - assert_eq!(expected, b_chip[HASH_CYCLE_LEN]); - - // at cycle 8 the initialization of the log_precompile hash is provided by the hasher - expected *= build_expected_from_trace(&trace, &challenges, HASH_CYCLE_LEN.into()); - assert_eq!(expected, b_chip[HASH_CYCLE_LEN + 1]); - - // Nothing changes when there is no communication with the hash chiplet. - for row in (HASH_CYCLE_LEN + 2)..(2 * HASH_CYCLE_LEN) { - assert_eq!(expected, b_chip[row]); + let log_addr = logprecompile_addr.expect("program should contain a LOGPRECOMPILE row"); + let log_return_addr = log_addr + CONTROLLER_ROWS_PER_PERM_FELT - ONE; + + let mut sponge_start_count = 0usize; + let mut sout_count = 0usize; + for (idx, kind) in hasher_response_rows(main) { + let addr = main.clk(idx) + ONE; + let state = main.chiplet_hasher_state(idx); + match kind { + HasherResponseKind::SpongeStart => { + exp.add(usize::from(idx), &HasherMsg::linear_hash_init(addr, state)); + if addr == log_addr { + sponge_start_count += 1; + } + }, + HasherResponseKind::Sout => { + exp.add(usize::from(idx), &HasherMsg::return_state(addr, state)); + if addr == log_return_addr { + sout_count += 1; + } + }, + _ => {}, + } } - // at cycle 15 the result of the log_precompile hash is provided by the hasher - expected *= - build_expected_from_trace(&trace, &challenges, (HASH_CYCLE_LEN + LAST_CYCLE_ROW).into()); - assert_eq!(expected, b_chip[2 * HASH_CYCLE_LEN]); - - // The value in b_chip should be ONE now and for the rest of the trace. - for row in (2 * HASH_CYCLE_LEN)..trace.length() { - assert_eq!(ONE, b_chip[row]); - } + assert_eq!(request_count, 2, "LOGPRECOMPILE: expected 2 removes (init + return)"); + assert_eq!( + sponge_start_count, 1, + "LOGPRECOMPILE: expected 1 LOGPRECOMPILE-paired sponge_start" + ); + assert_eq!(sout_count, 1, "LOGPRECOMPILE: expected 1 LOGPRECOMPILE-paired SOUT"); + log.assert_contains(&exp); } -/// Tests the generation of the `b_chip` bus column when the hasher performs a Merkle path -/// verification requested by the `MpVerify` user operation. #[test] -#[expect(clippy::needless_range_loop)] -fn b_chip_mpverify() { +fn mpverify_hasher_bus() { let index = 5usize; let leaves = init_leaves(&[1, 2, 3, 4, 5, 6, 7, 8]); let tree = MerkleTree::new(&leaves).unwrap(); @@ -628,123 +422,78 @@ fn b_chip_mpverify() { stack_inputs, advice_inputs, ); - let challenges = rand_array::(); - let aux_columns = trace.build_aux_trace(&challenges).unwrap(); - let b_chip = aux_columns.get_column(CHIPLETS_BUS_AUX_TRACE_OFFSET); - - let challenges = Challenges::::new(challenges[0], challenges[1]); - - assert_eq!(trace.length(), b_chip.len()); - assert_eq!(ONE, b_chip[0]); - - // at cycle 0 the following are added for inclusion in the next row: - // - the initialization of the span hash is requested by the decoder - // - the initialization of the span hash is provided by the hasher - - // initialize the request state. - let mut span_state = [ZERO; STATE_WIDTH]; - fill_state_from_decoder_with_domain(&trace, &mut span_state, 0.into()); - // request the initialization of the span hash - let span_init = - build_expected(&challenges, LINEAR_HASH_LABEL, span_state, [ZERO; STATE_WIDTH], ONE, ZERO); - let mut expected = span_init.inverse(); - // provide the initialization of the span hash - expected *= build_expected_from_trace(&trace, &challenges, 0.into()); - assert_eq!(expected, b_chip[1]); - - // at cycle 1 a merkle path verification is executed and the initialization and result of the - // hash are both requested by the stack. - let path = tree - .get_path(NodeIndex::new(tree.depth(), index as u64).unwrap()) - .expect("failed to get Merkle tree path"); - let mp_state = init_state_from_words(&path[0], &leaves[index]); - let mp_init = build_expected( - &challenges, - MP_VERIFY_LABEL, - mp_state, - [ZERO; STATE_WIDTH], - Felt::new((HASH_CYCLE_LEN + 1) as u64), - Felt::new(index as u64), - ); - // request the initialization of the Merkle path verification - expected *= mp_init.inverse(); - - let mp_verify_complete = HASH_CYCLE_LEN + (tree.depth() as usize) * HASH_CYCLE_LEN; - let mut result_state = [ZERO; STATE_WIDTH]; - result_state[DIGEST_RANGE].copy_from_slice(tree.root().as_elements()); - let mp_result = build_expected( - &challenges, - RETURN_HASH_LABEL, - result_state, - [ZERO; STATE_WIDTH], - Felt::new(mp_verify_complete as u64), - Felt::new(index as u64 >> tree.depth()), - ); - // request the result of the Merkle path verification - expected *= mp_result.inverse(); - assert_eq!(expected, b_chip[2]); - - // at cycle 2 the result of the span hash is requested by the decoder - apply_permutation(&mut span_state); - let span_result = build_expected( - &challenges, - RETURN_HASH_LABEL, - span_state, - [ZERO; STATE_WIDTH], - Felt::new(HASH_CYCLE_LEN as u64), - ZERO, - ); - expected *= span_result.inverse(); - assert_eq!(expected, b_chip[3]); + let log = InteractionLog::new(&trace); + let main = trace.main_trace(); - // Nothing changes when there is no communication with the hash chiplet. - for row in 4..HASH_CYCLE_LEN { - assert_eq!(expected, b_chip[row]); - } + let mut exp = Expectations::new(&log); + let mut request_count = 0usize; - // At the end of the span hash cycle, the result of the span hash is provided by the hasher. - expected *= build_expected_from_trace(&trace, &challenges, LAST_CYCLE_ROW.into()); - assert_eq!(expected, b_chip[HASH_CYCLE_LEN]); - - // At the start of the next hash cycle, the initialization of the merkle path is provided by - // the hasher. - expected *= build_expected_from_trace(&trace, &challenges, HASH_CYCLE_LEN.into()); - assert_eq!(expected, b_chip[HASH_CYCLE_LEN + 1]); - - // Nothing changes when there is no communication with the hash chiplet. - for row in (HASH_CYCLE_LEN + 2)..(mp_verify_complete) { - assert_eq!(expected, b_chip[row]); + for row in 0..main.num_rows() { + let idx = RowIndex::from(row); + let op = main.get_op_code(idx).as_canonical_u64(); + if op != opcodes::MPVERIFY as u64 { + continue; + } + let helper0 = main.helper_register(0, idx); + let mp_depth = main.stack_element(4, idx); + let mp_index = main.stack_element(5, idx); + let leaf_word: [Felt; 4] = core::array::from_fn(|i| main.stack_element(i, idx)); + let old_root: [Felt; 4] = core::array::from_fn(|i| main.stack_element(6 + i, idx)); + + let return_addr = helper0 + mp_depth * CONTROLLER_ROWS_PER_PERM_FELT - ONE; + exp.remove(row, &HasherMsg::merkle_verify_init(helper0, mp_index, leaf_word)); + exp.remove(row, &HasherMsg::return_hash(return_addr, old_root)); + request_count += 2; } - // when the merkle path verification has been completed the hasher provides the result - expected *= build_expected_from_trace(&trace, &challenges, (mp_verify_complete - 1).into()); - assert_eq!(expected, b_chip[mp_verify_complete]); - - // The value in b_chip should be ONE now and for the rest of the trace. - for row in mp_verify_complete..trace.length() { - assert_eq!(ONE, b_chip[row]); + let mut mp_input_count = 0usize; + let mut hout_count = 0usize; + for (idx, kind) in hasher_response_rows(main) { + let addr = main.clk(idx) + ONE; + let state = main.chiplet_hasher_state(idx); + let rate_0: [Felt; 4] = [state[0], state[1], state[2], state[3]]; + let rate_1: [Felt; 4] = [state[4], state[5], state[6], state[7]]; + match kind { + HasherResponseKind::MpInput => { + let node_index = main.chiplet_node_index(idx); + // Match the emitter's own `bit = node_index - 2·node_index_next` formula rather + // than reading `chiplet_direction_bit`: keeps this assertion independent of the + // column whose constraints are under test. + let bit = merkle_direction_bit(main, idx); + let word: [Felt; 4] = if bit == ZERO { rate_0 } else { rate_1 }; + exp.add(usize::from(idx), &HasherMsg::merkle_verify_init(addr, node_index, word)); + mp_input_count += 1; + }, + HasherResponseKind::Hout => { + // `chiplet_node_index(idx)` is `ZERO` at MPVERIFY's final HOUT row (Merkle walk + // terminates with node_index halved to 0). Using `return_hash` keeps the test + // aligned with the decoder-side `HasherMsg::return_hash(...)` shape. + exp.add(usize::from(idx), &HasherMsg::return_hash(addr, rate_0)); + hout_count += 1; + }, + _ => {}, + } } + + assert_eq!(request_count, 2, "MPVERIFY: expected 2 removes (init + return)"); + assert_eq!(mp_input_count, 1, "MPVERIFY: expected 1 mp_verify_input add"); + // Depth-3 MPVERIFY emits HOUT on every merkle-verify sub-cycle return (one per level). + assert_eq!(hout_count, 2, "MPVERIFY: expected exactly 2 HOUT adds"); + log.assert_contains(&exp); } -/// Tests the generation of the `b_chip` bus column when the hasher performs a Merkle root update -/// requested by the `MrUpdate` user operation. #[test] -#[expect(clippy::needless_range_loop)] -fn b_chip_mrupdate() { +fn mrupdate_hasher_bus() { let index = 5usize; let leaves = init_leaves(&[1, 2, 3, 4, 5, 6, 7, 8]); - let mut tree = MerkleTree::new(&leaves).unwrap(); - - let old_root = tree.root(); - let old_leaf_value = leaves[index]; - + let tree = MerkleTree::new(&leaves).unwrap(); let new_leaf_value = leaves[0]; let mut runtime_stack = Vec::new(); - runtime_stack.extend_from_slice(&word_to_ints(old_leaf_value)); + runtime_stack.extend_from_slice(&word_to_ints(leaves[index])); runtime_stack.push(tree.depth() as u64); runtime_stack.push(index as u64); - runtime_stack.extend_from_slice(&word_to_ints(old_root)); + runtime_stack.extend_from_slice(&word_to_ints(tree.root())); runtime_stack.extend_from_slice(&word_to_ints(new_leaf_value)); let stack_inputs = StackInputs::try_from_ints(runtime_stack).unwrap(); let store = MerkleStore::from(&tree); @@ -752,336 +501,246 @@ fn b_chip_mrupdate() { let trace = build_trace_from_ops_with_inputs(vec![Operation::MrUpdate], stack_inputs, advice_inputs); - let challenges = rand_array::(); - let aux_columns = trace.build_aux_trace(&challenges).unwrap(); - let b_chip = aux_columns.get_column(CHIPLETS_BUS_AUX_TRACE_OFFSET); - - let challenges = Challenges::::new(challenges[0], challenges[1]); - - assert_eq!(trace.length(), b_chip.len()); - assert_eq!(ONE, b_chip[0]); - - // at cycle 0 the following are added for inclusion in the next row: - // - the initialization of the span hash is requested by the decoder - // - the initialization of the span hash is provided by the hasher - - // initialize the request state. - let mut span_state = [ZERO; STATE_WIDTH]; - fill_state_from_decoder_with_domain(&trace, &mut span_state, 0.into()); - // request the initialization of the span hash - let span_init = - build_expected(&challenges, LINEAR_HASH_LABEL, span_state, [ZERO; STATE_WIDTH], ONE, ZERO); - let mut expected = span_init.inverse(); - // provide the initialization of the span hash - expected *= build_expected_from_trace(&trace, &challenges, 0.into()); - assert_eq!(expected, b_chip[1]); - - // at cycle 1 a merkle path verification is executed and the initialization and result of the - // hash are both requested by the stack. - let path = tree - .get_path(NodeIndex::new(tree.depth(), index as u64).unwrap()) - .expect("failed to get Merkle tree path"); - let mp_state = init_state_from_words(&path[0], &leaves[index]); - let mp_init_old = build_expected( - &challenges, - MR_UPDATE_OLD_LABEL, - mp_state, - [ZERO; STATE_WIDTH], - Felt::new((HASH_CYCLE_LEN + 1) as u64), - Felt::new(index as u64), - ); - // request the initialization of the (first) Merkle path verification - expected *= mp_init_old.inverse(); - - let mp_old_verify_complete = HASH_CYCLE_LEN + (tree.depth() as usize) * HASH_CYCLE_LEN; - let mut result_state_old = [ZERO; STATE_WIDTH]; - result_state_old[DIGEST_RANGE].copy_from_slice(tree.root().as_elements()); - let mp_result_old = build_expected( - &challenges, - RETURN_HASH_LABEL, - result_state_old, - [ZERO; STATE_WIDTH], - Felt::new(mp_old_verify_complete as u64), - Felt::new(index as u64 >> tree.depth()), - ); - - // request the result of the first Merkle path verification - expected *= mp_result_old.inverse(); - - let new_leaf_value = leaves[0]; - tree.update_leaf(index as u64, new_leaf_value).unwrap(); - let new_root = tree.root(); - - // a second merkle path verification is executed and the initialization and result of the - // hash are both requested by the stack. - let path = tree - .get_path(NodeIndex::new(tree.depth(), index as u64).unwrap()) - .expect("failed to get Merkle tree path"); - let mp_state = init_state_from_words(&path[0], &new_leaf_value); - - let mp_new_verify_complete = mp_old_verify_complete + (tree.depth() as usize) * HASH_CYCLE_LEN; - let mp_init_new = build_expected( - &challenges, - MR_UPDATE_NEW_LABEL, - mp_state, - [ZERO; STATE_WIDTH], - Felt::new(mp_old_verify_complete as u64 + 1), - Felt::new(index as u64), - ); + let log = InteractionLog::new(&trace); + let main = trace.main_trace(); - // request the initialization of the second Merkle path verification - expected *= mp_init_new.inverse(); - - let mut result_state_new = [ZERO; STATE_WIDTH]; - result_state_new[DIGEST_RANGE].copy_from_slice(new_root.as_elements()); - let mp_result_new = build_expected( - &challenges, - RETURN_HASH_LABEL, - result_state_new, - [ZERO; STATE_WIDTH], - Felt::new(mp_new_verify_complete as u64), - Felt::new(index as u64 >> tree.depth()), - ); - - // request the result of the second Merkle path verification - expected *= mp_result_new.inverse(); - assert_eq!(expected, b_chip[2]); - - // at cycle 2 the result of the span hash is requested by the decoder - apply_permutation(&mut span_state); - let span_result = build_expected( - &challenges, - RETURN_HASH_LABEL, - span_state, - [ZERO; STATE_WIDTH], - Felt::new(HASH_CYCLE_LEN as u64), - ZERO, - ); - expected *= span_result.inverse(); - assert_eq!(expected, b_chip[3]); + let mut exp = Expectations::new(&log); + let mut request_count = 0usize; - // Nothing changes when there is no communication with the hash chiplet. - for row in 4..HASH_CYCLE_LEN { - assert_eq!(expected, b_chip[row]); + for row in 0..main.num_rows() { + let idx = RowIndex::from(row); + let op = main.get_op_code(idx).as_canonical_u64(); + if op != opcodes::MRUPDATE as u64 { + continue; + } + let helper0 = main.helper_register(0, idx); + let next = RowIndex::from(row + 1); + let mr_depth = main.stack_element(4, idx); + let mr_index = main.stack_element(5, idx); + let old_leaf: [Felt; 4] = core::array::from_fn(|i| main.stack_element(i, idx)); + let old_root: [Felt; 4] = core::array::from_fn(|i| main.stack_element(6 + i, idx)); + let new_leaf: [Felt; 4] = core::array::from_fn(|i| main.stack_element(10 + i, idx)); + let new_root: [Felt; 4] = core::array::from_fn(|i| main.stack_element(i, next)); + + let old_return = helper0 + mr_depth * CONTROLLER_ROWS_PER_PERM_FELT - ONE; + let new_init = helper0 + mr_depth * CONTROLLER_ROWS_PER_PERM_FELT; + let new_return = helper0 + + mr_depth * (CONTROLLER_ROWS_PER_PERM_FELT + CONTROLLER_ROWS_PER_PERM_FELT) + - ONE; + + exp.remove(row, &HasherMsg::merkle_old_init(helper0, mr_index, old_leaf)); + exp.remove(row, &HasherMsg::return_hash(old_return, old_root)); + exp.remove(row, &HasherMsg::merkle_new_init(new_init, mr_index, new_leaf)); + exp.remove(row, &HasherMsg::return_hash(new_return, new_root)); + request_count += 4; } - // At the end of the span hash cycle, the result of the span hash is provided by the hasher. - expected *= build_expected_from_trace(&trace, &challenges, LAST_CYCLE_ROW.into()); - assert_eq!(expected, b_chip[HASH_CYCLE_LEN]); - - // At the start of the next hash cycle, the initialization of the first merkle path is provided - // by the hasher. - expected *= build_expected_from_trace(&trace, &challenges, HASH_CYCLE_LEN.into()); - assert_eq!(expected, b_chip[HASH_CYCLE_LEN + 1]); - - // Nothing changes when there is no communication with the hash chiplet. - for row in (HASH_CYCLE_LEN + 2)..(mp_old_verify_complete) { - assert_eq!(expected, b_chip[row]); + let mut mv_count = 0usize; + let mut mu_count = 0usize; + let mut hout_count = 0usize; + for (idx, kind) in hasher_response_rows(main) { + let addr = main.clk(idx) + ONE; + let state = main.chiplet_hasher_state(idx); + let rate_0: [Felt; 4] = [state[0], state[1], state[2], state[3]]; + let rate_1: [Felt; 4] = [state[4], state[5], state[6], state[7]]; + let node_index = main.chiplet_node_index(idx); + let bit = merkle_direction_bit(main, idx); + let word: [Felt; 4] = if bit == ZERO { rate_0 } else { rate_1 }; + + match kind { + HasherResponseKind::MvOldInput => { + exp.add(usize::from(idx), &HasherMsg::merkle_old_init(addr, node_index, word)); + mv_count += 1; + }, + HasherResponseKind::MuNewInput => { + exp.add(usize::from(idx), &HasherMsg::merkle_new_init(addr, node_index, word)); + mu_count += 1; + }, + HasherResponseKind::Hout => { + exp.add(usize::from(idx), &HasherMsg::return_hash(addr, rate_0)); + hout_count += 1; + }, + _ => {}, + } } - // when the first merkle path verification has been completed the hasher provides the result - expected *= build_expected_from_trace(&trace, &challenges, (mp_old_verify_complete - 1).into()); - assert_eq!(expected, b_chip[mp_old_verify_complete]); - - // at cycle 32 the initialization of the second merkle path is provided by the hasher - expected *= build_expected_from_trace(&trace, &challenges, mp_old_verify_complete.into()); - assert_eq!(expected, b_chip[mp_old_verify_complete + 1]); + assert_eq!( + request_count, 4, + "MRUPDATE: expected 4 removes (old_init + old_return + new_init + new_return)", + ); + assert_eq!(mv_count, 1, "MRUPDATE: expected 1 mr_update_old_input add"); + assert_eq!(mu_count, 1, "MRUPDATE: expected 1 mr_update_new_input add"); + // Depth-3 MRUPDATE emits HOUT on each old-path and new-path sub-cycle return. + assert_eq!(hout_count, 3, "MRUPDATE: expected exactly 3 HOUT adds"); + log.assert_contains(&exp); +} - // Nothing changes when there is no communication with the hash chiplet. - for row in (mp_old_verify_complete + 1)..(mp_new_verify_complete) { - assert_eq!(expected, b_chip[row]); - } +// HELPERS +// ================================================================================================ - // when the merkle path verification has been completed the hasher provides the result - expected *= build_expected_from_trace(&trace, &challenges, (mp_new_verify_complete - 1).into()); - assert_eq!(expected, b_chip[mp_new_verify_complete]); +fn single_block_program(ops: Vec) -> Program { + let mut mast_forest = MastForest::new(); + let id = BasicBlockNodeBuilder::new(ops, Vec::new()) + .add_to_forest(&mut mast_forest) + .unwrap(); + mast_forest.make_root(id); + Program::new(mast_forest.into(), id) +} - // The value in b_chip should be ONE now and for the rest of the trace. - for row in (mp_new_verify_complete)..trace.length() { - assert_eq!(ONE, b_chip[row]); - } +fn rate_from_hasher_state(main: &MainTrace, row: RowIndex) -> [Felt; 8] { + let first = main.decoder_hasher_state_first_half(row); + let second = main.decoder_hasher_state_second_half(row); + [ + first[0], first[1], first[2], first[3], second[0], second[1], second[2], second[3], + ] } -// TEST HELPERS -// ================================================================================================ +fn is_hasher_controller_row(main: &MainTrace, row: RowIndex) -> bool { + main.chiplet_selector_0(row) == ONE && main.chiplet_s_perm(row) == ZERO +} -/// Reduces the provided hasher row information to an expected value. -fn build_expected( - challenges: &Challenges, - label: u8, - state: HasherState, - next_state: HasherState, - addr: Felt, - index: Felt, -) -> Felt { - let first_cycle_row = addr_to_cycle_row(addr) == 0; - let transition_label = if first_cycle_row { label + 16_u8 } else { label + 32_u8 }; - let header = challenges.alpha - + challenges.beta_powers[0] * Felt::from_u8(transition_label) - + challenges.beta_powers[1] * addr - + challenges.beta_powers[2] * index; - let mut value = header; - - if (first_cycle_row && label == LINEAR_HASH_LABEL) || label == RETURN_STATE_LABEL { - // include the entire state (words a, b, c) - value += build_value(&challenges.beta_powers[3..15], &state); - } else if label == LINEAR_HASH_LABEL { - // Include the next absorbed rate portion of the state (RATE0 || RATE1). - // With LE sponge layout [RATE0, RATE1, CAP], rate is at indices 0..8. - value += build_value(&challenges.beta_powers[3..11], &next_state[0..RATE_LEN]); - } else if label == RETURN_HASH_LABEL { - // include the digest (word b) - value += build_value(&challenges.beta_powers[3..7], &state[DIGEST_RANGE]); +/// Returns `Some(false)` for ZERO, `Some(true)` for ONE, and `None` for any other value. +/// +/// Used to guard selector-bit reads: a malformed value (e.g. 2) yields `None` so the row is +/// skipped rather than silently misclassified. +fn as_bit(val: Felt) -> Option { + if val == ZERO { + Some(false) + } else if val == ONE { + Some(true) } else { - assert!( - label == MP_VERIFY_LABEL - || label == MR_UPDATE_NEW_LABEL - || label == MR_UPDATE_OLD_LABEL - ); - let bit = index.as_canonical_u64() & 1; - // For Merkle operations, RATE0 and RATE1 hold the two child digests. - // With LE sponge layout [RATE0, RATE1, CAP], they are at indices 0..4 and 4..8. - let left_word = build_value(&challenges.beta_powers[3..7], &state[0..4]); - let right_word = build_value(&challenges.beta_powers[3..7], &state[4..8]); - - value += Felt::new(1 - bit) * left_word + Felt::new(bit) * right_word; + None } +} - value +/// Recompute the Merkle direction bit the emitter uses: `bit = node_index - 2·node_index_next` +/// (see `chiplet_responses.rs::mp_verify_input`). Independent of the `chiplet_direction_bit` +/// column, so bugs in that column don't make the assertion vacuously pass. +fn merkle_direction_bit(main: &MainTrace, row: RowIndex) -> Felt { + let next = RowIndex::from(usize::from(row) + 1); + main.chiplet_node_index(row) - main.chiplet_node_index(next).double() } -/// Reduces the specified row in the execution trace to an expected value representing a hash -/// operation lookup. -fn build_expected_from_trace( - trace: &ExecutionTrace, - challenges: &Challenges, - row: RowIndex, -) -> Felt { - let s0 = trace.main_trace.get_column(HASHER_TRACE_OFFSET)[row]; - let s1 = trace.main_trace.get_column(HASHER_TRACE_OFFSET + 1)[row]; - let s2 = trace.main_trace.get_column(HASHER_TRACE_OFFSET + 2)[row]; - let selectors: Selectors = [s0, s1, s2]; - - let label = get_label_from_selectors(selectors) - .expect("unrecognized hasher operation label in hasher trace"); - - let addr = trace.main_trace.get_column(CLK_COL_IDX)[row] + ONE; - let index = trace.main_trace.get_column(HASHER_NODE_INDEX_COL_IDX)[row]; - - let cycle_row = addr_to_cycle_row(addr); - - // Trace is already in sponge order [RATE0, RATE1, CAP] - let mut state = [ZERO; STATE_WIDTH]; - let mut next_state = [ZERO; STATE_WIDTH]; - for (i, col_idx) in HASHER_STATE_COL_RANGE.enumerate() { - state[i] = trace.main_trace.get_column(col_idx)[row]; - if cycle_row == LAST_CYCLE_ROW && label == LINEAR_HASH_LABEL { - next_state[i] = trace.main_trace.get_column(col_idx)[row + 1]; +// SIBLING TABLE BUS (MRUPDATE add/remove pairing) +// ================================================================================================ +// +// MRUPDATE verifies the old Merkle root (MV leg, adds to sibling table) and then recomputes +// the new root (MU leg, removes from sibling table). Each of the 3 levels of a depth-3 tree +// emits one add on the MV leg and one remove on the MU leg, matched by `(mrupdate_id, +// node_index, sibling_word)`. +// +// The test iterates every hasher controller row, picks out the MV/MU sibling-emitting rows +// via the `(s0, s1, s2)` sub-selectors, and attaches a `SiblingMsg` expectation tagged with +// the direction bit. Column-blind — the subset matcher finds each message regardless of +// where the M4/C2 packing puts it. + +/// Drive a depth-3 Merkle MRUPDATE and assert the sibling-table bus fires one add per MV +/// controller row and one remove per MU controller row (3 levels → 3 adds + 3 removes). +#[rstest] +#[case(5_u64)] +#[case(4_u64)] +fn mrupdate_emits_sibling_add_and_remove_per_level(#[case] index: u64) { + let (tree, _) = build_merkle_tree(); + let old_node = tree.get_node(NodeIndex::new(3, index).unwrap()).unwrap(); + let new_node = init_leaf(11); + + let mut init_stack = Vec::new(); + init_stack.extend_from_slice(&word_to_ints(old_node)); + init_stack.extend_from_slice(&[3, index]); + init_stack.extend_from_slice(&word_to_ints(tree.root())); + init_stack.extend_from_slice(&word_to_ints(new_node)); + let stack_inputs = StackInputs::try_from_ints(init_stack).unwrap(); + let store = MerkleStore::from(&tree); + let advice_inputs = AdviceInputs::default().with_merkle_store(store); + + let ops = vec![Operation::MrUpdate]; + let trace = build_trace_from_ops_with_inputs(ops, stack_inputs, advice_inputs); + let log = InteractionLog::new(&trace); + let main = trace.main_trace(); + + // Collect MV / MU controller rows. A row is a sibling-table add/remove site when + // `chiplet_active.controller = 1` (s_ctrl column) AND the hasher internal + // `(s0, s1, s2)` sub-selectors pick out the MV-all (`s0·s1·(1-s2)`) or MU-all + // (`s0·s1·s2`) pattern. See `air/src/constraints/lookup/buses/hash_kernel.rs`. + let mut mv_rows: Vec = Vec::new(); + let mut mu_rows: Vec = Vec::new(); + for row in 0..main.num_rows() { + let idx = RowIndex::from(row); + if main.chiplet_selector_0(idx) != ONE || main.chiplet_s_perm(idx) != ZERO { + continue; + } + let hs0 = main.chiplet_selector_1(idx); + let hs1 = main.chiplet_selector_2(idx); + let hs2 = main.chiplet_selector_3(idx); + if hs0 == ONE && hs1 == ONE && hs2 == ZERO { + mv_rows.push(idx); + } else if hs0 == ONE && hs1 == ONE && hs2 == ONE { + mu_rows.push(idx); } } + assert_eq!(mv_rows.len(), 3, "depth-3 MRUPDATE should emit 3 MV sibling adds"); + assert_eq!(mu_rows.len(), 3, "depth-3 MRUPDATE should emit 3 MU sibling removes"); - build_expected(challenges, label, state, next_state, addr, index) -} - -/// Builds a value from coefficients and elements of matching lengths. This can be used to build -/// the value for a single word or for the entire state. -fn build_value(coeffs: &[Felt], elements: &[Felt]) -> Felt { - let mut value = ZERO; - for (&coeff, &element) in coeffs.iter().zip(elements.iter()) { - value += coeff * element; + let mut exp = Expectations::new(&log); + for &row in &mv_rows { + push_sibling(&mut exp, row, main, SiblingSide::Add); } - value -} - -/// Returns the hash operation label for the specified selectors. -fn get_label_from_selectors(selectors: Selectors) -> Option { - if selectors == LINEAR_HASH { - Some(LINEAR_HASH_LABEL) - } else if selectors == MP_VERIFY { - Some(MP_VERIFY_LABEL) - } else if selectors == MR_UPDATE_OLD { - Some(MR_UPDATE_OLD_LABEL) - } else if selectors == MR_UPDATE_NEW { - Some(MR_UPDATE_NEW_LABEL) - } else if selectors == RETURN_HASH { - Some(RETURN_HASH_LABEL) - } else if selectors == RETURN_STATE { - Some(RETURN_STATE_LABEL) - } else { - None + for &row in &mu_rows { + push_sibling(&mut exp, row, main, SiblingSide::Remove); } -} -/// Populates the provided HasherState with the state stored in the decoder's execution trace at the -/// specified row. -fn fill_state_from_decoder_with_domain( - trace: &ExecutionTrace, - state: &mut HasherState, - row: RowIndex, -) { - let domain = extract_control_block_domain_from_trace(trace, row); - state[CAPACITY_DOMAIN_IDX] = domain; - - fill_state_from_decoder(trace, state, row); + log.assert_contains(&exp); } -/// Populates the provided HasherState with the state stored in the decoder's execution trace at the -/// specified row. The decoder stores the 8 rate elements which go at sponge indices 0..8. -fn fill_state_from_decoder(trace: &ExecutionTrace, state: &mut HasherState, row: RowIndex) { - for (i, col_idx) in DECODER_HASHER_STATE_RANGE.enumerate() { - // In sponge order [RATE0, RATE1, CAP], rate is at indices 0..8 - state[i] = trace.main_trace.get_column(col_idx)[row]; - } +enum SiblingSide { + Add, + Remove, } -/// Extract the control block domain from the execution trace. This is achieved -/// by calculating the op code as [bit_0 * 2**0 + bit_1 * 2**1 + ... + bit_6 * 2**6] -fn extract_control_block_domain_from_trace(trace: &ExecutionTrace, row: RowIndex) -> Felt { - // calculate the op code - let opcode_value = DECODER_OP_BITS_RANGE.rev().fold(0u8, |result, bit_index| { - let op_bit = trace.main_trace.get_column(bit_index)[row].as_canonical_u64() as u8; - (result << 1) ^ op_bit - }); - - // opcode values that represent control block initialization (excluding span) - let control_block_initializers = - [opcodes::CALL, opcodes::JOIN, opcodes::LOOP, opcodes::SPLIT, opcodes::SYSCALL]; - - if control_block_initializers.contains(&opcode_value) { - Felt::from_u8(opcode_value) +fn push_sibling(exp: &mut Expectations<'_>, row: RowIndex, main: &MainTrace, side: SiblingSide) { + let mrupdate_id = main.chiplet_mrupdate_id(row); + let node_index = main.chiplet_node_index(row); + let state = main.chiplet_hasher_state(row); + let rate_0: [Felt; 4] = [state[0], state[1], state[2], state[3]]; + let rate_1: [Felt; 4] = [state[4], state[5], state[6], state[7]]; + + // Direction bit drives which rate half the sibling lives in. The trace's + // `chiplet_direction_bit` column carries the extracted bit on Merkle controller rows. + let bit = main.chiplet_direction_bit(row); + let row_usize = usize::from(row); + let (bit_tag, h) = if bit == ZERO { + (SiblingBit::Zero, rate_1) } else { - ZERO - } + (SiblingBit::One, rate_0) + }; + let msg = SiblingMsg { bit: bit_tag, mrupdate_id, node_index, h }; + match side { + SiblingSide::Add => exp.add(row_usize, &msg), + SiblingSide::Remove => exp.remove(row_usize, &msg), + }; } -/// Returns the row of the hash cycle which corresponds to the provided Hasher address. -fn addr_to_cycle_row(addr: Felt) -> usize { - let cycle = (addr.as_canonical_u64() - 1) as usize; - let cycle_row = cycle % HASH_CYCLE_LEN; - debug_assert!( - cycle_row == 0 || cycle_row == LAST_CYCLE_ROW, - "invalid address for hasher lookup" - ); - - cycle_row +fn build_merkle_tree() -> (MerkleTree, Vec) { + let leaves = init_leaves(&[1, 2, 3, 4, 5, 6, 7, 8]); + (MerkleTree::new(leaves.clone()).unwrap(), leaves) } -/// Initializes Merkle tree leaves with the specified values. +// MERKLE TEST HELPERS +// ================================================================================================ + fn init_leaves(values: &[u64]) -> Vec { values.iter().map(|&v| init_leaf(v)).collect() } -/// Initializes a Merkle tree leaf with the specified value. fn init_leaf(value: u64) -> Word { - [Felt::new(value), ZERO, ZERO, ZERO].into() + [Felt::new_unchecked(value), ZERO, ZERO, ZERO].into() } -/// Converts a Word to stack input values (u64 array) in element order. -fn word_to_ints(w: Word) -> [u64; 4] { +fn word_to_ints(word: Word) -> [u64; 4] { [ - w[0].as_canonical_u64(), - w[1].as_canonical_u64(), - w[2].as_canonical_u64(), - w[3].as_canonical_u64(), + word[0].as_canonical_u64(), + word[1].as_canonical_u64(), + word[2].as_canonical_u64(), + word[3].as_canonical_u64(), ] } diff --git a/processor/src/trace/tests/chiplets/memory.rs b/processor/src/trace/tests/chiplets/memory.rs index 25540c2420..f1ea573a9c 100644 --- a/processor/src/trace/tests/chiplets/memory.rs +++ b/processor/src/trace/tests/chiplets/memory.rs @@ -1,355 +1,289 @@ -use miden_air::trace::{ - Challenges, RowIndex, - chiplets::{ - MEMORY_CLK_COL_IDX, MEMORY_CTX_COL_IDX, MEMORY_IDX0_COL_IDX, MEMORY_IDX1_COL_IDX, - MEMORY_IS_READ_COL_IDX, MEMORY_IS_WORD_ACCESS_COL_IDX, MEMORY_V_COL_RANGE, - MEMORY_WORD_COL_IDX, - memory::{ - MEMORY_ACCESS_ELEMENT, MEMORY_ACCESS_WORD, MEMORY_READ, MEMORY_READ_ELEMENT_LABEL, - MEMORY_READ_WORD_LABEL, MEMORY_WRITE, MEMORY_WRITE_ELEMENT_LABEL, - MEMORY_WRITE_WORD_LABEL, - }, +//! Memory-chiplet bus tests. +//! +//! Exercises stack-issued memory opcodes (`MStoreW`, `MLoadW`, `MLoad`, `MStore`, `MStream`) +//! plus the `CryptoStream` double-word read+write pair, and verifies the chiplet-requests / +//! chiplet-responses bus pair. +//! +//! For each stack-level memory op the test registers an expected `-1` push of a +//! [`MemoryMsg`] (the "request" side). For each memory chiplet row the test registers an +//! expected `+1` push of a [`MemoryResponseMsg`] (the "response" side). The subset matcher in +//! `lookup_harness` is column-blind, so a `(mult, denom)` pair on the response side pairs up +//! with a matching `(-mult, denom)` on the request side regardless of which aux column the +//! framework routes them onto. +//! +//! # Scope +//! +//! Coverage is limited to the stack-only memory ops above plus `CryptoStream`. The DYN, +//! DYNCALL, CALL-FMP-write, and PIPE memory-request paths in +//! `air/src/constraints/lookup/buses/chiplet_requests.rs` are deferred to integration tests — +//! each is heavyweight to set up and small in algebraic surface. A bug in those paths would +//! escape this module. +//! +//! The programs run at ctx = 0 throughout (no CALL/SYSCALL), so a request/response bug that +//! mismatches stack-side `ctx` vs chiplet-side `mem_ctx` is not caught here. + +use miden_air::{ + logup::{MemoryMsg, MemoryResponseMsg}, + trace::{ + MainTrace, + chiplets::{MEMORY_IS_READ_COL_IDX, MEMORY_IS_WORD_ACCESS_COL_IDX}, }, }; -use miden_core::{WORD_SIZE, field::Field}; +use miden_core::{ + Felt, ONE, ZERO, + operations::{Operation, opcodes}, +}; -use super::{ - AUX_TRACE_RAND_CHALLENGES, CHIPLETS_BUS_AUX_TRACE_OFFSET, ExecutionTrace, Felt, HASH_CYCLE_LEN, - LAST_CYCLE_ROW, ONE, Operation, Word, ZERO, build_trace_from_ops, rand_array, +use super::super::{ + build_trace_from_ops, + lookup_harness::{Expectations, InteractionLog}, }; +use crate::RowIndex; -/// Tests the generation of the `b_chip` bus column when only memory lookups are included. It -/// ensures that trace generation is correct when all of the following are true. -/// -/// - All possible memory operations are called by the stack. -/// - Some requests from the Stack and responses from Memory occur at the same cycle. -/// - Multiple memory addresses are used. -/// -/// Note: Communication with the Hash chiplet is also required, due to the span block decoding, but -/// for this test we set those values explicitly, enforcing only that the same initial and final -/// values are requested & provided. -#[test] -#[expect(clippy::needless_range_loop)] -fn b_chip_trace_mem() { - const FOUR: Felt = Felt::new(4); +const FOUR: Felt = Felt::new_unchecked(4); +/// Covers `MStoreW`, `MLoad`, `MLoadW`, `MStore`, `MStream` — every memory opcode issuable +/// directly from the stack — asserting the chiplet-bus request/response pair fires at every +/// memory row. +#[test] +fn memory_chiplet_bus_request_response_pairs() { let stack = [0, 1, 2, 3, 4]; - let word = [ONE, Felt::new(2), Felt::new(3), Felt::new(4)]; let operations = vec![ - Operation::MStoreW, // store [1, 2, 3, 4] - Operation::Drop, // clear the stack + Operation::MStoreW, // store [1, 2, 3, 4] at addr 0 + Operation::Drop, Operation::Drop, Operation::Drop, Operation::Drop, - Operation::MLoad, // read the first value of the word - Operation::MovDn5, // put address 0 and space for a full word at top of stack - Operation::MLoadW, // load word from address 0 to stack - Operation::Push(ONE), // push a new value onto the stack - Operation::Push(FOUR), // push a new address on to the stack - Operation::MStore, // store 1 at address 4 - Operation::Drop, // ensure the stack overflow table is empty - Operation::MStream, // read 2 words starting at address 0 + Operation::MLoad, // read first element at addr 0 + Operation::MovDn5, // reshape stack + Operation::MLoadW, // load word from addr 0 + Operation::Push(ONE), // value = 1 + Operation::Push(FOUR), // addr = 4 + Operation::MStore, // store 1 at addr 4 + Operation::Drop, + Operation::MStream, // two-word read starting at stack[12] ]; let trace = build_trace_from_ops(operations, &stack); - - let challenges = rand_array::(); - let aux_columns = trace.build_aux_trace(&challenges).unwrap(); - let b_chip = aux_columns.get_column(CHIPLETS_BUS_AUX_TRACE_OFFSET); - let challenges = Challenges::::new(challenges[0], challenges[1]); - assert_eq!(trace.length(), b_chip.len()); - assert_eq!(ONE, b_chip[0]); - - // At cycle 0 the span hash initialization is requested from the decoder and provided by the - // hash chiplet, so the trace should still equal one. - assert_eq!(ONE, b_chip[1]); - - // The first memory request from the stack is sent when the `MStoreW` operation is executed, at - // cycle 1, so the request is included in the next row. (The trace begins by executing `span`). - let value = build_expected_bus_word_msg( - &challenges, - MEMORY_WRITE_WORD_LABEL, - ZERO, - ZERO, - ONE, - word.into(), - ); - let mut expected = value.inverse(); - assert_eq!(expected, b_chip[2]); - - // Nothing changes after user operations that don't make requests to the Chiplets. - for row in 3..7 { - assert_eq!(expected, b_chip[row]); + let log = InteractionLog::new(&trace); + let main = trace.main_trace(); + + let mut exp = Expectations::new(&log); + + // ---- Request side: stack rows emit `-1 × MemoryMsg` when their opcode is a memory op. + // + // We also count the number of `remove` calls and assert it matches the expected total at + // the end. Without this, a bug that stopped the emitter entirely would pass vacuously: + // the request-opcode loop iterates the trace, so no memory rows → no expectations → + // trivial subset match. + let mut request_exps_added = 0usize; + for row in 0..main.num_rows() { + let idx = RowIndex::from(row); + let ctx = main.ctx(idx); + let clk = main.clk(idx); + let next = RowIndex::from(row + 1); + let op = main.get_op_code(idx).as_canonical_u64(); + if op == opcodes::MLOAD as u64 { + let addr = main.stack_element(0, idx); + let value = main.stack_element(0, next); + exp.remove(row, &MemoryMsg::read_element(ctx, addr, clk, value)); + request_exps_added += 1; + } else if op == opcodes::MSTORE as u64 { + let addr = main.stack_element(0, idx); + let value = main.stack_element(1, idx); + exp.remove(row, &MemoryMsg::write_element(ctx, addr, clk, value)); + request_exps_added += 1; + } else if op == opcodes::MLOADW as u64 { + let addr = main.stack_element(0, idx); + let word = next_word(main, next, 0); + exp.remove(row, &MemoryMsg::read_word(ctx, addr, clk, word)); + request_exps_added += 1; + } else if op == opcodes::MSTOREW as u64 { + let addr = main.stack_element(0, idx); + let word = [ + main.stack_element(1, idx), + main.stack_element(2, idx), + main.stack_element(3, idx), + main.stack_element(4, idx), + ]; + exp.remove(row, &MemoryMsg::write_word(ctx, addr, clk, word)); + request_exps_added += 1; + } else if op == opcodes::MSTREAM as u64 { + let base = main.stack_element(12, idx); + let word0 = next_word(main, next, 0); + let word1 = next_word(main, next, 4); + exp.remove(row, &MemoryMsg::read_word(ctx, base, clk, word0)); + exp.remove(row, &MemoryMsg::read_word(ctx, base + FOUR, clk, word1)); + request_exps_added += 2; + } } - - // The next memory request from the stack is sent when `MLoad` is executed at cycle 6 and - // included at row 7 - let value = build_expected_bus_element_msg( - &challenges, - MEMORY_READ_ELEMENT_LABEL, - ZERO, - ZERO, - Felt::new(6), - word[0], - ); - expected *= value.inverse(); - assert_eq!(expected, b_chip[7]); - - // Nothing changes until the next memory request from the stack: `MLoadW` executed at cycle 8 - // and included at row 9. - let value = build_expected_bus_word_msg( - &challenges, - MEMORY_READ_WORD_LABEL, - ZERO, - ZERO, - Felt::new(8), - word.into(), - ); - expected *= value.inverse(); - assert_eq!(expected, b_chip[9]); - - // Nothing changes until the next memory request from the stack. - assert_eq!(expected, b_chip[10]); - - // At cycle 11, `MStore` is requested by the stack and included at row 12. - let value = build_expected_bus_element_msg( - &challenges, - MEMORY_WRITE_ELEMENT_LABEL, - ZERO, - FOUR, - Felt::new(11), - ONE, - ); - expected *= value.inverse(); - assert_eq!(expected, b_chip[12]); - - // Nothing changes until the next memory request from the stack. - assert_eq!(expected, b_chip[13]); - - // At cycle 13, `MStream` is requested by the stack, and the second read of `MStream` is - // requested for inclusion at row 14. - let value1 = build_expected_bus_word_msg( - &challenges, - MEMORY_READ_WORD_LABEL, - ZERO, - ZERO, - Felt::new(13), - word.into(), - ); - let value2 = build_expected_bus_word_msg( - &challenges, - MEMORY_READ_WORD_LABEL, - ZERO, - Felt::new(4), - Felt::new(13), - [ONE, ZERO, ZERO, ZERO].into(), - ); - expected *= (value1 * value2).inverse(); - assert_eq!(expected, b_chip[14]); - - // At cycle 14 the decoder requests the span hash. Capture the multiplicand; the hasher responds - // at the end of its cycle (row HASH_CYCLE_LEN). - assert_ne!(expected, b_chip[15]); - let span_request_mult = b_chip[15] * expected.inverse(); - expected = b_chip[15]; - - // Nothing changes until the hasher provides the span hash result at the end of the hash cycle. - for row in 16..HASH_CYCLE_LEN { - assert_eq!(expected, b_chip[row]); + // 5 stack opcodes (MStoreW, MLoad, MLoadW, MStore, MStream) + 1 extra for MStream's 2nd read. + assert_eq!(request_exps_added, 6, "expected 6 memory request expectations"); + + // ---- Response side: every memory chiplet row emits `+1 × MemoryResponseMsg`. + let mut mem_rows_seen = 0usize; + for row in 0..main.num_rows() { + let idx = RowIndex::from(row); + if !main.is_memory_row(idx) { + continue; + } + mem_rows_seen += 1; + + let is_read = main.get(idx, MEMORY_IS_READ_COL_IDX); + let is_word = main.get(idx, MEMORY_IS_WORD_ACCESS_COL_IDX); + let mem_ctx = main.chiplet_memory_ctx(idx); + let word_addr = main.chiplet_memory_word(idx); + let idx0 = main.chiplet_memory_idx0(idx); + let idx1 = main.chiplet_memory_idx1(idx); + let addr = word_addr + idx1.double() + idx0; + let mem_clk = main.chiplet_memory_clk(idx); + let word = [ + main.chiplet_memory_value_0(idx), + main.chiplet_memory_value_1(idx), + main.chiplet_memory_value_2(idx), + main.chiplet_memory_value_3(idx), + ]; + // `element` is ignored by `MemoryResponseMsg::encode` when `is_word = 1`, so on + // word-access rows the fallback `ZERO` is harmless. `element_idx` uses `u64` + // arithmetic (native `usize` indexing) while `addr` above uses felt arithmetic — + // same math, different domain required by the consumer. + let element = if is_word == ZERO { + let element_idx = (idx1.as_canonical_u64() * 2 + idx0.as_canonical_u64()) as usize; + word[element_idx] + } else { + ZERO + }; + + exp.add( + row, + &MemoryResponseMsg { + is_read, + ctx: mem_ctx, + addr, + clk: mem_clk, + is_word, + element, + word, + }, + ); } + // 6 memory operations: MStoreW, MLoad, MLoadW, MStore, MStream (2 rows). + assert_eq!(mem_rows_seen, 6, "expected 6 memory chiplet rows"); - let memory_start = HASH_CYCLE_LEN; - assert_ne!(expected, b_chip[memory_start]); - let span_response_mult = b_chip[memory_start] * b_chip[LAST_CYCLE_ROW].inverse(); - assert_eq!(span_request_mult * span_response_mult, ONE); - expected *= span_response_mult; - assert_eq!(expected, b_chip[memory_start]); - - // Memory responses are provided during the memory segment after the hash cycle. There will be 6 - // rows, corresponding to the 5 memory operations (MStream requires 2 rows). - - // At cycle 8 `MLoadW` was requested by the stack; `MStoreW` is provided by memory here. - expected *= build_expected_bus_msg_from_trace(&trace, &challenges, memory_start.into()); - assert_eq!(expected, b_chip[memory_start + 1]); - - // At cycle 9, `MLoad` is provided by memory. - expected *= build_expected_bus_msg_from_trace(&trace, &challenges, (memory_start + 1).into()); - assert_eq!(expected, b_chip[memory_start + 2]); - - // At cycle 10, `MLoadW` is provided by memory. - expected *= build_expected_bus_msg_from_trace(&trace, &challenges, (memory_start + 2).into()); - assert_eq!(expected, b_chip[memory_start + 3]); - - // At cycle 11, `MStore` is provided by the memory. - expected *= build_expected_bus_msg_from_trace(&trace, &challenges, (memory_start + 3).into()); - assert_eq!(expected, b_chip[memory_start + 4]); - - // At cycle 12, the first read of `MStream` is provided by the memory. - expected *= build_expected_bus_msg_from_trace(&trace, &challenges, (memory_start + 4).into()); - assert_eq!(expected, b_chip[memory_start + 5]); - - // At cycle 13, the second read of `MStream` is provided by the memory. - expected *= build_expected_bus_msg_from_trace(&trace, &challenges, (memory_start + 5).into()); - assert_eq!(expected, b_chip[memory_start + 6]); - - // The value in b_chip should be ONE now and for the rest of the trace. - for row in (memory_start + 6)..trace.length() { - assert_eq!(ONE, b_chip[row]); - } + log.assert_contains(&exp); } +/// Verifies that `CryptoStream`'s four memory requests land on the chiplet-requests bus +/// as the exact read+read+write+write pattern, using hand-coded expected values +/// (ciphertext = plaintext + rate) rather than values read back from the trace — a missing +/// emission, a wrong opcode label, or a swapped addr/clk would all fail the subset match. #[test] -fn crypto_stream_missing_chiplets_bus_requests() { - // `crypto_stream` stack layout: [rate(8), cap(4), src_ptr, dst_ptr, ...] +fn cryptostream_emits_four_memory_requests() { + // `crypto_stream` stack layout: [rate(8), cap(4), src_ptr, dst_ptr, pad, pad] let stack = [ 1, 2, 3, 4, 5, 6, 7, 8, // rate(8) 0, 0, 0, 0, // cap(4) 0, // src_ptr 8, // dst_ptr - 0, 0, // unused + 0, 0, // pad ]; let trace = build_trace_from_ops(vec![Operation::CryptoStream], &stack); - let rand_challenges = rand_array::(); - let aux_columns = trace.build_aux_trace(&rand_challenges).unwrap(); - let b_chip = aux_columns.get_column(CHIPLETS_BUS_AUX_TRACE_OFFSET); - let challenges = Challenges::::new(rand_challenges[0], rand_challenges[1]); - - // --- Assert exact bus requests for the four CryptoStream memory operations. --- - - // CryptoStream with src_ptr=0, dst_ptr=8, rate=[1..8], and uninitialized (zero) memory: - // - reads word at addr 0: plaintext = [0, 0, 0, 0] - // - reads word at addr 4: plaintext = [0, 0, 0, 0] - // - writes word at addr 8: ciphertext = plaintext + rate = [1, 2, 3, 4] - // - writes word at addr 12: ciphertext = [5, 6, 7, 8] - let ctx = ZERO; - let clk = ONE; // CryptoStream executes at cycle 1 (cycle 0 is SPAN) - - let read1 = build_expected_bus_word_msg( - &challenges, - MEMORY_READ_WORD_LABEL, - ctx, - ZERO, // src_ptr = 0 - clk, - [ZERO, ZERO, ZERO, ZERO].into(), - ); - let read2 = build_expected_bus_word_msg( - &challenges, - MEMORY_READ_WORD_LABEL, - ctx, - Felt::new(4), // src_ptr + 4 - clk, - [ZERO, ZERO, ZERO, ZERO].into(), - ); - let write1 = build_expected_bus_word_msg( - &challenges, - MEMORY_WRITE_WORD_LABEL, - ctx, - Felt::new(8), // dst_ptr = 8 - clk, - [ONE, Felt::new(2), Felt::new(3), Felt::new(4)].into(), - ); - let write2 = build_expected_bus_word_msg( - &challenges, - MEMORY_WRITE_WORD_LABEL, - ctx, - Felt::new(12), // dst_ptr + 4 - clk, - [Felt::new(5), Felt::new(6), Felt::new(7), Felt::new(8)].into(), - ); - - // All four requests are emitted at the same cycle, so they multiply together. - let combined_request = (read1 * read2 * write1 * write2).inverse(); - - // b_chip[0] and b_chip[1] should be ONE (span hash init at cycle 0). - assert_eq!(ONE, b_chip[0]); - assert_eq!(ONE, b_chip[1]); - - // At cycle 1, CryptoStream issues 4 memory requests; included at row 2. - assert_eq!(combined_request, b_chip[2]); + let log = InteractionLog::new(&trace); + + let mut exp = Expectations::new(&log); + + // CryptoStream runs at cycle 1 (cycle 0 is SPAN), ctx = 0, uninitialized source memory + // (reads return zeros). Ciphertext = plaintext + rate = rate in this case. + const ROW: usize = 1; + let zero_word = [ZERO, ZERO, ZERO, ZERO]; + let cipher1 = [ + Felt::new_unchecked(1), + Felt::new_unchecked(2), + Felt::new_unchecked(3), + Felt::new_unchecked(4), + ]; + let cipher2 = [ + Felt::new_unchecked(5), + Felt::new_unchecked(6), + Felt::new_unchecked(7), + Felt::new_unchecked(8), + ]; - // The chiplets bus should be balanced: final value must be ONE. - assert_eq!(*b_chip.last().unwrap(), ONE); + let mut request_exps_added = 0usize; + // read src_ptr, read src_ptr + 4 + exp.remove(ROW, &MemoryMsg::read_word(ZERO, ZERO, ONE, zero_word)); + request_exps_added += 1; + exp.remove(ROW, &MemoryMsg::read_word(ZERO, FOUR, ONE, zero_word)); + request_exps_added += 1; + // write dst_ptr, write dst_ptr + 4 + exp.remove(ROW, &MemoryMsg::write_word(ZERO, Felt::new_unchecked(8), ONE, cipher1)); + request_exps_added += 1; + exp.remove(ROW, &MemoryMsg::write_word(ZERO, Felt::new_unchecked(12), ONE, cipher2)); + request_exps_added += 1; + + assert_eq!(request_exps_added, 4, "expected 4 CryptoStream request expectations"); + + log.assert_contains(&exp); } -// TEST HELPERS -// ================================================================================================ +/// Verifies that `HornerBase`'s two element-reads land on the chiplet-requests bus. +/// HornerBase reads α = (α₀, α₁) from memory at (`alpha_ptr`, `alpha_ptr + 1`); +/// uninitialized memory returns zeros, and the trace stores those same zeros into +/// helpers[0..2], so a missing request or a swapped addr/clk would fail the subset match. +#[test] +fn hornerbase_emits_two_memory_requests() { + // HornerBase stack layout: [c0..c7, _, _, _, _, _, alpha_ptr, acc_low, acc_high] + let stack = [ + 1, 2, 3, 4, 5, 6, 7, 8, // coeffs[0..8] + 0, 0, 0, 0, 0, // pad (5 slots) + 0, // alpha_ptr (stack[13]) + 0, 0, // acc_low, acc_high + ]; -fn build_expected_bus_element_msg( - challenges: &Challenges, - op_label: u8, - ctx: Felt, - addr: Felt, - clk: Felt, - value: Felt, -) -> Felt { - assert!(op_label == MEMORY_READ_ELEMENT_LABEL || op_label == MEMORY_WRITE_ELEMENT_LABEL); + let trace = build_trace_from_ops(vec![Operation::HornerBase], &stack); + let log = InteractionLog::new(&trace); - challenges.encode([Felt::from_u8(op_label), ctx, addr, clk, value]) -} + let mut exp = Expectations::new(&log); -fn build_expected_bus_word_msg( - challenges: &Challenges, - op_label: u8, - ctx: Felt, - addr: Felt, - clk: Felt, - word: Word, -) -> Felt { - assert!(op_label == MEMORY_READ_WORD_LABEL || op_label == MEMORY_WRITE_WORD_LABEL); + // HornerBase runs at cycle 1 (cycle 0 is SPAN), ctx = 0, uninitialized memory returns zeros. + const ROW: usize = 1; + exp.remove(ROW, &MemoryMsg::read_element(ZERO, ZERO, ONE, ZERO)); + exp.remove(ROW, &MemoryMsg::read_element(ZERO, ONE, ONE, ZERO)); - challenges.encode([Felt::from_u8(op_label), ctx, addr, clk, word[0], word[1], word[2], word[3]]) + log.assert_contains(&exp); } -fn build_expected_bus_msg_from_trace( - trace: &ExecutionTrace, - challenges: &Challenges, - row: RowIndex, -) -> Felt { - // get the memory access operation - let read_write = trace.main_trace.get_column(MEMORY_IS_READ_COL_IDX)[row]; - let element_or_word = trace.main_trace.get_column(MEMORY_IS_WORD_ACCESS_COL_IDX)[row]; - let op_label = if read_write == MEMORY_WRITE { - if element_or_word == MEMORY_ACCESS_ELEMENT { - MEMORY_WRITE_ELEMENT_LABEL - } else { - MEMORY_WRITE_WORD_LABEL - } - } else if read_write == MEMORY_READ { - if element_or_word == MEMORY_ACCESS_ELEMENT { - MEMORY_READ_ELEMENT_LABEL - } else { - MEMORY_READ_WORD_LABEL - } - } else { - panic!("invalid read_write value: {read_write}"); - }; +/// Verifies that `HornerExt`'s single word-read lands on the chiplet-requests bus. +/// HornerExt reads `[α₀, α₁, k₀, k₁]` as a single word from `alpha_ptr`; +/// uninitialized memory returns the zero word, which the trace parks in helpers[0..4]. +#[test] +fn hornerext_emits_one_memory_request() { + // HornerExt stack layout: [s0_lo, s0_hi, ..., s3_lo, s3_hi, _, _, _, _, _, alpha_ptr, + // acc_low, acc_high] + let stack = [ + 1, 2, 3, 4, 5, 6, 7, 8, // 4 extension coeffs (s0..s3) + 0, 0, 0, 0, 0, // pad (5 slots) + 0, // alpha_ptr (stack[13]) + 0, 0, // acc_low, acc_high + ]; - // get the memory access data - let ctx = trace.main_trace.get_column(MEMORY_CTX_COL_IDX)[row]; - let addr = { - let word = trace.main_trace.get_column(MEMORY_WORD_COL_IDX)[row]; - let idx1 = trace.main_trace.get_column(MEMORY_IDX1_COL_IDX)[row]; - let idx0 = trace.main_trace.get_column(MEMORY_IDX0_COL_IDX)[row]; + let trace = build_trace_from_ops(vec![Operation::HornerExt], &stack); + let log = InteractionLog::new(&trace); - word + idx1.double() + idx0 - }; - let clk = trace.main_trace.get_column(MEMORY_CLK_COL_IDX)[row]; + let mut exp = Expectations::new(&log); - // get the memory value - let mut word = [ZERO; WORD_SIZE]; - for (i, element) in word.iter_mut().enumerate() { - *element = trace.main_trace.get_column(MEMORY_V_COL_RANGE.start + i)[row]; - } + const ROW: usize = 1; + let zero_word = [ZERO, ZERO, ZERO, ZERO]; + exp.remove(ROW, &MemoryMsg::read_word(ZERO, ZERO, ONE, zero_word)); - if element_or_word == MEMORY_ACCESS_ELEMENT { - let idx1 = trace.main_trace.get_column(MEMORY_IDX1_COL_IDX)[row].as_canonical_u64(); - let idx0 = trace.main_trace.get_column(MEMORY_IDX0_COL_IDX)[row].as_canonical_u64(); - let idx = idx1 * 2 + idx0; + log.assert_contains(&exp); +} - build_expected_bus_element_msg(challenges, op_label, ctx, addr, clk, word[idx as usize]) - } else if element_or_word == MEMORY_ACCESS_WORD { - build_expected_bus_word_msg(challenges, op_label, ctx, addr, clk, word.into()) - } else { - panic!("invalid element_or_word value: {element_or_word}"); - } +fn next_word(main: &MainTrace, next: RowIndex, start: usize) -> [Felt; 4] { + [ + main.stack_element(start, next), + main.stack_element(start + 1, next), + main.stack_element(start + 2, next), + main.stack_element(start + 3, next), + ] } diff --git a/processor/src/trace/tests/chiplets/mod.rs b/processor/src/trace/tests/chiplets/mod.rs index 39abd71328..10283dc1d4 100644 --- a/processor/src/trace/tests/chiplets/mod.rs +++ b/processor/src/trace/tests/chiplets/mod.rs @@ -1,15 +1,14 @@ -use miden_air::trace::{ - AUX_TRACE_RAND_CHALLENGES, CHIPLETS_BUS_AUX_TRACE_OFFSET, - chiplets::hasher::{HASH_CYCLE_LEN, LAST_CYCLE_ROW}, -}; -use miden_core::{ONE, Word, ZERO, operations::Operation}; -use miden_utils_testing::rand::rand_value; - -use super::{ - super::utils::build_span_with_respan_ops, AdviceInputs, ExecutionTrace, Felt, - build_trace_from_ops, build_trace_from_ops_with_inputs, build_trace_from_program, - init_state_from_words, rand_array, -}; +//! Chiplet-bus tests (bitwise, hasher, memory). +//! +//! Each submodule drives a small program against the relevant chiplet and asserts that every +//! chiplet-request (`-1` push) the constraints expect, and every chiplet-response (`+1` push) +//! the chiplet emits, shows up in the prover's `(mult, denom)` bag at the right row. The +//! subset matcher in [`super::lookup_harness`] is column-blind, so a test passes regardless +//! of which aux column the framework routes a given bus message onto. +//! +//! Tests pair the subset match with explicit cardinality guardrails (e.g. "exactly 2 HOUT +//! adds") so a silent-pass bug — extra emissions, missing emissions, or the matcher ignoring +//! a whole category — fails structurally rather than just by shape. mod bitwise; mod hasher; diff --git a/processor/src/trace/tests/decoder.rs b/processor/src/trace/tests/decoder.rs index ab6276adfb..9359871bc5 100644 --- a/processor/src/trace/tests/decoder.rs +++ b/processor/src/trace/tests/decoder.rs @@ -1,936 +1,936 @@ -use alloc::vec::Vec; +//! Decoder virtual-table bus tests. +//! +//! Covers the block-stack table (merged with u32 range checks and the log-precompile +//! capacity bus) and the block-hash + op-group table column. +//! +//! Under the LogUp framework the interactions look like "+1 / encode(Msg)" on push rows +//! and "-1 / encode(Msg)" on pop rows. Each test runs a tiny program that exercises one +//! push/pop pair (or a small batch) and checks both halves land via the subset matcher. +//! +//! Coverage is targeted rather than exhaustive: the tests below hit the control-flow variants +//! prone to off-by-one or selector-muxing bugs (JOIN, LOOP+REPEAT, CALL, SPAN/RESPAN op-group +//! batching). Broader end-to-end soundness comes from +//! `build_lookup_fractions_matches_constraint_path_oracle` in `tests/lookup.rs`. -use miden_air::trace::{ - AUX_TRACE_RAND_CHALLENGES, Challenges, - chiplets::hasher::HASH_CYCLE_LEN_FELT, - decoder::{P1_COL_IDX, P2_COL_IDX, P3_COL_IDX}, -}; -use miden_utils_testing::rand::rand_array; +use alloc::vec::Vec; -use super::super::{ - decoder::{BlockHashTableRow, build_op_group}, - tests::{build_trace_from_ops, build_trace_from_program}, - utils::build_span_with_respan_ops, -}; -use crate::{ - ContextId, Felt, ONE, Program, Word, ZERO, - field::{ExtensionField, Field}, +use miden_air::logup::{BlockHashMsg, BlockStackMsg, OpGroupMsg}; +use miden_core::{ + Felt, ONE, ZERO, mast::{ - BasicBlockNodeBuilder, JoinNodeBuilder, LoopNodeBuilder, MastForest, MastForestContributor, - MastNodeExt, SplitNodeBuilder, + BasicBlockNodeBuilder, CallNodeBuilder, JoinNodeBuilder, LoopNodeBuilder, MastForest, + MastForestContributor, MastNodeExt, SplitNodeBuilder, }, - operation::Operation, + operations::{Operation, opcodes}, + program::Program, +}; + +use super::{ + ExecutionTrace, build_trace_from_ops, build_trace_from_program, + build_trace_from_program_with_stack, + lookup_harness::{Expectations, InteractionLog}, }; +use crate::{RowIndex, StackInputs, trace::MainTrace}; -// BLOCK STACK TABLE TESTS +// HELPERS // ================================================================================================ -#[test] -#[expect(clippy::needless_range_loop)] -fn decoder_p1_span_with_respan() { - let (ops, _) = build_span_with_respan_ops(); - let trace = build_trace_from_ops(ops, &[]); - let challenges = rand_array::(); - let aux_columns = trace.build_aux_trace(&challenges).unwrap(); - let p1 = aux_columns.get_column(P1_COL_IDX); - - let challenges = Challenges::::new(challenges[0], challenges[1]); - let row_values = [ - BlockStackTableRow::new(ONE, ZERO, false).to_value(&challenges), - BlockStackTableRow::new(ONE + HASH_CYCLE_LEN_FELT, ZERO, false).to_value(&challenges), - ]; - - // make sure the first entry is ONE - assert_eq!(ONE, p1[0]); - - // when SPAN operation is executed, entry for span block is added to the table - let expected_value = row_values[0]; - assert_eq!(expected_value, p1[1]); - - // for the next 8 cycles (as we execute user ops), the table is not affected - for i in 2..10 { - assert_eq!(expected_value, p1[i]); +/// Mirrors the `is_first_child = 1 - end_next - repeat_next - respan_next - halt_next` +/// arithmetic from the END-overlay constraint. Since END/REPEAT/RESPAN/HALT are distinct +/// 7-bit opcodes, at most one term is non-zero per row, so the arithmetic form collapses to +/// the trace-level OR — but we encode it arithmetically to mirror the constraint expression. +fn next_op_first_child_flag(main: &MainTrace, next: RowIndex) -> Felt { + let op_next = main.get_op_code(next); + let is = |code: u8| if op_next == Felt::from_u8(code) { ONE } else { ZERO }; + ONE - is(opcodes::END) - is(opcodes::REPEAT) - is(opcodes::RESPAN) - is(opcodes::HALT) +} + +/// Calls `f(row, opcode)` for every row except the last. +/// +/// Most decoder tests need `row + 1` lookups (next-row flags, addr_next, etc.) so stopping one +/// short of the end avoids per-test bounds checks. +fn for_each_op(trace: &ExecutionTrace, mut f: F) +where + F: FnMut(usize, Felt), +{ + let main = trace.main_trace(); + let num_rows = main.num_rows(); + for row in 0..num_rows - 1 { + let idx = RowIndex::from(row); + f(row, main.get_op_code(idx)); } +} - // when RESPAN is executed, the first entry is replaced with a new entry - let expected_value = expected_value * row_values[0].inverse() * row_values[1]; - assert_eq!(expected_value, p1[10]); +// BLOCK STACK TABLE (M1) TESTS +// ================================================================================================ - // for the next 11 cycles (as we execute user ops), the table is not affected - for i in 11..22 { - assert_eq!(expected_value, p1[i]); - } +/// A lone SPAN pushes one simple entry and the matching END pops it. +#[test] +fn block_stack_span_push_pop() { + let ops = vec![Operation::Add, Operation::Mul]; + let trace = build_trace_from_ops(ops, &[]); + let log = InteractionLog::new(&trace); + let main = trace.main_trace(); + + let mut exp = Expectations::new(&log); + for_each_op(&trace, |row, op| { + let idx = RowIndex::from(row); + let addr = main.addr(idx); + let addr_next = main.addr(RowIndex::from(row + 1)); + + if op == Felt::from_u8(opcodes::SPAN) { + exp.add( + row, + &BlockStackMsg::Simple { + block_id: addr_next, + parent_id: addr, + is_loop: ZERO, + }, + ); + } else if op == Felt::from_u8(opcodes::END) { + exp.remove( + row, + &BlockStackMsg::Simple { + block_id: addr, + parent_id: addr_next, + is_loop: ZERO, + }, + ); + } + }); - // at cycle 22, the END operation is executed and the table is cleared - let expected_value = expected_value * row_values[1].inverse(); - assert_eq!(expected_value, ONE); - for i in 22..(p1.len()) { - assert_eq!(ONE, p1[i]); - } + assert_eq!(exp.count_adds(), 1, "expected exactly one SPAN push"); + assert_eq!(exp.count_removes(), 1, "expected exactly one matching END pop"); + log.assert_contains(&exp); } +/// CALL pushes a `Full` entry saving caller context (ctx, fmp, depth, fn_hash); the matching +/// END pops a `Full` entry reading the *next* row's system/stack state (the restored caller +/// context). #[test] -#[expect(clippy::needless_range_loop)] -fn decoder_p1_join() { +fn block_stack_call_full_push_pop() { let program = { - let mut mast_forest = MastForest::new(); - - let basic_block_1_id = BasicBlockNodeBuilder::new(vec![Operation::Mul], Vec::new()) - .add_to_forest(&mut mast_forest) - .unwrap(); - let basic_block_2_id = BasicBlockNodeBuilder::new(vec![Operation::Add], Vec::new()) - .add_to_forest(&mut mast_forest) - .unwrap(); - let join_id = JoinNodeBuilder::new([basic_block_1_id, basic_block_2_id]) - .add_to_forest(&mut mast_forest) + let mut forest = MastForest::new(); + let callee = BasicBlockNodeBuilder::new(vec![Operation::Noop], Vec::new()) + .add_to_forest(&mut forest) .unwrap(); - mast_forest.make_root(join_id); - - Program::new(mast_forest.into(), join_id) + let call_id = CallNodeBuilder::new(callee).add_to_forest(&mut forest).unwrap(); + forest.make_root(call_id); + Program::new(forest.into(), call_id) }; - let trace = build_trace_from_program(&program, &[]); - let challenges = rand_array::(); - let aux_columns = trace.build_aux_trace(&challenges).unwrap(); - let p1 = aux_columns.get_column(P1_COL_IDX); - - let challenges = Challenges::::new(challenges[0], challenges[1]); - let a_33 = ONE + HASH_CYCLE_LEN_FELT; - let a_65 = a_33 + HASH_CYCLE_LEN_FELT; - let row_values = [ - BlockStackTableRow::new(ONE, ZERO, false).to_value(&challenges), - BlockStackTableRow::new(a_33, ONE, false).to_value(&challenges), - BlockStackTableRow::new(a_65, ONE, false).to_value(&challenges), - ]; - - // make sure the first entry is ONE - assert_eq!(ONE, p1[0]); - - // when JOIN operation is executed, entry for the JOIN block is added to the table - let mut expected_value = row_values[0]; - assert_eq!(expected_value, p1[1]); - - // when the first SPAN is executed, its entry is added to the table - expected_value *= row_values[1]; - assert_eq!(expected_value, p1[2]); - - // when the user op is executed, the table is not affected - assert_eq!(expected_value, p1[3]); - - // when the first SPAN block ends, its entry is removed from the table - expected_value *= row_values[1].inverse(); - assert_eq!(expected_value, p1[4]); - - // when the second SPAN is executed, its entry is added to the table - expected_value *= row_values[2]; - assert_eq!(expected_value, p1[5]); - - // when the user op is executed, the table is not affected - assert_eq!(expected_value, p1[6]); - - // when the second SPAN block ends, its entry is removed from the table - expected_value *= row_values[2].inverse(); - assert_eq!(expected_value, p1[7]); - - // when the JOIN block ends, its entry is removed from the table - expected_value *= row_values[0].inverse(); - assert_eq!(expected_value, p1[8]); - - // at this point the table should be empty, and thus, all subsequent values must be ONE - assert_eq!(expected_value, ONE); - for i in 9..(p1.len()) { - assert_eq!(ONE, p1[i]); - } + let log = InteractionLog::new(&trace); + let main = trace.main_trace(); + + let mut exp = Expectations::new(&log); + for_each_op(&trace, |row, op| { + let idx = RowIndex::from(row); + let next = RowIndex::from(row + 1); + + if op == Felt::from_u8(opcodes::CALL) { + exp.add( + row, + &BlockStackMsg::Full { + block_id: main.addr(next), + parent_id: main.addr(idx), + is_loop: ZERO, + ctx: main.ctx(idx), + fmp: main.stack_depth(idx), + depth: main.parent_overflow_address(idx), + fn_hash: main.fn_hash(idx), + }, + ); + } + + // END-of-CALL branch: `is_call_flag` at the END row selects the Full variant. Caller + // context is restored on the *next* row, so the emitter reads ctx/b0/b1/fn_hash from + // row+1. + if op == Felt::from_u8(opcodes::END) && main.is_call_flag(idx) == ONE { + exp.remove( + row, + &BlockStackMsg::Full { + block_id: main.addr(idx), + parent_id: main.addr(next), + is_loop: ZERO, + ctx: main.ctx(next), + fmp: main.stack_depth(next), + depth: main.parent_overflow_address(next), + fn_hash: main.fn_hash(next), + }, + ); + } + }); + + assert_eq!(exp.count_adds(), 1, "expected exactly one CALL push"); + assert_eq!(exp.count_removes(), 1, "expected exactly one matching END pop"); + log.assert_contains(&exp); } -#[test] -#[expect(clippy::needless_range_loop)] -fn decoder_p1_split() { +/// SPLIT pushes a `Simple { is_loop: 0 }` entry (parent = current block, block = addr_next) and +/// the matching END pops it. Runs twice — once with `s0 = 1` (TRUE branch), once with `s0 = 0` +/// (FALSE branch) — since the block-stack emission is identical either way but the END reached +/// for the matching pop differs between branches. +#[rstest::rstest] +#[case::taken(1)] +#[case::not_taken(0)] +fn block_stack_split_push_pop(#[case] cond: u64) { let program = { - let mut mast_forest = MastForest::new(); - - let basic_block_1_id = BasicBlockNodeBuilder::new(vec![Operation::Mul], Vec::new()) - .add_to_forest(&mut mast_forest) - .unwrap(); - let basic_block_2_id = BasicBlockNodeBuilder::new(vec![Operation::Add], Vec::new()) - .add_to_forest(&mut mast_forest) + let mut f = MastForest::new(); + let t = BasicBlockNodeBuilder::new(vec![Operation::Add], Vec::new()) + .add_to_forest(&mut f) .unwrap(); - let split_id = SplitNodeBuilder::new([basic_block_1_id, basic_block_2_id]) - .add_to_forest(&mut mast_forest) + let e = BasicBlockNodeBuilder::new(vec![Operation::Mul], Vec::new()) + .add_to_forest(&mut f) .unwrap(); - mast_forest.make_root(split_id); - - Program::new(mast_forest.into(), split_id) + let s = SplitNodeBuilder::new([t, e]).add_to_forest(&mut f).unwrap(); + f.make_root(s); + Program::new(f.into(), s) }; + let trace = build_trace_from_program(&program, &[cond]); + let log = InteractionLog::new(&trace); + let main = trace.main_trace(); + + let mut split_adds = 0usize; + let mut exp = Expectations::new(&log); + for_each_op(&trace, |row, op| { + let idx = RowIndex::from(row); + let addr = main.addr(idx); + let addr_next = main.addr(RowIndex::from(row + 1)); + + if op == Felt::from_u8(opcodes::SPLIT) { + exp.add( + row, + &BlockStackMsg::Simple { + block_id: addr_next, + parent_id: addr, + is_loop: ZERO, + }, + ); + split_adds += 1; + } else if op == Felt::from_u8(opcodes::END) && main.is_call_flag(idx) == ZERO { + // is_loop on the END overlay comes from the typed END flags; for non-loop ENDs it + // is zero. We can read it back from the trace to stay agnostic about which END row + // matches which push. + let is_loop = main.is_loop_flag(idx); + exp.remove( + row, + &BlockStackMsg::Simple { + block_id: addr, + parent_id: addr_next, + is_loop, + }, + ); + } + }); - let trace = build_trace_from_program(&program, &[1]); - let challenges = rand_array::(); - let aux_columns = trace.build_aux_trace(&challenges).unwrap(); - let p1 = aux_columns.get_column(P1_COL_IDX); - - let challenges = Challenges::::new(challenges[0], challenges[1]); - let a_33 = ONE + HASH_CYCLE_LEN_FELT; - let row_values = [ - BlockStackTableRow::new(ONE, ZERO, false).to_value(&challenges), - BlockStackTableRow::new(a_33, ONE, false).to_value(&challenges), - ]; - - // make sure the first entry is ONE - assert_eq!(ONE, p1[0]); - - // when SPLIT operation is executed, entry for the SPLIT block is added to the table - let mut expected_value = row_values[0]; - assert_eq!(expected_value, p1[1]); - - // when the true branch SPAN is executed, its entry is added to the table - expected_value *= row_values[1]; - assert_eq!(expected_value, p1[2]); - - // when the user op is executed, the table is not affected - assert_eq!(expected_value, p1[3]); - - // when the SPAN block ends, its entry is removed from the table - expected_value *= row_values[1].inverse(); - assert_eq!(expected_value, p1[4]); - - // when the SPLIT block ends, its entry is removed from the table - expected_value *= row_values[0].inverse(); - assert_eq!(expected_value, p1[5]); - - // at this point the table should be empty, and thus, all subsequent values must be ONE - assert_eq!(expected_value, ONE); - for i in 6..(p1.len()) { - assert_eq!(ONE, p1[i]); - } + assert_eq!(split_adds, 1, "expected exactly one SPLIT push"); + // One END for the taken inner branch, one for the SPLIT itself (parent). Both pop Simple. + assert_eq!(exp.count_removes(), 2, "expected two Simple pops (child END + SPLIT END)"); + log.assert_contains(&exp); } -#[test] -#[expect(clippy::needless_range_loop)] -fn decoder_p1_loop_with_repeat() { +/// LOOP with `s0 = 1` pushes a `Simple { is_loop: 1 }` entry and the matching END pops it. +/// LOOP with `s0 = 0` also pushes (emitter is unconditional on LOOP), but with `is_loop = 0` +/// and no body executes — the END on the very next row pops immediately. This test runs both +/// variants via `rstest`. +#[rstest::rstest] +#[case::enters(1, ONE)] +#[case::skips(0, ZERO)] +fn block_stack_loop_is_loop_flag(#[case] cond: u64, #[case] expected_is_loop: Felt) { let program = { - let mut mast_forest = MastForest::new(); - - let basic_block_1_id = BasicBlockNodeBuilder::new(vec![Operation::Pad], Vec::new()) - .add_to_forest(&mut mast_forest) - .unwrap(); - let basic_block_2_id = BasicBlockNodeBuilder::new(vec![Operation::Drop], Vec::new()) - .add_to_forest(&mut mast_forest) - .unwrap(); - let join_id = JoinNodeBuilder::new([basic_block_1_id, basic_block_2_id]) - .add_to_forest(&mut mast_forest) + let mut f = MastForest::new(); + let body = BasicBlockNodeBuilder::new(vec![Operation::Pad, Operation::Drop], Vec::new()) + .add_to_forest(&mut f) .unwrap(); - let loop_node_id = LoopNodeBuilder::new(join_id).add_to_forest(&mut mast_forest).unwrap(); - mast_forest.make_root(loop_node_id); - - Program::new(mast_forest.into(), loop_node_id) + let loop_id = LoopNodeBuilder::new(body).add_to_forest(&mut f).unwrap(); + f.make_root(loop_id); + Program::new(f.into(), loop_id) }; + // Stack is laid out top-first: `cond` on top (drives LOOP), trailing zero drives the + // single REPEAT/exit read when `cond == 1`. + let trace = build_trace_from_program(&program, &[cond, 0]); + let log = InteractionLog::new(&trace); + let main = trace.main_trace(); + + let mut loop_pushes = 0usize; + let mut loop_pops = 0usize; + let mut exp = Expectations::new(&log); + for_each_op(&trace, |row, op| { + let idx = RowIndex::from(row); + let addr = main.addr(idx); + let addr_next = main.addr(RowIndex::from(row + 1)); + + if op == Felt::from_u8(opcodes::LOOP) { + let is_loop = main.stack_element(0, idx); + assert_eq!(is_loop, expected_is_loop, "s0 sanity at LOOP row"); + exp.add( + row, + &BlockStackMsg::Simple { + block_id: addr_next, + parent_id: addr, + is_loop, + }, + ); + loop_pushes += 1; + } else if op == Felt::from_u8(opcodes::END) + && main.is_call_flag(idx) == ZERO + && main.is_loop_flag(idx) == expected_is_loop + && main.is_loop_body_flag(idx) == ZERO + { + exp.remove( + row, + &BlockStackMsg::Simple { + block_id: addr, + parent_id: addr_next, + is_loop: expected_is_loop, + }, + ); + loop_pops += 1; + } + }); + + assert_eq!(loop_pushes, 1, "expected one LOOP push"); + assert_eq!( + loop_pops, 1, + "expected one matching LOOP END pop (is_loop={expected_is_loop:?})" + ); + log.assert_contains(&exp); +} - // Input [1, 1, 0]: position 0 (top) = 1 (1st iteration enters) - // After Pad+Drop: position 0 = 1 (2nd iteration enters) - // After Pad+Drop: position 0 = 0 (loop exits) - let trace = build_trace_from_program(&program, &[1, 1, 0]); - let challenges = rand_array::(); - let aux_columns = trace.build_aux_trace(&challenges).unwrap(); - let p1 = aux_columns.get_column(P1_COL_IDX); - - let challenges = Challenges::::new(challenges[0], challenges[1]); - // The loop node consumes the first hasher cycle; join/span addresses follow sequentially. - let a_33 = ONE + HASH_CYCLE_LEN_FELT; // address of the JOIN block in the first iteration - let a_65 = a_33 + HASH_CYCLE_LEN_FELT; // address of the first SPAN block in the first iteration - let a_97 = a_65 + HASH_CYCLE_LEN_FELT; // address of the second SPAN block in the first iteration - let a_129 = a_97 + HASH_CYCLE_LEN_FELT; // address of the JOIN block in the second iteration - let a_161 = a_129 + HASH_CYCLE_LEN_FELT; // address of the first SPAN block in the second iteration - let a_193 = a_161 + HASH_CYCLE_LEN_FELT; // address of the second SPAN block in the second iteration - let row_values = [ - BlockStackTableRow::new(ONE, ZERO, true).to_value(&challenges), - BlockStackTableRow::new(a_33, ONE, false).to_value(&challenges), - BlockStackTableRow::new(a_65, a_33, false).to_value(&challenges), - BlockStackTableRow::new(a_97, a_33, false).to_value(&challenges), - BlockStackTableRow::new(a_129, ONE, false).to_value(&challenges), - BlockStackTableRow::new(a_161, a_129, false).to_value(&challenges), - BlockStackTableRow::new(a_193, a_129, false).to_value(&challenges), - ]; - - // make sure the first entry is ONE - assert_eq!(ONE, p1[0]); - - // --- first iteration ---------------------------------------------------- - - // when LOOP operation is executed, entry for the LOOP block is added to the table - let mut expected_value = row_values[0]; - assert_eq!(expected_value, p1[1]); - - // when JOIN operation is executed, entry for the JOIN block is added to the table - expected_value *= row_values[1]; - assert_eq!(expected_value, p1[2]); - - // when the first SPAN is executed, its entry is added to the table - expected_value *= row_values[2]; - assert_eq!(expected_value, p1[3]); - - // when the user op is executed, the table is not affected - assert_eq!(expected_value, p1[4]); - - // when the first SPAN block ends, its entry is removed from the table - expected_value *= row_values[2].inverse(); - assert_eq!(expected_value, p1[5]); - - // when the second SPAN is executed, its entry is added to the table - expected_value *= row_values[3]; - assert_eq!(expected_value, p1[6]); - - // when the user op is executed, the table is not affected - assert_eq!(expected_value, p1[7]); - - // when the second SPAN block ends, its entry is removed from the table - expected_value *= row_values[3].inverse(); - assert_eq!(expected_value, p1[8]); - - // when the JOIN block ends, its entry is removed from the table - expected_value *= row_values[1].inverse(); - assert_eq!(expected_value, p1[9]); - - // --- second iteration --------------------------------------------------- - - // when REPEAT operation is executed, the table is not affected - assert_eq!(expected_value, p1[10]); - - // when JOIN operation is executed, entry for the JOIN block is added to the table - expected_value *= row_values[4]; - assert_eq!(expected_value, p1[11]); - - // when the first SPAN is executed, its entry is added to the table - expected_value *= row_values[5]; - assert_eq!(expected_value, p1[12]); - - // when the user op is executed, the table is not affected - assert_eq!(expected_value, p1[13]); - - // when the first SPAN block ends, its entry is removed from the table - expected_value *= row_values[5].inverse(); - assert_eq!(expected_value, p1[14]); - - // when the second SPAN is executed, its entry is added to the table - expected_value *= row_values[6]; - assert_eq!(expected_value, p1[15]); - - // when the user op is executed, the table is not affected - assert_eq!(expected_value, p1[16]); - - // when the second SPAN block ends, its entry is removed from the table - expected_value *= row_values[6].inverse(); - assert_eq!(expected_value, p1[17]); - - // when the JOIN block ends, its entry is removed from the table - expected_value *= row_values[4].inverse(); - assert_eq!(expected_value, p1[18]); - - // when the LOOP block ends, its entry is removed from the table - expected_value *= row_values[0].inverse(); - assert_eq!(expected_value, p1[19]); - - // at this point the table should be empty, and thus, all subsequent values must be ONE - assert_eq!(expected_value, ONE); - for i in 20..(p1.len()) { - assert_eq!(ONE, p1[i]); - } +/// RESPAN fires a simultaneous push + pop on the block-stack bus (batch addition is recorded +/// as an Add, and the prior batch's entry is simultaneously Removed). Uses a SPAN long enough +/// to require two batches so at least one RESPAN row exists. +#[test] +fn block_stack_respan_add_and_remove() { + // 80 Noops require two batches (each batch holds up to 72 ops), so the SPAN decomposes + // into SPAN + 64 ops + RESPAN + remaining ops + END. + let ops: Vec = (0..80).map(|_| Operation::Noop).collect(); + let trace = build_trace_from_ops(ops, &[]); + let log = InteractionLog::new(&trace); + let main = trace.main_trace(); + + let mut respan_rows = 0usize; + let mut exp = Expectations::new(&log); + for_each_op(&trace, |row, op| { + if op != Felt::from_u8(opcodes::RESPAN) { + return; + } + let idx = RowIndex::from(row); + let next = RowIndex::from(row + 1); + let addr = main.addr(idx); + let addr_next = main.addr(next); + // The RESPAN emitter uses `h1_next` as the parent link for both the add and remove. + let parent = main.decoder_hasher_state_element(1, next); + + exp.add( + row, + &BlockStackMsg::Simple { + block_id: addr_next, + parent_id: parent, + is_loop: ZERO, + }, + ); + exp.remove( + row, + &BlockStackMsg::Simple { + block_id: addr, + parent_id: parent, + is_loop: ZERO, + }, + ); + respan_rows += 1; + }); + + assert!(respan_rows >= 1, "program did not produce a RESPAN row"); + assert_eq!(exp.count_adds(), respan_rows); + assert_eq!(exp.count_removes(), respan_rows); + log.assert_contains(&exp); } -// BLOCK HASH TABLE TESTS +// BLOCK HASH / OP-GROUP COLUMN TESTS // ================================================================================================ +/// A JOIN enqueues two children (first + subsequent) and the two child ENDs dequeue them. #[test] -#[expect(clippy::needless_range_loop)] -fn decoder_p2_span_with_respan() { +fn block_hash_join_enqueue_dequeue() { let program = { let mut mast_forest = MastForest::new(); - - let (ops, _) = build_span_with_respan_ops(); - let basic_block_id = BasicBlockNodeBuilder::new(ops, Vec::new()) + let bb1 = BasicBlockNodeBuilder::new(vec![Operation::Mul], Vec::new()) .add_to_forest(&mut mast_forest) .unwrap(); - mast_forest.make_root(basic_block_id); - - Program::new(mast_forest.into(), basic_block_id) + let bb2 = BasicBlockNodeBuilder::new(vec![Operation::Add], Vec::new()) + .add_to_forest(&mut mast_forest) + .unwrap(); + let join_id = JoinNodeBuilder::new([bb1, bb2]).add_to_forest(&mut mast_forest).unwrap(); + mast_forest.make_root(join_id); + Program::new(mast_forest.into(), join_id) }; let trace = build_trace_from_program(&program, &[]); - let challenges = rand_array::(); - let aux_columns = trace.build_aux_trace(&challenges).unwrap(); - let p2 = aux_columns.get_column(P2_COL_IDX); - - let challenges = Challenges::::new(challenges[0], challenges[1]); - let program_hash_msg = - BlockHashTableRow::new_test(ZERO, program.hash(), false, false).collapse(&challenges); - - // p2 starts at identity (1) - let mut expected_value = ONE; - assert_eq!(expected_value, p2[0]); + let log = InteractionLog::new(&trace); + let main = trace.main_trace(); + + let mut exp = Expectations::new(&log); + for_each_op(&trace, |row, op| { + let idx = RowIndex::from(row); + let next = RowIndex::from(row + 1); + let addr_next = main.addr(next); + let first = main.decoder_hasher_state_first_half(idx); + let h0: [Felt; 4] = [first[0], first[1], first[2], first[3]]; + let second = main.decoder_hasher_state_second_half(idx); + let h1: [Felt; 4] = [second[0], second[1], second[2], second[3]]; + + if op == Felt::from_u8(opcodes::JOIN) { + exp.add(row, &BlockHashMsg::FirstChild { parent: addr_next, child_hash: h0 }); + exp.add(row, &BlockHashMsg::Child { parent: addr_next, child_hash: h1 }); + } - // as operations inside the span execute (including RESPAN), the table is not affected - for i in 1..22 { - assert_eq!(expected_value, p2[i]); - } + if op == Felt::from_u8(opcodes::END) { + let is_first_child = next_op_first_child_flag(main, next); + let is_loop_body = main.is_loop_body_flag(idx); + exp.remove( + row, + &BlockHashMsg::End { + parent: addr_next, + child_hash: h0, + is_first_child, + is_loop_body, + }, + ); + } + }); - // at cycle 22, the END operation removes the root block hash (unmatched by any add) - expected_value *= program_hash_msg.inverse(); - for i in 22..(p2.len()) { - assert_eq!(expected_value, p2[i]); - } + // JOIN enqueues 2 children; ENDs fire for bb1, bb2, and the JOIN itself (3 total). + assert_eq!(exp.count_adds(), 2, "expected JOIN to enqueue FirstChild + Child"); + assert_eq!(exp.count_removes(), 3, "expected an END dequeue for bb1, bb2, and JOIN"); + log.assert_contains(&exp); } +/// LOOP (when `s0 = 1`) and REPEAT both enqueue a `LoopBody` entry for the body, and the END +/// at the end of each body dequeues it with `is_loop_body = 1`. Runs two iterations +/// (advice/inputs `[1, 1, 0]`) so both the LOOP and REPEAT branches fire. #[test] -#[expect(clippy::needless_range_loop)] -fn decoder_p2_join() { - let mut mast_forest = MastForest::new(); +fn block_hash_loop_body_with_repeat() { + let program = { + let mut mast_forest = MastForest::new(); + let bb1 = BasicBlockNodeBuilder::new(vec![Operation::Pad], Vec::new()) + .add_to_forest(&mut mast_forest) + .unwrap(); + let bb2 = BasicBlockNodeBuilder::new(vec![Operation::Drop], Vec::new()) + .add_to_forest(&mut mast_forest) + .unwrap(); + let join_id = JoinNodeBuilder::new([bb1, bb2]).add_to_forest(&mut mast_forest).unwrap(); + let loop_id = LoopNodeBuilder::new(join_id).add_to_forest(&mut mast_forest).unwrap(); + mast_forest.make_root(loop_id); + Program::new(mast_forest.into(), loop_id) + }; - let basic_block_1_id = BasicBlockNodeBuilder::new(vec![Operation::Mul], Vec::new()) - .add_to_forest(&mut mast_forest) - .unwrap(); - let basic_block_2_id = BasicBlockNodeBuilder::new(vec![Operation::Add], Vec::new()) - .add_to_forest(&mut mast_forest) - .unwrap(); + // Stack `[1, 1, 0]` drives two iterations: enter, repeat, exit. + let trace = build_trace_from_program(&program, &[1, 1, 0]); + let log = InteractionLog::new(&trace); + let main = trace.main_trace(); + + let mut fired_loop_body = 0usize; + let mut fired_loop_body_end = 0usize; + + let mut exp = Expectations::new(&log); + for_each_op(&trace, |row, op| { + let idx = RowIndex::from(row); + let next = RowIndex::from(row + 1); + let first = main.decoder_hasher_state_first_half(idx); + let h0: [Felt; 4] = [first[0], first[1], first[2], first[3]]; + let addr_next = main.addr(next); + + // `f_loop_body = loop_op * s0 + repeat`. LOOP with `s0 = 0` does not enter the body, so + // the body is only enqueued when `s0 = 1` (first iteration entry) or on REPEAT. + let is_loop_entering = + op == Felt::from_u8(opcodes::LOOP) && main.stack_element(0, idx) == ONE; + let is_repeat = op == Felt::from_u8(opcodes::REPEAT); + if is_loop_entering || is_repeat { + exp.add(row, &BlockHashMsg::LoopBody { parent: addr_next, child_hash: h0 }); + fired_loop_body += 1; + } - let join_id = JoinNodeBuilder::new([basic_block_1_id, basic_block_2_id]) - .add_to_forest(&mut mast_forest) - .unwrap(); - let basic_block_1 = mast_forest[basic_block_1_id].clone(); - let basic_block_2 = mast_forest[basic_block_2_id].clone(); - let join = mast_forest[join_id].clone(); - mast_forest.make_root(join_id); + // END of the loop body: `is_loop_body` bit is set on the END overlay. + if op == Felt::from_u8(opcodes::END) && main.is_loop_body_flag(idx) == ONE { + let is_first_child = next_op_first_child_flag(main, next); + exp.remove( + row, + &BlockHashMsg::End { + parent: addr_next, + child_hash: h0, + is_first_child, + is_loop_body: ONE, + }, + ); + fired_loop_body_end += 1; + } + }); - let program = Program::new(mast_forest.into(), join_id); + // Sanity: each iteration fires one LoopBody enqueue and one body-ending END remove. + assert_eq!(fired_loop_body, 2, "expected LOOP + REPEAT to each fire a LoopBody enqueue"); + assert_eq!(fired_loop_body_end, 2, "expected one END-of-loop-body remove per iteration"); - let trace = build_trace_from_program(&program, &[]); - let challenges = rand_array::(); - let aux_columns = trace.build_aux_trace(&challenges).unwrap(); - let p2 = aux_columns.get_column(P2_COL_IDX); - - let challenges = Challenges::::new(challenges[0], challenges[1]); - let program_hash_msg = - BlockHashTableRow::new_test(ZERO, join.digest(), false, false).collapse(&challenges); - let child1_msg = - BlockHashTableRow::new_test(ONE, basic_block_1.digest(), true, false).collapse(&challenges); - let child2_msg = BlockHashTableRow::new_test(ONE, basic_block_2.digest(), false, false) - .collapse(&challenges); - - // p2 starts at identity (1) - let mut expected_value = ONE; - assert_eq!(expected_value, p2[0]); - - // when JOIN operation is executed, entries for both children are added to the table - expected_value *= child1_msg * child2_msg; - assert_eq!(expected_value, p2[1]); - - // for the next 2 cycles, the table is not affected - assert_eq!(expected_value, p2[2]); - assert_eq!(expected_value, p2[3]); - - // when the first SPAN block ends, its entry is removed from the table - expected_value *= child1_msg.inverse(); - assert_eq!(expected_value, p2[4]); - - // for the next 2 cycles, the table is not affected - assert_eq!(expected_value, p2[5]); - assert_eq!(expected_value, p2[6]); - - // when the second SPAN block ends, its entry is removed from the table - expected_value *= child2_msg.inverse(); - assert_eq!(expected_value, p2[7]); - - // when the JOIN block ends, its entry (the root hash) is removed (unmatched by any add) - expected_value *= program_hash_msg.inverse(); - assert_eq!(expected_value, p2[8]); - - // the final value is 1/program_hash_msg - for i in 9..(p2.len()) { - assert_eq!(expected_value, p2[i]); - } + log.assert_contains(&exp); } -#[test] -#[expect(clippy::needless_range_loop)] -fn decoder_p2_split_true() { - // build program - let mut mast_forest = MastForest::new(); - - let basic_block_1_id = BasicBlockNodeBuilder::new(vec![Operation::Mul], Vec::new()) - .add_to_forest(&mut mast_forest) - .unwrap(); - let basic_block_2_id = BasicBlockNodeBuilder::new(vec![Operation::Add], Vec::new()) - .add_to_forest(&mut mast_forest) - .unwrap(); - let basic_block_1 = mast_forest[basic_block_1_id].clone(); - let _basic_block_2 = mast_forest[basic_block_2_id].clone(); - let split_id = SplitNodeBuilder::new([basic_block_1_id, basic_block_2_id]) - .add_to_forest(&mut mast_forest) - .unwrap(); - mast_forest.make_root(split_id); - - let program = Program::new(mast_forest.into(), split_id); - - // build trace from program - let trace = build_trace_from_program(&program, &[1]); - let challenges = rand_array::(); - let aux_columns = trace.build_aux_trace(&challenges).unwrap(); - let p2 = aux_columns.get_column(P2_COL_IDX); - - let challenges = Challenges::::new(challenges[0], challenges[1]); - let program_hash_msg = - BlockHashTableRow::new_test(ZERO, program.hash(), false, false).collapse(&challenges); - let child_msg = BlockHashTableRow::new_test(ONE, basic_block_1.digest(), false, false) - .collapse(&challenges); - - // p2 starts at identity (1) - let mut expected_value = ONE; - assert_eq!(expected_value, p2[0]); - - // when SPLIT operation is executed, entry for the true branch is added to the table - expected_value *= child_msg; - assert_eq!(expected_value, p2[1]); - - // for the next 2 cycles, the table is not affected - assert_eq!(expected_value, p2[2]); - assert_eq!(expected_value, p2[3]); - - // when the SPAN block ends, its entry is removed from the table - expected_value *= child_msg.inverse(); - assert_eq!(expected_value, p2[4]); +/// SPLIT enqueues exactly one `Child` entry carrying the `s0`-muxed child hash +/// (`s0 * h_0 + (1 - s0) * h_1`); the matching END on the taken branch dequeues it. +#[rstest::rstest] +#[case::taken(1)] +#[case::not_taken(0)] +fn block_hash_split_enqueue_dequeue(#[case] cond: u64) { + let program = { + let mut f = MastForest::new(); + let t = BasicBlockNodeBuilder::new(vec![Operation::Add], Vec::new()) + .add_to_forest(&mut f) + .unwrap(); + let e = BasicBlockNodeBuilder::new(vec![Operation::Mul], Vec::new()) + .add_to_forest(&mut f) + .unwrap(); + let s = SplitNodeBuilder::new([t, e]).add_to_forest(&mut f).unwrap(); + f.make_root(s); + Program::new(f.into(), s) + }; + let trace = build_trace_from_program(&program, &[cond]); + let log = InteractionLog::new(&trace); + let main = trace.main_trace(); + + let mut split_rows = 0usize; + let mut exp = Expectations::new(&log); + for_each_op(&trace, |row, op| { + let idx = RowIndex::from(row); + let next = RowIndex::from(row + 1); + let addr_next = main.addr(next); + let first = main.decoder_hasher_state_first_half(idx); + let second = main.decoder_hasher_state_second_half(idx); + + if op == Felt::from_u8(opcodes::SPLIT) { + let s0 = main.stack_element(0, idx); + let one_minus_s0 = ONE - s0; + let child_hash: [Felt; 4] = + std::array::from_fn(|i| s0 * first[i] + one_minus_s0 * second[i]); + exp.add(row, &BlockHashMsg::Child { parent: addr_next, child_hash }); + split_rows += 1; + } - // when the SPLIT block ends, its entry (the root hash) is removed (unmatched by any add) - expected_value *= program_hash_msg.inverse(); - assert_eq!(expected_value, p2[5]); + if op == Felt::from_u8(opcodes::END) { + let is_loop_body = main.is_loop_body_flag(idx); + let h0: [Felt; 4] = [first[0], first[1], first[2], first[3]]; + let is_first_child = next_op_first_child_flag(main, next); + exp.remove( + row, + &BlockHashMsg::End { + parent: addr_next, + child_hash: h0, + is_first_child, + is_loop_body, + }, + ); + } + }); - // the final value is 1/program_hash_msg - for i in 6..(p2.len()) { - assert_eq!(expected_value, p2[i]); - } + assert_eq!(split_rows, 1, "expected exactly one SPLIT enqueue"); + // END fires for: taken branch's child, the SPLIT itself. Two removes total. + assert_eq!(exp.count_removes(), 2, "expected END pops for child + SPLIT: cond={cond}"); + log.assert_contains(&exp); } -#[test] -#[expect(clippy::needless_range_loop)] -fn decoder_p2_split_false() { - // build program - let mut mast_forest = MastForest::new(); - - let basic_block_1_id = BasicBlockNodeBuilder::new(vec![Operation::Mul], Vec::new()) - .add_to_forest(&mut mast_forest) - .unwrap(); - let basic_block_2_id = BasicBlockNodeBuilder::new(vec![Operation::Add], Vec::new()) - .add_to_forest(&mut mast_forest) - .unwrap(); - let _basic_block_1 = mast_forest[basic_block_1_id].clone(); - let basic_block_2 = mast_forest[basic_block_2_id].clone(); - - let split_id = SplitNodeBuilder::new([basic_block_1_id, basic_block_2_id]) - .add_to_forest(&mut mast_forest) - .unwrap(); - mast_forest.make_root(split_id); - - let program = Program::new(mast_forest.into(), split_id); - - // build trace from program - let trace = build_trace_from_program(&program, &[0]); - let challenges = rand_array::(); - let aux_columns = trace.build_aux_trace(&challenges).unwrap(); - let p2 = aux_columns.get_column(P2_COL_IDX); - - let challenges = Challenges::::new(challenges[0], challenges[1]); - let program_hash_msg = - BlockHashTableRow::new_test(ZERO, program.hash(), false, false).collapse(&challenges); - let child_msg = BlockHashTableRow::new_test(ONE, basic_block_2.digest(), false, false) - .collapse(&challenges); - - // p2 starts at identity (1) - let mut expected_value = ONE; - assert_eq!(expected_value, p2[0]); - - // when SPLIT operation is executed, entry for the false branch is added to the table - expected_value *= child_msg; - assert_eq!(expected_value, p2[1]); - - // for the next 2 cycles, the table is not affected - assert_eq!(expected_value, p2[2]); - assert_eq!(expected_value, p2[3]); +// OP GROUP TABLE TESTS +// ================================================================================================ - // when the SPAN block ends, its entry is removed from the table - expected_value *= child_msg.inverse(); - assert_eq!(expected_value, p2[4]); +/// A SPAN whose batch holds 8 op groups triggers the g8 insert batch (7 adds for positions 1..=7; +/// position 0 is consumed inline by the SPAN decode row and not inserted). Each in-span decode +/// row where `group_count` decrements emits a matching remove — covered in +/// [`op_group_span_removal_covers_decode_rows`]. +/// +/// A batch of 64 simple stack-depth-neutral ops was picked because each op group packs 9 seven-bit +/// opcodes into a 63-bit group value, so 8 groups hold 72 ops max; 64 ops reliably fills the +/// batch up to the g8 threshold (`c0 == 1`) without spilling into a second batch. +#[test] +fn op_group_span_8_groups_inserts() { + let pattern = [Operation::Noop, Operation::Incr, Operation::Neg, Operation::Eqz]; + let ops: Vec = (0..64).map(|i| pattern[i % pattern.len()]).collect(); + let trace = build_trace_from_ops(ops, &[]); + let log = InteractionLog::new(&trace); + let main = trace.main_trace(); + + let mut g8_rows_seen = 0usize; + let mut exp = Expectations::new(&log); + for_each_op(&trace, |row, op| { + let idx = RowIndex::from(row); + if op != Felt::from_u8(opcodes::SPAN) && op != Felt::from_u8(opcodes::RESPAN) { + return; + } + let batch_flags = main.op_batch_flag(idx); + if batch_flags[0] != ONE { + return; + } + g8_rows_seen += 1; + + let addr_next = main.addr(RowIndex::from(row + 1)); + let gc = main.group_count(idx); + let first = main.decoder_hasher_state_first_half(idx); + let second = main.decoder_hasher_state_second_half(idx); + for i in 1u16..=3 { + let group_value = first[i as usize]; + exp.add(row, &OpGroupMsg::new(&addr_next, gc, i, group_value)); + } + for i in 4u16..=7 { + let group_value = second[(i - 4) as usize]; + exp.add(row, &OpGroupMsg::new(&addr_next, gc, i, group_value)); + } + }); - // when the SPLIT block ends, its entry (the root hash) is removed (unmatched by any add) - expected_value *= program_hash_msg.inverse(); - assert_eq!(expected_value, p2[5]); + assert!(g8_rows_seen > 0, "program did not produce a g8 SPAN/RESPAN batch"); + assert_eq!( + exp.count_adds(), + 7 * g8_rows_seen, + "expected 7 g8 inserts per SPAN/RESPAN row (positions 1..=7)" + ); + assert_eq!(exp.count_removes(), 0, "op_group_span_8_groups_inserts only checks inserts"); - // the final value is 1/program_hash_msg - for i in 6..(p2.len()) { - assert_eq!(expected_value, p2[i]); - } + log.assert_contains(&exp); } +/// Every in-span decode row where `group_count` strictly decrements removes one entry from the +/// op-group table. The removal's `group_value` is muxed by `is_push`: +/// +/// - PUSH rows: pull the immediate from `stk_next[0]` (pushed value is at stack top next cycle). +/// - Non-PUSH rows: `group_value = h0_next · 128 + opcode_next` — the residual group value after +/// the current op is "peeled off" the low 7 bits. +/// +/// Includes at least one PUSH to exercise both mux branches and enough in-group ops to force a +/// boundary decrement where the emitter could otherwise off-by-one. #[test] -#[expect(clippy::needless_range_loop)] -fn decoder_p2_loop_with_repeat() { - // build program - let mut mast_forest = MastForest::new(); - - let basic_block_1_id = BasicBlockNodeBuilder::new(vec![Operation::Pad], Vec::new()) - .add_to_forest(&mut mast_forest) - .unwrap(); - let basic_block_2_id = BasicBlockNodeBuilder::new(vec![Operation::Drop], Vec::new()) - .add_to_forest(&mut mast_forest) - .unwrap(); +fn op_group_span_removal_covers_decode_rows() { + // Two full groups (9 Noops) + PUSH(immediate) + a handful more. The 9th Noop closes the + // first op group (non-PUSH decrement, exercising the `h0_next * 128 + opcode_next` branch) + // and the PUSH pulls its immediate from a dedicated group (exercising the `stk_next[0]` + // branch). + let mut ops: Vec = (0..9).map(|_| Operation::Noop).collect(); + ops.push(Operation::Push(Felt::new_unchecked(42))); + ops.extend(vec![Operation::Add, Operation::Mul, Operation::Drop]); + let trace = build_trace_from_ops(ops, &[]); + let log = InteractionLog::new(&trace); + let main = trace.main_trace(); + + let mut fired_push_branch = false; + let mut fired_nonpush_branch = false; + + let mut exp = Expectations::new(&log); + for_each_op(&trace, |row, op| { + let idx = RowIndex::from(row); + let next = RowIndex::from(row + 1); + if main.is_in_span(idx) != ONE { + return; + } + let gc = main.group_count(idx); + let gc_next = main.group_count(next); + if gc == gc_next { + return; + } - let join_id = JoinNodeBuilder::new([basic_block_1_id, basic_block_2_id]) - .add_to_forest(&mut mast_forest) - .unwrap(); - let basic_block_1 = mast_forest[basic_block_1_id].clone(); - let basic_block_2 = mast_forest[basic_block_2_id].clone(); - let join = mast_forest[join_id].clone(); + let addr = main.addr(idx); + let group_value = if op == Felt::from_u8(opcodes::PUSH) { + fired_push_branch = true; + main.stack_element(0, next) + } else { + fired_nonpush_branch = true; + let h0_next = main.decoder_hasher_state_element(0, next); + let opcode_next = main.get_op_code(next); + h0_next * Felt::from_u16(128) + opcode_next + }; + exp.remove( + row, + &OpGroupMsg { + batch_id: addr, + group_pos: gc, + group_value, + }, + ); + }); + + assert!( + fired_push_branch, + "test did not cover the PUSH-mux branch of the op-group remove" + ); + assert!( + fired_nonpush_branch, + "test did not cover the non-PUSH branch of the op-group remove" + ); + + log.assert_contains(&exp); +} - let loop_node_id = LoopNodeBuilder::new(join_id).add_to_forest(&mut mast_forest).unwrap(); - mast_forest.make_root(loop_node_id); +/// A SPAN that spans two batches exercises the RESPAN-boundary op-group dispatch. Runs with +/// op counts that force each non-g8 batch variant in the second batch to catch off-by-one / +/// batch-flag muxing bugs at the transition: +/// +/// - 80 Noops: first batch g8 (7 adds) + RESPAN + g1 second batch (0 adds — single group consumed +/// inline; emitter has no branch for `(c0, c1, c2) = (0, 1, 1)`). +/// - 100 Noops: first batch g8 + RESPAN + g4 second batch (3 adds for positions 1..=3). +/// +/// The batch-flag dispatch below mirrors the emitter exactly: `c0` is the g8 selector, +/// `(1-c0)·c1·(1-c2)` is g4, `(1-c0)·(1-c1)·c2` is g2, and `(1-c0)·c1·c2` is g1. +#[rstest::rstest] +#[case::g8_plus_g1(80, 1, 0, 0, 1)] +#[case::g8_plus_g4(100, 1, 1, 0, 0)] +fn op_group_span_two_batch_transition_inserts( + #[case] noop_count: usize, + #[case] expected_g8_rows: usize, + #[case] expected_g4_rows: usize, + #[case] expected_g2_rows: usize, + #[case] expected_g1_rows: usize, +) { + let ops: Vec = (0..noop_count).map(|_| Operation::Noop).collect(); + let trace = build_trace_from_ops(ops, &[]); + let log = InteractionLog::new(&trace); + let main = trace.main_trace(); + + let mut g8_rows = 0usize; + let mut g4_rows = 0usize; + let mut g2_rows = 0usize; + let mut g1_rows = 0usize; + let mut respan_observed = false; + let mut exp = Expectations::new(&log); + for_each_op(&trace, |row, op| { + let idx = RowIndex::from(row); + if op != Felt::from_u8(opcodes::SPAN) && op != Felt::from_u8(opcodes::RESPAN) { + return; + } + if op == Felt::from_u8(opcodes::RESPAN) { + respan_observed = true; + } + let batch_flags = main.op_batch_flag(idx); + let (c0, c1, c2) = (batch_flags[0], batch_flags[1], batch_flags[2]); + let addr_next = main.addr(RowIndex::from(row + 1)); + let gc = main.group_count(idx); + let first = main.decoder_hasher_state_first_half(idx); + let second = main.decoder_hasher_state_second_half(idx); + + if c0 == ONE && c1 == ZERO && c2 == ZERO { + g8_rows += 1; + for i in 1u16..=3 { + exp.add(row, &OpGroupMsg::new(&addr_next, gc, i, first[i as usize])); + } + for i in 4u16..=7 { + exp.add(row, &OpGroupMsg::new(&addr_next, gc, i, second[(i - 4) as usize])); + } + } else if c0 == ZERO && c1 == ONE && c2 == ZERO { + g4_rows += 1; + for i in 1u16..=3 { + exp.add(row, &OpGroupMsg::new(&addr_next, gc, i, first[i as usize])); + } + } else if c0 == ZERO && c1 == ZERO && c2 == ONE { + g2_rows += 1; + exp.add(row, &OpGroupMsg::new(&addr_next, gc, 1, first[1])); + } else if c0 == ZERO && c1 == ONE && c2 == ONE { + // g1 batch: single group consumed inline by the RESPAN decode row; no inserts. + g1_rows += 1; + } else { + panic!("unexpected batch_flags on SPAN/RESPAN row: ({c0:?}, {c1:?}, {c2:?})"); + } + }); - let program = Program::new(mast_forest.into(), loop_node_id); + assert!(respan_observed, "program did not produce a RESPAN row"); + assert_eq!(g8_rows, expected_g8_rows); + assert_eq!(g4_rows, expected_g4_rows); + assert_eq!(g2_rows, expected_g2_rows); + assert_eq!(g1_rows, expected_g1_rows); + assert_eq!(exp.count_adds(), 7 * g8_rows + 3 * g4_rows + g2_rows); + assert_eq!(exp.count_removes(), 0); - // Input [1, 1, 0]: position 0 (top) = 1 (1st iteration enters) - // After Pad+Drop: position 0 = 1 (2nd iteration enters) - // After Pad+Drop: position 0 = 0 (loop exits) - let trace = build_trace_from_program(&program, &[1, 1, 0]); - let challenges = rand_array::(); - let aux_columns = trace.build_aux_trace(&challenges).unwrap(); - let p2 = aux_columns.get_column(P2_COL_IDX); - - let challenges = Challenges::::new(challenges[0], challenges[1]); - // The loop node consumes the first hasher cycle; join/span addresses follow sequentially. - let a_33 = ONE + HASH_CYCLE_LEN_FELT; // address of the JOIN block in the first iteration - let a_129 = a_33 + HASH_CYCLE_LEN_FELT * Felt::new(3); // address of the JOIN block in the second iteration - let program_hash_msg = - BlockHashTableRow::new_test(ZERO, program.hash(), false, false).collapse(&challenges); - let loop_body_msg = - BlockHashTableRow::new_test(ONE, join.digest(), false, true).collapse(&challenges); - let child1_iter1 = BlockHashTableRow::new_test(a_33, basic_block_1.digest(), true, false) - .collapse(&challenges); - let child2_iter1 = BlockHashTableRow::new_test(a_33, basic_block_2.digest(), false, false) - .collapse(&challenges); - let child1_iter2 = BlockHashTableRow::new_test(a_129, basic_block_1.digest(), true, false) - .collapse(&challenges); - let child2_iter2 = BlockHashTableRow::new_test(a_129, basic_block_2.digest(), false, false) - .collapse(&challenges); - - // p2 starts at identity (1) - let mut expected_value = ONE; - assert_eq!(expected_value, p2[0]); - - // --- first iteration ---------------------------------------------------- - - // when LOOP operation is executed, entry for loop body is added to the table - expected_value *= loop_body_msg; - assert_eq!(expected_value, p2[1]); - - // when JOIN operation is executed, entries for both children are added to the table - expected_value *= child1_iter1 * child2_iter1; - assert_eq!(expected_value, p2[2]); - - // for the next 2 cycles, the table is not affected - assert_eq!(expected_value, p2[3]); - assert_eq!(expected_value, p2[4]); - - // when the first SPAN block ends, its entry is removed from the table - expected_value *= child1_iter1.inverse(); - assert_eq!(expected_value, p2[5]); - - // for the next 2 cycles, the table is not affected - assert_eq!(expected_value, p2[6]); - assert_eq!(expected_value, p2[7]); - - // when the second SPAN block ends, its entry is removed from the table - expected_value *= child2_iter1.inverse(); - assert_eq!(expected_value, p2[8]); - - // when the JOIN block ends, its entry is removed from the table - expected_value *= loop_body_msg.inverse(); - assert_eq!(expected_value, p2[9]); - - // --- second iteration --------------------------------------------------- - - // when REPEAT operation is executed, entry for loop body is again added to the table - expected_value *= loop_body_msg; - assert_eq!(expected_value, p2[10]); - - // when JOIN operation is executed, entries for both children are added to the table - expected_value *= child1_iter2 * child2_iter2; - assert_eq!(expected_value, p2[11]); - - // for the next 2 cycles, the table is not affected - assert_eq!(expected_value, p2[12]); - assert_eq!(expected_value, p2[13]); - - // when the first SPAN block ends, its entry is removed from the table - expected_value *= child1_iter2.inverse(); - assert_eq!(expected_value, p2[14]); - - // for the next 2 cycles, the table is not affected - assert_eq!(expected_value, p2[15]); - assert_eq!(expected_value, p2[16]); - - // when the second SPAN block ends, its entry is removed from the table - expected_value *= child2_iter2.inverse(); - assert_eq!(expected_value, p2[17]); - - // when the JOIN block ends, its entry is removed from the table - expected_value *= loop_body_msg.inverse(); - assert_eq!(expected_value, p2[18]); - - // when the LOOP block ends, its entry (the root hash) is removed (unmatched by any add) - expected_value *= program_hash_msg.inverse(); - assert_eq!(expected_value, p2[19]); - - // the final value is 1/program_hash_msg - for i in 20..(p2.len()) { - assert_eq!(expected_value, p2[i]); - } + log.assert_contains(&exp); } -// OP GROUP TABLE TESTS +// DYNCALL REGRESSION TESTS // ================================================================================================ #[test] -fn decoder_p3_trace_empty_table() { - let stack = [1, 2]; - let operations = vec![Operation::Add]; - let trace = build_trace_from_ops(operations, &stack); - - let challenges = rand_array::(); - let aux_columns = trace.build_aux_trace(&challenges).unwrap(); - - // no rows should have been added or removed from the op group table, and thus, all values - // in the column must be ONE - let p3 = aux_columns.get_column(P3_COL_IDX); - for &value in p3.iter().take(p3.len()) { - assert_eq!(ONE, value); - } -} +fn decoder_dyncall_at_min_stack_depth_records_post_drop_ctx_info() { + use std::sync::Arc; -#[test] -#[expect(clippy::needless_range_loop)] -fn decoder_p3_trace_one_batch() { - let stack = [1, 2, 3, 4, 5, 6, 7, 8]; - let ops = vec![ - Operation::Add, - Operation::Mul, - Operation::Add, - Operation::Push(ONE), - Operation::Add, - Operation::Mul, - Operation::Add, - Operation::Push(Felt::new(2)), - Operation::Add, - Operation::Swap, - Operation::Mul, - Operation::Add, - ]; - let trace = build_trace_from_ops(ops.clone(), &stack); - let challenges = rand_array::(); - let aux_columns = trace.build_aux_trace(&challenges).unwrap(); - let p3 = aux_columns.get_column(P3_COL_IDX); - - let challenges = Challenges::::new(challenges[0], challenges[1]); - - // make sure the first entry is ONE - assert_eq!(ONE, p3[0]); - - // make sure 3 groups were inserted at clock cycle 1; these entries are for the two immediate - // values and the second operation group consisting of [SWAP, MUL, ADD] - let g1_value = OpGroupTableRow::new(ONE, Felt::new(3), ONE).to_value(&challenges); - let g2_value = OpGroupTableRow::new(ONE, Felt::new(2), Felt::new(2)).to_value(&challenges); - let g3_value = OpGroupTableRow::new(ONE, ONE, build_op_group(&ops[9..])).to_value(&challenges); - let expected_value = g1_value * g2_value * g3_value; - assert_eq!(expected_value, p3[1]); - - // for the next 3 cycles (2, 3, 4), op group table doesn't change - for i in 2..5 { - assert_eq!(expected_value, p3[i]); - } - - // at cycle 5, when PUSH(1) is executed, the entry for the first group is removed from the - // table - let expected_value = expected_value / g1_value; - assert_eq!(expected_value, p3[5]); + use crate::{ + MIN_STACK_DEPTH, + mast::{DynNodeBuilder, MastForestContributor}, + operation::opcodes, + }; - // for the next 3 cycles (6, 7, 8), op group table doesn't change - for i in 6..9 { - assert_eq!(expected_value, p3[i]); - } + // Build exactly the same program shape as `dyncall_program()` in parallel/tests.rs: + // join( + // block(push(HASH_ADDR), mem_storew, drop, drop, drop, drop, push(HASH_ADDR)), + // dyncall, + // ) + // The target procedure (single SWAP) is added as a second root so the VM can find it. + // + // The caller passes the 4-element procedure hash as the initial stack contents + // (top-of-stack first). The preamble stores that word at HASH_ADDR so that DYNCALL + // can load it and dispatch to the correct procedure. + const HASH_ADDR: Felt = Felt::new_unchecked(40); + + // --- build the forest in the same order as dyncall_program() --- + let mut forest = MastForest::new(); + + // 1. Build the root join node first (preamble + dyncall). + let root = { + let preamble = BasicBlockNodeBuilder::new( + vec![ + Operation::Push(HASH_ADDR), + Operation::MStoreW, + Operation::Drop, + Operation::Drop, + Operation::Drop, + Operation::Drop, + Operation::Push(HASH_ADDR), + ], + Vec::new(), + ) + .add_to_forest(&mut forest) + .unwrap(); - // at cycle 9, when PUSH(2) is executed, the entry for the second group is removed from the - // table - let expected_value = expected_value / g2_value; - assert_eq!(expected_value, p3[9]); + let dyncall = DynNodeBuilder::new_dyncall().add_to_forest(&mut forest).unwrap(); - // at cycle 10, op group 0 is completed, and the entry for the next op group is removed from - // the table - let expected_value = expected_value / g3_value; - assert_eq!(expected_value, p3[10]); + JoinNodeBuilder::new([preamble, dyncall]).add_to_forest(&mut forest).unwrap() + }; + forest.make_root(root); - // at this point, the table should be empty and thus, running product should be ONE - assert_eq!(expected_value, ONE); - for i in 11..(p3.len()) { - assert_eq!(ONE, p3[i]); - } + // 2. Add the procedure that DYNCALL will call, as a second forest root. + let target = BasicBlockNodeBuilder::new(vec![Operation::Swap], Vec::new()) + .add_to_forest(&mut forest) + .unwrap(); + forest.make_root(target); + + // 3. Derive the stack inputs from the target's digest (4 Felts, top-of-stack first). + let target_hash: Vec = + forest.get_node_by_id(target).unwrap().digest().iter().copied().collect(); + + let program = Program::new(Arc::new(forest), root); + + let trace = + build_trace_from_program_with_stack(&program, StackInputs::new(&target_hash).unwrap()); + let main = trace.main_trace(); + + // Locate the DYNCALL row. + let dyncall_opcode = Felt::from_u8(opcodes::DYNCALL); + let row = main + .row_iter() + .find(|&i| main.get_op_code(i) == dyncall_opcode) + .expect("DYNCALL row not found in trace"); + + // second_hasher_state[0] = parent_stack_depth → decoder_hasher_state_element(4) + // second_hasher_state[1] = parent_next_overflow_addr → decoder_hasher_state_element(5) + // + // With 4 hash elements on the stack the depth is still MIN_STACK_DEPTH (16); after + // DYNCALL drops those 4 elements the post-drop depth is 12 = MIN_STACK_DEPTH, which + // means no overflow entry was pushed, so parent_next_overflow_addr must be ZERO. + assert_eq!( + main.decoder_hasher_state_element(4, row), + Felt::new_unchecked(MIN_STACK_DEPTH as u64), + "parent_stack_depth should equal MIN_STACK_DEPTH" + ); + assert_eq!( + main.decoder_hasher_state_element(5, row), + ZERO, + "parent_next_overflow_addr should be ZERO when stack is at MIN_STACK_DEPTH" + ); } #[test] -#[expect(clippy::needless_range_loop)] -fn decoder_p3_trace_two_batches() { - let (ops, iv) = build_span_with_respan_ops(); - let trace = build_trace_from_ops(ops, &[]); - let challenges = rand_array::(); - let aux_columns = trace.build_aux_trace(&challenges).unwrap(); - let p3 = aux_columns.get_column(P3_COL_IDX); - - let challenges = Challenges::::new(challenges[0], challenges[1]); - - // make sure the first entry is ONE - assert_eq!(ONE, p3[0]); - - // --- first batch ---------------------------------------------------------------------------- - // make sure entries for 7 groups were inserted at clock cycle 1 - let b0_values = [ - OpGroupTableRow::new(ONE, Felt::new(11), iv[0]).to_value(&challenges), - OpGroupTableRow::new(ONE, Felt::new(10), iv[1]).to_value(&challenges), - OpGroupTableRow::new(ONE, Felt::new(9), iv[2]).to_value(&challenges), - OpGroupTableRow::new(ONE, Felt::new(8), iv[3]).to_value(&challenges), - OpGroupTableRow::new(ONE, Felt::new(7), iv[4]).to_value(&challenges), - OpGroupTableRow::new(ONE, Felt::new(6), iv[5]).to_value(&challenges), - OpGroupTableRow::new(ONE, Felt::new(5), iv[6]).to_value(&challenges), - ]; - let mut expected_value: Felt = b0_values.iter().fold(ONE, |acc, &val| acc * val); - assert_eq!(expected_value, p3[1]); - - // for the next 7 cycles (2, 3, 4, 5, 6, 7, 8), an entry for an op group is removed from the - // table - for (i, clk) in (2..9).enumerate() { - expected_value /= b0_values[i]; - assert_eq!(expected_value, p3[clk]); - } - - // at cycle 9, when we execute a NOOP to finish the first batch, op group table doesn't change; - // also, at this point op group table must be empty - assert_eq!(expected_value, p3[9]); - assert_eq!(expected_value, ONE); - - // --- second batch --------------------------------------------------------------------------- - // make sure entries for 3 group are inserted at clock cycle 10 (when RESPAN is executed) - // group 3 consists of two DROP operations which do not fit into group 0 - let batch1_addr = ONE + HASH_CYCLE_LEN_FELT; - let op_group3 = build_op_group(&[Operation::Drop; 2]); - let b1_values = [ - OpGroupTableRow::new(batch1_addr, Felt::new(3), iv[7]).to_value(&challenges), - OpGroupTableRow::new(batch1_addr, Felt::new(2), iv[8]).to_value(&challenges), - OpGroupTableRow::new(batch1_addr, ONE, op_group3).to_value(&challenges), - ]; - let mut expected_value: Felt = b1_values.iter().fold(ONE, |acc, &val| acc * val); - assert_eq!(expected_value, p3[10]); - - // for the next 2 cycles (11, 12), an entry for an op group is removed from the table - for (i, clk) in (11..13).enumerate() { - expected_value *= b1_values[i].inverse(); - assert_eq!(expected_value, p3[clk]); - } - - // then, as we executed ADD and DROP operations for group 0, op group table doesn't change - for i in 13..19 { - assert_eq!(expected_value, p3[i]); - } - - // at cycle 19 we start executing group 3 - so, the entry for the last op group is removed - // from the table - expected_value *= b1_values[2].inverse(); - assert_eq!(expected_value, p3[19]); - - // at this point, the table should be empty and thus, running product should be ONE - assert_eq!(expected_value, ONE); - for i in 20..(p3.len()) { - assert_eq!(ONE, p3[i]); - } -} +fn decoder_dyncall_with_multiple_overflow_entries_records_correct_overflow_addr() { + // Regression test: when the caller context has more than one overflow entry, the + // serial ExecutionTracer must record the post-pop overflow address (the clock of + // the second-to-last entry), not the pre-pop address (the clock of the top entry). + use std::sync::Arc; + + use crate::{ + mast::{DynNodeBuilder, MastForestContributor}, + operation::opcodes, + }; -// HELPER STRUCTS AND METHODS -// ================================================================================================ + const HASH_ADDR: Felt = Felt::new_unchecked(40); -/// Describes a single entry in the block stack table. -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct BlockStackTableRow { - block_id: Felt, - parent_id: Felt, - is_loop: bool, - parent_ctx: ContextId, - parent_fn_hash: Word, - parent_fmp: Felt, - parent_stack_depth: u32, - parent_next_overflow_addr: Felt, -} + let mut forest = MastForest::new(); -impl BlockStackTableRow { - /// Returns a new [BlockStackTableRow] instantiated with the specified parameters. This is - /// used for test purpose only. - #[cfg(test)] - pub fn new(block_id: Felt, parent_id: Felt, is_loop: bool) -> Self { - Self { - block_id, - parent_id, - is_loop, - parent_ctx: ContextId::root(), - parent_fn_hash: miden_core::EMPTY_WORD, - parent_fmp: ZERO, - parent_stack_depth: 0, - parent_next_overflow_addr: ZERO, - } - } -} - -impl BlockStackTableRow { - /// Reduces this row to a single field element in the field specified by E. This requires - /// at least 12 coefficients. - pub fn to_value>(&self, challenges: &Challenges) -> E { - let is_loop = if self.is_loop { ONE } else { ZERO }; - challenges.alpha - + challenges.beta_powers[0] * self.block_id - + challenges.beta_powers[1] * self.parent_id - + challenges.beta_powers[2] * is_loop - + challenges.beta_powers[3] * Felt::from_u32(u32::from(self.parent_ctx)) - + challenges.beta_powers[4] * self.parent_fmp - + challenges.beta_powers[5] * Felt::from_u32(self.parent_stack_depth) - + challenges.beta_powers[6] * self.parent_next_overflow_addr - + challenges.beta_powers[7] * self.parent_fn_hash[0] - + challenges.beta_powers[8] * self.parent_fn_hash[1] - + challenges.beta_powers[9] * self.parent_fn_hash[2] - + challenges.beta_powers[10] * self.parent_fn_hash[3] - } -} + // 1. Build the callee procedure first so we can get its digest. + let target = BasicBlockNodeBuilder::new(vec![Operation::Swap], Vec::new()) + .add_to_forest(&mut forest) + .unwrap(); + forest.make_root(target); + + let target_hash: Vec = + forest.get_node_by_id(target).unwrap().digest().iter().copied().collect(); + + // 2. Build the main program. + let root = { + let preamble = BasicBlockNodeBuilder::new( + vec![ + Operation::Push(HASH_ADDR), + Operation::MStoreW, + Operation::Drop, + Operation::Drop, + Operation::Drop, + Operation::Drop, + Operation::Push(ZERO), // depth=17, overflow[0]=0 (clk=T1) + Operation::Push(HASH_ADDR), // depth=18, overflow[1]=0 (clk=T2) + ], + Vec::new(), + ) + .add_to_forest(&mut forest) + .unwrap(); -/// Describes a single entry in the op group table. An entry in the op group table is a tuple -/// (batch_id, group_pos, group_value). -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct OpGroupTableRow { - batch_id: Felt, - group_pos: Felt, - group_value: Felt, -} + let dyncall = DynNodeBuilder::new_dyncall().add_to_forest(&mut forest).unwrap(); + let inner_join = + JoinNodeBuilder::new([preamble, dyncall]).add_to_forest(&mut forest).unwrap(); -impl OpGroupTableRow { - /// Returns a new [OpGroupTableRow] instantiated with the specified parameters. - pub fn new(batch_id: Felt, group_pos: Felt, group_value: Felt) -> Self { - Self { batch_id, group_pos, group_value } - } -} + let cleanup = BasicBlockNodeBuilder::new(vec![Operation::Drop], Vec::new()) + .add_to_forest(&mut forest) + .unwrap(); -impl OpGroupTableRow { - /// Reduces this row to a single field element in the field specified by E. This requires - /// at least 4 coefficients. - pub fn to_value>(&self, challenges: &Challenges) -> E { - challenges.alpha - + challenges.beta_powers[0] * self.batch_id - + challenges.beta_powers[1] * self.group_pos - + challenges.beta_powers[2] * self.group_value - } + JoinNodeBuilder::new([inner_join, cleanup]).add_to_forest(&mut forest).unwrap() + }; + forest.make_root(root); + + let program = Program::new(Arc::new(forest), root); + + let trace = + build_trace_from_program_with_stack(&program, StackInputs::new(&target_hash).unwrap()); + let main = trace.main_trace(); + + // Locate the DYNCALL row. + let dyncall_opcode = Felt::from_u8(opcodes::DYNCALL); + let dyncall_row = main + .row_iter() + .find(|&i| main.get_op_code(i) == dyncall_opcode) + .expect("DYNCALL row not found in trace"); + + let recorded_depth = main.decoder_hasher_state_element(4, dyncall_row); + let recorded_overflow_addr = main.decoder_hasher_state_element(5, dyncall_row); + + // At DYNCALL time depth=18 (>MIN_STACK_DEPTH), so post-drop depth = 17. + assert_eq!( + recorded_depth, + Felt::new_unchecked(17), + "parent_stack_depth should be 17 (= pre-DYNCALL depth 18 minus 1)" + ); + + // Independently determine T1 (clock of push(0)) by scanning for all PUSH rows before DYNCALL. + let push_opcode = Felt::from_u8(opcodes::PUSH); + let push_rows_before_dyncall: Vec<_> = main + .row_iter() + .filter(|&i| i < dyncall_row && main.get_op_code(i) == push_opcode) + .collect(); + let n = push_rows_before_dyncall.len(); + assert!(n >= 2, "expected at least 2 PUSH rows before DYNCALL, found {n}"); + let t1_row = push_rows_before_dyncall[n - 2]; // push(0) → overflow[0] + let t2_row = push_rows_before_dyncall[n - 1]; // push(HASH_ADDR) → overflow[1] + let t1 = main.clk(t1_row); + let t2 = main.clk(t2_row); + assert_eq!(t2, t1 + ONE, "push(0) and push(HASH_ADDR) must be at consecutive clocks"); + + // clk_after_pop_in_current_ctx() returns T1 (the second-to-last overflow entry's clock). + assert_eq!( + recorded_overflow_addr, t1, + "parent_next_overflow_addr must equal T1 (second-to-last overflow clock = {t1}); \ + T2 (top overflow clock = {t2}) would indicate the buggy path" + ); } diff --git a/processor/src/trace/tests/hasher.rs b/processor/src/trace/tests/hasher.rs deleted file mode 100644 index 804493d557..0000000000 --- a/processor/src/trace/tests/hasher.rs +++ /dev/null @@ -1,223 +0,0 @@ -use alloc::vec::Vec; - -use miden_air::trace::{ - AUX_TRACE_RAND_CHALLENGES, Challenges, MainTrace, - chiplets::hasher::{HASH_CYCLE_LEN, P1_COL_IDX}, -}; -use miden_core::{ - ONE, Word, ZERO, - crypto::merkle::{MerkleStore, MerkleTree, NodeIndex}, - field::{ExtensionField, Field}, - operations::Operation, -}; -use rstest::rstest; - -use super::{Felt, build_trace_from_ops_with_inputs, rand_array}; -use crate::{AdviceInputs, StackInputs}; - -// SIBLING TABLE TESTS -// ================================================================================================ - -#[rstest] -#[case(5_u64)] -#[case(4_u64)] -fn hasher_p1_mp_verify(#[case] index: u64) { - let (tree, _) = build_merkle_tree(); - let store = MerkleStore::from(&tree); - let depth = 3; - let node = tree.get_node(NodeIndex::new(depth as u8, index).unwrap()).unwrap(); - - // build program inputs - let mut init_stack = vec![]; - append_word(&mut init_stack, node); - init_stack.extend_from_slice(&[depth, index]); - append_word(&mut init_stack, tree.root()); - let stack_inputs = StackInputs::try_from_ints(init_stack).unwrap(); - let advice_inputs = AdviceInputs::default().with_merkle_store(store); - - // build execution trace and extract the sibling table column from it - let ops = vec![Operation::MpVerify(ZERO)]; - let trace = build_trace_from_ops_with_inputs(ops, stack_inputs, advice_inputs); - let challenges = rand_array::(); - let aux_columns = trace.build_aux_trace(&challenges).unwrap(); - let p1 = aux_columns.get_column(P1_COL_IDX); - - // executing MPVERIFY does not affect the sibling table - so, all values in the column must be - // ONE - for value in p1.iter() { - assert_eq!(ONE, *value); - } -} - -#[rstest] -#[case(5_u64)] -#[case(4_u64)] -fn hasher_p1_mr_update(#[case] index: u64) { - let (tree, _) = build_merkle_tree(); - let old_node = tree.get_node(NodeIndex::new(3, index).unwrap()).unwrap(); - let new_node = init_leaf(11); - let path = tree.get_path(NodeIndex::new(3, index).unwrap()).unwrap(); - - // build program inputs - let mut init_stack = vec![]; - append_word(&mut init_stack, old_node); - init_stack.extend_from_slice(&[3, index]); - append_word(&mut init_stack, tree.root()); - append_word(&mut init_stack, new_node); - let stack_inputs = StackInputs::try_from_ints(init_stack).unwrap(); - let store = MerkleStore::from(&tree); - let advice_inputs = AdviceInputs::default().with_merkle_store(store); - - // build execution trace and extract the sibling table column from it - let ops = vec![Operation::MrUpdate]; - let trace = build_trace_from_ops_with_inputs(ops, stack_inputs, advice_inputs); - let challenges = rand_array::(); - let aux_columns = trace.build_aux_trace(&challenges).unwrap(); - let p1 = aux_columns.get_column(P1_COL_IDX); - - let challenges = Challenges::::new(challenges[0], challenges[1]); - let row_values = [ - SiblingTableRow::new(Felt::new(index), path[0]).to_value(&trace.main_trace, &challenges), - SiblingTableRow::new(Felt::new(index >> 1), path[1]) - .to_value(&trace.main_trace, &challenges), - SiblingTableRow::new(Felt::new(index >> 2), path[2]) - .to_value(&trace.main_trace, &challenges), - ]; - - // Make sure the first entry is ONE. - let mut expected_value = ONE; - assert_eq!(expected_value, p1[0]); - - // The running product does not change while the hasher computes the hash of the SPAN block. - let row_add_1 = HASH_CYCLE_LEN + 1; - for value in p1.iter().take(row_add_1).skip(1) { - assert_eq!(expected_value, *value); - } - - // When computation of the "old Merkle root" is started, the first sibling is added to the - // table in the following row. - expected_value *= row_values[0]; - assert_eq!(expected_value, p1[row_add_1]); - - // The value remains the same until the next sibling is added. - let row_add_2 = 2 * HASH_CYCLE_LEN; - for value in p1.iter().take(row_add_2).skip(row_add_1 + 1) { - assert_eq!(expected_value, *value); - } - - // Next sibling is added. - expected_value *= row_values[1]; - assert_eq!(expected_value, p1[row_add_2]); - - // The value remains the same until the last sibling is added. - let row_add_3 = 3 * HASH_CYCLE_LEN; - for value in p1.iter().take(row_add_3).skip(row_add_2 + 1) { - assert_eq!(expected_value, *value); - } - - // Last sibling is added. - expected_value *= row_values[2]; - assert_eq!(expected_value, p1[row_add_3]); - - // The value remains the same until computation of the "new Merkle root" is started. - let row_remove_1 = 4 * HASH_CYCLE_LEN + 1; - for value in p1.iter().take(row_remove_1).skip(row_add_3 + 1) { - assert_eq!(expected_value, *value); - } - - // First sibling is removed from the table in the following row. - expected_value *= row_values[0].inverse(); - assert_eq!(expected_value, p1[row_remove_1]); - - // The value remains the same until the next sibling is removed. - let row_remove_2 = 5 * HASH_CYCLE_LEN; - for value in p1.iter().take(row_remove_2).skip(row_remove_1 + 1) { - assert_eq!(expected_value, *value); - } - - // Next sibling is removed. - expected_value *= row_values[1].inverse(); - assert_eq!(expected_value, p1[row_remove_2]); - - // The value remains the same until the last sibling is removed. - let row_remove_3 = 6 * HASH_CYCLE_LEN; - for value in p1.iter().take(row_remove_3).skip(row_remove_2 + 1) { - assert_eq!(expected_value, *value); - } - - // Last sibling is removed. - expected_value *= row_values[2].inverse(); - assert_eq!(expected_value, p1[row_remove_3]); - - // at this point the table should be empty again, and it should stay empty until the end - assert_eq!(expected_value, ONE); - for value in p1.iter().skip(row_remove_3 + 1) { - assert_eq!(ONE, *value); - } -} - -// HELPER STRUCTS, METHODS AND FUNCTIONS -// ================================================================================================ - -fn build_merkle_tree() -> (MerkleTree, Vec) { - // build a Merkle tree - let leaves = init_leaves(&[1, 2, 3, 4, 5, 6, 7, 8]); - (MerkleTree::new(leaves.clone()).unwrap(), leaves) -} - -fn init_leaves(values: &[u64]) -> Vec { - values.iter().map(|&v| init_leaf(v)).collect() -} - -fn init_leaf(value: u64) -> Word { - [Felt::new(value), ZERO, ZERO, ZERO].into() -} - -fn append_word(target: &mut Vec, word: Word) { - word.iter().for_each(|v| target.push(v.as_canonical_u64())); -} - -/// Describes a single entry in the sibling table which consists of a tuple `(index, node)` where -/// index is the index of the node at its depth. For example, assume a leaf has index n. For the -/// leaf's parent the index will be n << 1. For the parent of the parent, the index will be -/// n << 2 etc. -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct SiblingTableRow { - index: Felt, - sibling: Word, -} - -impl SiblingTableRow { - pub fn new(index: Felt, sibling: Word) -> Self { - Self { index, sibling } - } - - /// Reduces this row to a single field element in the field specified by E. This requires - /// at least 12 coefficients. - pub fn to_value>( - &self, - _main_trace: &MainTrace, - challenges: &Challenges, - ) -> E { - // when the least significant bit of the index is 0, the sibling will be in the 3rd word - // of the hasher state, and when the least significant bit is 1, it will be in the 2nd - // word. we compute the value in this way to make constraint evaluation a bit easier since - // we need to compute the 2nd and the 3rd word values for other purposes as well. - let lsb = self.index.as_canonical_u64() & 1; - if lsb == 0 { - challenges.alpha - + challenges.beta_powers[2] * self.index - + challenges.beta_powers[7] * self.sibling[0] - + challenges.beta_powers[8] * self.sibling[1] - + challenges.beta_powers[9] * self.sibling[2] - + challenges.beta_powers[10] * self.sibling[3] - } else { - challenges.alpha - + challenges.beta_powers[2] * self.index - + challenges.beta_powers[3] * self.sibling[0] - + challenges.beta_powers[4] * self.sibling[1] - + challenges.beta_powers[5] * self.sibling[2] - + challenges.beta_powers[6] * self.sibling[3] - } - } -} diff --git a/processor/src/trace/tests/lookup.rs b/processor/src/trace/tests/lookup.rs new file mode 100644 index 0000000000..276bb4fd71 --- /dev/null +++ b/processor/src/trace/tests/lookup.rs @@ -0,0 +1,140 @@ +//! End-to-end collection-phase smoke test for the prover-side LogUp pipeline. +//! +//! Runs a tiny MASM basic block through `build_trace_from_ops`, materialises the resulting +//! main trace as a [`RowMajorMatrix`], and pipes it through [`build_lookup_fractions`] +//! + [`accumulate`]. The test validates: +//! +//! 1. **Shape-const drift**: every bus emitter's declared `MAX_INTERACTIONS_PER_ROW` is large +//! enough to accommodate real trace data (the `debug_assert!` inside +//! `ProverLookupBuilder::column` panics on overflow). +//! 2. **Zero-denominator bugs**: every encoded `LookupMessage` evaluates to a non-zero +//! extension-field element, so per-fraction `try_inverse` inside the accumulator does not panic. +//! 3. **Pipeline plumbing**: row slicing with wraparound, per-row periodic composition, `RowWindow` +//! construction over a real matrix, and the dense `LookupFractions` buffer all line up. +//! 4. **Prover/constraint agreement**: the fused `accumulate` prover path must agree with the +//! constraint-path `(V_col, U_col)` oracle bit-exactly on every `(row, col)` delta. If any pair +//! disagrees, either the prover path or the oracle has a bug. +//! +//! The oracle cross-check in (4) subsumes the "does it run to completion?" shape of a +//! separate plumbing test, so both live in one function below. + +use alloc::vec::Vec; + +use miden_air::{ + LOGUP_AUX_TRACE_WIDTH, LiftedAir, ProcessorAir, + logup::{BusId, MIDEN_MAX_MESSAGE_WIDTH}, + lookup::{Challenges, accumulate, build_lookup_fractions, debug::collect_column_oracle_folds}, +}; +use miden_core::{ + field::{Field, QuadFelt}, + utils::Matrix, +}; + +use super::{Felt, build_trace_from_ops, rand_array}; +use crate::operation::Operation; + +/// Pad/Add/Mul/Drop inside a span — same flavour of ops the decoder/stack tests use, with +/// enough variety to exercise decoder, stack, and range-check bus emitters. +fn tiny_span() -> Vec { + vec![ + Operation::Pad, + Operation::Pad, + Operation::Add, + Operation::Pad, + Operation::Mul, + Operation::Drop, + ] +} + +/// Cross-check: the fused `accumulate` prover path must agree with the constraint-path +/// `(V_col, U_col)` oracle bit-exactly on every `(row, col)` delta. +/// +/// - **Prover path**: collect `(m_i, d_i)` fractions via `ProverLookupBuilder` on each row, then +/// `accumulate` runs batched Montgomery inversion + per-column partial sums to produce +/// `aux[col][r+1] - aux[col][r] = Σ m_i · d_i^{-1}`. +/// - **Constraint path**: `ColumnOracleBuilder` evaluates `ProcessorAir` row-by-row using the same +/// `(V_g, U_g)` algebra the constraint system uses, folded per column via cross-multiplication, +/// producing `expected_delta = V_col · U_col^{-1}`. +/// +/// A divergence means either the prover path or the oracle has a bug — fix the root cause. +#[test] +fn build_lookup_fractions_matches_constraint_path_oracle() { + let trace = build_trace_from_ops(tiny_span(), &[]); + + let main_trace = trace.main_trace().to_row_major(); + let public_vals = trace.to_public_values(); + let periodic = LiftedAir::::periodic_columns(&ProcessorAir); + + // QuadFelt challenges for LogUp, built from 4 random Felts (QuadFelt itself doesn't + // implement Randomizable, so we draw base-field elements and pair them). + let raw = rand_array::(); + let alpha = QuadFelt::new([raw[0], raw[1]]); + let beta = QuadFelt::new([raw[2], raw[3]]); + let air = ProcessorAir; + let challenges = + Challenges::::new(alpha, beta, MIDEN_MAX_MESSAGE_WIDTH, BusId::COUNT); + + // --- Prover path: collect fractions and run the fused accumulator. --- + let fractions = build_lookup_fractions(&air, &main_trace, &periodic, &challenges); + + // Shape / non-degenerate smoke checks — if these trip, the oracle check below is moot. + let num_rows = trace.main_trace().num_rows(); + assert_eq!(fractions.num_rows(), num_rows); + assert_eq!(fractions.num_columns(), LOGUP_AUX_TRACE_WIDTH); + assert_eq!(fractions.counts().len(), num_rows * LOGUP_AUX_TRACE_WIDTH); + assert!( + !fractions.fractions().is_empty(), + "no fractions collected — trace is degenerate or emitters are broken", + ); + + // `accumulate` returns a row-major matrix with `num_rows + 1` rows and `num_cols` + // columns. Col 0 is the running-sum accumulator; cols 1+ hold per-row fraction values. + let aux = accumulate(&fractions); + let aux_width = aux.width(); + let aux_values = &aux.values; + assert_eq!(aux_width, LOGUP_AUX_TRACE_WIDTH); + assert_eq!(aux.height(), num_rows + 1); + + // --- Constraint path: walk the trace through the oracle to collect per-row folded + // `(V_col, U_col)` pairs. --- + let oracle_folds = + collect_column_oracle_folds(&air, &main_trace, &periodic, &public_vals, &challenges); + assert_eq!(oracle_folds.len(), num_rows); + + // --- Per-(row, col) value check. --- + // Col 0 (accumulator): aux[r+1][0] - aux[r][0] == Σ_col per_row_value[col]. + // Cols 1+ (fraction): aux[r][col] == V/U per-row value. + for (r, row_folds) in oracle_folds.iter().enumerate() { + assert_eq!(row_folds.len(), LOGUP_AUX_TRACE_WIDTH); + let per_row_values: Vec = row_folds + .iter() + .enumerate() + .map(|(col, &(v_col, u_col))| { + let u_inv = u_col.try_inverse().unwrap_or_else(|| { + panic!( + "row {r} col {col}: oracle U_col is zero — bus has a zero-denominator \ + product, indicating a bug in the emitter or message encoding", + ) + }); + v_col * u_inv + }) + .collect(); + + // Accumulator (col 0): delta == sum of all columns' per-row values. + let expected_delta: QuadFelt = per_row_values.iter().copied().sum(); + let actual_delta = aux_values[(r + 1) * aux_width] - aux_values[r * aux_width]; + assert_eq!( + actual_delta, expected_delta, + "row {r} col 0 (accumulator): prover vs constraint path mismatch", + ); + + // Fraction columns (cols 1+): aux[r][col] == per-row V/U. + for col in 1..LOGUP_AUX_TRACE_WIDTH { + let actual_value = aux_values[r * aux_width + col]; + assert_eq!( + actual_value, per_row_values[col], + "row {r} col {col} (fraction): prover vs constraint path mismatch", + ); + } + } +} diff --git a/processor/src/trace/tests/lookup_harness.rs b/processor/src/trace/tests/lookup_harness.rs new file mode 100644 index 0000000000..8876e6e1d6 --- /dev/null +++ b/processor/src/trace/tests/lookup_harness.rs @@ -0,0 +1,170 @@ +//! Column-agnostic, subset-based LogUp interaction harness. +//! +//! The prover path pushes one `(multiplicity, encoded_denominator)` pair per interaction into a +//! flat buffer. [`InteractionLog`] slices that buffer into per-row bags (across all columns) and +//! exposes one assertion, [`InteractionLog::assert_contains`]: for each row, the bag of expected +//! `(mult, msg)` pairs the test describes must be a multiset-subset of the bag of actual pushes. +//! +//! Tests describe expected interactions via [`Expectations`], which accepts raw +//! [`LookupMessage`] instances and encodes them against the log's challenges. `Expectations` is +//! column-blind by construction — two messages routed onto different aux columns still compare +//! equal if they share both multiplicity and encoded denominator. +//! +//! No scalar sums, no per-column deltas, no terminals: those views invite missing + spurious +//! interactions to cancel silently. Subset semantics over raw `(mult, denom)` tuples keeps every +//! expected interaction independently observable. + +use alloc::vec::Vec; + +use miden_air::{ + LiftedAir, ProcessorAir, + logup::{BusId, MIDEN_MAX_MESSAGE_WIDTH}, + lookup::{Challenges, LookupFractions, LookupMessage, build_lookup_fractions}, +}; +use miden_core::field::QuadFelt; +use miden_utils_testing::rand::rand_array; + +use super::{ExecutionTrace, Felt}; + +// INTERACTION LOG +// ================================================================================================ + +/// Per-row record of every `(multiplicity, denominator)` pair the prover path emitted for a +/// given execution trace, aggregated across all aux columns. +/// +/// Column identity is intentionally discarded: a row's contribution to the LogUp closure +/// identity is the union of its per-column pushes, and processor-side tests should stay +/// invariant under any AIR-side column repack. +pub(super) struct InteractionLog { + /// Random challenges used to encode messages. Exposed so `Expectations` can encode + /// hand-built [`LookupMessage`] instances against the same challenges used by the prover + /// path above. + pub challenges: Challenges, + /// `rows[r]` = multiset of `(mult, denom)` pushes the prover produced at main-trace row + /// `r`, across all columns, in builder order. + rows: Vec>, +} + +impl InteractionLog { + /// Drive the prover-path pipeline on `trace` with fresh random challenges and slice the + /// resulting [`LookupFractions`] buffer into per-row bags. + pub fn new(trace: &ExecutionTrace) -> Self { + let main_trace = trace.main_trace().to_row_major(); + let periodic = LiftedAir::::periodic_columns(&ProcessorAir); + + // `QuadFelt` itself isn't `Randomizable`, so draw 4 base-field elements and pair them. + let raw = rand_array::(); + let alpha = QuadFelt::new([raw[0], raw[1]]); + let beta = QuadFelt::new([raw[2], raw[3]]); + let challenges = + Challenges::::new(alpha, beta, MIDEN_MAX_MESSAGE_WIDTH, BusId::COUNT); + + let fractions = build_lookup_fractions(&ProcessorAir, &main_trace, &periodic, &challenges); + + Self { challenges, rows: split_rows(&fractions) } + } + + /// Verify that each row's expected bag is a multiset-subset of that row's actual bag of + /// prover pushes. + /// + /// For every `(row, mult, denom)` in `expected`, there must be at least as many matching + /// pushes at that row. Unclaimed actual pushes are ignored — this is the whole point of + /// subset semantics, so partial tests can focus on one bus or one instruction without + /// enumerating every other interaction that happens to fire. + pub fn assert_contains(&self, expected: &Expectations) { + for &entry in &expected.entries { + let (row, mult, denom) = entry; + let want = expected.entries.iter().filter(|&&e| e == entry).count(); + let have = self.rows[row].iter().filter(|&&(m, d)| m == mult && d == denom).count(); + assert!( + have >= want, + "row {row}: expected at least {want}× (mult={mult:?}, denom={denom:?}), saw {have}.\n\ + actual row bag: {:?}", + self.rows[row], + ); + } + } +} + +// EXPECTATIONS +// ================================================================================================ + +/// Hand-assembled list of `(row, multiplicity, encoded_denominator)` triples representing the +/// interactions a test expects to see somewhere on that row. +/// +/// [`Expectations`] is column-blind by construction: `add` / `remove` / `signed` encode a +/// [`LookupMessage`] against the owning [`InteractionLog`]'s challenges and store only the +/// resulting denominator plus the signed multiplicity, so the subsequent subset check never +/// consults column identity. +pub(super) struct Expectations<'a> { + challenges: &'a Challenges, + entries: Vec<(usize, Felt, QuadFelt)>, +} + +impl<'a> Expectations<'a> { + /// Start an empty expectation set tied to `log`'s challenges. + pub fn new(log: &'a InteractionLog) -> Self { + Self { + challenges: &log.challenges, + entries: Vec::new(), + } + } + + /// Add an expected `+1 · 1 / encode(msg)` interaction at `row`. + pub fn add(&mut self, row: usize, msg: &M) -> &mut Self + where + M: LookupMessage, + { + self.push(row, Felt::ONE, msg) + } + + /// Add an expected `-1 · 1 / encode(msg)` interaction at `row`. + pub fn remove(&mut self, row: usize, msg: &M) -> &mut Self + where + M: LookupMessage, + { + self.push(row, -Felt::ONE, msg) + } + + /// Add an expected `mult · 1 / encode(msg)` interaction at `row` with arbitrary + /// multiplicity. Use for range-check table lookups and kernel-ROM table multiplicities. + pub fn push(&mut self, row: usize, mult: Felt, msg: &M) -> &mut Self + where + M: LookupMessage, + { + let denom = msg.encode(self.challenges); + self.entries.push((row, mult, denom)); + self + } + + /// Number of expected entries registered via `add` (multiplicity = +1). + pub fn count_adds(&self) -> usize { + self.entries.iter().filter(|(_, m, _)| *m == Felt::ONE).count() + } + + /// Number of expected entries registered via `remove` (multiplicity = -1). + pub fn count_removes(&self) -> usize { + self.entries.iter().filter(|(_, m, _)| *m == -Felt::ONE).count() + } +} + +// HELPERS +// ================================================================================================ + +/// Slice the flat `LookupFractions` buffer into per-row bags using the row-major `counts` +/// layout (see `air/src/lookup/fractions.rs` for the ordering spec). +fn split_rows(fractions: &LookupFractions) -> Vec> { + let num_cols = fractions.num_columns(); + let counts = fractions.counts(); + let flat = fractions.fractions(); + + let num_rows = counts.len() / num_cols; + let mut rows = Vec::with_capacity(num_rows); + let mut cursor = 0usize; + for per_row in counts.chunks(num_cols) { + let total: usize = per_row.iter().sum(); + rows.push(flat[cursor..cursor + total].to_vec()); + cursor += total; + } + rows +} diff --git a/processor/src/trace/tests/mod.rs b/processor/src/trace/tests/mod.rs index cf20b974d9..1a8880a4fa 100644 --- a/processor/src/trace/tests/mod.rs +++ b/processor/src/trace/tests/mod.rs @@ -9,13 +9,13 @@ use miden_utils_testing::rand::rand_array; use super::{ExecutionTrace, Felt}; use crate::{ - AdviceInputs, DefaultHost, ExecutionOptions, FastProcessor, StackInputs, - trace::{build_trace, chiplets::init_state_from_words}, + AdviceInputs, DefaultHost, ExecutionOptions, FastProcessor, StackInputs, trace::build_trace, }; mod chiplets; mod decoder; -mod hasher; +mod lookup; +mod lookup_harness; mod range; mod stack; @@ -29,7 +29,7 @@ const TEST_TRACE_FRAGMENT_SIZE: usize = 1 << 10; /// Builds a sample trace by executing the provided code block against the provided stack inputs. pub fn build_trace_from_program(program: &Program, stack_inputs: &[u64]) -> ExecutionTrace { - let stack_inputs = stack_inputs.iter().map(|&v| Felt::new(v)).collect::>(); + let stack_inputs = stack_inputs.iter().map(|&v| Felt::new_unchecked(v)).collect::>(); let mut host = DefaultHost::default(); let processor = FastProcessor::new_with_options( StackInputs::new(&stack_inputs).unwrap(), @@ -37,11 +37,32 @@ pub fn build_trace_from_program(program: &Program, stack_inputs: &[u64]) -> Exec ExecutionOptions::default() .with_core_trace_fragment_size(TEST_TRACE_FRAGMENT_SIZE) .unwrap(), - ); - let (execution_output, trace_generation_context) = - processor.execute_for_trace_sync(program, &mut host).unwrap(); + ) + .expect("processor advice inputs should fit advice map limits"); + let trace_inputs = processor.execute_trace_inputs_sync(program, &mut host).unwrap(); + build_trace(trace_inputs).unwrap() +} - build_trace(execution_output, trace_generation_context, program.to_info()).unwrap() +/// Builds a sample trace by executing the provided program with pre-built `StackInputs`. +/// +/// Unlike [`build_trace_from_program`], this helper accepts a `StackInputs` value directly so +/// that callers can supply `Felt` elements (e.g. a procedure hash word) without having to +/// convert them through `u64` first. +pub fn build_trace_from_program_with_stack( + program: &Program, + stack_inputs: StackInputs, +) -> ExecutionTrace { + let mut host = DefaultHost::default(); + let processor = FastProcessor::new_with_options( + stack_inputs, + AdviceInputs::default(), + ExecutionOptions::default() + .with_core_trace_fragment_size(TEST_TRACE_FRAGMENT_SIZE) + .unwrap(), + ) + .expect("processor advice inputs should fit advice map limits"); + let trace_inputs = processor.execute_trace_inputs_sync(program, &mut host).unwrap(); + build_trace(trace_inputs).unwrap() } /// Builds a sample trace by executing a span block containing the specified operations. This @@ -59,9 +80,10 @@ pub fn build_trace_from_ops(operations: Vec, stack: &[u64]) -> Execut build_trace_from_program(&program, stack) } -/// Builds a sample trace by executing a span block containing the specified operations. Unlike the -/// function above, this function accepts the full [AdviceInputs] object, which means it can run -/// the programs with initialized advice provider. +/// Builds a sample trace by executing a span block containing the specified operations. Unlike +/// [`build_trace_from_ops`], this variant accepts the full [`AdviceInputs`] object, so the +/// program can run against an initialised advice provider (e.g. to seed a Merkle tree for the +/// sibling-table tests). pub fn build_trace_from_ops_with_inputs( operations: Vec, stack_inputs: StackInputs, @@ -81,9 +103,8 @@ pub fn build_trace_from_ops_with_inputs( ExecutionOptions::default() .with_core_trace_fragment_size(TEST_TRACE_FRAGMENT_SIZE) .unwrap(), - ); - let (execution_output, trace_generation_context) = - processor.execute_for_trace_sync(&program, &mut host).unwrap(); - - build_trace(execution_output, trace_generation_context, program.to_info()).unwrap() + ) + .expect("processor advice inputs should fit advice map limits"); + let trace_inputs = processor.execute_trace_inputs_sync(&program, &mut host).unwrap(); + build_trace(trace_inputs).unwrap() } diff --git a/processor/src/trace/tests/range.rs b/processor/src/trace/tests/range.rs index a73c4442c8..9b0855710b 100644 --- a/processor/src/trace/tests/range.rs +++ b/processor/src/trace/tests/range.rs @@ -1,79 +1,68 @@ -use miden_air::trace::{ - AUX_TRACE_RAND_CHALLENGES, chiplets::hasher::HASH_CYCLE_LEN, range::B_RANGE_COL_IDX, +//! Range-check bus test. +//! +//! Verifies that every expected `RangeMsg` interaction fires at the right row, whether it +//! comes from a u32 stack op (decoder-side `user_op_helpers`) or a memory chiplet row (delta +//! limbs + word-address decomposition). The test is column-blind — since both call sites are +//! currently packed into different aux columns (M1 for u32rc, C2 for memory range checks), +//! the subset-based [`InteractionLog`] happens to pick up both without the test having to +//! know where each one landed. + +use alloc::vec::Vec; + +use miden_air::{ + logup::RangeMsg, + trace::{ + MainTrace, RANGE_CHECK_TRACE_OFFSET, + chiplets::{MEMORY_D0_COL_IDX, MEMORY_D1_COL_IDX}, + }, }; -use miden_core::{ONE, ZERO, field::Field, operations::Operation}; -use miden_utils_testing::rand::rand_array; +use miden_core::{Felt, operations::Operation}; +use miden_utils_testing::stack; -use super::{Felt, build_trace_from_ops}; +use super::{ + build_trace_from_ops, + lookup_harness::{Expectations, InteractionLog}, +}; +use crate::RowIndex; -/// This test checks that range check lookups from stack operations are balanced by the range checks -/// processed in the Range Checker. -/// -/// The `U32add` operation results in 4 16-bit range checks of 256, 0, 0, 0. +/// `U32add` range-checks its four decoder helper columns: for `1 + 255 = 256`, the four +/// values are `{0, 256, 0, 0}`, so we expect exactly three removes of `RangeMsg { value: 0 }` +/// and one remove of `RangeMsg { value: 256 }` at the U32add row. #[test] -fn b_range_trace_stack() { +fn u32_stack_op_emits_range_check_removes() { let stack = [1, 255]; let operations = vec![Operation::U32add]; let trace = build_trace_from_ops(operations, &stack); + let log = InteractionLog::new(&trace); + let main = trace.main_trace(); - let rand_elements = rand_array::(); - let alpha = rand_elements[0]; - let aux_columns = trace.build_aux_trace(&rand_elements).unwrap(); - let b_range = aux_columns.get_column(B_RANGE_COL_IDX); - - assert_eq!(trace.length(), b_range.len()); - - // --- Check the stack processor's range check lookups. --------------------------------------- - - // Before any range checks are executed, the value in b_range should be zero. - assert_eq!(ZERO, b_range[0]); - assert_eq!(ZERO, b_range[1]); - - // The first range check lookup from the stack will happen when the add operation is executed, - // at cycle 1. (The trace begins by executing `span`). It must be subtracted out of `b_range`. - // The range-checked values are 0, 256, 0, 0, so the values to subtract are 3/(alpha + 0) and - // 1/(alpha + 256). - let lookups = alpha.inverse() * Felt::new(3) + (alpha + Felt::new(256)).inverse(); - let mut expected = b_range[1] - lookups; - assert_eq!(expected, b_range[2]); - - // --- Check the range checker's lookups. ----------------------------------------------------- - - // 44 rows are needed for 0, 243, 252, 255, 256, ... 38 additional bridge rows of powers of - // 3 ..., 65535. (0 and 256 are range-checked. 65535 is the max, and the rest are "bridge" - // values.) An extra row is added to pad the u16::MAX value. - let len_16bit = 44 + 1; - // The start of the values in the range checker table. - let values_start = trace.length() - len_16bit; - - // After the padded rows, the first value will be unchanged. - assert_eq!(expected, b_range[values_start]); - // We include 3 lookups of 0. - expected += alpha.inverse() * Felt::new(3); - assert_eq!(expected, b_range[values_start + 1]); - // Then we have 3 bridge rows between 0 and 255 where the value does not change - assert_eq!(expected, b_range[values_start + 2]); - assert_eq!(expected, b_range[values_start + 3]); - assert_eq!(expected, b_range[values_start + 4]); - // Then we include 1 lookup of 256, so it should be multiplied by alpha + 256. - expected += (alpha + Felt::new(256)).inverse(); - assert_eq!(expected, b_range[values_start + 5]); - - // --- Check the last value of the b_range column is zero -------------------------------------- - - let last_row = b_range.len() - 1; - assert_eq!(ZERO, b_range[last_row]); + let u32add_row = find_op_row(main, miden_core::operations::opcodes::U32ADD); + + let mut exp = Expectations::new(&log); + for i in 0..4 { + let value = main.helper_register(i, u32add_row); + exp.remove(usize::from(u32add_row), &RangeMsg { value }); + } + + assert_eq!(exp.count_removes(), 4, "expected 4 helper-register range-check removes"); + assert_eq!(exp.count_adds(), 0); + log.assert_contains(&exp); } -/// This test checks that range check lookups from memory operations are balanced by the -/// range checks processed in the Range Checker. +/// Two memory ops (`MStoreW` + `MLoadW`) on the same word address emit 5 `RangeMsg` removes +/// per memory chiplet row: `d0`, `d1` (the 16-bit delta limbs used for sorted-access +/// constraints) and `w0`, `w1`, `4·w1` (the word-address decomposition). /// -/// The `StoreW` memory operation results in 2 16-bit range checks of 1, 0. -/// The `LoadW` memory operation results in 2 16-bit range checks of 5, 0. +/// The address `262148 = 4 · 65537` is word-aligned with `word_index = 65537 = 0x10001`, so +/// `w0 = 1`, `w1 = 1`, `4·w1 = 4` — a non-trivial decomposition that exercises the full +/// five-way range-check batch. #[test] -#[expect(clippy::needless_range_loop)] -fn b_range_trace_mem() { - let stack = [0, 1, 2, 3, 4, 0]; +fn memory_chiplet_row_emits_range_check_removes() { + let addr: u64 = 262148; + let stack_input = stack![addr, 1, 2, 3, 4, addr]; + + // MStoreW + 4×Drop + MLoadW, then 60 Noops so the memory chiplet segment does not overlap + // with the range checker's table segment at the end of the chiplet trace. let mut operations = vec![ Operation::MStoreW, Operation::Drop, @@ -82,67 +71,85 @@ fn b_range_trace_mem() { Operation::Drop, Operation::MLoadW, ]; - // Pad so that the memory chiplet and range checker sections don't overlap, - // in order to simplify the logic of the test. operations.resize(operations.len() + 60, Operation::Noop); - let trace = build_trace_from_ops(operations, &stack); - - let rand_elements = rand_array::(); - let alpha = rand_elements[0]; - let aux_columns = trace.build_aux_trace(&rand_elements).unwrap(); - let b_range = aux_columns.get_column(B_RANGE_COL_IDX); - - assert_eq!(trace.length(), b_range.len()); - - // The memory section of the chiplets trace starts after the span hash. - let memory_start = HASH_CYCLE_LEN; - - // 40 rows are needed for 0, 3, 4, ... 36 bridge additional bridge rows of powers of - // 3 ..., 65535. (0 and 4 are both range-checked. 65535 is the max, and the rest are "bridge" - // values.) An extra row is added to pad the u16::MAX value. - let len_16bit = 40 + 1; - let values_start = trace.length() - len_16bit; - - // The value should start at ZERO. - let mut expected = ZERO; - assert_eq!(expected, b_range[0]); - - // --- Check the memory processor's range check lookups. -------------------------------------- - - // There are two memory lookups. For each memory lookup, the context and address are unchanged, - // so the delta values indicated the clock cycle change clk' - clk. - // StoreW is executed at cycle 1 (after the initial span), so clk' - clk = 1. - let (d0_store, d1_store) = (ONE, ZERO); - // LoadW is executed at cycle 6, so i' - i = 6 - 1 = 5. - let (d0_load, d1_load) = (Felt::new(5), ZERO); - - // Include the lookups from the `MStoreW` operation at the next row. - expected -= (alpha + d0_store).inverse() + (alpha + d1_store).inverse(); - assert_eq!(expected, b_range[memory_start + 1]); - // Include the lookup from the `MLoadW` operation at the next row. - expected -= (alpha + d0_load).inverse() + (alpha + d1_load).inverse(); - assert_eq!(expected, b_range[memory_start + 2]); - - // --- Check the range checker's lookups. ----------------------------------------------------- - - // We include 2 lookups of ZERO in the next row. - expected += alpha.inverse() * Felt::new(2); - assert_eq!(expected, b_range[values_start + 1]); + let trace = build_trace_from_ops(operations, &stack_input); + let log = InteractionLog::new(&trace); + let main = trace.main_trace(); + + // Collect every memory chiplet row — we expect exactly two for the two memory ops. + let mut mem_rows: Vec = Vec::new(); + for row in 0..main.num_rows() { + let idx = RowIndex::from(row); + if main.is_memory_row(idx) { + mem_rows.push(idx); + } + } + assert_eq!(mem_rows.len(), 2, "expected exactly two memory chiplet rows"); + + let mut exp = Expectations::new(&log); + for mem_row in &mem_rows { + let row = usize::from(*mem_row); + let d0 = main.get(*mem_row, MEMORY_D0_COL_IDX); + let d1 = main.get(*mem_row, MEMORY_D1_COL_IDX); + let w0 = main.chiplet_memory_word_addr_lo(*mem_row); + let w1 = main.chiplet_memory_word_addr_hi(*mem_row); + let four_w1 = w1 * Felt::from_u8(4); + + for value in [d0, d1, w0, w1, four_w1] { + exp.remove(row, &RangeMsg { value }); + } + } - // We include 1 lookup of ONE in the next row. - expected += (alpha + d0_store).inverse(); - assert_eq!(expected, b_range[values_start + 2]); + assert_eq!(exp.count_removes(), 5 * mem_rows.len(), "expected 5 RC removes per memory row"); + assert_eq!(exp.count_adds(), 0); + log.assert_contains(&exp); +} - // We have one bridge row between 1 and 5 where the value does not change. - assert_eq!(expected, b_range[values_start + 3]); +/// Every trace row carries the range-checker table's response: a `RangeMsg { value: v }` add +/// with runtime multiplicity `m`. This test verifies the per-row add side of the bus using +/// hardcoded request demand: a `U32add` requests 4 values (helper columns) and each chiplet +/// row with a range-check demand adds its `m` copies of that value to the bus. +/// +/// Catches regressions where the range-checker add-back emitter misreads the multiplicity +/// column, the value column, or drops the always-active gate — bugs that the per-request +/// removes-only tests above cannot detect. +#[test] +fn range_checker_table_emits_per_row_adds() { + // U32add issues 4 range-check requests for values {0, 256, 0, 0} on 1 + 255 = 256. The + // range-checker chiplet will then add back four multiplicities of those values distributed + // across its trace rows. We don't need to predict where — subset semantics lets us verify + // that *every* row's add matches its `(m, v)` columns. + let stack = [1, 255]; + let operations = vec![Operation::U32add]; + let trace = build_trace_from_ops(operations, &stack); + let log = InteractionLog::new(&trace); + let main = trace.main_trace(); + + const M_COL_IDX: usize = RANGE_CHECK_TRACE_OFFSET; + const V_COL_IDX: usize = RANGE_CHECK_TRACE_OFFSET + 1; + + let mut nonzero_mult_rows = 0usize; + let mut exp = Expectations::new(&log); + for row in 0..main.num_rows() { + let idx = RowIndex::from(row); + let m = main.get(idx, M_COL_IDX); + let v = main.get(idx, V_COL_IDX); + exp.push(row, m, &RangeMsg { value: v }); + if m != Felt::from_u8(0) { + nonzero_mult_rows += 1; + } + } - // We include 1 lookup of 5 in the next row. - expected += (alpha + d0_load).inverse(); - assert_eq!(expected, b_range[values_start + 4]); + assert!(nonzero_mult_rows > 0, "range checker table is empty — test is vacuous"); + log.assert_contains(&exp); +} - // --- The value should now be ZERO for the rest of the trace. --------------------------------- - assert_eq!(expected, ZERO); - for i in (values_start + 4)..(b_range.len()) { - assert_eq!(ZERO, b_range[i]); +fn find_op_row(main: &MainTrace, opcode: u8) -> RowIndex { + for row in 0..main.num_rows() { + let idx = RowIndex::from(row); + if main.get_op_code(idx) == Felt::from_u8(opcode) { + return idx; + } } + panic!("no row with opcode 0x{opcode:02x} in trace"); } diff --git a/processor/src/trace/tests/stack.rs b/processor/src/trace/tests/stack.rs index 8a0f044cc3..56d7b40f9b 100644 --- a/processor/src/trace/tests/stack.rs +++ b/processor/src/trace/tests/stack.rs @@ -1,97 +1,86 @@ -use alloc::vec::Vec; - -use miden_air::trace::{AUX_TRACE_RAND_CHALLENGES, Challenges, STACK_AUX_TRACE_OFFSET}; -use miden_core::{ONE, ZERO, field::Field, operations::Operation}; - -use super::{super::stack::OverflowTableRow, Felt, build_trace_from_ops, rand_array}; +//! Stack overflow table bus test. +//! +//! Runs a PAD/DROP sequence and verifies that every interaction the stack-overflow bus emitter +//! fires at a right-shift (`PAD`) or left-shift-with-non-empty-overflow (`DROP`) row appears +//! somewhere in that row's bag of prover pushes. The test is column-blind — see +//! `processor/src/trace/tests/lookup_harness.rs` for the subset matcher. +//! +//! The DYNCALL branch of the bus is intentionally not exercised here; constructing a DYNCALL +//! with a non-empty overflow requires a full program around a host and fits better in an +//! integration test. -// CONSTANTS -// ================================================================================================ +use alloc::vec::Vec; -const P1_COL_IDX: usize = STACK_AUX_TRACE_OFFSET; -const TWO: Felt = Felt::new(2); +use miden_air::logup::StackOverflowMsg; +use miden_core::{ + Felt, + operations::{Operation, opcodes}, +}; -// OVERFLOW TABLE TESTS -// ================================================================================================ +use super::{ + build_trace_from_ops, + lookup_harness::{Expectations, InteractionLog}, +}; +use crate::RowIndex; #[test] -#[expect(clippy::needless_range_loop)] -fn p1_trace() { +fn stack_overflow_bus_emits_per_interaction_row() { + // Mix of right-shifts (PAD) and left-shifts (DROP) around a couple of U32add no-shift ops, + // ending with the overflow table empty. + // Overflow depth before each op (determines whether DROP emits): + // U32add:0 Pad:0→1 Pad:1→2 U32add:2 Drop:2→1 Pad:1→2 Drop:2→1 Drop:1→0 Drop:0 Pad:0→1 + // Drop:1→0 Four of the five DROPs run against a non-empty table and emit; the fourth DROP + // sees overflow=0 and is a no-op. All four PADs emit. let ops = vec![ - Operation::U32add, // no shift, clk 1 - Operation::Pad, // right shift, clk 2 - Operation::Pad, // right shift, clk 3 - Operation::U32add, // no shift, clk 4 - Operation::Drop, // left shift, clk 5 - Operation::Pad, // right shift, clk 6 - Operation::Drop, // left shift, clk 7 - Operation::Drop, // left shift, clk 8 - Operation::Drop, // left shift, clk 9 - Operation::Pad, // right shift, clk 10 - Operation::Drop, // left shift, clk 11 + Operation::U32add, // no shift + Operation::Pad, // right shift + Operation::Pad, // right shift + Operation::U32add, // no shift + Operation::Drop, // left shift (overflow=2 → remove) + Operation::Pad, // right shift + Operation::Drop, // left shift (overflow=2 → remove) + Operation::Drop, // left shift (overflow=1 → remove) + Operation::Drop, // left shift (overflow=0 → no interaction) + Operation::Pad, // right shift + Operation::Drop, // left shift (overflow=1 → remove) ]; - let init_stack = (1..17).rev().collect::>(); + let init_stack = (1..17).rev().collect::>(); let trace = build_trace_from_ops(ops, &init_stack); - let challenges = rand_array::(); - let aux_columns = trace.build_aux_trace(&challenges).unwrap(); - let p1 = aux_columns.get_column(P1_COL_IDX); - - let challenges: Challenges = Challenges::::new(challenges[0], challenges[1]); - let row_values = [ - OverflowTableRow::new(Felt::new(2), ONE, ZERO).to_value(&challenges), - OverflowTableRow::new(Felt::new(3), TWO, TWO).to_value(&challenges), - OverflowTableRow::new(Felt::new(6), TWO, TWO).to_value(&challenges), - OverflowTableRow::new(Felt::new(10), ZERO, ZERO).to_value(&challenges), - ]; - - // make sure the first entry is ONE - let mut expected_value = ONE; - assert_eq!(expected_value, p1[0]); - - // SPAN and U32ADD do not affect the overflow table - assert_eq!(expected_value, p1[1]); - assert_eq!(expected_value, p1[2]); - - // two PADs push values 1 and 2 onto the overflow table - expected_value *= row_values[0]; - assert_eq!(expected_value, p1[3]); - expected_value *= row_values[1]; - assert_eq!(expected_value, p1[4]); - - // U32ADD does not affect the overflow table - assert_eq!(expected_value, p1[5]); - - // DROP removes a row from the overflow table - expected_value *= row_values[1].inverse(); - assert_eq!(expected_value, p1[6]); - - // PAD pushes the value onto the overflow table again - expected_value *= row_values[2]; - assert_eq!(expected_value, p1[7]); - - // two DROPs remove both values from the overflow table - expected_value *= row_values[2].inverse(); - assert_eq!(expected_value, p1[8]); - expected_value *= row_values[0].inverse(); - assert_eq!(expected_value, p1[9]); - - // at this point the table should be empty - assert_eq!(expected_value, ONE); - - // the 3rd DROP should not affect the overflow table as it is already empty - assert_eq!(expected_value, p1[10]); - - // PAD pushes the value (ZERO) onto the overflow table again - expected_value *= row_values[3]; - assert_eq!(expected_value, p1[11]); - - // and then the last DROP removes it from the overflow table - expected_value *= row_values[3].inverse(); - assert_eq!(expected_value, p1[12]); - - // at this point the table should be empty again, and it should stay empty until the end - assert_eq!(expected_value, ONE); - for i in 13..(p1.len()) { - assert_eq!(ONE, p1[i]); + let log = InteractionLog::new(&trace); + let main = trace.main_trace(); + + let mut exp = Expectations::new(&log); + for row in 0..main.num_rows() { + let idx = RowIndex::from(row); + let next = RowIndex::from(row + 1); + let op = main.get_op_code(idx); + + if op == Felt::from_u8(opcodes::PAD) { + // Right shift: `add (clk, s15, b1)`. + exp.add( + row, + &StackOverflowMsg { + clk: main.clk(idx), + val: main.stack_element(15, idx), + prev: main.parent_overflow_address(idx), + }, + ); + } else if op == Felt::from_u8(opcodes::DROP) && main.is_non_empty_overflow(idx) { + // Left shift with non-empty overflow: `remove (b1, s15', b1')`. + exp.remove( + row, + &StackOverflowMsg { + clk: main.parent_overflow_address(idx), + val: main.stack_element(15, next), + prev: main.parent_overflow_address(next), + }, + ); + } } + + // 4 PADs and 4 DROPs-with-non-empty-overflow (only the lone DROP on an empty overflow + // table emits nothing). + assert_eq!(exp.count_adds(), 4, "expected one add per PAD"); + assert_eq!(exp.count_removes(), 4, "expected one remove per DROP with non-empty overflow"); + log.assert_contains(&exp); } diff --git a/processor/src/trace/trace_state.rs b/processor/src/trace/trace_state.rs index 9232ac5fc6..4b49af3498 100644 --- a/processor/src/trace/trace_state.rs +++ b/processor/src/trace/trace_state.rs @@ -128,18 +128,17 @@ impl DecoderState { /// This function is called when we hit an `END` operation, signaling the end of execution for a /// node. It updates the decoder state to point to the previous node in the block stack (which - /// could be renamed to "node stack"), and returns the address of the node that just ended, - /// along with any flags associated with it. + /// could be renamed to "node stack"), and returns the address of the node that just ended. pub fn replay_node_end( &mut self, block_stack_replay: &mut BlockStackReplay, - ) -> Result<(Felt, NodeFlags), ExecutionError> { + ) -> Result { let node_end_data = block_stack_replay.replay_node_end()?; self.current_addr = node_end_data.prev_addr; self.parent_addr = node_end_data.prev_parent_addr; - Ok((node_end_data.ended_node_addr, node_end_data.flags)) + Ok(node_end_data.ended_node_addr) } } @@ -241,7 +240,7 @@ impl StackState { /// It is expected that this values gets later inverted via batch inversion. pub fn overflow_helper(&self) -> Felt { let denominator = self.stack_depth() - MIN_STACK_DEPTH; - Felt::new(denominator as u64) + Felt::new_unchecked(denominator as u64) } /// Starts a new execution context for this stack, resetting the stack depth to its minimum @@ -348,13 +347,11 @@ impl BlockStackReplay { pub fn record_node_end( &mut self, ended_node_addr: Felt, - flags: NodeFlags, prev_addr: Felt, prev_parent_addr: Felt, ) { self.node_end.push_back(NodeEndData { ended_node_addr, - flags, prev_addr, prev_parent_addr, }); @@ -425,16 +422,13 @@ impl NodeFlags { /// The data needed to fully recover the state on an END operation. /// -/// We record `ended_node_addr` and `flags` in order to be able to properly populate the trace -/// row for the node operation. Additionally, we record `prev_addr` and `prev_parent_addr` to -/// allow emulating peeking into the block stack, which is needed when processing REPEAT or RESPAN -/// nodes. +/// We record `ended_node_addr` in order to be able to properly populate the trace row for the +/// node operation. Additionally, we record `prev_addr` and `prev_parent_addr` to allow emulating +/// peeking into the block stack, which is needed when processing REPEAT or RESPAN nodes. #[derive(Debug)] pub struct NodeEndData { /// the address of the node that is ending pub ended_node_addr: Felt, - /// the flags associated with the node that is ending - pub flags: NodeFlags, /// the address of the node sitting on top of the block stack after the END operation (or 0 if /// the block stack is empty) pub prev_addr: Felt, diff --git a/processor/src/trace/utils.rs b/processor/src/trace/utils.rs index 893e003b17..984ab7837e 100644 --- a/processor/src/trace/utils.rs +++ b/processor/src/trace/utils.rs @@ -1,18 +1,38 @@ -use alloc::{string::ToString, vec::Vec}; -use core::{mem::MaybeUninit, slice}; +use alloc::vec::Vec; +use core::slice; -use miden_air::trace::{Challenges, MIN_TRACE_LEN, MainTrace}; +use miden_air::trace::MIN_TRACE_LEN; use super::chiplets::Chiplets; -use crate::{ - Felt, RowIndex, - debug::BusDebugger, - field::ExtensionField, - utils::{assume_init_vec, uninit_vector}, -}; +use crate::{Felt, RowIndex}; #[cfg(test)] use crate::{operation::Operation, utils::ToElements}; +// ROW-MAJOR TRACE WRITER +// ================================================================================================ + +/// Row-major flat buffer writer (`write_row` is a single `copy_from_slice`). +#[derive(Debug)] +pub struct RowMajorTraceWriter<'a, E> { + data: &'a mut [E], + width: usize, +} + +impl<'a, E: Copy> RowMajorTraceWriter<'a, E> { + pub fn new(data: &'a mut [E], width: usize) -> Self { + debug_assert_eq!(data.len() % width, 0, "buffer length must be a multiple of width"); + Self { data, width } + } + + /// Writes one row; `values.len()` must equal `width`. + #[inline(always)] + pub fn write_row(&mut self, row: usize, values: &[E]) { + debug_assert_eq!(values.len(), self.width); + let start = row * self.width; + self.data[start..start + self.width].copy_from_slice(values); + } +} + // TRACE FRAGMENT // ================================================================================================ @@ -152,13 +172,13 @@ impl TraceLenSummary { // CHIPLET LENGTHS // ================================================================================================ -/// Contains trace lengths of all chilplets: hash, bitwise, memory and kernel ROM trace -/// lengths. +/// Contains trace lengths of all chiplets: hash, bitwise, memory, ACE, and kernel ROM. #[derive(Default, Clone, Copy, Debug, PartialEq, Eq)] pub struct ChipletsLengths { hash_chiplet_len: usize, bitwise_chiplet_len: usize, memory_chiplet_len: usize, + ace_chiplet_len: usize, kernel_rom_len: usize, } @@ -167,7 +187,8 @@ impl ChipletsLengths { ChipletsLengths { hash_chiplet_len: chiplets.bitwise_start().into(), bitwise_chiplet_len: chiplets.memory_start() - chiplets.bitwise_start(), - memory_chiplet_len: chiplets.kernel_rom_start() - chiplets.memory_start(), + memory_chiplet_len: chiplets.ace_start() - chiplets.memory_start(), + ace_chiplet_len: chiplets.kernel_rom_start() - chiplets.ace_start(), kernel_rom_len: chiplets.padding_start() - chiplets.kernel_rom_start(), } } @@ -176,32 +197,39 @@ impl ChipletsLengths { hash_len: usize, bitwise_len: usize, memory_len: usize, + ace_len: usize, kernel_len: usize, ) -> Self { ChipletsLengths { hash_chiplet_len: hash_len, bitwise_chiplet_len: bitwise_len, memory_chiplet_len: memory_len, + ace_chiplet_len: ace_len, kernel_rom_len: kernel_len, } } - /// Returns the length of the hash chiplet trace + /// Returns the length of the hash chiplet trace. pub fn hash_chiplet_len(&self) -> usize { self.hash_chiplet_len } - /// Returns the length of the bitwise trace + /// Returns the length of the bitwise trace. pub fn bitwise_chiplet_len(&self) -> usize { self.bitwise_chiplet_len } - /// Returns the length of the memory trace + /// Returns the length of the memory trace. pub fn memory_chiplet_len(&self) -> usize { self.memory_chiplet_len } - /// Returns the length of the kernel ROM trace + /// Returns the length of the ACE chiplet trace. + pub fn ace_chiplet_len(&self) -> usize { + self.ace_chiplet_len + } + + /// Returns the length of the kernel ROM trace. pub fn kernel_rom_len(&self) -> usize { self.kernel_rom_len } @@ -213,99 +241,12 @@ impl ChipletsLengths { self.hash_chiplet_len() + self.bitwise_chiplet_len() + self.memory_chiplet_len() + + self.ace_chiplet_len() + self.kernel_rom_len() + 1 } } -// AUXILIARY COLUMN BUILDER -// ================================================================================================ - -/// Defines a builder responsible for building a single auxiliary bus column in the execution -/// trace. -/// -/// Columns are initialized to the multiset identity. Public-input-dependent boundary -/// terms are used in the check by the verifier in `reduced_aux_values` for the final values of -/// the auxiliary columns. -pub(crate) trait AuxColumnBuilder> { - // REQUIRED METHODS - // -------------------------------------------------------------------------------------------- - - fn get_requests_at( - &self, - main_trace: &MainTrace, - challenges: &Challenges, - row: RowIndex, - debugger: &mut BusDebugger, - ) -> E; - - fn get_responses_at( - &self, - main_trace: &MainTrace, - challenges: &Challenges, - row: RowIndex, - debugger: &mut BusDebugger, - ) -> E; - - /// Whether to assert that all requests/responses balance in debug mode. - /// - /// Buses whose final value encodes a public-input-dependent boundary term (checked - /// via `reduced_aux_values`) will NOT balance to identity and should return `false`. - #[cfg(any(test, feature = "bus-debugger"))] - fn enforce_bus_balance(&self) -> bool; - - // PROVIDED METHODS - // -------------------------------------------------------------------------------------------- - - /// Builds an auxiliary bus trace column as a running product of responses over requests. - /// - /// The column is initialized to 1; boundary terms are checked via `reduced_aux_values` - /// in the verifier. - fn build_aux_column(&self, main_trace: &MainTrace, challenges: &Challenges) -> Vec { - let mut bus_debugger = BusDebugger::new("aux bus".to_string()); - - let mut requests: Vec> = uninit_vector(main_trace.num_rows()); - requests[0].write(E::ONE); - - let mut responses_prod: Vec> = uninit_vector(main_trace.num_rows()); - responses_prod[0].write(E::ONE); - - let mut requests_running_prod = E::ONE; - let mut prev_prod = E::ONE; - - // Product of all requests to be inverted, used to compute inverses of requests. - for row_idx in 0..main_trace.num_rows() - 1 { - let row = row_idx.into(); - - let response = self.get_responses_at(main_trace, challenges, row, &mut bus_debugger); - prev_prod *= response; - responses_prod[row_idx + 1].write(prev_prod); - - let request = self.get_requests_at(main_trace, challenges, row, &mut bus_debugger); - requests[row_idx + 1].write(request); - requests_running_prod *= request; - } - - // all elements are now initialized - let requests = unsafe { assume_init_vec(requests) }; - let mut result_aux_column = unsafe { assume_init_vec(responses_prod) }; - - // Use batch-inversion method to compute running product of `response[i]/request[i]`. - let mut requests_running_divisor = requests_running_prod.inverse(); - for i in (0..main_trace.num_rows()).rev() { - result_aux_column[i] *= requests_running_divisor; - requests_running_divisor *= requests[i]; - } - - #[cfg(any(test, feature = "bus-debugger"))] - if self.enforce_bus_balance() { - assert!(bus_debugger.is_empty(), "{bus_debugger}"); - } - - result_aux_column - } -} - // U32 HELPERS // ================================================================================================ @@ -313,7 +254,7 @@ pub(crate) trait AuxColumnBuilder> { /// valid 32-bit integer value. pub(crate) fn split_element_u32_into_u16(value: Felt) -> (Felt, Felt) { let (hi, lo) = split_u32_into_u16(value.as_canonical_u64()); - (Felt::new(hi as u64), Felt::new(lo as u64)) + (Felt::new_unchecked(hi as u64), Felt::new_unchecked(lo as u64)) } /// Splits a u64 integer assumed to contain a 32-bit value into two u16 integers. @@ -333,10 +274,13 @@ pub(crate) fn split_u32_into_u16(value: u64) -> (u16, u16) { // TEST HELPERS // ================================================================================================ +/// Builds a 17-op basic block payload that straddles a RESPAN batch boundary, plus the initial +/// values its `Push` ops emit. Consumed by decoder / hasher tests that exercise multi-batch +/// SPAN execution. #[cfg(test)] pub fn build_span_with_respan_ops() -> (Vec, Vec) { let iv = [1, 3, 5, 7, 9, 11, 13, 15, 17].to_elements(); - let ops = vec![ + let ops = alloc::vec![ Operation::Push(iv[0]), Operation::Push(iv[1]), Operation::Push(iv[2]), diff --git a/processor/src/tracer.rs b/processor/src/tracer.rs index 328553e66b..b9e3676042 100644 --- a/processor/src/tracer.rs +++ b/processor/src/tracer.rs @@ -20,9 +20,9 @@ use crate::{ /// A trait for tracing the execution of a processor. /// /// Allows for recording different aspects of the processor's execution. For example, the -/// [`crate::FastProcessor::execute_for_trace`] execution mode needs to build a -/// [`crate::fast::execution_tracer::TraceGenerationContext`] which records information necessary to -/// build the trace at each clock cycle. +/// [`crate::FastProcessor::execute_trace_inputs`] execution mode needs to build a +/// [`crate::TraceGenerationContext`] which records information necessary to build the trace at each +/// clock cycle. /// /// A useful mental model to differentiate between the processor and the tracer is: /// - Processor: maintains and mutates the state of the VM components (system, stack, memory, etc) @@ -66,7 +66,7 @@ pub trait Tracer { /// the current clock cycle. /// /// `continuation` represents what is to be executed at the beginning of this clock cycle, while - /// `continuation_stack` represents whatever comes after execution `continuation`. + /// `continuation_stack` represents whatever comes after executing `continuation`. /// /// The following continuations do not occur at the start of a clock cycle, and hence will never /// be passed to this method: diff --git a/processor/tests/async_compat.rs b/processor/tests/async_compat.rs new file mode 100644 index 0000000000..58570b2175 --- /dev/null +++ b/processor/tests/async_compat.rs @@ -0,0 +1,138 @@ +use std::sync::Arc; + +use miden_assembly::Assembler; +use miden_debug_types::{Location, SourceFile, SourceSpan}; +use miden_processor::{ + BaseHost, DefaultHost, ExecutionOptions, FastProcessor, Felt, FutureMaybeSend, Host, + ProcessorState, StackInputs, Word, + advice::{AdviceInputs, AdviceMutation}, + event::{EventError, EventName}, + mast::MastForest, +}; + +struct YieldingAsyncHost { + event_calls: usize, +} + +impl YieldingAsyncHost { + fn new() -> Self { + Self { event_calls: 0 } + } +} + +impl BaseHost for YieldingAsyncHost { + fn get_label_and_source_file( + &self, + _location: &Location, + ) -> (SourceSpan, Option>) { + (SourceSpan::UNKNOWN, None) + } +} + +impl Host for YieldingAsyncHost { + fn get_mast_forest( + &self, + _node_digest: &Word, + ) -> impl FutureMaybeSend>> { + async { None } + } + + fn on_event( + &mut self, + _process: &ProcessorState<'_>, + ) -> impl FutureMaybeSend, EventError>> { + self.event_calls += 1; + async { + tokio::task::yield_now().await; + Ok(Vec::new()) + } + } +} + +fn simple_program() -> miden_processor::Program { + Assembler::default() + .assemble_program( + r#" + begin + push.2 + add + end + "#, + ) + .expect("program should compile") +} + +#[tokio::test(flavor = "current_thread")] +async fn execute_async_matches_execute() { + let program = simple_program(); + let stack_inputs = StackInputs::new(&[Felt::new_unchecked(3)]).unwrap(); + let advice_inputs = AdviceInputs::default(); + + let mut sync_host = DefaultHost::default(); + let sync_output = miden_processor::execute_sync( + &program, + stack_inputs, + advice_inputs.clone(), + &mut sync_host, + ExecutionOptions::default(), + ) + .unwrap(); + + let mut async_host = DefaultHost::default(); + let async_output = miden_processor::execute( + &program, + stack_inputs, + advice_inputs, + &mut async_host, + ExecutionOptions::default(), + ) + .await + .unwrap(); + + assert_eq!(sync_output.stack, async_output.stack); +} + +#[tokio::test(flavor = "current_thread")] +async fn fast_processor_execute_for_trace_async_matches_sync() { + let program = simple_program(); + let stack_inputs = StackInputs::new(&[Felt::new_unchecked(3)]).unwrap(); + + let mut sync_host = DefaultHost::default(); + let sync_trace_inputs = FastProcessor::new(stack_inputs) + .execute_trace_inputs_sync(&program, &mut sync_host) + .unwrap(); + + let mut async_host = DefaultHost::default(); + let async_trace_inputs = FastProcessor::new(stack_inputs) + .execute_trace_inputs(&program, &mut async_host) + .await + .unwrap(); + + assert_eq!(sync_trace_inputs.stack_outputs(), async_trace_inputs.stack_outputs()); + assert_eq!( + sync_trace_inputs.trace_generation_context().fragment_size, + async_trace_inputs.trace_generation_context().fragment_size + ); + assert_eq!( + sync_trace_inputs.trace_generation_context().core_trace_contexts.len(), + async_trace_inputs.trace_generation_context().core_trace_contexts.len() + ); +} + +#[tokio::test(flavor = "current_thread")] +async fn execute_async_supports_async_only_host_events() { + let event_name = EventName::new("test::async::emit"); + let event_id = event_name.to_event_id().as_u64(); + let program = Assembler::default() + .assemble_program(format!("begin push.{event_id} emit drop end")) + .expect("program should compile"); + + let mut host = YieldingAsyncHost::new(); + let output = FastProcessor::new(StackInputs::default()) + .execute(&program, &mut host) + .await + .expect("async execution should succeed"); + + assert_eq!(host.event_calls, 1); + assert_eq!(output.stack.get_num_elements(16).len(), 16); +} diff --git a/processor/tests/eval_circuit_overflow.rs b/processor/tests/eval_circuit_overflow.rs index c38e06b13a..71b6c23bbb 100644 --- a/processor/tests/eval_circuit_overflow.rs +++ b/processor/tests/eval_circuit_overflow.rs @@ -9,9 +9,9 @@ use miden_processor::{ #[test] fn eval_circuit_overflow_panic_check() { - let ptr = Felt::new(0); - let n_read = Felt::new(Felt::ORDER_U64 - 3); // = 2^64 - 2^32 - 2 - let n_eval = Felt::new((1u64 << 32) + 4); // = 2^32 + 4 + let ptr = Felt::new_unchecked(0); + let n_read = Felt::new_unchecked(Felt::ORDER_U64 - 3); // = 2^64 - 2^32 - 2 + let n_eval = Felt::new_unchecked((1u64 << 32) + 4); // = 2^32 + 4 let stack_inputs = StackInputs::new(&[ptr, n_read, n_eval]).unwrap(); @@ -29,7 +29,8 @@ fn eval_circuit_overflow_panic_check() { stack_inputs, AdviceInputs::default(), miden_processor::ExecutionOptions::default(), - ); + ) + .expect("processor advice inputs should fit advice map limits"); // Namely, this checks that execution doesn't panic due to an overflow. assert!(matches!( diff --git a/prover/Cargo.toml b/prover/Cargo.toml index 365f58dfd9..4faa3d02f8 100644 --- a/prover/Cargo.toml +++ b/prover/Cargo.toml @@ -15,28 +15,22 @@ edition.workspace = true [features] default = ["std"] -concurrent = ["std", "miden-crypto/concurrent", "miden-processor/concurrent"] +concurrent = ["std", "miden-air/concurrent", "miden-crypto/concurrent", "miden-processor/concurrent"] std = ["miden-air/std", "miden-debug-types/std", "miden-processor/std"] [dependencies] # Miden dependencies miden-air.workspace = true miden-core.workspace = true -miden-debug-types.workspace = true miden-processor.workspace = true miden-crypto.workspace = true # External dependencies bincode.workspace = true serde.workspace = true -thiserror.workspace = true tracing.workspace = true -# Platform-specific tokio dependencies -# On non-wasm targets, enable rt-multi-thread for better performance -[target.'cfg(not(target_family = "wasm"))'.dependencies] -tokio = { workspace = true, features = ["rt", "rt-multi-thread"] } - -# On wasm32, only basic tokio features are supported -[target.'cfg(target_family = "wasm")'.dependencies] -tokio = { workspace = true, features = ["rt", "macros"] } +[dev-dependencies] +miden-assembly.workspace = true +miden-debug-types.workspace = true +tokio = { workspace = true, features = ["macros", "rt"] } diff --git a/prover/src/lib.rs b/prover/src/lib.rs index 4a915c9019..5b67eb650e 100644 --- a/prover/src/lib.rs +++ b/prover/src/lib.rs @@ -8,17 +8,13 @@ extern crate std; use alloc::{string::ToString, vec::Vec}; use ::serde::Serialize; -use miden_core::{ - Felt, - field::QuadFelt, - utils::{Matrix, RowMajorMatrix}, -}; +use miden_core::{Felt, WORD_SIZE, field::QuadFelt, utils::RowMajorMatrix}; use miden_crypto::stark::{ StarkConfig, air::VarLenPublicInputs, challenger::CanObserve, lmcs::Lmcs, proof::StarkOutput, }; use miden_processor::{ FastProcessor, Program, - trace::{AuxTraceBuilders, build_trace}, + trace::{ExecutionTrace, build_trace}, }; use tracing::instrument; @@ -29,23 +25,43 @@ mod proving_options; pub use miden_air::{DeserializationError, ProcessorAir, PublicInputs, config}; pub use miden_core::proof::{ExecutionProof, HashFunction}; pub use miden_processor::{ - ExecutionError, Host, InputError, StackInputs, StackOutputs, Word, advice::AdviceInputs, - crypto, field, serde, utils, + ExecutionError, ExecutionOptions, ExecutionOutput, FutureMaybeSend, Host, InputError, + ProgramInfo, StackInputs, StackOutputs, SyncHost, TraceBuildInputs, TraceGenerationContext, + Word, advice::AdviceInputs, crypto, field, serde, utils, }; pub use proving_options::ProvingOptions; +/// Inputs required to prove from pre-executed trace data. +#[derive(Debug)] +pub struct TraceProvingInputs { + trace_inputs: TraceBuildInputs, + options: ProvingOptions, +} + +impl TraceProvingInputs { + /// Creates a new bundle of post-execution trace inputs and proof-generation options. + pub fn new(trace_inputs: TraceBuildInputs, options: ProvingOptions) -> Self { + Self { trace_inputs, options } + } + + /// Consumes this bundle and returns its trace inputs and proof-generation options. + pub fn into_parts(self) -> (TraceBuildInputs, ProvingOptions) { + (self.trace_inputs, self.options) + } +} + // PROVER // ================================================================================================ /// Executes and proves the specified `program` and returns the result together with a STARK-based /// proof of the program's execution. /// -/// This is an async function that works on all platforms including wasm32. -/// /// - `stack_inputs` specifies the initial state of the stack for the VM. +/// - `advice_inputs` provides the initial nondeterministic inputs for the VM. /// - `host` specifies the host environment which contain non-deterministic (secret) inputs for the -/// prover -/// - `options` defines parameters for STARK proof generation. +/// prover. +/// - `execution_options` defines VM execution parameters such as cycle limits and fragmentation. +/// - `proving_options` defines parameters for STARK proof generation. /// /// # Errors /// Returns an error if program execution or STARK proof generation fails for any reason. @@ -55,17 +71,52 @@ pub async fn prove( stack_inputs: StackInputs, advice_inputs: AdviceInputs, host: &mut impl Host, - options: ProvingOptions, + execution_options: ExecutionOptions, + proving_options: ProvingOptions, ) -> Result<(StackOutputs, ExecutionProof), ExecutionError> { // execute the program to create an execution trace using FastProcessor - let processor = - FastProcessor::new_with_options(stack_inputs, advice_inputs, *options.execution_options()); + let processor = FastProcessor::new_with_options(stack_inputs, advice_inputs, execution_options) + .map_err(ExecutionError::advice_error_no_context)?; - let (execution_output, trace_generation_context) = - processor.execute_for_trace(program, host).await?; + let trace_inputs = processor.execute_trace_inputs(program, host).await?; + prove_from_trace_sync(TraceProvingInputs::new(trace_inputs, proving_options)) +} - let trace = build_trace(execution_output, trace_generation_context, program.to_info())?; +/// Synchronous wrapper for [`prove()`]. +#[instrument("prove_program_sync", skip_all)] +pub fn prove_sync( + program: &Program, + stack_inputs: StackInputs, + advice_inputs: AdviceInputs, + host: &mut impl SyncHost, + execution_options: ExecutionOptions, + proving_options: ProvingOptions, +) -> Result<(StackOutputs, ExecutionProof), ExecutionError> { + let processor = FastProcessor::new_with_options(stack_inputs, advice_inputs, execution_options) + .map_err(ExecutionError::advice_error_no_context)?; + let trace_inputs = processor.execute_trace_inputs_sync(program, host)?; + prove_from_trace_sync(TraceProvingInputs::new(trace_inputs, proving_options)) +} + +/// Builds an execution trace from pre-executed trace inputs and proves it synchronously. +/// +/// This is useful when program execution has already happened elsewhere and only trace building +/// plus proof generation remain. The execution settings are already reflected in the supplied +/// `TraceBuildInputs`, so only proof-generation options remain in this API. +#[instrument("prove_trace_sync", skip_all)] +pub fn prove_from_trace_sync( + inputs: TraceProvingInputs, +) -> Result<(StackOutputs, ExecutionProof), ExecutionError> { + let (trace_inputs, options) = inputs.into_parts(); + let trace = build_trace(trace_inputs)?; + prove_execution_trace(trace, options) +} + +fn prove_execution_trace( + trace: ExecutionTrace, + options: ProvingOptions, +) -> Result<(StackOutputs, ExecutionProof), ExecutionError> { tracing::event!( tracing::Level::INFO, "Generated execution trace of {} columns and {} steps (padded from {})", @@ -78,41 +129,35 @@ pub async fn prove( let precompile_requests = trace.precompile_requests().to_vec(); let hash_fn = options.hash_fn(); - // Convert trace to row-major format let trace_matrix = { let _span = tracing::info_span!("to_row_major_matrix").entered(); trace.to_row_major_matrix() }; - // Build public inputs and extract fixed/variable-length components let (public_values, kernel_felts) = trace.public_inputs().to_air_inputs(); let var_len_public_inputs: &[&[Felt]] = &[&kernel_felts]; - // Get aux trace builders - let aux_builder = trace.aux_trace_builders(); - - // Generate STARK proof using lifted prover let params = config::pcs_params(); let proof_bytes = match hash_fn { HashFunction::Blake3_256 => { let config = config::blake3_256_config(params); - prove_stark(&config, &trace_matrix, &public_values, var_len_public_inputs, &aux_builder) + prove_stark(&config, &trace_matrix, &public_values, var_len_public_inputs) }, HashFunction::Keccak => { let config = config::keccak_config(params); - prove_stark(&config, &trace_matrix, &public_values, var_len_public_inputs, &aux_builder) + prove_stark(&config, &trace_matrix, &public_values, var_len_public_inputs) }, HashFunction::Rpo256 => { let config = config::rpo_config(params); - prove_stark(&config, &trace_matrix, &public_values, var_len_public_inputs, &aux_builder) + prove_stark(&config, &trace_matrix, &public_values, var_len_public_inputs) }, HashFunction::Poseidon2 => { let config = config::poseidon2_config(params); - prove_stark(&config, &trace_matrix, &public_values, var_len_public_inputs, &aux_builder) + prove_stark(&config, &trace_matrix, &public_values, var_len_public_inputs) }, HashFunction::Rpx256 => { let config = config::rpx_config(params); - prove_stark(&config, &trace_matrix, &public_values, var_len_public_inputs, &aux_builder) + prove_stark(&config, &trace_matrix, &public_values, var_len_public_inputs) }, }?; @@ -120,42 +165,6 @@ pub async fn prove( Ok((stack_outputs, proof)) } - -/// Synchronous wrapper for the async `prove()` function. -/// -/// This method is only available on non-wasm32 targets. On wasm32, use the -/// async `prove()` method directly since wasm32 runs in the browser's event loop. -/// -/// # Panics -/// Panics if called from within an existing Tokio runtime. Use the async `prove()` -/// method instead in async contexts. -#[cfg(not(target_family = "wasm"))] -#[instrument("prove_program_sync", skip_all)] -pub fn prove_sync( - program: &Program, - stack_inputs: StackInputs, - advice_inputs: AdviceInputs, - host: &mut impl Host, - options: ProvingOptions, -) -> Result<(StackOutputs, ExecutionProof), ExecutionError> { - match tokio::runtime::Handle::try_current() { - Ok(_handle) => { - // We're already inside a Tokio runtime - this is not supported - // because we cannot safely create a nested runtime or move the - // non-Send host reference to another thread - panic!( - "Cannot call prove_sync from within a Tokio runtime. \ - Use the async prove() method instead." - ) - }, - Err(_) => { - // No runtime exists - create one and use it - let rt = tokio::runtime::Builder::new_current_thread().build().unwrap(); - rt.block_on(prove(program, stack_inputs, advice_inputs, host, options)) - }, - } -} - // STARK PROOF GENERATION // ================================================================================================ @@ -168,36 +177,27 @@ pub fn prove_stark( trace: &RowMajorMatrix, public_values: &[Felt], var_len_public_inputs: VarLenPublicInputs<'_, Felt>, - aux_builder: &AuxTraceBuilders, ) -> Result, ExecutionError> where SC: StarkConfig, ::Commitment: Serialize, { - let log_trace_height = trace.height().ilog2() as u8; - let mut challenger = config.challenger(); + config::observe_protocol_params(&mut challenger); challenger.observe_slice(public_values); - // TODO: observe log_trace_height in the transcript for Fiat-Shamir binding. - // TODO: observe var_len_public_inputs in the transcript for Fiat-Shamir binding. - // This also requires updating the recursive verifier to absorb both fixed and - // variable-length public inputs. - // TODO: observe ACE commitment once ACE verification is integrated. - // See https://github.com/0xMiden/miden-vm/issues/2822 + config::observe_var_len_public_inputs(&mut challenger, var_len_public_inputs, &[WORD_SIZE]); let output: StarkOutput = miden_crypto::stark::prover::prove_single( config, &ProcessorAir, trace, public_values, var_len_public_inputs, - aux_builder, + &ProcessorAir, challenger, ) .map_err(|e| ExecutionError::ProvingError(e.to_string()))?; - // Proof serialization via bincode; see https://github.com/0xMiden/miden-vm/issues/2550 - // We serialize `(log_trace_height, proof)` as a tuple; this is a temporary approach until - // the lifted STARK integrates trace height on its side. - let proof_bytes = bincode::serialize(&(log_trace_height, &output.proof)) + // Proof serialization via bincode; see https://github.com/0xMiden/miden-vm/issues/2550. + let proof_bytes = bincode::serialize(&output.proof) .map_err(|e| ExecutionError::ProvingError(e.to_string()))?; Ok(proof_bytes) } diff --git a/prover/src/proving_options.rs b/prover/src/proving_options.rs index ba77c82e76..fd345f6252 100644 --- a/prover/src/proving_options.rs +++ b/prover/src/proving_options.rs @@ -1,17 +1,15 @@ use miden_core::proof::HashFunction; -use miden_processor::ExecutionOptions; // PROVING OPTIONS // ================================================================================================ /// A set of parameters specifying how Miden VM execution proofs are to be generated. /// -/// This struct combines execution options (VM parameters) with the hash function to use -/// for proof generation. The actual STARK proving parameters (FRI config, security level, etc.) -/// are determined by the hash function and hardcoded in the prover's config module. +/// This struct stores the proof-generation hash function only. The actual STARK proving parameters +/// (FRI config, security level, etc.) are determined by the hash function and hardcoded in the +/// prover's config module. #[derive(Debug, Clone, Eq, PartialEq)] pub struct ProvingOptions { - exec_options: ExecutionOptions, hash_fn: HashFunction, } @@ -24,10 +22,7 @@ impl ProvingOptions { /// The STARK proving parameters (security level, FRI config, etc.) are determined /// by the hash function and hardcoded in the prover's config module. pub fn new(hash_fn: HashFunction) -> Self { - Self { - exec_options: ExecutionOptions::default(), - hash_fn, - } + Self { hash_fn } } /// Creates a new instance of [ProvingOptions] targeting 96-bit security level. @@ -38,27 +33,10 @@ impl ProvingOptions { Self::new(hash_fn) } - /// Sets [ExecutionOptions] for this [ProvingOptions]. - /// - /// This sets the maximum number of cycles a program is allowed to execute as well as - /// the number of cycles the program is expected to execute. - pub fn with_execution_options(mut self, exec_options: ExecutionOptions) -> Self { - self.exec_options = exec_options; - self - } - - // PUBLIC ACCESSORS - // -------------------------------------------------------------------------------------------- - /// Returns the hash function to be used in STARK proof generation. pub const fn hash_fn(&self) -> HashFunction { self.hash_fn } - - /// Returns the execution options specified for this [ProvingOptions] - pub const fn execution_options(&self) -> &ExecutionOptions { - &self.exec_options - } } impl Default for ProvingOptions { diff --git a/prover/tests/async_compat.rs b/prover/tests/async_compat.rs new file mode 100644 index 0000000000..80813e225f --- /dev/null +++ b/prover/tests/async_compat.rs @@ -0,0 +1,125 @@ +use std::sync::Arc; + +use miden_assembly::Assembler; +use miden_debug_types::{Location, SourceFile, SourceSpan}; +use miden_processor::{ + BaseHost, DefaultHost, ExecutionOptions, Felt, FutureMaybeSend, Host, ProcessorState, Word, + advice::AdviceMutation, + event::{EventError, EventName}, + mast::MastForest, +}; +use miden_prover::{AdviceInputs, ProvingOptions, StackInputs, prove, prove_sync}; + +struct YieldingAsyncHost { + event_calls: usize, +} + +impl YieldingAsyncHost { + fn new() -> Self { + Self { event_calls: 0 } + } +} + +impl BaseHost for YieldingAsyncHost { + fn get_label_and_source_file( + &self, + _location: &Location, + ) -> (SourceSpan, Option>) { + (SourceSpan::UNKNOWN, None) + } +} + +impl Host for YieldingAsyncHost { + fn get_mast_forest( + &self, + _node_digest: &Word, + ) -> impl FutureMaybeSend>> { + async { None } + } + + fn on_event( + &mut self, + _process: &ProcessorState<'_>, + ) -> impl FutureMaybeSend, EventError>> { + self.event_calls += 1; + async { + tokio::task::yield_now().await; + Ok(Vec::new()) + } + } +} + +fn simple_program() -> miden_processor::Program { + Assembler::default() + .assemble_program( + r#" + begin + repeat.64 + swap dup.1 add + end + end + "#, + ) + .expect("program should compile") +} + +#[tokio::test(flavor = "current_thread")] +async fn prove_async_matches_prove() { + let program = simple_program(); + let stack_inputs = StackInputs::new(&[Felt::new_unchecked(0), Felt::new_unchecked(1)]).unwrap(); + let advice_inputs = AdviceInputs::default(); + let execution_options = ExecutionOptions::default(); + let options = ProvingOptions::default(); + + let mut sync_host = DefaultHost::default(); + let (sync_outputs, sync_proof) = prove_sync( + &program, + stack_inputs, + advice_inputs.clone(), + &mut sync_host, + execution_options, + options.clone(), + ) + .unwrap(); + + let mut async_host = DefaultHost::default(); + let (async_outputs, async_proof) = prove( + &program, + stack_inputs, + advice_inputs, + &mut async_host, + execution_options, + options, + ) + .await + .unwrap(); + + assert_eq!(sync_outputs, async_outputs); + assert_eq!(sync_proof.hash_fn(), async_proof.hash_fn()); + assert!(!sync_proof.stark_proof().is_empty()); + assert!(!async_proof.stark_proof().is_empty()); +} + +#[tokio::test(flavor = "current_thread")] +async fn prove_async_supports_async_only_host_events() { + let event_name = EventName::new("test::async::prove"); + let event_id = event_name.to_event_id().as_u64(); + let program = Assembler::default() + .assemble_program(format!("begin push.{event_id} emit drop end")) + .expect("program should compile"); + + let mut host = YieldingAsyncHost::new(); + let (_outputs, proof) = prove( + &program, + StackInputs::default(), + AdviceInputs::default(), + &mut host, + ExecutionOptions::default(), + ProvingOptions::default(), + ) + .await + .expect("async proving should succeed"); + + assert_eq!(host.event_calls, 1); + assert!(!proof.stark_proof().is_empty()); +} diff --git a/rust-toolchain.toml b/rust-toolchain.toml index eef0263e45..bc6ef46b66 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,5 +1,5 @@ [toolchain] -channel = "1.90" +channel = "1.95" components = ["rustfmt", "rust-src", "clippy"] targets = ["wasm32-unknown-unknown"] profile = "minimal" diff --git a/scripts/blake3_nonregression.py b/scripts/blake3_nonregression.py new file mode 100644 index 0000000000..703c3d5966 --- /dev/null +++ b/scripts/blake3_nonregression.py @@ -0,0 +1,525 @@ +#!/usr/bin/env python3 + +from __future__ import annotations + +import argparse +import json +import os +import re +import subprocess +import sys +import time +from pathlib import Path +from typing import Any + +BENCHMARK_PATH = "./miden-vm/masm-examples/hashing/blake3_1to1/blake3_1to1.masm" +BENCHMARK_COMMAND = [ + "./target/optimized/miden-vm", + "prove", + BENCHMARK_PATH, + "--release", +] + +ANSI_RE = re.compile(r"\x1B\[[0-?]*[ -/]*[@-~]") +TIMING_RE = re.compile( + r"^(?:(?P(?:[ \u2502]{3})*)(?P[\u251d\u2515]\u2501)\s+)?" + r"(?P.+?)\s+\[\s*(?P[^|]+?)\s*\|" +) +PROGRAM_PROVED_RE = re.compile(r"^Program proved in (?P\d+) ms$") + +KEY_METRICS = [ + ("prove_program_sync", "prove_program_sync"), + ( + "prove_program_sync > execute_trace_inputs_sync", + "execute_trace_inputs_sync", + ), + ("prove_program_sync > prove_trace_sync", "prove_trace_sync"), + ("prove_program_sync > prove_trace_sync > build_trace", "build_trace"), + ( + "prove_program_sync > prove_trace_sync > to_row_major_matrix", + "to_row_major_matrix", + ), + ("prove_program_sync > prove_trace_sync > prove", "prove"), + ( + "prove_program_sync > prove_trace_sync > prove > commit to main traces", + "commit to main traces", + ), + ( + "prove_program_sync > prove_trace_sync > prove > build_aux_trace", + "build_aux_trace", + ), + ( + "prove_program_sync > prove_trace_sync > prove > commit to aux traces", + "commit to aux traces", + ), + ( + "prove_program_sync > prove_trace_sync > prove > evaluate constraints", + "evaluate constraints", + ), + ( + "prove_program_sync > prove_trace_sync > prove > commit to quotient poly chunks", + "commit to quotient poly chunks", + ), + ("prove_program_sync > prove_trace_sync > prove > open", "open"), +] + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser( + description="Run and compare the blake3 1-to-1 non-regression benchmark." + ) + subparsers = parser.add_subparsers(dest="command", required=True) + + parse_log = subparsers.add_parser("parse-log", help="Parse a prove log into JSON.") + parse_log.add_argument("--log", required=True, type=Path) + parse_log.add_argument("--output", required=True, type=Path) + parse_log.add_argument("--repo-root", type=Path) + parse_log.add_argument("--build-wall-ms", type=float) + parse_log.add_argument("--prove-wall-ms", type=float) + parse_log.add_argument("--rayon-num-threads", type=int) + parse_log.add_argument("--git-ref") + + run = subparsers.add_parser("run", help="Build from clean state and run the benchmark.") + run.add_argument("--repo-root", required=True, type=Path) + run.add_argument("--output-dir", required=True, type=Path) + run.add_argument("--rayon-num-threads", type=int, default=8) + run.add_argument("--git-ref", default="") + + compare = subparsers.add_parser( + "compare", help="Compare two parsed benchmark result JSON files." + ) + compare.add_argument("--baseline", required=True, type=Path) + compare.add_argument("--current", required=True, type=Path) + compare.add_argument("--summary-out", required=True, type=Path) + compare.add_argument("--json-out", required=True, type=Path) + compare.add_argument("--threshold-pct", required=True, type=float) + compare.add_argument("--github-output", type=Path) + + return parser.parse_args() + + +def strip_ansi(text: str) -> str: + return ANSI_RE.sub("", text) + + +def parse_duration_ms(raw: str) -> float: + value = raw.strip() + if value.endswith("ms"): + return float(value[:-2]) + if value.endswith("us"): + return float(value[:-2]) / 1000.0 + if value.endswith("\u00b5s"): + return float(value[:-2]) / 1000.0 + if value.endswith("ns"): + return float(value[:-2]) / 1_000_000.0 + if value.endswith("s"): + return float(value[:-1]) * 1000.0 + raise ValueError(f"Unsupported duration format: {raw}") + + +def run_logged_command( + command: list[str], + *, + cwd: Path, + env: dict[str, str] | None, + log_path: Path, +) -> float: + start = time.perf_counter() + with log_path.open("w", encoding="utf-8") as handle: + handle.write(f"$ {' '.join(command)}\n") + handle.flush() + + process = subprocess.Popen( + command, + cwd=cwd, + env=env, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + text=True, + bufsize=1, + ) + assert process.stdout is not None + + for line in process.stdout: + sys.stdout.write(line) + handle.write(line) + + code = process.wait() + if code != 0: + raise subprocess.CalledProcessError(code, command) + + return (time.perf_counter() - start) * 1000.0 + + +def current_sha(repo_root: Path) -> str: + return subprocess.check_output( + ["git", "rev-parse", "HEAD"], cwd=repo_root, text=True + ).strip() + + +def parse_log_contents(contents: str) -> dict[str, Any]: + timings: list[dict[str, Any]] = [] + first_by_base_path: dict[str, float] = {} + stack: list[str] = [] + path_counts: dict[str, int] = {} + program_proved_ms: float | None = None + + for line_number, raw_line in enumerate(contents.splitlines(), start=1): + line = strip_ansi(raw_line) + + proved_match = PROGRAM_PROVED_RE.match(line) + if proved_match: + program_proved_ms = float(proved_match.group("ms")) + continue + + if not line.startswith("INFO"): + continue + + rest = line[4:] + if rest.startswith(" "): + rest = rest[5:] + else: + rest = rest.lstrip(" ") + + match = TIMING_RE.match(rest) + if not match: + continue + + depth = 0 + if match.group("branch"): + depth = (len(match.group("prefix") or "") // 3) + 1 + + name = match.group("name").strip() + duration_ms = parse_duration_ms(match.group("duration")) + + stack = stack[:depth] + stack.append(name) + base_path = " > ".join(stack) + occurrence = path_counts.get(base_path, 0) + 1 + path_counts[base_path] = occurrence + unique_path = base_path if occurrence == 1 else f"{base_path} [{occurrence}]" + + first_by_base_path.setdefault(base_path, duration_ms) + timings.append( + { + "name": name, + "base_path": base_path, + "path": unique_path, + "depth": depth, + "duration_ms": duration_ms, + "line": line_number, + } + ) + + if program_proved_ms is None and "prove_program_sync" in first_by_base_path: + program_proved_ms = first_by_base_path["prove_program_sync"] + + if program_proved_ms is None: + raise ValueError("Could not find the overall prove time in the benchmark log.") + + key_metrics = { + label: first_by_base_path[path] + for path, label in KEY_METRICS + if path in first_by_base_path + } + + return { + "program_proved_ms": program_proved_ms, + "timings": timings, + "timings_by_base_path": first_by_base_path, + "key_metrics": key_metrics, + } + + +def parse_log_file( + log_path: Path, + *, + repo_root: Path | None, + git_ref: str | None, + build_wall_ms: float | None, + prove_wall_ms: float | None, + rayon_num_threads: int | None, +) -> dict[str, Any]: + parsed = parse_log_contents(log_path.read_text(encoding="utf-8")) + metadata = { + "log_path": str(log_path), + "git_ref": git_ref or "", + "rayon_num_threads": rayon_num_threads, + "build_wall_ms": build_wall_ms, + "prove_wall_ms": prove_wall_ms, + } + if repo_root is not None: + metadata["repo_root"] = str(repo_root) + metadata["git_sha"] = current_sha(repo_root) + return {**metadata, **parsed} + + +def write_json(path: Path, payload: dict[str, Any]) -> None: + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text(json.dumps(payload, indent=2, sort_keys=True) + "\n", encoding="utf-8") + + +def format_ms(value: float | None) -> str: + if value is None: + return "n/a" + return f"{value:,.2f} ms" + + +def format_delta(value: float) -> str: + sign = "+" if value >= 0 else "" + return f"{sign}{value:,.2f} ms" + + +def format_pct(value: float | None) -> str: + if value is None: + return "n/a" + sign = "+" if value >= 0 else "" + return f"{sign}{value:.2f}%" + + +def percent_delta(current: float | None, baseline: float | None) -> float | None: + if baseline in (None, 0) or current is None: + return None + return ((current - baseline) / baseline) * 100.0 + + +def format_optional_delta(current: float | None, baseline: float | None) -> str: + if current is None or baseline is None: + return "n/a" + return format_delta(current - baseline) + + +def build_stage_rows( + baseline: dict[str, Any], + current: dict[str, Any], +) -> list[dict[str, Any]]: + rows: list[dict[str, Any]] = [] + baseline_metrics = baseline.get("key_metrics", {}) + current_metrics = current.get("key_metrics", {}) + + for _, label in KEY_METRICS: + baseline_ms = baseline_metrics.get(label) + current_ms = current_metrics.get(label) + if baseline_ms is None or current_ms is None: + continue + delta_ms = current_ms - baseline_ms + delta_pct = percent_delta(current_ms, baseline_ms) + rows.append( + { + "stage": label, + "baseline_ms": baseline_ms, + "current_ms": current_ms, + "delta_ms": delta_ms, + "delta_pct": delta_pct, + } + ) + + return rows + + +def compare_results( + baseline: dict[str, Any], + current: dict[str, Any], + threshold_pct: float, +) -> dict[str, Any]: + baseline_total = baseline["program_proved_ms"] + current_total = current["program_proved_ms"] + delta_ms = current_total - baseline_total + delta_pct = percent_delta(current_total, baseline_total) + regression = bool(delta_pct is not None and delta_pct > threshold_pct) + stage_rows = build_stage_rows(baseline, current) + + slowdown_rows = [ + row + for row in stage_rows + if row["delta_pct"] is not None + and row["delta_pct"] > 0 + and row["stage"] != "prove_program_sync" + ] + slowdown_rows.sort(key=lambda row: row["delta_pct"], reverse=True) + + result = { + "status": "regression" if regression else "ok", + "regression": regression, + "threshold_pct": threshold_pct, + "baseline_sha": baseline.get("git_sha", ""), + "current_sha": current.get("git_sha", ""), + "baseline_ref": baseline.get("git_ref", ""), + "current_ref": current.get("git_ref", ""), + "baseline_program_proved_ms": baseline_total, + "current_program_proved_ms": current_total, + "program_delta_ms": delta_ms, + "program_delta_pct": delta_pct, + "baseline_build_wall_ms": baseline.get("build_wall_ms"), + "current_build_wall_ms": current.get("build_wall_ms"), + "baseline_prove_wall_ms": baseline.get("prove_wall_ms"), + "current_prove_wall_ms": current.get("prove_wall_ms"), + "stage_rows": stage_rows, + "top_slowdowns": slowdown_rows[:5], + } + return result + + +def summary_markdown(result: dict[str, Any]) -> str: + status_word = "REGRESSION" if result["regression"] else "OK" + baseline_sha = result["baseline_sha"][:12] or result["baseline_ref"] or "baseline" + current_sha = result["current_sha"][:12] or result["current_ref"] or "current" + stage_rows = result["stage_rows"] + top_slowdowns = result["top_slowdowns"] + + lines = [ + "# BENCHMARK REPORT: blake3-1to1-nonregression", + "", + "## Blake3 1-to-1 Non-Regression", + "", + f"Status: **{status_word}**", + f"Threshold: `{result['threshold_pct']:.2f}%`", + f"Baseline: `{baseline_sha}` ({format_ms(result['baseline_program_proved_ms'])})", + f"Current: `{current_sha}` ({format_ms(result['current_program_proved_ms'])})", + f"Overall delta: `{format_delta(result['program_delta_ms'])}` ({format_pct(result['program_delta_pct'])})", + "", + "| Metric | Baseline | Current | Delta | Delta % |", + "| --- | ---: | ---: | ---: | ---: |", + ( + "| build wall | " + f"{format_ms(result['baseline_build_wall_ms'])} | " + f"{format_ms(result['current_build_wall_ms'])} | " + f"{format_optional_delta(result['current_build_wall_ms'], result['baseline_build_wall_ms'])} | " + f"{format_pct(percent_delta(result['current_build_wall_ms'], result['baseline_build_wall_ms']))} |" + ), + ( + "| prove wall | " + f"{format_ms(result['baseline_prove_wall_ms'])} | " + f"{format_ms(result['current_prove_wall_ms'])} | " + f"{format_optional_delta(result['current_prove_wall_ms'], result['baseline_prove_wall_ms'])} | " + f"{format_pct(percent_delta(result['current_prove_wall_ms'], result['baseline_prove_wall_ms']))} |" + ), + ( + "| program proved | " + f"{format_ms(result['baseline_program_proved_ms'])} | " + f"{format_ms(result['current_program_proved_ms'])} | " + f"{format_delta(result['program_delta_ms'])} | " + f"{format_pct(result['program_delta_pct'])} |" + ), + ] + + if stage_rows: + lines.extend( + [ + "", + "| Stage | Baseline | Current | Delta | Delta % |", + "| --- | ---: | ---: | ---: | ---: |", + ] + ) + for row in stage_rows: + lines.append( + "| " + f"{row['stage']} | " + f"{format_ms(row['baseline_ms'])} | " + f"{format_ms(row['current_ms'])} | " + f"{format_delta(row['delta_ms'])} | " + f"{format_pct(row['delta_pct'])} |" + ) + + if top_slowdowns: + lines.extend(["", "Top slowdowns:"]) + for row in top_slowdowns: + lines.append( + "- " + f"`{row['stage']}` moved by {format_delta(row['delta_ms'])} " + f"({format_pct(row['delta_pct'])})." + ) + + return "\n".join(lines) + "\n" + + +def write_github_output(path: Path, result: dict[str, Any]) -> None: + lines = [ + f"status={result['status']}", + f"regression={'true' if result['regression'] else 'false'}", + f"baseline_sha={result['baseline_sha']}", + f"current_sha={result['current_sha']}", + f"program_delta_ms={result['program_delta_ms']:.6f}", + f"program_delta_pct={result['program_delta_pct']:.6f}", + ] + with path.open("a", encoding="utf-8") as handle: + handle.write("\n".join(lines) + "\n") + + +def cmd_parse_log(args: argparse.Namespace) -> int: + payload = parse_log_file( + args.log, + repo_root=args.repo_root, + git_ref=args.git_ref, + build_wall_ms=args.build_wall_ms, + prove_wall_ms=args.prove_wall_ms, + rayon_num_threads=args.rayon_num_threads, + ) + write_json(args.output, payload) + return 0 + + +def cmd_run(args: argparse.Namespace) -> int: + repo_root = args.repo_root.resolve() + output_dir = args.output_dir.resolve() + output_dir.mkdir(parents=True, exist_ok=True) + + build_log = output_dir / "build.log" + prove_log = output_dir / "prove.log" + result_json = output_dir / "result.json" + + run_logged_command(["cargo", "clean"], cwd=repo_root, env=os.environ.copy(), log_path=output_dir / "clean.log") + build_wall_ms = run_logged_command( + ["make", "exec-info"], + cwd=repo_root, + env=os.environ.copy(), + log_path=build_log, + ) + + prove_env = os.environ.copy() + prove_env["MIDEN_LOG"] = "info" + prove_env["RAYON_NUM_THREADS"] = str(args.rayon_num_threads) + prove_wall_ms = run_logged_command( + BENCHMARK_COMMAND, + cwd=repo_root, + env=prove_env, + log_path=prove_log, + ) + + payload = parse_log_file( + prove_log, + repo_root=repo_root, + git_ref=args.git_ref, + build_wall_ms=build_wall_ms, + prove_wall_ms=prove_wall_ms, + rayon_num_threads=args.rayon_num_threads, + ) + write_json(result_json, payload) + return 0 + + +def cmd_compare(args: argparse.Namespace) -> int: + baseline = json.loads(args.baseline.read_text(encoding="utf-8")) + current = json.loads(args.current.read_text(encoding="utf-8")) + result = compare_results(baseline, current, args.threshold_pct) + write_json(args.json_out, result) + args.summary_out.parent.mkdir(parents=True, exist_ok=True) + args.summary_out.write_text(summary_markdown(result), encoding="utf-8") + if args.github_output is not None: + write_github_output(args.github_output, result) + return 0 + + +def main() -> int: + args = parse_args() + if args.command == "parse-log": + return cmd_parse_log(args) + if args.command == "run": + return cmd_run(args) + if args.command == "compare": + return cmd_compare(args) + raise ValueError(f"Unhandled command: {args.command}") + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/scripts/check-changelog.sh b/scripts/check-changelog.sh index 7d7529daa2..e36238e3d4 100755 --- a/scripts/check-changelog.sh +++ b/scripts/check-changelog.sh @@ -3,11 +3,12 @@ set -uo pipefail CHANGELOG_FILE="${1:-CHANGELOG.md}" -if [ "${NO_CHANGELOG_LABEL}" = "true" ]; then +if [ "${NO_CHANGELOG_LABEL:-false}" = "true" ]; then # 'no changelog' set, so finish successfully echo "\"no changelog\" label has been set" exit 0 else + : "${BASE_REF:?BASE_REF is not set}" # a changelog check is required # fail if the diff is empty if git diff --exit-code "origin/${BASE_REF}" -- "${CHANGELOG_FILE}"; then diff --git a/scripts/publish-release.sh b/scripts/publish-release.sh deleted file mode 100755 index 8e6f6d8b97..0000000000 --- a/scripts/publish-release.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/sh - -# Deprecated: please use the Github actions workflow, -# This is meant to be used in a break-the-glass situation -# -# Expects -# 1. to be run from the root of the repository -# 2. for ~/.cargo/credentials.toml to contain your crates.io token (see -# https://doc.rust-lang.org/cargo/reference/publishing.html) -# -# It is recommended to run this script while still on the `next` branch right before merging it into -# `main`, so that if any error occurs, we can fix it and re-run the script directly without having -# to merge the fix into `next`, and then merge `next` into `main` again. - -cargo publish -p miden-utils-sync -cargo publish -p miden-utils-diagnostics -cargo publish -p miden-utils-indexing -cargo publish -p miden-debug-types -cargo publish -p miden-utils-core-derive -cargo publish -p miden-core -cargo publish -p miden-air -cargo publish -p miden-assembly-syntax -cargo publish -p miden-mast-package -cargo publish -p miden-assembly -cargo publish -p miden-processor -cargo publish -p miden-prover -cargo publish -p miden-verifier -cargo publish -p miden-core-lib -cargo publish -p miden-vm diff --git a/scripts/synthetic_tx_nonregression.py b/scripts/synthetic_tx_nonregression.py new file mode 100644 index 0000000000..2daf852b20 --- /dev/null +++ b/scripts/synthetic_tx_nonregression.py @@ -0,0 +1,519 @@ +#!/usr/bin/env python3 + +from __future__ import annotations + +import argparse +import json +import os +import subprocess +import sys +import time +import unittest +import unittest.mock as mock +from pathlib import Path +from typing import Any + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser( + description="Run and compare the synthetic transaction kernel non-regression benchmark." + ) + commands = parser.add_subparsers(dest="command", required=True) + + run = commands.add_parser("run", help="Build from clean state and run the benchmark.") + run.add_argument("--repo-root", required=True, type=Path) + run.add_argument("--output-dir", required=True, type=Path) + run.add_argument("--rayon-num-threads", type=int, default=8) + run.add_argument("--scenario-filter", default="") + run.add_argument("--sample-size", type=int) + run.add_argument("--measurement-time-secs", type=int) + run.add_argument("--warm-up-time-secs", type=int) + run.add_argument("--git-ref", default="") + + collect = commands.add_parser("collect", help="Collect Criterion estimates into JSON.") + collect.add_argument("--repo-root", required=True, type=Path) + collect.add_argument("--output", required=True, type=Path) + collect.add_argument("--bench-wall-ms", type=float) + collect.add_argument("--rayon-num-threads", type=int) + collect.add_argument("--scenario-filter", default="") + collect.add_argument("--git-ref", default="") + + compare = commands.add_parser("compare", help="Compare two benchmark result JSON files.") + compare.add_argument("--baseline", required=True, type=Path) + compare.add_argument("--current", required=True, type=Path) + compare.add_argument("--summary-out", required=True, type=Path) + compare.add_argument("--json-out", required=True, type=Path) + compare.add_argument("--threshold-pct", required=True, type=float) + compare.add_argument("--github-output", type=Path) + + self_test = commands.add_parser("self-test", help="Run parser and comparison tests.") + self_test.add_argument("--runs", type=int, default=1) + + return parser.parse_args() + + +def run_logged_command(command: list[str], *, cwd: Path, env: dict[str, str], log_path: Path) -> float: + start = time.perf_counter() + with log_path.open("w", encoding="utf-8") as handle: + handle.write(f"$ {' '.join(command)}\n") + handle.flush() + + process = subprocess.Popen( + command, + cwd=cwd, + env=env, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + text=True, + bufsize=1, + ) + assert process.stdout is not None + for line in process.stdout: + sys.stdout.write(line) + handle.write(line) + + code = process.wait() + if code != 0: + raise subprocess.CalledProcessError(code, command) + + return (time.perf_counter() - start) * 1000.0 + + +def current_sha(repo_root: Path) -> str: + return subprocess.check_output(["git", "rev-parse", "HEAD"], cwd=repo_root, text=True).strip() + + +def write_json(path: Path, payload: dict[str, Any]) -> None: + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text(json.dumps(payload, indent=2, sort_keys=True) + "\n", encoding="utf-8") + + +def parse_criterion_estimate_path(criterion_root: Path, estimates_path: Path) -> tuple[str, str, str]: + relative_parts = estimates_path.relative_to(criterion_root).parts + if len(relative_parts) == 5 and relative_parts[-2:] == ("new", "estimates.json"): + producer, scenario, axis = relative_parts[:3] + return producer, scenario, axis + + if len(relative_parts) == 4 and relative_parts[-2:] == ("new", "estimates.json"): + group, axis = relative_parts[:2] + producer, separator, scenario = group.partition("_") + if separator and scenario: + return producer, scenario, axis + + raise ValueError(f"Unexpected synthetic benchmark estimate path: {estimates_path}") + + +def collect_criterion_metrics(repo_root: Path, *, estimate: str = "mean") -> dict[str, dict[str, Any]]: + criterion_root = repo_root / "target" / "criterion" + metrics: dict[str, dict[str, Any]] = {} + + for estimates_path in sorted(criterion_root.glob("**/new/estimates.json")): + producer, scenario, axis = parse_criterion_estimate_path(criterion_root, estimates_path) + name = f"{producer}/{scenario}/{axis}" + estimate_data = json.loads(estimates_path.read_text(encoding="utf-8"))[estimate] + metrics[name] = { + "name": name, + "producer": producer, + "scenario": scenario, + "axis": axis, + "estimate_ms": float(estimate_data["point_estimate"]) / 1_000_000.0, + "low_ms": float(estimate_data["confidence_interval"]["lower_bound"]) / 1_000_000.0, + "high_ms": float(estimate_data["confidence_interval"]["upper_bound"]) / 1_000_000.0, + } + + if not metrics: + raise ValueError(f"No Criterion estimates found under {criterion_root}") + return dict(sorted(metrics.items())) + + +def collect_result( + repo_root: Path, + *, + git_ref: str, + bench_wall_ms: float | None, + rayon_num_threads: int | None, + scenario_filter: str, +) -> dict[str, Any]: + return { + "repo_root": str(repo_root), + "git_ref": git_ref, + "git_sha": current_sha(repo_root), + "bench_wall_ms": bench_wall_ms, + "rayon_num_threads": rayon_num_threads, + "scenario_filter": scenario_filter, + "metrics": collect_criterion_metrics(repo_root), + } + + +def cmd_run(args: argparse.Namespace) -> int: + repo_root = args.repo_root.resolve() + output_dir = args.output_dir.resolve() + output_dir.mkdir(parents=True, exist_ok=True) + + env = os.environ.copy() + env["RAYON_NUM_THREADS"] = str(args.rayon_num_threads) + if args.scenario_filter: + env["SYNTH_SCENARIO"] = args.scenario_filter + + run_logged_command(["cargo", "clean"], cwd=repo_root, env=env, log_path=output_dir / "clean.log") + + bench_command = [ + "cargo", + "bench", + "--profile", + "optimized", + "-p", + "miden-vm-synthetic-bench", + "--bench", + "synthetic_bench", + "--", + "--noplot", + ] + if args.sample_size is not None: + bench_command.extend(["--sample-size", str(args.sample_size)]) + if args.measurement_time_secs is not None: + bench_command.extend(["--measurement-time", str(args.measurement_time_secs)]) + if args.warm_up_time_secs is not None: + bench_command.extend(["--warm-up-time", str(args.warm_up_time_secs)]) + + bench_wall_ms = run_logged_command( + bench_command, cwd=repo_root, env=env, log_path=output_dir / "bench.log" + ) + write_json( + output_dir / "result.json", + collect_result( + repo_root, + git_ref=args.git_ref, + bench_wall_ms=bench_wall_ms, + rayon_num_threads=args.rayon_num_threads, + scenario_filter=args.scenario_filter, + ), + ) + return 0 + + +def cmd_collect(args: argparse.Namespace) -> int: + write_json( + args.output, + collect_result( + args.repo_root.resolve(), + git_ref=args.git_ref, + bench_wall_ms=args.bench_wall_ms, + rayon_num_threads=args.rayon_num_threads, + scenario_filter=args.scenario_filter, + ), + ) + return 0 + + +def percent_delta(current: float | None, baseline: float | None) -> float | None: + if baseline in (None, 0) or current is None: + return None + return ((current - baseline) / baseline) * 100.0 + + +def fmt_ms(value: float | None) -> str: + return "n/a" if value is None else f"{value:,.2f} ms" + + +def fmt_delta(value: float | None) -> str: + if value is None: + return "n/a" + return f"{'+' if value >= 0 else ''}{value:,.2f} ms" + + +def fmt_pct(value: float | None) -> str: + if value is None: + return "n/a" + return f"{'+' if value >= 0 else ''}{value:.2f}%" + + +def compare_results( + baseline: dict[str, Any], current: dict[str, Any], threshold_pct: float +) -> dict[str, Any]: + baseline_metrics = baseline.get("metrics", {}) + current_metrics = current.get("metrics", {}) + shared = sorted(set(baseline_metrics) & set(current_metrics)) + if not shared: + raise ValueError("Baseline and current benchmark results have no metric names in common.") + + rows = [] + for name in shared: + baseline_ms = baseline_metrics[name]["estimate_ms"] + current_ms = current_metrics[name]["estimate_ms"] + rows.append( + { + "name": name, + "baseline_ms": baseline_ms, + "current_ms": current_ms, + "delta_ms": current_ms - baseline_ms, + "delta_pct": percent_delta(current_ms, baseline_ms), + } + ) + rows.sort(key=lambda r: r["delta_pct"] if r["delta_pct"] is not None else float("-inf"), reverse=True) + worst = rows[0] + regression = bool(worst["delta_pct"] is not None and worst["delta_pct"] > threshold_pct) + return { + "status": "regression" if regression else "ok", + "regression": regression, + "threshold_pct": threshold_pct, + "baseline_sha": baseline.get("git_sha", ""), + "current_sha": current.get("git_sha", ""), + "baseline_ref": baseline.get("git_ref", ""), + "current_ref": current.get("git_ref", ""), + "baseline_bench_wall_ms": baseline.get("bench_wall_ms"), + "current_bench_wall_ms": current.get("bench_wall_ms"), + "max_delta_metric": worst["name"], + "max_delta_ms": worst["delta_ms"], + "max_delta_pct": worst["delta_pct"], + "metric_rows": rows, + "missing_in_current": sorted(set(baseline_metrics) - set(current_metrics)), + "missing_in_baseline": sorted(set(current_metrics) - set(baseline_metrics)), + } + + +def summary_markdown(result: dict[str, Any]) -> str: + status = "REGRESSION" if result["regression"] else "OK" + baseline = result["baseline_sha"][:12] or result["baseline_ref"] or "baseline" + current = result["current_sha"][:12] or result["current_ref"] or "current" + wall_delta = ( + None + if result["baseline_bench_wall_ms"] is None or result["current_bench_wall_ms"] is None + else result["current_bench_wall_ms"] - result["baseline_bench_wall_ms"] + ) + wall_delta_pct = percent_delta(result["current_bench_wall_ms"], result["baseline_bench_wall_ms"]) + over_threshold = [ + row + for row in result["metric_rows"] + if row["delta_pct"] is not None and row["delta_pct"] > result["threshold_pct"] + ] + metric_rows = result["metric_rows"] + lines = [ + "# BENCHMARK REPORT: synthetic-tx-kernel-nonregression", + "", + "## Synthetic Transaction Kernel Non-Regression", + "", + "### Run", + "", + f"- Baseline: `{baseline}`", + f"- Current: `{current}`", + f"- Threshold: `{result['threshold_pct']:.2f}%`", + "- Bench wall: " + f"{fmt_ms(result['baseline_bench_wall_ms'])} -> " + f"{fmt_ms(result['current_bench_wall_ms'])} " + f"({fmt_delta(wall_delta)}, {fmt_pct(wall_delta_pct)})", + "", + "### Result", + "", + f"- Status: **{status}**", + "- Worst regression: " + f"`{result['max_delta_metric']}` moved by " + f"`{fmt_delta(result['max_delta_ms'])}` ({fmt_pct(result['max_delta_pct'])})", + "", + "### Metrics over threshold", + "", + ] + if over_threshold: + lines.extend( + f"- `{row['name']}`: {fmt_delta(row['delta_ms'])} ({fmt_pct(row['delta_pct'])})" + for row in over_threshold + ) + else: + lines.append("- None") + lines += [ + "", + f"### Per-benchmark results ({len(metric_rows)} of {len(metric_rows)})", + "", + "| Benchmark | Baseline | Current | Delta | Delta % |", + "| --- | ---: | ---: | ---: | ---: |", + ] + lines += [ + ( + f"| {row['name']} | {fmt_ms(row['baseline_ms'])} | {fmt_ms(row['current_ms'])} | " + f"{fmt_delta(row['delta_ms'])} | {fmt_pct(row['delta_pct'])} |" + ) + for row in metric_rows + ] + if result["missing_in_current"] or result["missing_in_baseline"]: + lines.append("\nMetric set changed:") + if result["missing_in_current"]: + lines.append( + "- Missing in current: " + + ", ".join(f"`{name}`" for name in result["missing_in_current"][:10]) + ) + if result["missing_in_baseline"]: + lines.append( + "- Missing in baseline: " + + ", ".join(f"`{name}`" for name in result["missing_in_baseline"][:10]) + ) + return "\n".join(lines) + "\n" + + +def write_github_output(path: Path, result: dict[str, Any]) -> None: + with path.open("a", encoding="utf-8") as handle: + handle.write( + "\n".join( + [ + f"status={result['status']}", + f"regression={'true' if result['regression'] else 'false'}", + f"baseline_sha={result['baseline_sha']}", + f"current_sha={result['current_sha']}", + f"max_delta_metric={result['max_delta_metric']}", + f"max_delta_ms={result['max_delta_ms']:.6f}", + f"max_delta_pct={result['max_delta_pct']:.6f}", + ] + ) + + "\n" + ) + + +def cmd_compare(args: argparse.Namespace) -> int: + result = compare_results( + json.loads(args.baseline.read_text(encoding="utf-8")), + json.loads(args.current.read_text(encoding="utf-8")), + args.threshold_pct, + ) + write_json(args.json_out, result) + args.summary_out.parent.mkdir(parents=True, exist_ok=True) + args.summary_out.write_text(summary_markdown(result), encoding="utf-8") + if args.github_output is not None: + write_github_output(args.github_output, result) + return 0 + + +class Tests(unittest.TestCase): + def test_collect_criterion_estimate(self) -> None: + with mock.patch("subprocess.check_output", return_value="abc\n"): + root = Path(self.id().replace("/", "_")) + estimates = ( + root + / "target" + / "criterion" + / "bench-tx" + / "consume-single-p2id-note" + / "prove" + / "new" + / "estimates.json" + ) + estimates.parent.mkdir(parents=True, exist_ok=True) + write_json( + estimates, + { + "mean": { + "point_estimate": 1_500_000.0, + "confidence_interval": {"lower_bound": 1_000_000.0, "upper_bound": 2_000_000.0}, + } + }, + ) + try: + metrics = collect_criterion_metrics(root) + self.assertEqual(metrics["bench-tx/consume-single-p2id-note/prove"]["estimate_ms"], 1.5) + finally: + subprocess.run(["rm", "-rf", str(root)], check=False) + + def test_collect_criterion_estimate_from_sanitized_group_dir(self) -> None: + with mock.patch("subprocess.check_output", return_value="abc\n"): + root = Path(self.id().replace("/", "_")) + estimates = ( + root + / "target" + / "criterion" + / "bench-tx_create-single-p2id-note" + / "prove" + / "new" + / "estimates.json" + ) + estimates.parent.mkdir(parents=True, exist_ok=True) + write_json( + estimates, + { + "mean": { + "point_estimate": 1_500_000.0, + "confidence_interval": {"lower_bound": 1_000_000.0, "upper_bound": 2_000_000.0}, + } + }, + ) + try: + metrics = collect_criterion_metrics(root) + self.assertEqual(metrics["bench-tx/create-single-p2id-note/prove"]["estimate_ms"], 1.5) + finally: + subprocess.run(["rm", "-rf", str(root)], check=False) + + def test_compare_uses_worst_positive_delta(self) -> None: + baseline = {"metrics": {"bench-tx/a/prove": {"estimate_ms": 100.0}, "bench-tx/a/verify": {"estimate_ms": 50.0}}} + current = {"metrics": {"bench-tx/a/prove": {"estimate_ms": 104.0}, "bench-tx/a/verify": {"estimate_ms": 60.0}}} + result = compare_results(baseline, current, 5.0) + self.assertTrue(result["regression"]) + self.assertEqual(result["max_delta_metric"], "bench-tx/a/verify") + + def test_summary_markdown_uses_requested_report_shape(self) -> None: + result = compare_results( + { + "git_sha": "1764d66ca1c6deadbeef", + "bench_wall_ms": 145_000.0, + "metrics": { + "bench-tx/consume-b2agg-note-bridge-out/exec": {"estimate_ms": 23.96}, + "bench-tx/consume-single-p2id-note/prove": {"estimate_ms": 1_987.33}, + }, + }, + { + "git_sha": "1234567890abcdef", + "bench_wall_ms": 152_000.0, + "metrics": { + "bench-tx/consume-b2agg-note-bridge-out/exec": {"estimate_ms": 23.96}, + "bench-tx/consume-single-p2id-note/prove": {"estimate_ms": 2_132.40}, + }, + }, + 5.0, + ) + + summary = summary_markdown(result) + + self.assertIn("# BENCHMARK REPORT: synthetic-tx-kernel-nonregression", summary) + self.assertIn("### Run", summary) + self.assertIn("- Baseline: `1764d66ca1c6`", summary) + self.assertIn("- Current: `1234567890ab`", summary) + self.assertIn("- Threshold: `5.00%`", summary) + self.assertIn("- Bench wall: 145,000.00 ms -> 152,000.00 ms (+7,000.00 ms, +4.83%)", summary) + self.assertIn("### Result", summary) + self.assertIn("- Status: **REGRESSION**", summary) + self.assertIn( + "- Worst regression: `bench-tx/consume-single-p2id-note/prove` moved by `+145.07 ms` (+7.30%)", + summary, + ) + self.assertIn("### Metrics over threshold", summary) + self.assertIn("- `bench-tx/consume-single-p2id-note/prove`: +145.07 ms (+7.30%)", summary) + self.assertIn("### Per-benchmark results (2 of 2)", summary) + self.assertIn( + "| bench-tx/consume-single-p2id-note/prove | 1,987.33 ms | 2,132.40 ms | +145.07 ms | +7.30% |", + summary, + ) + + +def cmd_self_test(args: argparse.Namespace) -> int: + for run in range(args.runs): + result = unittest.TextTestRunner(verbosity=1, stream=sys.stderr).run( + unittest.defaultTestLoader.loadTestsFromTestCase(Tests) + ) + if not result.wasSuccessful(): + return 1 + if args.runs > 1: + print(f"self-test run {run + 1}/{args.runs} passed") + return 0 + + +def main() -> int: + args = parse_args() + if args.command == "run": + return cmd_run(args) + if args.command == "collect": + return cmd_collect(args) + if args.command == "compare": + return cmd_compare(args) + if args.command == "self-test": + return cmd_self_test(args) + raise ValueError(f"Unhandled command: {args.command}") + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/verifier/src/lib.rs b/verifier/src/lib.rs index 11a13544e7..8f0a7a142d 100644 --- a/verifier/src/lib.rs +++ b/verifier/src/lib.rs @@ -8,10 +8,7 @@ extern crate std; use alloc::{boxed::Box, vec::Vec}; use miden_air::{ProcessorAir, PublicInputs, config}; -use miden_core::{ - Felt, - field::{QuadFelt, TwoAdicField}, -}; +use miden_core::{Felt, WORD_SIZE, field::QuadFelt}; use miden_crypto::stark::{ StarkConfig, air::VarLenPublicInputs, challenger::CanObserve, lmcs::Lmcs, proof::StarkProof, }; @@ -212,28 +209,16 @@ where SC: StarkConfig, ::Commitment: DeserializeOwned, { - // Proof deserialization via bincode; see https://github.com/0xMiden/miden-vm/issues/2550 - // The proof is serialized as a `(log_trace_height, stark_proof)` tuple; this is a temporary - // approach until the lifted STARK integrates trace height on its side. - let (log_trace_height, proof): (u8, StarkProof) = - bincode::deserialize(proof_bytes)?; - - if log_trace_height as usize > Felt::TWO_ADICITY { - return Err(StarkVerificationError::InvalidTraceHeight(log_trace_height)); - } + // Proof deserialization via bincode; see https://github.com/0xMiden/miden-vm/issues/2550. + let proof: StarkProof = bincode::deserialize(proof_bytes)?; let mut challenger = config.challenger(); + config::observe_protocol_params(&mut challenger); challenger.observe_slice(public_values); - // TODO: observe log_trace_height in the transcript for Fiat-Shamir binding. - // TODO: observe var_len_public_inputs in the transcript for Fiat-Shamir binding. - // This also requires updating the recursive verifier to absorb both fixed and - // variable-length public inputs. - // TODO: observe ACE commitment once ACE verification is integrated. - // See https://github.com/0xMiden/miden-vm/issues/2822 + config::observe_var_len_public_inputs(&mut challenger, var_len_public_inputs, &[WORD_SIZE]); miden_crypto::stark::verifier::verify_single( config, &ProcessorAir, - log_trace_height, public_values, var_len_public_inputs, &proof, diff --git a/zizmor.yml b/zizmor.yml new file mode 100644 index 0000000000..0648316e1d --- /dev/null +++ b/zizmor.yml @@ -0,0 +1,8 @@ +rules: + dangerous-triggers: + ignore: + - contribution-quality.yml + - signed-commits.yml + secrets-outside-env: + ignore: + - trigger-deploy-docs.yml